feat(channels): data-table channel manager

Replace the stacked card rows with the reusable DataTable: sortable columns, in-header
Channel/Tags filters, status chips + page controls in one row, wider layout. Tag toggle
is now optimistic (no full refetch). Sync column collapses to one 'fully synced' chip;
Actions column carries hide/unsubscribe + a backfill control (admin reset / per-user
full-history opt-in). Channel status filter persists across reloads.
This commit is contained in:
npeter83 2026-06-17 19:16:23 +02:00
parent 2941832566
commit cab700bca5
5 changed files with 476 additions and 259 deletions

View file

@ -1,7 +1,7 @@
{
"intro": "Lege die <0>Priorität</0> eines Kanals fest, um seine Videos nach oben zu schieben, wenn du nach „Kanalpriorität“ sortierst, hänge eigene <1>Tags</1> an, um den Feed zu filtern, oder <2>blende</2> einen Kanal <2>aus</2>, um ihn ohne Abbestellung aus dem Feed zu entfernen.",
"filterPlaceholder": "Kanäle filtern…",
"syncSubscriptions": "Abos synchronisieren",
"syncSubscriptions": "Abos von YouTube lesen",
"syncSubscriptionsHint": "Importiert deine Abo-Liste erneut von YouTube — fügt neu abonnierte Kanäle hinzu und entfernt abbestellte. Die Videos selbst werden weiterhin automatisch im Hintergrund synchronisiert; sie werden hierbei nicht neu geladen.",
"backfillEverything": "Alles nachladen",
"backfillEverythingHint": "Fordert das vollständige Nachladen des gesamten Katalogs für jeden abonnierten Kanal an. Ältere Videos und die Suche werden vollständig, soweit das gemeinsame Tageskontingent es zulässt — das kann eine Weile dauern.",
@ -19,6 +19,20 @@
},
"loading": "Kanäle werden geladen…",
"empty": "Keine Kanäle.",
"pager": {
"prev": "Zurück",
"next": "Weiter",
"page": "Seite {{page}} von {{total}}"
},
"cols": {
"priority": "Prio",
"channel": "Kanal",
"stored": "Gespeichert",
"subs": "Abonnenten",
"sync": "Sync",
"tags": "Tags",
"actions": "Aktionen"
},
"stats": {
"channels": "Kanäle",
"channelsHint": "Kanäle, die du abonniert hast.",
@ -45,6 +59,13 @@
"recentNotSyncedHint": "Neueste Uploads noch nicht geladen.",
"full": "vollständig",
"fullHint": "Vollständiger Verlauf geladen.",
"fullNotFetchedHint": "Das vollständige Archiv ist noch nicht geladen — nutze die Backfill-Aktion in der Spalte Aktionen.",
"fullySynced": "vollständig synchron",
"fullySyncedHint": "Aktuelle Uploads und das vollständige Archiv sind beide vorhanden.",
"backfillThis": "Diesen Kanal vollständig laden",
"backfillThisHint": "Das vollständige Archiv dieses Kanals laden (ältere Videos + komplette Suche). Erneut klicken, um die Anfrage zurückzuziehen.",
"resetBackfill": "Kanal zurücksetzen & neu laden",
"resetHint": "Admin: diesen Kanal von Grund auf neu laden (aktuelle + vollständiges Archiv), unabhängig vom aktuellen Sync-Status.",
"fullHistoryQueued": "vollständiger Verlauf in Warteschlange",
"fullHistoryComing": "vollständiger Verlauf unterwegs",
"queuedRequestedHint": "Vollständiger Verlauf angefordert — der gesamte Katalog dieses Kanals wird nachgeladen, soweit das gemeinsame Kontingent es zulässt. Klicke, um deine Anforderung abzubrechen.",
@ -67,7 +88,10 @@
"fullHistoryRequested": "Vollständiger Verlauf für {{count}} Kanäle angefordert",
"fullHistoryFailed": "Vollständiger Verlauf konnte nicht angefordert werden",
"needYouTube": "Verbinde dein YouTube-Konto, um dies zu tun.",
"connect": "Verbinden"
"connect": "Verbinden",
"resetDone": "Kanal zurückgesetzt — wird neu geladen",
"resetFailed": "Kanal konnte nicht zurückgesetzt werden"
},
"confirmUnsubscribe": "Kanal „{{name}}“ bei YouTube abbestellen? Dies ändert dein echtes YouTube-Konto. Um ihn nur aus deinem Feed zu entfernen, blende ihn stattdessen aus."
"confirmUnsubscribe": "Kanal „{{name}}“ bei YouTube abbestellen? Dies ändert dein echtes YouTube-Konto. Um ihn nur aus deinem Feed zu entfernen, blende ihn stattdessen aus.",
"confirmReset": "Kanal „{{name}}“ von Grund auf neu laden? Dies startet den Backfill neu (aktuell + vollständiger Verlauf) und verbraucht etwas API-Kontingent."
}

