Files
siftlode/frontend/src/lib/channelOrder.ts
T
peter 4aaaaa7860 chore(comments): drop epic, sprint and review-round ids from the code
The code cited its plan instead of saying why: `E28 review J4`, `(R6 S3b)`, `S1 justified…`,
`deep-review round 5`. That plan lives in the private ops repo, so for every reader of this one the
citation was noise, and a sentence whose subject was the plan step ("round 2 showed…") hid its
lesson behind an id. Each one is gone and the "why" kept: a bare citation is deleted, a sentence
carrying a lesson is reworded around it ("a later attempt showed…").

Measured (`scripts/audit_metrics.py`, product code): 652 lines in 270 files carried an epic code by
the definition the next commit holds (507 / 241 by the old, two-digit-only one) -> 0. Across all
code, tests, scripts and configs: ~1100 epic-code lines plus ~320 sprint/round ids.

Behaviour unchanged, checked mechanically: every changed .py file has the same AST once docstrings
are blanked; css/sh/toml/yml/json files are identical once comments are stripped; the only
non-comment changes in TS/JS are test titles, one description string in a contract table, and five
ESLint messages, whose text is all the gates snapshot diff holds. Not touched: Markdown (docs and
the changelog keep their history), Alembic migrations, TV episode notation (`S2 · E5`), DESIGN.md
ids (`C1`, `B4`, `S3h`), tracker ids (`SEC-16`, `DX-17`).

One stale claim fixed on the way: test_hls_reaper's docstring said the player checkpoints "every
10 s whether or not it is playing", which plex/stream.py calls wrong; it now says what the code does.
2026-10-05 00:19:39 +02:00

51 lines
2.2 KiB
TypeScript

import { compareText } from "./collate";
import { serverOrderLang } from "./saveLanguage";
// The channel manager's list order, and the priority steps its menu offers.
/** The steps a channel's menu offers (owner, 2026-09-26): fixed levels, so bubbling a channel up
* the list is one pick, not a run of +1 presses, and not straight to the top either. The row's
* stepper still sets any value, negatives included. */
const PRIORITY_STEPS: readonly number[] = [10, 5, 3, 2, 1, 0];
/** The steps to offer for a channel at `current`: the fixed ones, plus `current` itself in its
* place when it is off the scale (a 7, a -2) — the menu always shows, ticked, where it is now. */
export function priorityChoices(current: number): number[] {
return PRIORITY_STEPS.includes(current)
? [...PRIORITY_STEPS]
: [...PRIORITY_STEPS, current].sort((a, b) => b - a);
}
interface Ordered {
id: string;
priority: number;
title?: string | null;
}
/** The server's order (`routes/channels.py`: priority desc, then the title in the reader's alphabet —
* the ICU collation of `app/collation.py`, which `compareText` shares — a missing title last). */
function before(a: Ordered, b: Ordered, lang: string): boolean {
if (a.priority !== b.priority) return a.priority > b.priority;
if (a.title == null) return false;
if (b.title == null) return true;
return compareText(a.title, b.title, lang) < 0;
}
/** `rows` with the channel `id` taken out and put back where its priority now places it, every
* other row left exactly where it was — the server's order, without a refetch that would reorder
* anything the reader did not touch. It takes the account's `preferences`, not a language: the
* server sorts in the STORED language (`serverOrderLang`), which a UI language is not always. */
export function placeByPriority<T extends Ordered>(
rows: readonly T[],
id: string,
preferences: Record<string, unknown> | null | undefined,
): T[] {
const moved = rows.find((r) => r.id === id);
if (!moved) return [...rows];
const lang = serverOrderLang(preferences);
const rest = rows.filter((r) => r !== moved);
const at = rest.findIndex((r) => before(moved, r, lang));
rest.splice(at < 0 ? rest.length : at, 0, moved);
return rest;
}