feat(ui): F8-10 — tables planets / ship-groups / fleets, ship-classes delete guard (#53)
Lights up three previously-stubbed table active views and tightens the
existing one:
- table-planets: 4 kind checkboxes (own / foreign / uninhabited /
unknown) + race dropdown that filters the foreign slice; row click
selects + centres the planet on the map.
- table-ship-groups: local + foreign groups in one grid, owner
checkboxes, planet dropdown (destination OR origin), class
dropdown; on-planet click focuses the destination planet, in-space
click focuses the ship group itself (camera follows interpolated
position).
- table-fleets: own fleets only with the shared planet dropdown;
on-planet click focuses the planet, in-space click centres the
camera on the interpolated fleet position without altering the
selection (no fleet variant in Selected).
- table-ship-classes: per-row Delete is disabled with a count tooltip
while at least one local ship group references the class. The
engine refuses the removal anyway; the UI pre-empts the surface.
Wires the click → map flow through a transient `SelectionStore.focus`
/ `focusPoint` channel that `map.svelte` consumes once on mount —
in-memory only, so an F5 does not re-centre.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -17,7 +17,11 @@ import {
|
||||
} from "vitest";
|
||||
|
||||
import { i18n } from "../src/lib/i18n/index.svelte";
|
||||
import type { GameReport, ShipClassSummary } from "../src/api/game-state";
|
||||
import type {
|
||||
GameReport,
|
||||
ReportLocalShipGroup,
|
||||
ShipClassSummary,
|
||||
} from "../src/api/game-state";
|
||||
import {
|
||||
ORDER_DRAFT_CONTEXT_KEY,
|
||||
OrderDraftStore,
|
||||
@@ -89,7 +93,10 @@ function shipClass(
|
||||
};
|
||||
}
|
||||
|
||||
function makeReport(localShipClass: ShipClassSummary[]): GameReport {
|
||||
function makeReport(
|
||||
localShipClass: ShipClassSummary[],
|
||||
localShipGroups: ReportLocalShipGroup[] = [],
|
||||
): GameReport {
|
||||
return {
|
||||
turn: 1,
|
||||
mapWidth: 1000,
|
||||
@@ -104,6 +111,29 @@ function makeReport(localShipClass: ShipClassSummary[]): GameReport {
|
||||
localPlayerShields: 0,
|
||||
localPlayerCargo: 0,
|
||||
...EMPTY_SHIP_GROUPS,
|
||||
localShipGroups,
|
||||
};
|
||||
}
|
||||
|
||||
function shipGroup(
|
||||
overrides: Partial<ReportLocalShipGroup> &
|
||||
Pick<ReportLocalShipGroup, "class">,
|
||||
): ReportLocalShipGroup {
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
state: "In_Orbit",
|
||||
fleet: null,
|
||||
count: 1,
|
||||
tech: { drive: 0, weapons: 0, shields: 0, cargo: 0 },
|
||||
cargo: "NONE",
|
||||
load: 0,
|
||||
destination: 1,
|
||||
origin: null,
|
||||
range: null,
|
||||
speed: 0,
|
||||
mass: 0,
|
||||
race: "Foo",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -210,6 +240,34 @@ describe("ship-classes table", () => {
|
||||
expect(cmd.name).toBe("Drone");
|
||||
});
|
||||
|
||||
test("delete is disabled when a local ship group uses the class", async () => {
|
||||
const ui = mountTable(
|
||||
makeReport(
|
||||
[shipClass({ name: "Cruiser" }), shipClass({ name: "Drone" })],
|
||||
[
|
||||
shipGroup({ class: "Cruiser" }),
|
||||
shipGroup({ class: "Cruiser", count: 4 }),
|
||||
],
|
||||
),
|
||||
);
|
||||
const buttons = ui.getAllByTestId("ship-classes-delete");
|
||||
const map = new Map(
|
||||
buttons.map((b) => {
|
||||
const row = b.closest('[data-testid="ship-classes-row"]');
|
||||
return [row?.getAttribute("data-name") ?? "", b];
|
||||
}),
|
||||
);
|
||||
const cruiserBtn = map.get("Cruiser") as HTMLButtonElement;
|
||||
const droneBtn = map.get("Drone") as HTMLButtonElement;
|
||||
expect(cruiserBtn).toBeDisabled();
|
||||
expect(cruiserBtn).toHaveAttribute(
|
||||
"title",
|
||||
expect.stringContaining("2"),
|
||||
);
|
||||
expect(droneBtn).not.toBeDisabled();
|
||||
expect(droneBtn).toHaveAttribute("title", "");
|
||||
});
|
||||
|
||||
test("new button requests a fresh calculator design", async () => {
|
||||
const ui = mountTable(makeReport([]));
|
||||
const before = calculatorLoadRequest.token;
|
||||
|
||||
Reference in New Issue
Block a user