View file

@ -1,7 +1,7 @@
{
"intro": "Set a channel's <0>priority</0> to push its videos up when you sort by “Channel priority”, attach your own <1>tags</1> to filter the feed, or <2>hide</2> a channel to drop it from the feed without unsubscribing.",
"filterPlaceholder": "Filter channels…",
"syncSubscriptions": "Sync subscriptions",
"syncSubscriptions": "Read subscriptions from YouTube",
"syncSubscriptionsHint": "Re-import your subscription list from YouTube — adds channels you've newly followed and drops ones you've unfollowed. The videos themselves keep syncing automatically in the background; this does not re-fetch them.",
"backfillEverything": "Backfill everything",
"backfillEverythingHint": "Request full back-catalog backfill for every channel you're subscribed to. Older videos and search become complete as the shared daily quota allows — this can take a while.",
@ -19,6 +19,20 @@
},
"loading": "Loading channels…",
"empty": "No channels.",
"pager": {
"prev": "Previous",
"next": "Next",
"page": "Page {{page}} of {{total}}"
},
"cols": {
"priority": "Prio",
"channel": "Channel",
"stored": "Stored",
"subs": "Subscribers",
"sync": "Sync",
"tags": "Tags",
"actions": "Actions"
},
"stats": {
"channels": "Channels",
"channelsHint": "Channels you're subscribed to.",
@ -45,6 +59,13 @@
"recentNotSyncedHint": "Recent uploads not fetched yet.",
"full": "full",
"fullHint": "Full history fetched.",
"fullNotFetchedHint": "Full back-catalog not fetched yet — use the backfill action in the Actions column.",
"fullySynced": "fully synced",
"fullySyncedHint": "Recent uploads and the full back-catalog are both in.",
"backfillThis": "Backfill this channel",
"backfillThisHint": "Fetch this channel's full back-catalog (older videos + complete search). Click again to cancel the request.",
"resetBackfill": "Reset & re-fetch this channel",
"resetHint": "Admin: re-fetch this channel from scratch (recent + full back-catalog), regardless of its current sync state.",
"fullHistoryQueued": "full history queued",
"fullHistoryComing": "full history coming",
"queuedRequestedHint": "Full history requested — this channel's whole back-catalog will backfill as the shared quota allows. Click to cancel your request.",
@ -67,7 +88,10 @@
"fullHistoryRequested": "Full history requested for {{count}} channels",
"fullHistoryFailed": "Couldn't request full history",
"needYouTube": "Connect your YouTube account to do this.",
"connect": "Connect"
"connect": "Connect",
"resetDone": "Channel reset — re-fetching now",
"resetFailed": "Couldn't reset this channel"
},
"confirmUnsubscribe": "Unsubscribe from \"{{name}}\" on YouTube? This changes your real YouTube account. To just remove it from your feed, hide it instead."
"confirmUnsubscribe": "Unsubscribe from \"{{name}}\" on YouTube? This changes your real YouTube account. To just remove it from your feed, hide it instead.",
"confirmReset": "Re-fetch \"{{name}}\" from scratch? This re-runs its backfill (recent + full history) and spends some API quota."
}

View file

