feat(ui+legacy): F8-05 owner-feedback round 1 — inspector tweaks + parser
Owner-reported polish on top of #48, plus a legacy-parser gap that prevented verifying stationed ship groups against a real .REP fixture. UI: - Production: drop the empty `(production)` placeholder option. Owned planets always produce something, so the primary select now opens on `industry` by default when `planet.production` is null/unknown, keeping the row inside the four real production kinds at all times. - Production: lock the row to a single line (no flex-wrap) and strip border + padding from the ✓/✗ buttons so the apply/cancel icons read as glyphs and the row no longer breaks into two visual rows for Research / Ship contexts where both selects are present. - Cargo routes: the placeholder option is now an `<option disabled>` styled like a section header (greyed, italic) and reads "manage routes" instead of "cargo routes". The wording shifts the intent from a section label to an action prompt. Legacy parser: - F8-05 (#48 п.32) "Stationed ship groups" couldn't be verified against the dg fixture because the legacy `<Race> Groups` blocks (outside battles) and the `Unidentified Groups` block were dropped by the parser — both are now wired up. Foreign group rows parse the `# T D W S C T Q D P M` columns and resolve the destination against the parsed planet tables (rows with an invisible destination drop, matching the existing local-group convention). The legacy row carries no origin / range columns, so foreign groups surface as stationed at the destination. - Smoke tests on every fixture extended with `otherGroups` and `unidentifiedGroups` counts. New focused unit test `TestParseOtherAndUnidentifiedGroups` covers the column layout, the drop-on-unknown-destination rule, and the `X Y`-only unidentified rows. - `tools/local-dev/reports/dg/KNNTS039.json` and `tools/local-dev/reports/dg/KNNTS041.json` regenerated so the synthetic-loader fixtures carry the new arrays. - README updated: the two sections move out of "Skipped sections" into a "Foreign and unidentified groups" block; package doc-comment reflects the broader scope. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -124,13 +124,15 @@ function getTarget(
|
||||
|
||||
describe("planet inspector — production controls", () => {
|
||||
test("renders the main select with localised options and ✓/✗ icons", () => {
|
||||
// No production is set on the seeded planet → the select falls
|
||||
// back to the documented `industry` default (an owned planet
|
||||
// always produces something on the engine side, so there is no
|
||||
// "(none)" placeholder option).
|
||||
const ui = mountProduction(localPlanet({ number: 1 }));
|
||||
const main = getMain(ui);
|
||||
expect(main.value).toBe("");
|
||||
expect(main.value).toBe("industry");
|
||||
const labels = Array.from(main.options).map((o) => o.textContent?.trim());
|
||||
// One placeholder + the four production kinds, in the documented order.
|
||||
expect(labels).toEqual([
|
||||
"(production)",
|
||||
"industry",
|
||||
"materials",
|
||||
"research",
|
||||
@@ -140,18 +142,20 @@ describe("planet inspector — production controls", () => {
|
||||
expect(
|
||||
ui.queryByTestId("inspector-planet-production-target"),
|
||||
).toBeNull();
|
||||
// The row is dirty against the seeded `production: null`, so
|
||||
// both icon buttons are enabled — the player can either ✓ to
|
||||
// confirm the default or ✗ to revert (back to industry again).
|
||||
expect(
|
||||
ui.getByTestId("inspector-planet-production-apply"),
|
||||
).toBeDisabled();
|
||||
).not.toBeDisabled();
|
||||
expect(
|
||||
ui.getByTestId("inspector-planet-production-cancel"),
|
||||
).toBeDisabled();
|
||||
).not.toBeDisabled();
|
||||
});
|
||||
|
||||
test("Industry pick + ✓ emits a CAP setProductionType command", async () => {
|
||||
test("Industry default + ✓ emits a CAP setProductionType command", async () => {
|
||||
const ui = mountProduction(localPlanet({ number: 7 }));
|
||||
const main = getMain(ui);
|
||||
await fireEvent.change(main, { target: { value: "industry" } });
|
||||
expect(getMain(ui).value).toBe("industry");
|
||||
const apply = ui.getByTestId("inspector-planet-production-apply");
|
||||
expect(apply).not.toBeDisabled();
|
||||
await fireEvent.click(apply);
|
||||
@@ -268,7 +272,7 @@ describe("planet inspector — production controls", () => {
|
||||
test("active main derivation seeds the select from planet.production", () => {
|
||||
const cases: ReadonlyArray<{
|
||||
production: string | null;
|
||||
expected: "" | "industry" | "materials" | "research" | "ship";
|
||||
expected: "industry" | "materials" | "research" | "ship";
|
||||
}> = [
|
||||
{ production: "Capital", expected: "industry" },
|
||||
{ production: "Material", expected: "materials" },
|
||||
@@ -277,9 +281,11 @@ describe("planet inspector — production controls", () => {
|
||||
{ production: "Shields", expected: "research" },
|
||||
{ production: "Cargo", expected: "research" },
|
||||
{ production: "Scout", expected: "ship" },
|
||||
{ production: "-", expected: "" },
|
||||
{ production: null, expected: "" },
|
||||
{ production: "UnknownThing", expected: "" },
|
||||
// Falls back to the documented `industry` default when the
|
||||
// engine display string is missing or unrecognised.
|
||||
{ production: "-", expected: "industry" },
|
||||
{ production: null, expected: "industry" },
|
||||
{ production: "UnknownThing", expected: "industry" },
|
||||
];
|
||||
for (const tc of cases) {
|
||||
const ui = mountProduction(
|
||||
|
||||
Reference in New Issue
Block a user