diff --git a/frontend/src/views/Dashboard.vue b/frontend/src/views/Dashboard.vue index b610032..ab65890 100644 --- a/frontend/src/views/Dashboard.vue +++ b/frontend/src/views/Dashboard.vue @@ -53,6 +53,10 @@ :loading="checkingAll" @click="checkAllSources" > + Check All Sources - Retry All Failed ({{ failedCount }}) + + Retry All Failed + Reset Stuck ({{ stuckRunningCount }}) @@ -189,35 +201,48 @@ - - - - - {{ getDownloadLabel(download) }} - - - {{ formatRelativeTime(download.created_at) }} - - {{ download.file_count }} new file{{ download.file_count !== 1 ? 's' : '' }} - - - - + +
mdi-history @@ -354,6 +379,29 @@ let refreshInterval = null const stats = computed(() => downloadsStore.stats) const recentActivity = computed(() => downloadsStore.recentActivity) +const recentActivityGrouped = computed(() => { + const singles = [] + const groups = new Map() + for (const d of recentActivity.value) { + if (d.status === 'failed') { + const key = `${d.subscription_name || '?'}:${d.platform || '?'}` + const g = groups.get(key) || { kind: 'group', key, label: key, items: [], latest: d } + g.items.push(d) + if (new Date(d.created_at) > new Date(g.latest.created_at)) g.latest = d + groups.set(key, g) + } else { + singles.push({ kind: 'single', key: `d-${d.id}`, download: d }) + } + } + const out = [...singles, ...groups.values()] + out.sort((a, b) => { + const tA = new Date(a.kind === 'single' ? a.download.created_at : a.latest.created_at) + const tB = new Date(b.kind === 'single' ? b.download.created_at : b.latest.created_at) + return tB - tA + }) + return out +}) + // Read threshold from settings, default 5 if unset or invalid const failureThreshold = computed(() => { const n = Number(settingsStore.settings['dashboard.failure_threshold'])