feat(dashboards): 1600px max-width, richer Downloads filters, needs-attention + sticky headers
Operator-flagged 2026-05-28: the Subscriptions/Downloads dashboards were full-bleed and thin on filtering. Chosen via AskUserQuestion. **Layout** - SubscriptionsView capped at a centered max-width 1600px (covers all three subtabs) so rows aren't a mile wide on ultrawide monitors. - Sticky control headers on both tabs (top: 48px, below the top nav, opaque bg) so filters/stat-chips stay reachable while scrolling a long list. **Downloads filters (all four requested)** - Stat chips are now clickable filters: click Queued/Running/Completed/ Failed/Skipped to filter the list to that status; the active chip is outlined + elevated; re-click clears. - Free-text search box over the loaded events (artist / platform / error substring). - Artist filter: the filter popover's numeric "Source ID" field is replaced with an artist autocomplete (sources.autocompleteArtist → artist_id, which /api/downloads already supports). Pill shows the artist name. - "Show no-change scans" toggle (default OFF): hides status=ok/skipped rows with 0 files (the scheduled scans that found nothing) so real downloads + failures stand out. **Subscriptions** - "Needs attention" quick-filter chip: one click to show only artists with sources that have errors OR have never been checked; chip shows the count and disables the status dropdown while active. Frontend-only — backend filter params (status/artist_id/date) and the /api/downloads endpoint already supported everything.
This commit is contained in:
@@ -7,10 +7,22 @@
|
||||
<v-btn variant="outlined" prepend-icon="mdi-account-plus" @click="showArtistDialog = true">
|
||||
New artist
|
||||
</v-btn>
|
||||
<v-chip
|
||||
:color="needsAttention ? 'error' : undefined"
|
||||
:variant="needsAttention ? 'flat' : 'outlined'"
|
||||
prepend-icon="mdi-alert-circle-outline"
|
||||
@click="needsAttention = !needsAttention"
|
||||
>
|
||||
Needs attention
|
||||
<v-chip v-if="attentionCount" size="x-small" class="ms-2" variant="tonal">
|
||||
{{ attentionCount }}
|
||||
</v-chip>
|
||||
</v-chip>
|
||||
<v-spacer />
|
||||
<v-select
|
||||
v-model="statusFilter"
|
||||
:items="STATUS_OPTIONS"
|
||||
:disabled="needsAttention"
|
||||
density="compact" variant="outlined" hide-details
|
||||
style="max-width: 180px"
|
||||
/>
|
||||
@@ -218,6 +230,7 @@ const importStore = useImportStore()
|
||||
|
||||
const search = ref('')
|
||||
const statusFilter = ref('all')
|
||||
const needsAttention = ref(false)
|
||||
const expanded = ref([])
|
||||
const selected = ref([])
|
||||
const showSourceDialog = ref(false)
|
||||
@@ -277,12 +290,23 @@ const groups = computed(() => {
|
||||
})
|
||||
})
|
||||
|
||||
// A group "needs attention" if any of its sources has accumulated
|
||||
// failures OR has never been checked — the ones worth acting on.
|
||||
function groupNeedsAttention(g) {
|
||||
return groupMatchesStatus(g, 'errors') || groupMatchesStatus(g, 'stale')
|
||||
}
|
||||
const attentionCount = computed(
|
||||
() => groups.value.filter(groupNeedsAttention).length,
|
||||
)
|
||||
|
||||
const filteredGroups = computed(() => {
|
||||
let arr = groups.value
|
||||
if (artistFilter.value != null) {
|
||||
arr = arr.filter((g) => g.artist.id === artistFilter.value)
|
||||
}
|
||||
if (statusFilter.value !== 'all') {
|
||||
if (needsAttention.value) {
|
||||
arr = arr.filter(groupNeedsAttention)
|
||||
} else if (statusFilter.value !== 'all') {
|
||||
arr = arr.filter((g) => groupMatchesStatus(g, statusFilter.value))
|
||||
}
|
||||
const q = search.value?.trim().toLowerCase()
|
||||
@@ -478,9 +502,17 @@ async function bulkDelete() {
|
||||
<style scoped>
|
||||
.fc-subs__bar {
|
||||
display: flex; gap: 0.75rem; align-items: center;
|
||||
padding-bottom: 1rem;
|
||||
flex-wrap: wrap;
|
||||
/* Sticky below the top nav so the filter/search controls stay
|
||||
reachable while scrolling a long subscription list. Opaque bg so
|
||||
table rows don't bleed through. Operator-flagged 2026-05-28. */
|
||||
position: sticky;
|
||||
top: 48px;
|
||||
z-index: 3;
|
||||
background: rgb(var(--v-theme-background));
|
||||
padding: 8px 0 1rem;
|
||||
}
|
||||
.fc-subs__bar .v-chip { cursor: pointer; }
|
||||
.fc-subs__loading, .fc-subs__empty {
|
||||
display: flex; justify-content: center; padding: 2rem;
|
||||
color: rgb(var(--v-theme-on-surface-variant));
|
||||
|
||||
Reference in New Issue
Block a user