ui/phase-20: pick-first Send + lock after Modernize/Dismantle/Transfer

Send no longer carries a destination control inside the form: a
click on the action drops the inspector straight into map-pick
mode, and the form (ship count + confirm) only mounts after the
player chooses a destination. Cancelling the picker leaves no
form behind.

A queued Modernize / Dismantle / Transfer for a given group
locks every action button on its inspector and surfaces a banner
that points the player at the order list. Cancelling the queued
entry from the order tab releases the lock on the next render —
the derivation watches draft.commands directly. Send / Load /
Unload / Split / Join Fleet do not lock; Send is naturally
followed by an out-of-orbit state at turn cutoff, the rest can
stack legitimately.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-10 17:20:48 +02:00
parent de824dfc9a
commit ac14eaff10
7 changed files with 332 additions and 77 deletions
+12 -17
View File
@@ -14,18 +14,9 @@ import { expect, test, type Page } from "@playwright/test";
const SESSION_ID = "phase-20-send-session";
interface DebugSurface {
ready?: boolean;
loadSession(): Promise<unknown>;
clearSession?(): Promise<void>;
setDeviceSessionId(id: string): Promise<void>;
}
declare global {
interface Window {
__galaxyDebug?: DebugSurface;
}
}
// `Window.__galaxyDebug` is declared as a global in
// `tests/e2e/storage-keypair-persistence.spec.ts`; reuse that
// declaration so the two specs do not collide on the symbol type.
const SYNTHETIC_FIXTURE = {
turn: 1,
@@ -226,15 +217,19 @@ test("send 2 of 3 ships emits implicit Break + Send into the order draft", async
sidebar.getByTestId("inspector-ship-group-class"),
).toHaveText("Frontier");
// Open Send.
// Click Send: the inspector enters map-pick mode immediately; the
// form (ship count + confirm) only mounts after the destination
// is chosen.
await sidebar.getByTestId("inspector-ship-group-action-send").click();
const sendShips = sidebar.getByTestId("inspector-ship-group-form-send-ships");
await sendShips.fill("2");
await expect(
sidebar.getByTestId("inspector-ship-group-form-send-pick-prompt"),
).toBeVisible();
// Pick Mars on the map.
await sidebar.getByTestId("inspector-ship-group-form-send-pick").click();
const marsScreen = await projectWorldToScreen(page, 110, 100);
await page.mouse.click(marsScreen.x, marsScreen.y);
const sendShips = sidebar.getByTestId("inspector-ship-group-form-send-ships");
await sendShips.fill("2");
await expect(
sidebar.getByTestId("inspector-ship-group-form-send-destination"),
).toContainText("Mars");