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:
@@ -7,7 +7,8 @@ import { notify } from "../lib/notifications";
|
||||
import Tooltip from "./Tooltip";
|
||||
import Tabs, { usePersistedTab } from "./Tabs";
|
||||
import { Switch } from "./ui/form";
|
||||
import { DraftSaveBar } from "./ui/DraftSaveBar";
|
||||
import { DraftSaveBar, type SaveState } from "./ui/DraftSaveBar";
|
||||
import { LS } from "../lib/storage";
|
||||
|
||||
// Admin Configuration page: edit DB-overridable operational settings (registry-driven from the
|
||||
// backend — adding a key there makes it appear here automatically). Edits are drafted and
|
||||
@@ -15,7 +16,6 @@ import { DraftSaveBar } from "./ui/DraftSaveBar";
|
||||
// the server until Save. Group order is fixed where known so logically related settings (e.g.
|
||||
// Email/SMTP) stay together.
|
||||
const GROUP_ORDER = ["access", "email", "youtube", "google", "quota", "backfill", "shorts", "batch", "downloads", "plex"];
|
||||
type SaveState = "idle" | "saving" | "saved" | "error";
|
||||
|
||||
export default function ConfigPanel() {
|
||||
const { t } = useTranslation();
|
||||
@@ -40,7 +40,7 @@ export default function ConfigPanel() {
|
||||
const [saveState, setSaveState] = useState<SaveState>("idle");
|
||||
// One tab per config group (persisted). Called before the loading guard so hook order is
|
||||
// stable; the active id is clamped to a real group at render time once data has loaded.
|
||||
const [tab, setTab] = usePersistedTab("siftlode.configTab");
|
||||
const [tab, setTab] = usePersistedTab(LS.configTab);
|
||||
|
||||
// Re-seed the draft whenever the server data changes (initial load + after a save/reset).
|
||||
useEffect(() => {
|
||||
@@ -110,9 +110,14 @@ export default function ConfigPanel() {
|
||||
});
|
||||
const plexLibs = (draft["plex_libraries"] ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
||||
const togglePlexLib = (key: string) => {
|
||||
const next = plexLibs.includes(key)
|
||||
? plexLibs.filter((k) => k !== key)
|
||||
: [...plexLibs, key];
|
||||
// An empty list means "all libraries" — every box renders checked. Unchecking one from that
|
||||
// state must select all-except-this, so expand "all" to the explicit section set first;
|
||||
// otherwise the toggle would ADD the key and leave it as the ONLY selected library.
|
||||
const allKeys = plexResult?.sections?.map((s) => s.key) ?? [];
|
||||
const current = plexLibs.length === 0 ? allKeys : plexLibs;
|
||||
const next = current.includes(key)
|
||||
? current.filter((k) => k !== key)
|
||||
: [...current, key];
|
||||
setDraft((d) => ({ ...d, plex_libraries: next.join(",") }));
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user