diff --git a/apps/fabro-web/app/components/runs-list/preferences.ts b/apps/fabro-web/app/components/runs-list/preferences.ts index b544209a2..04369fc7e 100644 --- a/apps/fabro-web/app/components/runs-list/preferences.ts +++ b/apps/fabro-web/app/components/runs-list/preferences.ts @@ -1,6 +1,35 @@ import type { ListRunsDirectionEnum, ListRunsSortEnum } from "@qltysh/fabro-api-client"; import { parseHiddenColumns, serializeHiddenColumns } from "./toggleable-column"; +import type { ToggleableColumn } from "./toggleable-column"; + +// Columns hidden by default in both the main runs list and the Children +// sub-tab. Users can still reveal them via the column picker. +export const DEFAULT_HIDDEN_RUN_LIST_COLUMNS: readonly ToggleableColumn[] = [ + "updated", + "changes", +]; + +function defaultHideString(): string { + return serializeHiddenColumns(new Set(DEFAULT_HIDDEN_RUN_LIST_COLUMNS)) ?? ""; +} + +// Read the `hide` URL param honouring the convention that an absent param +// means "use defaults" while an explicit empty value means "show every +// column". Both forms persist round-trips through the column picker. +export function hiddenColumnsFromSearchParams( + searchParams: URLSearchParams, +): Set { + const raw = searchParams.get("hide"); + if (raw == null) return new Set(DEFAULT_HIDDEN_RUN_LIST_COLUMNS); + return parseHiddenColumns(raw); +} + +function readHideField(searchParams: URLSearchParams): string { + const raw = searchParams.get("hide"); + if (raw == null) return defaultHideString(); + return serializeHiddenColumns(parseHiddenColumns(raw)) ?? ""; +} export type ViewMode = "columns" | "list"; @@ -111,7 +140,7 @@ export function defaultRunsWorkspacePreferences(): RunsWorkspacePreferences { sort: "created_at", direction: "desc", size: DEFAULT_LIST_PAGE_SIZE, - hide: "", + hide: defaultHideString(), page: 1, }; } @@ -144,7 +173,6 @@ function normalizeStoredRunsWorkspacePreferences(value: unknown): RunsWorkspaceP return defaultRunsWorkspacePreferences(); } - const hiddenColumns = parseHiddenColumns(stringValue(record.hide)); const size = record.size; return { @@ -158,11 +186,20 @@ function normalizeStoredRunsWorkspacePreferences(value: unknown): RunsWorkspaceP sort: parseSort(stringValue(record.sort)), direction: parseDirection(stringValue(record.direction)), size: parsePageSize(typeof size === "number" || typeof size === "string" ? String(size) : null), - hide: serializeHiddenColumns(hiddenColumns) ?? "", + hide: normalizeStoredHide(stringValue(record.hide)), page: 1, }; } +// Stored records from before the default-hidden-columns change have no `hide` +// field. Treat the absence as "use the new defaults" so existing users pick up +// the new default automatically. An explicit empty string means the user +// chose to show every column, so preserve it. +function normalizeStoredHide(stored: string | null): string { + if (stored == null) return defaultHideString(); + return serializeHiddenColumns(parseHiddenColumns(stored)) ?? ""; +} + export function runsWorkspacePreferencesFromSearchParams( searchParams: URLSearchParams, ): RunsWorkspacePreferences { @@ -177,7 +214,7 @@ export function runsWorkspacePreferencesFromSearchParams( sort: parseSort(searchParams.get("sort")), direction: parseDirection(searchParams.get("direction")), size: parsePageSize(searchParams.get("size")), - hide: serializeHiddenColumns(parseHiddenColumns(searchParams.get("hide"))) ?? "", + hide: readHideField(searchParams), page: parsePage(searchParams.get("page")), }; } @@ -195,7 +232,7 @@ export function runsWorkspacePreferencesToSearchParams( if (preferences.sort !== "created_at") params.set("sort", preferences.sort); if (preferences.direction === "asc") params.set("direction", "asc"); if (preferences.size !== DEFAULT_LIST_PAGE_SIZE) params.set("size", String(preferences.size)); - if (preferences.hide !== "") params.set("hide", preferences.hide); + if (preferences.hide !== defaultHideString()) params.set("hide", preferences.hide); if (preferences.page > 1) params.set("page", String(preferences.page)); return params; } @@ -281,7 +318,7 @@ export function defaultChildRunsListPreferences(): ChildRunsListPreferences { sort: "created_at", direction: "desc", size: DEFAULT_LIST_PAGE_SIZE, - hide: "", + hide: defaultHideString(), page: 1, }; } @@ -292,7 +329,6 @@ function normalizeStoredChildRunsListPreferences(value: unknown): ChildRunsListP return defaultChildRunsListPreferences(); } - const hiddenColumns = parseHiddenColumns(stringValue(record.hide)); const size = record.size; return { @@ -303,7 +339,7 @@ function normalizeStoredChildRunsListPreferences(value: unknown): ChildRunsListP sort: parseSort(stringValue(record.sort)), direction: parseDirection(stringValue(record.direction)), size: parsePageSize(typeof size === "number" || typeof size === "string" ? String(size) : null), - hide: serializeHiddenColumns(hiddenColumns) ?? "", + hide: normalizeStoredHide(stringValue(record.hide)), page: 1, }; } @@ -319,7 +355,7 @@ export function childRunsListPreferencesFromSearchParams( sort: parseSort(searchParams.get("sort")), direction: parseDirection(searchParams.get("direction")), size: parsePageSize(searchParams.get("size")), - hide: serializeHiddenColumns(parseHiddenColumns(searchParams.get("hide"))) ?? "", + hide: readHideField(searchParams), page: parsePage(searchParams.get("page")), }; } @@ -334,7 +370,7 @@ export function childRunsListPreferencesToSearchParams( if (preferences.sort !== "created_at") params.set("sort", preferences.sort); if (preferences.direction === "asc") params.set("direction", "asc"); if (preferences.size !== DEFAULT_LIST_PAGE_SIZE) params.set("size", String(preferences.size)); - if (preferences.hide !== "") params.set("hide", preferences.hide); + if (preferences.hide !== defaultHideString()) params.set("hide", preferences.hide); if (preferences.page > 1) params.set("page", String(preferences.page)); return params; } diff --git a/apps/fabro-web/app/components/runs-list/run-table-row.tsx b/apps/fabro-web/app/components/runs-list/run-table-row.tsx index de39d465e..79f11ec47 100644 --- a/apps/fabro-web/app/components/runs-list/run-table-row.tsx +++ b/apps/fabro-web/app/components/runs-list/run-table-row.tsx @@ -112,11 +112,6 @@ export function RunTableRow({ {run.statusLabel} - {show("elapsed") && ( - - {run.elapsed} - - )} {show("repo") && ( {run.repo} @@ -164,6 +159,11 @@ export function RunTableRow({ {run.lastEventAt != null ? formatRelativeTime(run.lastEventAt) : ""} )} + {show("elapsed") && ( + + {run.elapsed} + + )} {show("changes") && ( {run.additions != null && +{run.additions.toLocaleString()}} diff --git a/apps/fabro-web/app/components/runs-list/runs-list-view.tsx b/apps/fabro-web/app/components/runs-list/runs-list-view.tsx index 392fe8fc8..84780c578 100644 --- a/apps/fabro-web/app/components/runs-list/runs-list-view.tsx +++ b/apps/fabro-web/app/components/runs-list/runs-list-view.tsx @@ -134,9 +134,6 @@ export function RunsListView({ /> - {show("elapsed") && ( - - )} {show("repo") && ( )} @@ -150,6 +147,9 @@ export function RunsListView({ {show("updated") && ( )} + {show("elapsed") && ( + + )} {show("changes") && ( )} diff --git a/apps/fabro-web/app/routes/run-children.tsx b/apps/fabro-web/app/routes/run-children.tsx index eda2b344a..60c4bdcc5 100644 --- a/apps/fabro-web/app/routes/run-children.tsx +++ b/apps/fabro-web/app/routes/run-children.tsx @@ -11,6 +11,7 @@ import { childRunsListPreferencesToSearchParams, createdCutoffMsFor, createdFilterOptions, + hiddenColumnsFromSearchParams, parseCreatedFilter, parseDirection, parsePage, @@ -21,7 +22,7 @@ import { } from "../components/runs-list/preferences"; import type { ChildRunsListPreferences, CreatedFilter } from "../components/runs-list/preferences"; import { RunsListView } from "../components/runs-list/runs-list-view"; -import { parseHiddenColumns, serializeHiddenColumns } from "../components/runs-list/toggleable-column"; +import { serializeHiddenColumns } from "../components/runs-list/toggleable-column"; import type { ToggleableColumn } from "../components/runs-list/toggleable-column"; import { SECONDARY_BUTTON_CLASS } from "../components/ui"; import { ApiError } from "../lib/api-client"; @@ -48,7 +49,7 @@ export default function RunChildren() { const page = parsePage(searchParams.get("page")); const pageSize = parsePageSize(searchParams.get("size")); const hiddenColumns = useMemo( - () => parseHiddenColumns(searchParams.get("hide")), + () => hiddenColumnsFromSearchParams(searchParams), [searchParams], ); diff --git a/apps/fabro-web/app/routes/runs.tsx b/apps/fabro-web/app/routes/runs.tsx index a58b270a4..f34af3c37 100644 --- a/apps/fabro-web/app/routes/runs.tsx +++ b/apps/fabro-web/app/routes/runs.tsx @@ -34,6 +34,7 @@ import { FilterButton } from "../components/runs-list/filter-button"; import { createdCutoffMsFor, createdFilterOptions, + hiddenColumnsFromSearchParams, parseCreatedFilter, parseDirection, parsePage, @@ -51,7 +52,7 @@ import type { ViewMode, } from "../components/runs-list/preferences"; import { RunsListView } from "../components/runs-list/runs-list-view"; -import { parseHiddenColumns, serializeHiddenColumns } from "../components/runs-list/toggleable-column"; +import { serializeHiddenColumns } from "../components/runs-list/toggleable-column"; import type { ToggleableColumn } from "../components/runs-list/toggleable-column"; import { mutateRunListCaches } from "../lib/board-cache"; import { shouldRefreshBoardForEvent, useBoardEvents } from "../lib/board-events"; @@ -746,7 +747,7 @@ export default function Runs() { const page = parsePage(searchParams.get("page")); const pageSize = parsePageSize(searchParams.get("size")); const hiddenColumns = useMemo( - () => parseHiddenColumns(searchParams.get("hide")), + () => hiddenColumnsFromSearchParams(searchParams), [searchParams], );