feat(search): ephemeral results UX, count selector, channel blocklist (frontend)
- Live-search view: a results-count selector (20/40/60/100) replaces manual load-more (the free scrape source pages until that many are gathered); an 'these results are temporary' banner with a 'Clear now' button that discards them 'as if never added' (api.clearSearch) and returns to the feed. - Channel blocklist: a Block/Unblock toggle + 'Blocked' badge on the channel page (blocked channels don't auto-explore and their videos are hidden), and a 'Blocked channels' section in the Channel manager with one-click unblock. ChannelDetail.blocked from the backend. - Admin: a 'Purge discovery' button on the Scheduler page (immediate un-kept search/explore cleanup). EN/HU/DE throughout.
This commit is contained in:
parent
f27f31b6db
commit
0c18845c34
21 changed files with 263 additions and 65 deletions
|
|
@ -13,6 +13,7 @@ import {
|
|||
Pencil,
|
||||
Play,
|
||||
RadioTower,
|
||||
Trash2,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { api, type SchedulerJob, type SchedulerStatus } from "../lib/api";
|
||||
|
|
@ -354,6 +355,15 @@ export default function Scheduler() {
|
|||
mutationFn: (v: number) => api.updateMaintenanceBatch(v),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ["scheduler"] }),
|
||||
});
|
||||
const purgeMut = useMutation({
|
||||
mutationFn: () => api.purgeDiscovery(),
|
||||
onSuccess: (res) => {
|
||||
const removed =
|
||||
(res.search_videos_deleted ?? 0) + (res.videos_deleted ?? 0) + (res.channels_deleted ?? 0);
|
||||
notify({ level: "success", message: t("scheduler.purgedDiscovery", { count: removed }) });
|
||||
qc.invalidateQueries({ queryKey: ["scheduler"] });
|
||||
},
|
||||
});
|
||||
|
||||
if (q.isLoading && !data)
|
||||
return <div className="p-8 text-muted">{t("scheduler.loading")}</div>;
|
||||
|
|
@ -398,6 +408,16 @@ export default function Scheduler() {
|
|||
{t("scheduler.runAll")}
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip hint={t("scheduler.purgeDiscoveryHint")}>
|
||||
<button
|
||||
onClick={() => 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"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
{t("scheduler.purgeDiscovery")}
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip hint={t("scheduler.pauseHint")}>
|
||||
<button
|
||||
onClick={() => pauseResume.mutate(data.paused)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue