diff --git a/frontend/src/views/Dashboard.vue b/frontend/src/views/Dashboard.vue index 668865f..2a6abac 100644 --- a/frontend/src/views/Dashboard.vue +++ b/frontend/src/views/Dashboard.vue @@ -300,12 +300,14 @@ import { useSourcesStore } from '../stores/sources' import { useDownloadsStore } from '../stores/downloads' import { useCredentialsStore } from '../stores/credentials' import { useNotificationStore } from '../stores/notifications' +import { useSettingsStore } from '../stores/settings' import { settingsApi, downloadsApi } from '../services/api' const sourcesStore = useSourcesStore() const downloadsStore = useDownloadsStore() const credentialsStore = useCredentialsStore() const notifications = useNotificationStore() +const settingsStore = useSettingsStore() // Supported platforms for credential status const supportedPlatforms = ['patreon', 'subscribestar', 'hentaifoundry', 'discord', 'pixiv', 'deviantart'] @@ -326,6 +328,41 @@ let refreshInterval = null const stats = computed(() => downloadsStore.stats) const recentActivity = computed(() => downloadsStore.recentActivity) +// Fixed display order for platform health bars +const PLATFORM_ORDER = [ + 'patreon', 'subscribestar', 'hentaifoundry', + 'discord', 'pixiv', 'deviantart', +] + +// Read threshold from settings, default 5 if unset +const failureThreshold = computed(() => + settingsStore.settings?.['dashboard.failure_threshold'] ?? 5 +) + +// Per-platform health for platforms with ≥1 enabled source +const platformHealth = computed(() => { + const enabled = sourcesStore.sources.filter(s => s.enabled) + return PLATFORM_ORDER + .map(platform => { + const sources = enabled.filter(s => s.platform === platform) + if (sources.length === 0) return null + const failing = sources.filter( + s => (s.error_count || 0) >= failureThreshold.value + ).length + return { platform, total: sources.length, failing } + }) + .filter(Boolean) +}) + +// Sources currently in failing state, most-recent-check first +const failingSources = computed(() => { + return sourcesStore.sources + .filter(s => s.enabled && (s.error_count || 0) >= failureThreshold.value) + .sort((a, b) => new Date(b.last_check || 0) - new Date(a.last_check || 0)) +}) + +const totalFailingCount = computed(() => failingSources.value.length) + // Sources with recent failures - derived from recent activity // Only shows sources where a recent download failed (not cumulative error_count) const sourcesWithErrors = computed(() => { @@ -369,6 +406,7 @@ function loadDashboardData() { // Each section handles its own loading state sourcesStore.fetchSources().catch(e => console.error('Failed to fetch sources:', e)) credentialsStore.fetchCredentials().catch(e => console.error('Failed to fetch credentials:', e)) + settingsStore.fetchSettings().catch(e => console.error('Failed to fetch settings:', e)) downloadsStore.fetchStats() .catch(e => console.error('Failed to fetch stats:', e))