fix(admin-ui): Plex library toggle inversion + Purge-discovery confirm (+ cleanups)

Bugs:
- ConfigPanel (CB1): unchecking a Plex library from the "all" (empty) state made
  that library the ONLY selected one instead of all-except-it, because the toggle
  ADDED the key to an empty list. Expand "all" to the explicit section set before
  toggling. E2E-verified: uncheck from all → all-except-one.
- Scheduler (SB1): "Purge discovery" bulk-deleted search videos/videos/channels
  immediately with no confirm (every AdminUsers destructive action uses useConfirm).
  Wrapped in a danger useConfirm dialog (+ trilingual purgeConfirmTitle key).
  E2E-verified: dialog appears, Cancel aborts.

Cleanups (behavior-neutral):
- Register LS.configTab; ConfigPanel uses it instead of the bare "siftlode.configTab".
- ConfigPanel + SettingsPanel import SaveState from ui/DraftSaveBar instead of
  redeclaring the union (PrefsSaveState is now an alias).

tsc green, re-review clean, localdev boots.
This commit is contained in:
npeter83 2026-07-11 19:44:53 +02:00
parent a6ffcf9577
commit 3d00d75863
7 changed files with 28 additions and 9 deletions

View file

@ -18,6 +18,7 @@ import {
} from "lucide-react";
import { api, type SchedulerJob, type SchedulerStatus } from "../lib/api";
import { useLiveQuery } from "../lib/useLiveQuery";
import { useConfirm } from "./ConfirmProvider";
import { relativeTime } from "../lib/format";
import { notify } from "../lib/notifications";
import Tooltip from "./Tooltip";
@ -309,6 +310,7 @@ function Stat({
export default function Scheduler() {
const { t } = useTranslation();
const qc = useQueryClient();
const confirm = useConfirm();
// Poll faster while any job is running so live progress is smooth, then ease back when
// idle. Derived from the freshest data by react-query itself (see useLiveQuery).
const q = useLiveQuery<SchedulerStatus>(["scheduler"], api.schedulerStatus, {
@ -411,7 +413,15 @@ export default function Scheduler() {
</Tooltip>
<Tooltip hint={t("scheduler.purgeDiscoveryHint")}>
<button
onClick={() => purgeMut.mutate()}
onClick={async () => {
const ok = await confirm({
title: t("scheduler.purgeConfirmTitle"),
message: t("scheduler.purgeDiscoveryHint"),
confirmLabel: t("scheduler.purgeDiscovery"),
danger: true,
});
if (ok) purgeMut.mutate();
}}
disabled={purgeMut.isPending}
className="glass-card glass-hover flex items-center gap-2 px-3 py-2 rounded-xl text-sm disabled:opacity-50 transition"
>