From 403bdb5abecb73c203262dd2ed24f1fe9df38f6a Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Sat, 6 Jun 2026 02:40:24 +0200 Subject: [PATCH] =?UTF-8?q?docs(furni-editor):=20client/renderer=20plan=20?= =?UTF-8?q?=E2=80=94=20furnidata=20editing=20UI=20+=20typography=20refresh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...026-06-06-furni-editor-furnidata-client.md | 240 ++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-06-furni-editor-furnidata-client.md diff --git a/docs/superpowers/plans/2026-06-06-furni-editor-furnidata-client.md b/docs/superpowers/plans/2026-06-06-furni-editor-furnidata-client.md new file mode 100644 index 0000000..44c57ec --- /dev/null +++ b/docs/superpowers/plans/2026-06-06-furni-editor-furnidata-client.md @@ -0,0 +1,240 @@ +# Furni editor — furnidata editing UI + typography refresh (Client/Renderer) Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:subagent-driven-development. Steps use checkbox (`- [ ]`). + +**Goal:** Expose the server-side furnidata name/description editing (Plan A, already on Arcturus `main`) in the React furni editor: make Classname/Public Name read-only, add an editable **Furnidata** section (Display Name + Description) with diff-confirm + revert, search by furnidata name, and refresh the editor's typography/colors to the theme tokens. + +**Architecture:** Renderer (`Nitro_Render_V3`) gains 2 outgoing composers matching the server's incoming headers (update **10046**, revert **10048**); the success result reuses the existing `FurniEditorResult` (10044) and live propagation reuses the merged `FurnitureDataReload` (10047). Client (`Nitro-V3`) adds hook actions + UI. A small server tweak lets search match furnidata display names. + +**Tech Stack:** React 19 + Vite + TailwindCSS 4 (theme tokens in `tailwind.config.js`), TS, Vitest (client); TS/PixiJS (renderer); Java/Maven (server tweak). Server feature already built (Plan A). + +**Companion:** spec `Arcturus-Morningstar-Extended/docs/superpowers/specs/2026-06-06-furni-editor-furnidata-names-design.md`; server plan `…/plans/2026-06-06-furni-editor-furnidata-names-server.md`. Exploration of the client (exact file:line) is in this session's history — follow the cited patterns. + +**Server header contract (already on Arcturus main):** incoming `FurniEditorUpdateFurnidataEvent = 10046` reads `int itemId` + `String` (JSON `{name,description}`); incoming `FurniEditorRevertFurnidataEvent = 10048` reads `int itemId`; both respond with `FurniEditorResultComposer` (10044) and broadcast `FurnitureDataReloadComposer` (10047). + +--- + +## Task 1 (renderer): outgoing composers + headers + +**Files (in `E:\Users\simol\Desktop\DEV\Nitro_Render_V3\packages\communication\src\messages`):** +- Modify: `outgoing/OutgoingHeader.ts` (after `FURNI_EDITOR_DELETE = 10045`, ~line 505) +- Create: `outgoing/furnieditor/FurniEditorUpdateFurnidataComposer.ts` +- Create: `outgoing/furnieditor/FurniEditorRevertFurnidataComposer.ts` +- Modify: the furnieditor `index.ts` barrel (same folder as the existing furni-editor composers) + +- [ ] **Step 1: Add headers** in `OutgoingHeader.ts`: +```ts + public static readonly FURNI_EDITOR_UPDATE_FURNIDATA = 10046; + public static readonly FURNI_EDITOR_REVERT_FURNIDATA = 10048; +``` +(Match the real declaration style in that file — `public static readonly NAME: number = id;` or the enum/const pattern actually used. Verify 10046/10048 are unused in OutgoingHeader.) + +- [ ] **Step 2: Create `FurniEditorUpdateFurnidataComposer.ts`** (mirror the existing `FurniEditorUpdateComposer` in the same folder): +```ts +import { IMessageComposer } from '../../../../api'; +import { OutgoingHeader } from '../OutgoingHeader'; + +export class FurniEditorUpdateFurnidataComposer implements IMessageComposer> +{ + private _data: ConstructorParameters; + + constructor(itemId: number, jsonFields: string) + { + this._data = [ itemId, jsonFields ]; + } + + public getMessageArray() { return this._data; } + public dispose() { this._data = null; } + public getHeader() { return OutgoingHeader.FURNI_EDITOR_UPDATE_FURNIDATA; } +} +``` +**Before writing, open the real `FurniEditorUpdateComposer.ts`** and copy its EXACT structure/imports (the `IMessageComposer` import path + the `getMessageArray/getHeader/dispose` shape may differ from the above; match it verbatim, only changing the header constant and that the payload is `[itemId, jsonFields]`). + +- [ ] **Step 3: Create `FurniEditorRevertFurnidataComposer.ts`** — same pattern, constructor `(itemId: number)`, payload `[ itemId ]`, header `FURNI_EDITOR_REVERT_FURNIDATA`. + +- [ ] **Step 4: Export both** from the furnieditor composers `index.ts` barrel (add the two `export * from './FurniEditor...Composer';` lines next to the existing furni-editor composer exports). + +- [ ] **Step 5: Build** — `cd E:\Users\simol\Desktop\DEV\Nitro_Render_V3 && yarn compile:fast` (or the real compile script in package.json). Expected: clean, no TS errors. + +- [ ] **Step 6: Commit** (renderer repo): +``` +git -C "E:/Users/simol/Desktop/DEV/Nitro_Render_V3" add packages/communication/src/messages/outgoing/OutgoingHeader.ts packages/communication/src/messages/outgoing/furnieditor/ +git -C "E:/Users/simol/Desktop/DEV/Nitro_Render_V3" commit -m "feat(furnieditor): outgoing composers for furnidata update (10046) + revert (10048)" +``` +NO `Co-Authored-By` trailer. + +--- + +## Task 2 (client): hook actions + +**Files:** Modify `E:\Users\simol\Desktop\DEV\Nitro-V3\src\hooks\furni-editor\useFurniEditor.ts` + +- [ ] **Step 1: Parse furnidata name/desc into state.** Where the detail handler parses `furniDataJson` into `furniDataEntry` (lines ~140–152), also derive convenience strings. The `furniDataEntry` is `Record` with `name`/`description` keys. No new state needed — the EditView will read `furniDataEntry?.name`/`furniDataEntry?.description`. (No change required here if the EditView reads `furniDataEntry`; otherwise expose `furniDataName`/`furniDataDescription` strings. Choose the minimal path — prefer reading `furniDataEntry` directly in the view.) + +- [ ] **Step 2: Add actions.** Mirror `updateItem` (lines ~233–239). Add inside the hook body and to the return object (lines ~254–259): +```ts +const updateFurnidata = useCallback((id: number, name: string, description: string) => +{ + pendingActionRef.current = { type: 'update', id }; + setLoading(true); + SendMessageComposer(new FurniEditorUpdateFurnidataComposer(id, JSON.stringify({ name, description }))); +}, []); + +const revertFurnidata = useCallback((id: number) => +{ + pendingActionRef.current = { type: 'update', id }; + setLoading(true); + SendMessageComposer(new FurniEditorRevertFurnidataComposer(id)); +}, []); +``` +Use the REAL send-composer helper this hook already uses (the exploration shows `updateItem` sends `new FurniEditorUpdateComposer(...)` — copy its exact send mechanism, whether `SendMessageComposer(...)` or a local `send`). Import the two new composers from `@nitrots/nitro-renderer`. Reusing `pendingActionRef.type='update'` makes the existing `FurniEditorResultEvent` success handler (lines ~162–210) auto-reload the detail — which is what we want after a furnidata write. + +- [ ] **Step 3: Export** `updateFurnidata`, `revertFurnidata` in the hook's return object. + +- [ ] **Step 4: Typecheck** — `cd E:\Users\simol\Desktop\DEV\Nitro-V3 && yarn typecheck`. Expected: no new errors (pre-existing renderer-SDK TS2307 in a sandbox without the renderer are acceptable, but here the renderer IS present so it should be clean for these files). + +- [ ] **Step 5: Commit:** +``` +git -C "E:/Users/simol/Desktop/DEV/Nitro-V3" add src/hooks/furni-editor/useFurniEditor.ts +git -C "E:/Users/simol/Desktop/DEV/Nitro-V3" commit -m "feat(furni-editor): updateFurnidata/revertFurnidata hook actions" +``` +NO `Co-Authored-By`. + +--- + +## Task 3 (client): EditView — read-only classname/public_name + editable Furnidata section + props + +**Files:** Modify `src\components\furni-editor\views\FurniEditorEditView.tsx` and `src\components\furni-editor\FurniEditorView.tsx`. + +- [ ] **Step 1: Thread props.** In `FurniEditorEditViewProps` add `onUpdateFurnidata: (id: number, name: string, description: string) => void;` and `onRevertFurnidata: (id: number) => void;`. In `FurniEditorView.tsx` (where `` is rendered, ~lines 149–158), pass `onUpdateFurnidata={ updateFurnidata }` and `onRevertFurnidata={ revertFurnidata }` (destructure them from `useFurniEditor()`). + +- [ ] **Step 2: Make Classname + Public Name read-only.** In the Basic Info section (lines ~232–256): replace the **Item Name** `` with a read-only display, relabel to **"Classname"**, and render the value in monospace on a muted background (see Task 4 classes). Same for **Public Name** (label it "Public Name (DB fallback)"). Use a shared `readonlyClass` (Task 4). Keep `form.itemName`/`form.publicName` in state (so `updateItem` still sends unchanged values harmlessly) but do NOT let them be edited. Example: +```tsx +
+ +
{ form.itemName }
+
+
+ +
{ form.publicName }
+
+``` + +- [ ] **Step 3: New editable Furnidata section.** Replace the read-only `FurniData.json` section (lines ~323–334) with: +```tsx +
+ +
+ + setFurniName(e.target.value) } maxLength={ 256 } /> +
+
+ +