feat(web): render SxxEyy chips in attention queues

This commit is contained in:
Miguel Palhas
2026-08-23 19:45:33 +01:00
parent 7f7f26dbc7
commit 1d31ea7d1b
2 changed files with 37 additions and 16 deletions
+22 -14
View File
@@ -575,6 +575,18 @@ function rowTitle(title: string, year: number | null): HTMLElement {
return wrap; return wrap;
} }
function seasonTag(seasonNumber: number): string {
return `S${two(seasonNumber)}`;
}
function episodeTag(seasonNumber: number, episodeNumber: number): string {
return `${seasonTag(seasonNumber)}E${two(episodeNumber)}`;
}
function two(value: number): string {
return value < 10 ? `0${value}` : String(value);
}
function libraryRow( function libraryRow(
movie: LibraryMovie, movie: LibraryMovie,
roots: Root[], roots: Root[],
@@ -1922,9 +1934,10 @@ function queuesMain(board: HTMLElement, releases: ReleasesView, views: HideableV
} }
/** /**
* One TV lane entry: the series plus chips counting the episodes or * One TV lane entry: the series plus one chip per episode or season that put
* seasons that put it there. The API carries internal row ids, not SxxEyy * it there, named `SxxEyy` so the operator knows what to act on (#140).
* numbers, so counts are what can be named honestly. Inert — see above. * Inert — the release deck and overrides arrive with the series detail view
* (issues 129 and 39).
*/ */
function seriesAttentionRow(entry: SeriesAttention): HTMLLIElement { function seriesAttentionRow(entry: SeriesAttention): HTMLLIElement {
const item = document.createElement("li"); const item = document.createElement("li");
@@ -1932,21 +1945,16 @@ function seriesAttentionRow(entry: SeriesAttention): HTMLLIElement {
row.className = "row"; row.className = "row";
const chips = document.createElement("span"); const chips = document.createElement("span");
chips.className = "row-chips"; chips.className = "row-chips";
if (entry.episodes.length > 0) { for (const episode of entry.episodes) {
const n = entry.episodes.length; const tag = episodeTag(episode.season_number, episode.episode_number);
chips.append( chips.append(
chip(`${n} ${n === 1 ? "episode" : "episodes"}`, (span) => { chip(tag, (span) => {
span.setAttribute("aria-label", `${n} ${n === 1 ? "episode" : "episodes"} waiting`); span.setAttribute("aria-label", `${tag} waiting`);
}), }),
); );
} }
if (entry.seasons.length > 0) { for (const season of entry.seasons) {
const n = entry.seasons.length; chips.append(chip(seasonTag(season.number)));
chips.append(
chip(`${n} ${n === 1 ? "season" : "seasons"}`, (span) => {
span.setAttribute("aria-label", `${n} ${n === 1 ? "season" : "seasons"} waiting`);
}),
);
} }
row.append(rowTitle(entry.title, entry.year), chips); row.append(rowTitle(entry.title, entry.year), chips);
item.append(row); item.append(row);
+15 -2
View File
@@ -11,14 +11,27 @@ export interface AttentionMovie extends LibraryMovie {
last_searched_at: string | null; last_searched_at: string | null;
} }
/** An episode that put its series here, named for SxxEyy rendering (#140). */
export interface QueuedEpisode {
id: number;
season_number: number;
episode_number: number;
}
/** A season whose failed pack put its series here. */
export interface QueuedSeason {
id: number;
number: number;
}
/** A series in a TV attention queue, with what put it there (§9.5). */ /** A series in a TV attention queue, with what put it there (§9.5). */
export interface SeriesAttention { export interface SeriesAttention {
series_id: number; series_id: number;
tmdb_id: number; tmdb_id: number;
title: string; title: string;
year: number | null; year: number | null;
episodes: number[]; episodes: QueuedEpisode[];
seasons: number[]; seasons: QueuedSeason[];
} }
export interface AttentionQueues { export interface AttentionQueues {