feat(tags): tag UX overhaul + per-card video reset
- Channel-row tags show only what's attached; a '+' opens a per-channel picker. Clicking a tag filters the feed by it; a 'Your tags' sidebar widget makes that filter visible/clearable. - Tag manager dialog (add/rename/delete; delete only confirms when the tag is in use), reachable from the Channel manager and the feed sidebar; hovering a tag's count lists its channels, each a link that focuses it in the Channel manager (DataTable gains an external filter input). - Video cards get a reset action that clears all watch state (incl. an in-progress position). - api.req() now raises the error dialog on 5xx and 400/409/422 with the server's reason.
This commit is contained in:
parent
14b8eb6084
commit
d33a109ea2
22 changed files with 445 additions and 49 deletions
|
|
@ -1,4 +1,6 @@
|
|||
import { notify } from "./notifications";
|
||||
import i18n from "../i18n";
|
||||
import { reportError } from "./errorDialog";
|
||||
|
||||
export interface Me {
|
||||
id: number;
|
||||
|
|
@ -196,9 +198,14 @@ async function req(url: string, opts: RequestInit = {}): Promise<any> {
|
|||
} catch {
|
||||
/* no JSON body */
|
||||
}
|
||||
// Server faults are worth surfacing; 401/403/404 etc. are handled by callers.
|
||||
// Surface anything the server definitively refused as a self-explanatory dialog the
|
||||
// user must acknowledge: 5xx (a fault) and 400/409/422 (validation/conflict, with the
|
||||
// server's own reason). 401/403/404 are control flow handled by callers (auth, demo
|
||||
// gating, not-found), so they just throw.
|
||||
if (r.status >= 500) {
|
||||
notifyErrorThrottled(`Server error ${r.status}`, `${method} ${url}`);
|
||||
reportError(detail || `${i18n.t("errors.server")} (${r.status})`);
|
||||
} else if (r.status === 400 || r.status === 409 || r.status === 422) {
|
||||
reportError(detail);
|
||||
}
|
||||
throw new HttpError(r.status, detail);
|
||||
}
|
||||
|
|
@ -365,6 +372,7 @@ export const api = {
|
|||
req(`/api/facets?${filterParams(f).toString()}`),
|
||||
setState: (id: string, status: string) =>
|
||||
req(`/api/videos/${id}/state`, { method: "POST", body: JSON.stringify({ status }) }),
|
||||
clearState: (id: string) => req(`/api/videos/${id}/state`, { method: "DELETE" }),
|
||||
saveProgress: (id: string, positionSeconds: number, durationSeconds: number) =>
|
||||
req(`/api/videos/${id}/progress`, {
|
||||
method: "POST",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue