chore(downloads-ui): FE-C4 follow-up cleanup

- Delete dead top-level downloads.rename.* i18n block (en/hu/de); the
  metadata modal moved to downloads.edit.*. Keep downloads.actions.rename
  (still used by ProfileEditor).
- Rename misnamed state renameJob/setRenameJob -> metaJob/setMetaJob in
  DownloadCenter (it opens MetaEditModal, not a rename dialog).
- Extract the duplicated [downloads]/[download-index]/[download-usage]
  invalidation trio into lib/downloads.ts invalidateDownloads(qc);
  used by DownloadCenter and DownloadDialog.

Behavior-neutral. tsc green, knip shows no new unused export, JSON valid.
This commit is contained in:
npeter83 2026-07-11 17:10:15 +02:00
parent 94fd7ba9a6
commit 477056bfa8
6 changed files with 16 additions and 29 deletions

View file

@ -27,6 +27,7 @@ const ShareDialog = lazy(() => import("./ShareDialog"));
import { useConfirm } from "./ConfirmProvider";
import { useLiveQuery } from "../lib/useLiveQuery";
import { api, type DownloadJob, type Me } from "../lib/api";
import { invalidateDownloads } from "../lib/downloads";
import { notify } from "../lib/notifications";
import { formatBytes, formatDuration, formatEta, formatSpeed } from "../lib/format";
@ -546,7 +547,7 @@ export default function DownloadCenter({ me }: { me: Me }) {
const [addUrl, setAddUrl] = useState("");
const [addSource, setAddSource] = useState<string | null>(null);
const [manage, setManage] = useState(false);
const [renameJob, setRenameJob] = useState<DownloadJob | null>(null);
const [metaJob, setMetaJob] = useState<DownloadJob | null>(null);
const [shareJob, setShareJob] = useState<DownloadJob | null>(null);
const [editJob, setEditJob] = useState<DownloadJob | null>(null);
@ -556,11 +557,7 @@ export default function DownloadCenter({ me }: { me: Me }) {
const queue = jobs.filter((j) => ["queued", "running", "paused", "error"].includes(j.status));
const library = jobs.filter((j) => j.status === "done");
const invalidate = () => {
qc.invalidateQueries({ queryKey: ["downloads"] });
qc.invalidateQueries({ queryKey: ["download-index"] });
qc.invalidateQueries({ queryKey: ["download-usage"] });
};
const invalidate = () => invalidateDownloads(qc);
const act = useMutation({
mutationFn: ({ id, op }: { id: number; op: "pause" | "resume" | "cancel" | "delete" }) =>
op === "pause" ? api.pauseDownload(id)
@ -674,7 +671,7 @@ export default function DownloadCenter({ me }: { me: Me }) {
<Scissors className="w-4 h-4" />
</IconBtn>
)}
<IconBtn onClick={() => setRenameJob(job)} title={t("downloads.actions.editDetails")}>
<IconBtn onClick={() => setMetaJob(job)} title={t("downloads.actions.editDetails")}>
<Pencil className="w-4 h-4" />
</IconBtn>
<IconBtn onClick={() => setShareJob(job)} title={t("downloads.actions.share")}>
@ -738,7 +735,7 @@ export default function DownloadCenter({ me }: { me: Me }) {
/>
)}
{manage && <ProfileEditor onClose={() => setManage(false)} />}
{renameJob && <MetaEditModal job={renameJob} onClose={() => setRenameJob(null)} />}
{metaJob && <MetaEditModal job={metaJob} onClose={() => setMetaJob(null)} />}
{shareJob && <ShareDialog job={shareJob} onClose={() => setShareJob(null)} />}
{editJob && <VideoEditor job={editJob} onClose={() => setEditJob(null)} />}
</Suspense>

View file

@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import Modal from "./Modal";
import { api } from "../lib/api";
import { invalidateDownloads } from "../lib/downloads";
// Lazy: the full profile editor only opens from the dialog's "manage presets" affordance.
const ProfileEditor = lazy(() => import("./ProfileEditor"));
@ -43,9 +44,7 @@ export default function DownloadDialog({
profile_id: chosen,
display_name: name.trim() || undefined,
});
qc.invalidateQueries({ queryKey: ["downloads"] });
qc.invalidateQueries({ queryKey: ["download-index"] });
qc.invalidateQueries({ queryKey: ["download-usage"] });
invalidateDownloads(qc);
notify({
level: "success",
message: t("downloads.dialog.added"),

View file

@ -78,12 +78,6 @@
"copied": "Quell-Link in die Zwischenablage kopiert",
"copyFailed": "Link konnte nicht kopiert werden"
},
"rename": {
"title": "Download umbenennen",
"label": "Anzeigename",
"hint": "Ändert nur den angezeigten und beim Speichern verwendeten Namen — die gespeicherte Datei behält ihren Namen.",
"save": "Speichern"
},
"edit": {
"title": "Details bearbeiten",
"name": "Titel",

View file

@ -78,12 +78,6 @@
"copied": "Source link copied to clipboard",
"copyFailed": "Couldn't copy the link"
},
"rename": {
"title": "Rename download",
"label": "Display name",
"hint": "Only changes the name you see and download with — the stored file keeps its own name.",
"save": "Save"
},
"edit": {
"title": "Edit details",
"name": "Title",

View file

@ -78,12 +78,6 @@
"copied": "Forráslink a vágólapra másolva",
"copyFailed": "Nem sikerült a link másolása"
},
"rename": {
"title": "Letöltés átnevezése",
"label": "Megjelenített név",
"hint": "Csak a megjelenített és letöltéskor használt nevet módosítja — a tárolt fájl neve nem változik.",
"save": "Mentés"
},
"edit": {
"title": "Adatok szerkesztése",
"name": "Cím",

View file

@ -0,0 +1,9 @@
import type { QueryClient } from "@tanstack/react-query";
// The download queue, the per-card download index, and the storage-usage meter all move together
// whenever a job is enqueued, deleted, or its state changes — invalidate them as one unit.
export function invalidateDownloads(qc: QueryClient) {
qc.invalidateQueries({ queryKey: ["downloads"] });
qc.invalidateQueries({ queryKey: ["download-index"] });
qc.invalidateQueries({ queryKey: ["download-usage"] });
}