feat(channels): status filter + header full-history link + stable priority

- header: per-user "N without full history" count (channels_deep_pending),
  clickable with a hint -> opens the channel manager filtered to those.
- channel manager: status filter chips (All / Needs full history / Fully synced
  / Hidden); the header link deep-links to "Needs full history".
- fix: priority up/down is now an optimistic in-place cache update (no refetch /
  re-sort), so the list no longer jumps to the top and loses your scroll position;
  the new order applies on the next page load.
This commit is contained in:
npeter83 2026-06-14 07:08:59 +02:00
parent c949630b89
commit aa38e972fd
4 changed files with 92 additions and 10 deletions

View file

@ -1,12 +1,19 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { Database, Loader2, Pause, Play } from "lucide-react";
import { Database, History, Loader2, Pause, Play } from "lucide-react";
import { api } from "../lib/api";
import { formatViews } from "../lib/format";
import Tooltip from "./Tooltip";
// Per-user status (not the global catalog): shows the number of videos available to *this*
// user and how many of *their* channels are still being fetched. The pause control is
// admin-only (it pauses the shared background sync).
export default function SyncStatus({ isAdmin }: { isAdmin: boolean }) {
// user, how many of *their* channels are still being fetched, and how many lack full
// history (clickable -> channel manager filtered to those). The pause control is admin-only.
export default function SyncStatus({
isAdmin,
onGoToFullHistory,
}: {
isAdmin: boolean;
onGoToFullHistory: () => void;
}) {
const qc = useQueryClient();
const { data } = useQuery({
queryKey: ["my-status"],
@ -23,6 +30,7 @@ export default function SyncStatus({ isAdmin }: { isAdmin: boolean }) {
if (!data) return null;
const syncing = data.channels_recent_pending;
const notFull = data.channels_deep_pending; // your channels without full history yet
return (
<div className="hidden lg:flex items-center gap-2 text-xs text-muted">
@ -39,6 +47,20 @@ export default function SyncStatus({ isAdmin }: { isAdmin: boolean }) {
) : (
<span>all synced</span>
)}
{notFull > 0 && (
<>
<span className="opacity-40">·</span>
<Tooltip hint="Some of your channels only have their recent uploads. Click to open the channel manager (filtered to these) and request their full back-catalog.">
<button
onClick={onGoToFullHistory}
className="flex items-center gap-1 hover:text-fg underline decoration-dotted decoration-muted/40 underline-offset-4 transition cursor-pointer"
>
<History className="w-3.5 h-3.5" />
{notFull} without full history
</button>
</Tooltip>
</>
)}
{isAdmin && (
<button
onClick={() => toggle.mutate()}