@ -1,7 +1,7 @@
{
"intro": "Állíts be egy csatornának <0>prioritást</0>, hogy a videói előrébb kerüljenek, amikor „Csatorna prioritás” szerint rendezel, csatolj saját <1>címkéket</1> a hírfolyam szűréséhez, vagy <2>rejts el</2> egy csatornát, hogy leiratkozás nélkül kivedd a hírfolyamból.",
"filterPlaceholder": "Csatornák szűrése…",
"syncSubscriptions": "Feliratkozások szinkronizálása",
"syncSubscriptions": "Feliratkozások beolvasása a YouTube-ról",
"syncSubscriptionsHint": "Újraimportálja a feliratkozási listádat a YouTube-ról — hozzáadja az újonnan követett csatornákat, és eltávolítja azokat, amelyekről leiratkoztál. Maguk a videók a háttérben automatikusan tovább szinkronizálódnak; ez nem tölti le őket újra.",
"backfillEverything": "Minden letöltése",
"backfillEverythingHint": "Teljes archívum letöltését kéri minden csatornához, amelyre feliratkoztál. A régebbi videók és a keresés a megosztott napi kvóta függvényében válik teljessé — ez eltarthat egy ideig.",
@ -19,6 +19,20 @@
},
"loading": "Csatornák betöltése…",
"empty": "Nincsenek csatornák.",
"pager": {
"prev": "Előző",
"next": "Következő",
"page": "{{page}}. oldal / {{total}}"
},
"cols": {
"priority": "Prio",
"channel": "Csatorna",
"stored": "Tárolt",
"subs": "Feliratkozók",
"sync": "Szinkron",
"tags": "Címkék",
"actions": "Műveletek"
},
"stats": {
"channels": "Csatorna",
"channelsHint": "Csatornák, amelyekre feliratkoztál.",
@ -45,6 +59,13 @@
"recentNotSyncedHint": "A legutóbbi feltöltések még nincsenek letöltve.",
"full": "teljes",
"fullHint": "Teljes előzmény letöltve.",
"fullNotFetchedHint": "A teljes archívum még nincs letöltve — használd a Műveletek oszlop backfill gombját.",
"fullySynced": "teljesen szinkronban",
"fullySyncedHint": "A legutóbbi feltöltések és a teljes archívum is megvan.",
"backfillThis": "Csatorna teljes letöltése",
"backfillThisHint": "A csatorna teljes archívumának letöltése (régebbi videók + teljes keresés). Újra kattintva visszavonod a kérést.",
"resetBackfill": "Csatorna resetelése és újraletöltése",
"resetHint": "Admin: a csatorna teljes újraletöltése a nulláról (legutóbbi + teljes archívum), a jelenlegi szinkron-állapottól függetlenül.",
"fullHistoryQueued": "teljes előzmény sorban",
"fullHistoryComing": "teljes előzmény úton",
"queuedRequestedHint": "Teljes előzmény kérve — a csatorna teljes archívuma letöltődik, ahogy a megosztott kvóta engedi. Kattints a kérés visszavonásához.",
@ -67,7 +88,10 @@
"fullHistoryRequested": "Teljes előzmény kérve {{count}} csatornához",
"fullHistoryFailed": "Nem sikerült teljes előzményt kérni",
"needYouTube": "Ehhez csatlakoztasd a YouTube-fiókod.",
"connect": "Csatlakoztatás"
"connect": "Csatlakoztatás",
"resetDone": "Csatorna resetelve — újraletöltés folyamatban",
"resetFailed": "Nem sikerült resetelni a csatornát"
},
"confirmUnsubscribe": "Leiratkozol a(z) „{{name}}” csatornáról a YouTube-on? Ez megváltoztatja a valódi YouTube-fiókodat. Ha csak a hírfolyamodból szeretnéd eltávolítani, inkább rejtsd el."
"confirmUnsubscribe": "Leiratkozol a(z) „{{name}}” csatornáról a YouTube-on? Ez megváltoztatja a valódi YouTube-fiókodat. Ha csak a hírfolyamodból szeretnéd eltávolítani, inkább rejtsd el.",
"confirmReset": "Újraletöltöd a(z) „{{name}}” csatornát a nulláról? Ez újrafuttatja a backfillt (legutóbbi + teljes előzmény), és némi API-kvótát fogyaszt."
}