ui/phase-20: lock after Send + dashed tracks for in-flight & pending sends

Send joins Modernize / Dismantle / Transfer as a lockable command:
once any of the four lands in the draft for a group, every action
button on its inspector is disabled with a "command pending"
tooltip and the banner names the queued kind. Load / Unload /
Split / Join Fleet stay non-locking — they stack legitimately on
the engine side.

Two dashed overlays now run alongside the cargo-route arrows:

- Yellow dashed track for own in-space groups, drawn from the
  origin planet to the destination (matches the in-space point
  colour so eye reads both as one entity).
- Green dashed track for every wire-valid sendShipGroup command
  in the order draft, drawn from the source group's orbit planet
  to the chosen destination. Disappears when the command is
  removed from the order tab, when the engine rejects it, or
  when the group has left orbit (in-space track replaces it).

Both tracks are wrap-aware via torusShortestDelta and never
participate in hit-test.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-10 17:55:43 +02:00
parent 2d201537ee
commit 54733bfb14
11 changed files with 511 additions and 58 deletions
@@ -123,6 +123,18 @@ describe("reportToWorld — ship groups", () => {
// dest along the segment of length 100 → (25, 0).
expect(group.x).toBe(25);
expect(group.y).toBe(0);
// Yellow dashed track from origin to destination matches the
// in-space point colour.
const lineId = SHIP_GROUP_ID_OFFSETS.localLine + 0;
const line = world.primitives.find((p) => p.id === lineId);
if (line?.kind !== "line") throw new Error("expected line");
expect(line.x1).toBe(100);
expect(line.y1).toBe(0);
expect(line.x2).toBe(0);
expect(line.y2).toBe(0);
expect(line.style.strokeColor).toBe(0xfff176);
expect(line.style.strokeDashPx).toBeGreaterThan(0);
});
test("incoming-group line crosses the torus seam via the shortest path", () => {