From 209f8508cd89ff8a4c86d36fbbf143dd9beab645 Mon Sep 17 00:00:00 2001 From: Ilia Denisov Date: Wed, 27 May 2026 22:12:51 +0200 Subject: [PATCH] =?UTF-8?q?feat(ui):=20F8-11=20=E2=80=94=20battles=20table?= =?UTF-8?q?=20under=20table=20submenu=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a sortable battles list as a new entity under the existing `view → table` submenu (entity slug `battles`), replacing the standalone top-level `battle log` shortcut which always opened a "battle not found" placeholder. The single-battle viewer stays put and is reached only by clicking a row (or a battle marker on the map), identical to the existing `section-battles.svelte` flow. Columns are planet (via the shared `planetLabel` helper) and shots (the per-battle action count carried by `BattleSummary`), sortable both ways with shots-desc default. No backend / FBS / map changes: the wire payload is unchanged. Participants / observers / total mass require the full BattleReport and were intentionally dropped to avoid N round trips per menu open. The top-level `battle log` item is removed from `header/view-menu` and `sidebar/bottom-tabs` (and their stale comment blocks updated); the now-orphan `game.view.battle` i18n key is dropped from both locales. --- .../active-view/table-battles-state.svelte.ts | 34 +++ .../src/lib/active-view/table-battles.svelte | 226 +++++++++++++++++ ui/frontend/src/lib/active-view/table.svelte | 3 + ui/frontend/src/lib/header/view-menu.svelte | 22 +- ui/frontend/src/lib/i18n/locales/en.ts | 7 +- ui/frontend/src/lib/i18n/locales/ru.ts | 7 +- .../src/lib/sidebar/bottom-tabs.svelte | 19 +- ui/frontend/tests/e2e/game-shell.spec.ts | 2 +- ui/frontend/tests/game-shell-header.test.ts | 2 +- ui/frontend/tests/table-battles.test.ts | 237 ++++++++++++++++++ 10 files changed, 529 insertions(+), 30 deletions(-) create mode 100644 ui/frontend/src/lib/active-view/table-battles-state.svelte.ts create mode 100644 ui/frontend/src/lib/active-view/table-battles.svelte create mode 100644 ui/frontend/tests/table-battles.test.ts diff --git a/ui/frontend/src/lib/active-view/table-battles-state.svelte.ts b/ui/frontend/src/lib/active-view/table-battles-state.svelte.ts new file mode 100644 index 0000000..b414c44 --- /dev/null +++ b/ui/frontend/src/lib/active-view/table-battles-state.svelte.ts @@ -0,0 +1,34 @@ +// F8-11 battles table — module-level sort rune. +// +// Held outside the component so the user's sort choice survives the +// component being unmounted (row click → battle viewer → back to the +// table). Held in memory only; an F5 reloads the report and the +// defaults take over. + +export type BattlesSortColumn = "planet" | "shots"; + +export type BattlesSortDirection = "asc" | "desc"; + +export interface BattlesTableState { + sortColumn: BattlesSortColumn; + sortDirection: BattlesSortDirection; +} + +const DEFAULT_STATE: BattlesTableState = { + sortColumn: "shots", + sortDirection: "desc", +}; + +export const battlesTableState: BattlesTableState = $state({ + ...DEFAULT_STATE, +}); + +/** + * resetBattlesTableState restores every field to its default value. + * Production code never calls it; the Vitest harness uses it from + * `beforeEach` to keep cases independent (the rune is a module-level + * singleton that otherwise carries state across test boundaries). + */ +export function resetBattlesTableState(): void { + Object.assign(battlesTableState, DEFAULT_STATE); +} diff --git a/ui/frontend/src/lib/active-view/table-battles.svelte b/ui/frontend/src/lib/active-view/table-battles.svelte new file mode 100644 index 0000000..36e70cc --- /dev/null +++ b/ui/frontend/src/lib/active-view/table-battles.svelte @@ -0,0 +1,226 @@ + + + +
+
+

{i18n.t("game.table.battles.title")}

+
+ + {#if !reportLoaded} + + {:else if battles.length === 0} + + {:else} + + + + {#each COLUMNS as column (column)} + + {/each} + + + + {#each sorted as b (b.id)} + openBattle(b)} + > + + + + {/each} + +
+ +
+ {planetLabel(b.planet, planets)} + + {formatInt(b.shots)} +
+ {/if} +
+ + diff --git a/ui/frontend/src/lib/active-view/table.svelte b/ui/frontend/src/lib/active-view/table.svelte index fe8a1ba..f862b1a 100644 --- a/ui/frontend/src/lib/active-view/table.svelte +++ b/ui/frontend/src/lib/active-view/table.svelte @@ -14,6 +14,7 @@ e2e specs (`game-shell.spec.ts`, `view-menu`) keep matching. import TableFleets from "./table-fleets.svelte"; import TableSciences from "./table-sciences.svelte"; import TableRaces from "./table-races.svelte"; + import TableBattles from "./table-battles.svelte"; type Props = { entity: string }; let { entity }: Props = $props(); @@ -36,6 +37,8 @@ e2e specs (`game-shell.spec.ts`, `view-menu`) keep matching. {:else if entity === "races"} +{:else if entity === "battles"} + {:else}