feat(fc2a): add SettingsView shell with Overview tab (SystemStatsCards)
Overview tab shows total images/tags/storage/pending/failed using Fraunces for the big numbers. Inline alert nudges the operator to the Import tab when pending tasks exist. Polls /api/system/stats every 5s while the tab is visible (pauses when the document is hidden). Import tab references three placeholders (TriggerPanel/FiltersForm/ TaskList); real implementations land in Task 15. Router replaces the placeholder view for /settings with SettingsView. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<v-container class="py-6">
|
||||
<h1 class="fc-h1 mb-6">Settings</h1>
|
||||
|
||||
<v-tabs v-model="tab" color="accent" class="mb-4">
|
||||
<v-tab value="overview">Overview</v-tab>
|
||||
<v-tab value="import">Import</v-tab>
|
||||
</v-tabs>
|
||||
|
||||
<v-window v-model="tab">
|
||||
<v-window-item value="overview">
|
||||
<SystemStatsCards :stats="system.stats" />
|
||||
<v-alert
|
||||
v-if="system.stats && (system.stats.tasks.pending + system.stats.tasks.queued) > 0"
|
||||
type="info" variant="tonal" class="mt-4" closable
|
||||
>
|
||||
{{ system.stats.tasks.pending + system.stats.tasks.queued }} import task(s) pending.
|
||||
<v-btn variant="text" size="small" @click="tab = 'import'">Go to Import tab</v-btn>
|
||||
</v-alert>
|
||||
</v-window-item>
|
||||
|
||||
<v-window-item value="import">
|
||||
<ImportTriggerPanel />
|
||||
<v-divider class="my-6" />
|
||||
<ImportFiltersForm />
|
||||
<v-divider class="my-6" />
|
||||
<ImportTaskList />
|
||||
</v-window-item>
|
||||
</v-window>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { useSystemStore } from '../stores/system.js'
|
||||
import { useImportStore } from '../stores/import.js'
|
||||
import SystemStatsCards from '../components/settings/SystemStatsCards.vue'
|
||||
import ImportTriggerPanel from '../components/settings/ImportTriggerPanel.vue'
|
||||
import ImportFiltersForm from '../components/settings/ImportFiltersForm.vue'
|
||||
import ImportTaskList from '../components/settings/ImportTaskList.vue'
|
||||
|
||||
const tab = ref('overview')
|
||||
const system = useSystemStore()
|
||||
const importStore = useImportStore()
|
||||
|
||||
let pollId = null
|
||||
|
||||
function startPolling() {
|
||||
if (pollId) return
|
||||
system.refreshStats()
|
||||
pollId = setInterval(() => {
|
||||
if (!document.hidden) {
|
||||
system.refreshStats()
|
||||
if (tab.value === 'import') importStore.refreshStatus()
|
||||
}
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
if (pollId) { clearInterval(pollId); pollId = null }
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
startPolling()
|
||||
importStore.loadSettings()
|
||||
importStore.refreshStatus()
|
||||
importStore.loadTasks(true)
|
||||
})
|
||||
onUnmounted(stopPolling)
|
||||
|
||||
watch(tab, (t) => {
|
||||
if (t === 'import') {
|
||||
importStore.refreshStatus()
|
||||
importStore.loadTasks(true)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fc-h1 {
|
||||
font-family: 'Fraunces', Georgia, serif;
|
||||
font-size: 32px;
|
||||
font-weight: 500;
|
||||
color: rgb(var(--v-theme-on-surface));
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user