feat(design): a channel's and a Plex playlist's one action list (C1) — the row's "…", Delete + undo, an action toast's 8 s floor (E28 S3e2)
- Channels: the row's full-history, hide and unsubscribe buttons become its "…" at the row end (useChannelActions: open, pin, YouTube, copy name / link, full history or the admin reset, hide with an undo toast, unsubscribe behind its danger confirm); the card layout docks the "…" beside the name (ChannelLayoutGrid moreKey). The admin reset's confirm now names the reset. - Plex playlist page: a title, a show group and a season each open the page's one row menu (a title's is its usePlexCardActions list plus the removal); no X at rest; removals take an undo toast whose Undo puts every row back at its own index in one request (bulk add `positions`); j/k walk the visible rows, Delete removes the walked one; rename and delete in the header's "…". - notify: a toast with an action lives at least 8 s (the owner's call), whatever the toast setting.
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
// "fully" | "needsFull" | "" vocab + predicate — asserted here so a regression can't silently change
|
||||
// which channels the top chips show.
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { applySyncFilter, tagsColumnTest } from "./channelColumns";
|
||||
import { applySyncFilter, buildChannelColumns, tagsColumnTest } from "./channelColumns";
|
||||
import { NO_TAG_SENTINEL, type ManagedChannel } from "../lib/api";
|
||||
|
||||
const ch = (over: Partial<ManagedChannel>): ManagedChannel => ({
|
||||
@@ -71,3 +71,28 @@ describe("tagsColumnTest (item B — 'No tag')", () => {
|
||||
expect(tagsColumnTest(tagged, [NO_TAG_SENTINEL, "1"])).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildChannelColumns — the row's end", () => {
|
||||
it('ends every row in the channel\'s "…", with no action buttons before it', () => {
|
||||
const more = (c: ManagedChannel) => `more:${c.id}`;
|
||||
const noop = () => {};
|
||||
const cols = buildChannelColumns({
|
||||
t: ((k: string) => k) as never,
|
||||
prioOptions: [],
|
||||
userTags: [],
|
||||
bumpPriority: noop,
|
||||
setPriority: noop,
|
||||
more,
|
||||
onView: noop,
|
||||
toggleTag: noop,
|
||||
createAndAttachTag: noop,
|
||||
onFilterByTag: noop,
|
||||
suggestionsFor: () => [],
|
||||
onAcceptSuggestion: noop,
|
||||
onDismissSuggestion: noop,
|
||||
});
|
||||
expect(cols[cols.length - 1]!.key).toBe("actions");
|
||||
expect(cols.filter((c) => c.key === "actions")).toHaveLength(1);
|
||||
expect(cols[cols.length - 1]!.render(ch({ id: "UCz" }))).toBe("more:UCz");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user