ui/phase-21: sciences CRUD list, designer, and production-picker integration
Lights up the player-defined sciences feature: a table view with sort and filter, a designer with four percent inputs and a strict sum-equals-100 gate, and a Research-sub-row integration so the planet production picker lists the user's sciences alongside the four tech buttons. Phase 21 decisions are baked back into ui/PLAN.md (no UpdateScience on the wire — write-once via createScience + removeScience; percentages instead of fractions; sciences live under the existing Research segment). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,7 @@ import {
|
||||
import { submitOrder } from "./submit";
|
||||
import { validateEntityName } from "$lib/util/entity-name";
|
||||
import { validateShipClass } from "$lib/util/ship-class-validation";
|
||||
import { validateScience } from "$lib/util/science-validation";
|
||||
|
||||
const NAMESPACE = "order-drafts";
|
||||
const draftKey = (gameId: string): string => `${gameId}/draft`;
|
||||
@@ -518,6 +519,27 @@ function validateCommand(cmd: OrderCommand): CommandStatus {
|
||||
// active production / ship groups. Local validation only
|
||||
// guards the name shape.
|
||||
return validateEntityName(cmd.name).ok ? "valid" : "invalid";
|
||||
case "createScience":
|
||||
// Mirrors `pkg/calc/validator.go.ValidateScienceValues`
|
||||
// plus the entity-name rules. The wire shape is fractions
|
||||
// (sum to 1.0); the validator runs without `existingNames`
|
||||
// here for the same reason ship-class create does — a
|
||||
// duplicate-name check is the designer's UX responsibility,
|
||||
// not the draft store's.
|
||||
return validateScience({
|
||||
name: cmd.name,
|
||||
drive: cmd.drive * 100,
|
||||
weapons: cmd.weapons * 100,
|
||||
shields: cmd.shields * 100,
|
||||
cargo: cmd.cargo * 100,
|
||||
}).ok
|
||||
? "valid"
|
||||
: "invalid";
|
||||
case "removeScience":
|
||||
// `removeScience` carries only the name; the engine checks
|
||||
// that the science exists and is not referenced by active
|
||||
// production. Local validation only guards the name shape.
|
||||
return validateEntityName(cmd.name).ok ? "valid" : "invalid";
|
||||
case "breakShipGroup":
|
||||
// Engine rule (`controller/ship_group.go.breakGroup`):
|
||||
// quantity must be at least 1 and strictly less than the
|
||||
|
||||
Reference in New Issue
Block a user