ui/phase-12: order composer skeleton
OrderDraftStore persists per-game command drafts in Cache; the sidebar Order tab renders the list with a per-row delete control. The layout passes a `historyMode` prop through Sidebar / BottomTabs as a constant `false`, so Phase 26 only flips the source. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+90
-10
@@ -1332,17 +1332,97 @@ Goal: implement the empty order composer as a persistent vertical list
|
||||
that survives navigation and reloads, ready to receive commands in
|
||||
later phases.
|
||||
|
||||
Artifacts:
|
||||
Decisions taken with the project owner during implementation:
|
||||
|
||||
- `ui/frontend/src/lib/sidebar/order-tab.svelte` vertical command list
|
||||
with empty state copy
|
||||
- `ui/frontend/src/sync/order-draft.ts` draft order store backed by
|
||||
`Cache`, persisting across reloads
|
||||
- `ui/frontend/src/sync/order-types.ts` typed command shape
|
||||
(`OrderCommand` discriminated union)
|
||||
- topic doc `ui/docs/order-composer.md` describing the
|
||||
draft-replaces-server-order model, the local-validation invariant,
|
||||
and command status semantics
|
||||
1. **Store filename uses the runes extension.** PLAN.md originally
|
||||
listed `ui/frontend/src/sync/order-draft.ts`. Svelte 5 runes only
|
||||
compile inside `*.svelte` / `*.svelte.ts` files; the draft state
|
||||
has to be reactive so `order-tab.svelte` re-renders on
|
||||
add/remove/move. The artifact ships as
|
||||
`ui/frontend/src/sync/order-draft.svelte.ts`, mirroring the
|
||||
Phase 11 `lib/game-state.svelte.ts` pattern.
|
||||
2. **Single `placeholder` variant in the discriminated union.** The
|
||||
project compactness rule rejects defining surface for the next
|
||||
phase. Phase 14 owns `planetRename` end-to-end (inspector UI,
|
||||
command type, submit pipeline, server-result merging) and is the
|
||||
right place to add the first real variant. Phase 12 ships exactly
|
||||
one variant — `{ kind: "placeholder"; id: string; label: string }`
|
||||
— sufficient for the add/remove/reorder/persist tests.
|
||||
3. **Reorder API is `move(fromIndex, toIndex)`.** One canonical
|
||||
operation; up/down at the call site is a one-line index
|
||||
arithmetic. No `moveUp`/`moveDown` aliases.
|
||||
4. **Write-on-every-mutation persistence.** `add`/`remove`/`move`
|
||||
each call `Cache.put` with the full draft snapshot. Phase 25 may
|
||||
profile the submit pipeline and batch writes if needed; until
|
||||
then deterministic writes are easier to test.
|
||||
5. **Per-game scoping via Svelte context.** One `OrderDraftStore`
|
||||
instance per game is created in `routes/games/[id]/+layout.svelte`
|
||||
alongside `GameStateStore`, exposed through
|
||||
`ORDER_DRAFT_CONTEXT_KEY`, disposed on layout destroy.
|
||||
6. **`historyMode` as a prop, not a module.** Layout passes
|
||||
`historyMode={false}` (a constant in Phase 12) to `Sidebar` and
|
||||
`BottomTabs`; both forward to their tab-bar children which omit
|
||||
the order entry when the flag is true. Phase 26 introduces the
|
||||
real `lib/history-mode.ts` module and replaces the constant in
|
||||
one place.
|
||||
7. **Empty-state copy is `order is empty` / `приказ пуст`.** The
|
||||
`coming soon` placeholder text is replaced; per-row delete
|
||||
button reads `delete` / `удалить`.
|
||||
8. **e2e seeding via `__galaxyDebug.seedOrderDraft`.** The existing
|
||||
debug surface in `routes/__debug/store/+page.svelte` is extended
|
||||
with `seedOrderDraft(gameId, commands)` and
|
||||
`clearOrderDraft(gameId)` helpers that write directly to the
|
||||
`order-drafts` cache namespace. The store loads the seeded draft
|
||||
on the next layout mount the same way it would after a real
|
||||
reload.
|
||||
9. **Race / disposal hygiene mirrors `GameStateStore`.** Mutations
|
||||
are gated on `status === "ready"` so calls before `init`
|
||||
resolves are no-ops, and `persist` checks a `destroyed` flag so
|
||||
in-flight writes after `dispose` resolve into nothing.
|
||||
|
||||
Artifacts (delivered):
|
||||
|
||||
- `ui/frontend/src/sync/order-types.ts` — `OrderCommand`
|
||||
discriminated union (single `placeholder` variant) and
|
||||
`CommandStatus` lifecycle type.
|
||||
- `ui/frontend/src/sync/order-draft.svelte.ts` —
|
||||
`OrderDraftStore` runes class with
|
||||
`init` / `add` / `remove` / `move` / `dispose`, plus
|
||||
`ORDER_DRAFT_CONTEXT_KEY`. Persists the full draft on every
|
||||
mutation under namespace `order-drafts`, key `{gameId}/draft`.
|
||||
- `ui/frontend/src/lib/sidebar/order-tab.svelte` — replaces the
|
||||
Phase 10 stub. Empty state from `game.sidebar.empty.order`;
|
||||
ordered list with stable `data-testid="order-command-{i}"`
|
||||
rows and a per-row delete button.
|
||||
- `ui/frontend/src/lib/sidebar/sidebar.svelte`,
|
||||
`tab-bar.svelte`, `bottom-tabs.svelte` — `historyMode` prop on
|
||||
the sidebar forwards to `hideOrder` on tab-bar / bottom-tabs;
|
||||
active-tab `order` is reset to `inspector` if the flag flips
|
||||
on, and the `?sidebar=order` URL seed falls back to
|
||||
`inspector` while the flag is true.
|
||||
- `ui/frontend/src/routes/games/[id]/+layout.svelte` —
|
||||
instantiates `OrderDraftStore`, sets context, runs
|
||||
`init({ cache, gameId })` next to `gameState.init` through
|
||||
one `Promise.all`, disposes on destroy, passes
|
||||
`historyMode={false}` down.
|
||||
- `ui/frontend/src/routes/__debug/store/+page.svelte` — extended
|
||||
`DebugSurface` with `seedOrderDraft` / `clearOrderDraft`.
|
||||
- `ui/frontend/src/lib/i18n/locales/{en,ru}.ts` — new
|
||||
`game.sidebar.order.command_delete` key plus updated
|
||||
`game.sidebar.empty.order` copy.
|
||||
- `ui/docs/order-composer.md` — topic doc describing the
|
||||
draft-replaces-server-order model, local-validation invariant,
|
||||
command status state machine, persistence, history-mode wiring,
|
||||
and test layout. Cross-references `storage.md` and
|
||||
`navigation.md`.
|
||||
- `ui/docs/storage.md` — namespace registry row for
|
||||
`order-drafts`.
|
||||
- `ui/docs/navigation.md` — describes the historyMode prop wiring
|
||||
through Sidebar / BottomTabs.
|
||||
- `ui/README.md` — new entry under topic docs for
|
||||
`order-composer.md`.
|
||||
- Vitest: `ui/frontend/tests/order-draft.test.ts`.
|
||||
- Playwright: `ui/frontend/tests/e2e/order-composer.spec.ts`.
|
||||
|
||||
Dependencies: Phases 6, 10.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user