rapid interations of server side app and firefox extension

This commit is contained in:
Bryan Van Deusen
2026-01-24 22:52:51 -05:00
commit b9b8048a2d
81 changed files with 9675 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { downloadsApi } from '../services/api'
export const useDownloadsStore = defineStore('downloads', () => {
const downloads = ref([])
const stats = ref(null)
const loading = ref(false)
const total = ref(0)
const currentPage = ref(1)
const perPage = ref(20)
async function fetchDownloads(params = {}) {
loading.value = true
try {
const response = await downloadsApi.list({
page: currentPage.value,
per_page: perPage.value,
...params,
})
downloads.value = response.data.items
total.value = response.data.total
return response.data
} finally {
loading.value = false
}
}
async function fetchStats(params = {}) {
const response = await downloadsApi.stats(params)
stats.value = response.data
return response.data
}
async function retryDownload(id) {
return await downloadsApi.retry(id)
}
return {
downloads,
stats,
loading,
total,
currentPage,
perPage,
fetchDownloads,
fetchStats,
retryDownload,
}
})
+41
View File
@@ -0,0 +1,41 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useNotificationStore = defineStore('notifications', () => {
const show = ref(false)
const message = ref('')
const color = ref('info')
function notify(msg, type = 'info') {
message.value = msg
color.value = type
show.value = true
}
function success(msg) {
notify(msg, 'success')
}
function error(msg) {
notify(msg, 'error')
}
function warning(msg) {
notify(msg, 'warning')
}
function info(msg) {
notify(msg, 'info')
}
return {
show,
message,
color,
notify,
success,
error,
warning,
info,
}
})
+48
View File
@@ -0,0 +1,48 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { settingsApi } from '../services/api'
export const useSettingsStore = defineStore('settings', () => {
const settings = ref({})
const galleryDLConfig = ref({})
const loading = ref(false)
async function fetchSettings() {
loading.value = true
try {
const response = await settingsApi.get()
settings.value = response.data.settings
return response.data.settings
} finally {
loading.value = false
}
}
async function updateSettings(data) {
const response = await settingsApi.update(data)
settings.value = response.data.settings
return response.data.settings
}
async function fetchGalleryDLConfig() {
const response = await settingsApi.getGalleryDL()
galleryDLConfig.value = response.data.config
return response.data.config
}
async function updateGalleryDLConfig(config) {
const response = await settingsApi.updateGalleryDL(config)
galleryDLConfig.value = response.data.config
return response.data.config
}
return {
settings,
galleryDLConfig,
loading,
fetchSettings,
updateSettings,
fetchGalleryDLConfig,
updateGalleryDLConfig,
}
})
+69
View File
@@ -0,0 +1,69 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { sourcesApi } from '../services/api'
export const useSourcesStore = defineStore('sources', () => {
const sources = ref([])
const loading = ref(false)
const total = ref(0)
const currentPage = ref(1)
const perPage = ref(20)
const enabledSources = computed(() => sources.value.filter(s => s.enabled))
const disabledSources = computed(() => sources.value.filter(s => !s.enabled))
async function fetchSources(params = {}) {
loading.value = true
try {
const response = await sourcesApi.list({
page: currentPage.value,
per_page: perPage.value,
...params,
})
sources.value = response.data.items
total.value = response.data.total
return response.data
} finally {
loading.value = false
}
}
async function createSource(data) {
const response = await sourcesApi.create(data)
sources.value.push(response.data)
return response.data
}
async function updateSource(id, data) {
const response = await sourcesApi.update(id, data)
const index = sources.value.findIndex(s => s.id === id)
if (index !== -1) {
sources.value[index] = response.data
}
return response.data
}
async function deleteSource(id) {
await sourcesApi.delete(id)
sources.value = sources.value.filter(s => s.id !== id)
}
async function triggerCheck(id) {
return await sourcesApi.triggerCheck(id)
}
return {
sources,
loading,
total,
currentPage,
perPage,
enabledSources,
disabledSources,
fetchSources,
createSource,
updateSource,
deleteSource,
triggerCheck,
}
})
+112
View File
@@ -0,0 +1,112 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { subscriptionsApi, sourcesApi } from '../services/api'
export const useSubscriptionsStore = defineStore('subscriptions', () => {
const subscriptions = ref([])
const loading = ref(false)
const total = ref(0)
const currentPage = ref(1)
const perPage = ref(20)
const enabledSubscriptions = computed(() => subscriptions.value.filter(s => s.enabled))
const disabledSubscriptions = computed(() => subscriptions.value.filter(s => !s.enabled))
async function fetchSubscriptions(params = {}) {
loading.value = true
try {
const response = await subscriptionsApi.list({
page: currentPage.value,
per_page: perPage.value,
...params,
})
subscriptions.value = response.data.items
total.value = response.data.total
return response.data
} finally {
loading.value = false
}
}
async function getSubscription(id) {
const response = await subscriptionsApi.get(id)
return response.data
}
async function createSubscription(data) {
const response = await subscriptionsApi.create(data)
subscriptions.value.push(response.data)
return response.data
}
async function updateSubscription(id, data) {
const response = await subscriptionsApi.update(id, data)
const index = subscriptions.value.findIndex(s => s.id === id)
if (index !== -1) {
subscriptions.value[index] = response.data
}
return response.data
}
async function deleteSubscription(id) {
await subscriptionsApi.delete(id)
subscriptions.value = subscriptions.value.filter(s => s.id !== id)
}
async function triggerCheck(id) {
return await subscriptionsApi.triggerCheck(id)
}
async function addSource(subscriptionId, sourceData) {
const response = await subscriptionsApi.addSource(subscriptionId, sourceData)
// Update the subscription in the store
const index = subscriptions.value.findIndex(s => s.id === subscriptionId)
if (index !== -1 && subscriptions.value[index].sources) {
subscriptions.value[index].sources.push(response.data)
}
return response.data
}
async function deleteSource(sourceId) {
await sourcesApi.delete(sourceId)
// Update subscriptions that contain this source
for (const sub of subscriptions.value) {
if (sub.sources) {
sub.sources = sub.sources.filter(s => s.id !== sourceId)
}
}
}
async function updateSource(sourceId, data) {
const response = await sourcesApi.update(sourceId, data)
// Update in subscriptions
for (const sub of subscriptions.value) {
if (sub.sources) {
const idx = sub.sources.findIndex(s => s.id === sourceId)
if (idx !== -1) {
sub.sources[idx] = response.data
}
}
}
return response.data
}
return {
subscriptions,
loading,
total,
currentPage,
perPage,
enabledSubscriptions,
disabledSubscriptions,
fetchSubscriptions,
getSubscription,
createSubscription,
updateSubscription,
deleteSubscription,
triggerCheck,
addSource,
deleteSource,
updateSource,
}
})
+52
View File
@@ -0,0 +1,52 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { useWebSocket } from '../composables/useWebSocket'
import { useNotificationStore } from './notifications'
import { useDownloadsStore } from './downloads'
import { useSourcesStore } from './sources'
export const useWebSocketStore = defineStore('websocket', () => {
const { isConnected, subscribe } = useWebSocket()
const initialized = ref(false)
function init() {
if (initialized.value) return
initialized.value = true
const notifications = useNotificationStore()
const downloadsStore = useDownloadsStore()
const sourcesStore = useSourcesStore()
// Subscribe to download events
subscribe('download.started', (data) => {
notifications.info(`Download started for source ${data.source_id}`)
})
subscribe('download.completed', (data) => {
notifications.success(`Download completed: ${data.file_count} files`)
// Refresh downloads list
downloadsStore.fetchDownloads()
downloadsStore.fetchStats()
})
subscribe('download.failed', (data) => {
notifications.error(`Download failed: ${data.error_message}`)
downloadsStore.fetchDownloads()
})
// Subscribe to source events
subscribe('source.updated', (data) => {
sourcesStore.fetchSources()
})
// Subscribe to credential events
subscribe('credential.expiring', (data) => {
notifications.warning(`${data.platform} credentials expiring in ${data.expires_in_hours} hours`)
})
}
return {
isConnected,
init,
}
})