Migrate graph-maker block to the structurer and BlockModelV3#133
Migrate graph-maker block to the structurer and BlockModelV3#133vadimpiven wants to merge 7 commits into
Conversation
- Apply oxfmt formatting across ui/test sources (oxfmt could not run in the refresh commit until the lint errors below were fixed). - Add a *.svg ambient module declaration so vue-tsc resolves icon imports (vite still handles the actual asset bundling). - Narrow GraphPageState.settings to the chartType actually consumed; in SDK 1.79 OutputWithStatus<PFrameHandle> no longer admits the placeholder `pFrame: undefined` set at graph creation (pFrame comes live from outputs). - Remove a stray console.log and an unused RenderCtx import. - Add the structurer block smoke test (replacing the empty placeholder). - Bump @milaboratories/graph-maker 1.4.1 -> 1.4.6.
Hand-rolled V3 migration that keeps the multi-graph model (the planned multi-graph plugin is not ready, so the graphMakerPlugin is intentionally not adopted here). - Model: BlockModelV3.create(blockDataModel); the graph-page list is unified UI-only state (BlockData.graphs) projected to empty args. A one-time upgradeLegacy carries the V1 uiState.graphs over; fresh projects init to []. - pFrame stays an outputWithStatus via createPFrameForGraphs(ctx); sections are derived from ctx.data.graphs. - UI: defineApp -> defineAppV3; app.model.ui.graphs -> app.model.data.graphs; drop the now-unnecessary uiState init guard (V3 data is always initialized).
There was a problem hiding this comment.
Code Review
This pull request migrates the graph-maker block to the block-tools structurer and BlockModelV3, which includes upgrading the SDK dependencies, transitioning the model from the legacy V1 API, and updating UI bindings to use app.model.data with defineAppV3. The feedback recommends improving robustness by avoiding non-null assertions in tests, filtering out non-numeric IDs when calculating the next graph ID to prevent NaN propagation, and directly using mapped item settings in GraphPage.vue instead of relying on an external computed property.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
- wf.test.ts: add { timeout: 30000 } to the block smoke test; the default
5s vitest timeout is too short for the addBlock + runBlock + awaitBlockDone
backend round-trip (CI failure). Matches the 20-30s convention used by other
block tests.
- GraphPage.vue: write `item.settings` directly in the state setter instead of
the external `graphProps.value` computed (per review) — local, non-undefined.
The structurer's refresh flipped build.yaml `test` to true; the original graph-maker config (and the table block) use `test: false`. With a real backend-driven smoke test now present, `test: true` made block CI try to run it without a pl backend -> RpcError ECONNREFUSED 127.0.0.1:6345. Restore `test: false`; the smoke test stays in-repo for local/manual backend runs.
…d start Revert the earlier test:false workaround — respect the structurer's test:true. The block smoke test runs against a CI-provisioned pl backend whose cold start has no readiness gate (pl-compose uses a bare `sleep 1`), so a single attempt loses the startup race -> RpcError ECONNREFUSED 127.0.0.1:6345. Match the green test:true blocks (clonotype-browser, mixcr-clonotyping): add retry: 2 + testTimeout to test/vitest.config.mts. No pl-docker-tag pin (default image).
Migrates the graph-maker block onto the block-tools structurer, completes the SDK upgrade, and moves the model to BlockModelV3.
Changes
1dd9d91): tool-managed layout (oxlint/oxfmt, managed tsconfig/turbo/catalog), dropping the vite/prettier toolchain. Full SDK upgrade — model/ui-vue 1.79, workflow-tengo 6, tengo-builder 4, block-tools 2.11.109706b):*.svgambient declaration for the newvue-tsccheck (vite still bundles the assets);GraphPageState.settingsnarrowed to thechartTypeactually consumed (SDK 1.79OutputWithStatus<PFrameHandle>no longer admits the placeholderpFrame: undefined); removed a strayconsole.logand an unused import; added the structurer block smoke test. Bumped@milaboratories/graph-maker1.4.1 → 1.4.6.774be19): the multi-graph page list is unified UI-only state (BlockData.graphs) projected to empty args; a one-timeupgradeLegacycarries the V1uiState.graphsover.pFramestays anoutputWithStatusviacreatePFrameForGraphs; sections derive fromctx.data.graphs. UI moves todefineAppV3andapp.model.data.Notes
graphMakerPluginis single-instance, but this block is multi-graph (unbounded user-created pages); the multi-graph plugin is not yet available. The V3 model is therefore hand-rolled, keeping the existing multi-graph behavior.upgradeLegacyfires on a V1-saved project needs a running backend; CI build is green.Greptile Summary
This PR migrates the graph-maker block to the structurer toolchain (oxlint/oxfmt), upgrades the full SDK stack (model/ui-vue 1.79, workflow-tengo 6, tengo-builder 4, block-tools 2.11), and moves the block model from
BlockModel(V1/V2) toBlockModelV3with aDataModelBuilder. The multi-graph page list moves from splitargs+uiStateinto a single unifiedBlockData.graphs, with a one-timeupgradeLegacymigration path for V1-saved projects.BlockModelV3+DataModelBuilder:blockDataModeldefines the on-disk format as"v1"(BlockData { graphs: GraphPageState[] });.upgradeLegacyextracts the olduiState.graphslist;.initseeds empty graphs for new blocks.platformais built with.args<BlockArgs>(() => ({}))(no-op) and.outputWithStatus("pFrame", createPFrameForGraphs).defineApp→defineAppV3; allapp.model.ui.*accesses replaced withapp.model.data.*; stale null-guard onapp.model.uiand a leftoverconsole.logremoved fromMainPage.vue;GraphPageState.settingsnarrowed toPick<GraphMakerProps, "chartType">sincepFrameis now sourced from the model output.GraphPageState.settingstype narrowing: Thesettingsfield previously held the fullGraphMakerProps(includingpFrame: undefined); it is now typed asPick<GraphMakerProps, "chartType">. Thestatesetter inGraphPage.vueassignssettings: graphProps.valueinside anas GraphPageStatecast, which hides the fact thatgraphProps.valuecan beundefined— runtime safety is preserved by thev-ifguard but the cast is type-unsafe.Key terms touched in this PR:
BlockModelV3DataModelBuilder-produced data model rather than separate args/uiStateBlockModel.create('Heavy')throughoutBlockData{ graphs: GraphPageState[] }) that replaces the former splitBlockArgs + UiStatemodel/src/types.tsDataModelBuilderblockDataModelinmodel/src/dataModel.tsupgradeLegacyDataModelBuildermethod that transforms legacy(args, uiState)pairs toBlockData; fires once on first load of a V1 projectuiState.graphsforward; V1 args were always emptyGraphPageState{ id, label, state: GraphMakerState, settings }settingsnarrowed fromGraphMakerPropstoPick<GraphMakerProps, "chartType">—pFrameremoved since it now comes from the model outputLegacyUiStateuiStateshape consumed byupgradeLegacyGraphPageState(extrapFramefield in legacy JSON is harmless at runtime)defineAppV3BlockModelV3-based appsdefineApp; accessed viaapp.model.datainstead ofapp.model.uiOutputWithStatus<PFrameHandle>PFrameHandleoutput that carries load/error status.outputWithStatus("pFrame", (ctx) => createPFrameForGraphs(ctx)); no longer admitspFrame: undefinedplaceholderConfidence Score: 4/5
The migration is structurally sound; the only concern is a type-unsafe cast in GraphPage.vue that a v-if guard makes safe at runtime, and a console.dir without assertion in the new smoke test.
The core V3 model wiring, upgradeLegacy path, and UI migration all look correct. The state setter in GraphPage.vue uses
as GraphPageStateto hide a potentialundefinedin the settings field — the v-if guard prevents this from firing at runtime but the cast makes the invariant invisible to future editors. The smoke test logs the block state but makes no assertion, so it can never fail even on a broken block.ui/src/GraphPage.vue (type-unsafe cast in state setter) and test/src/wf.test.ts (assertion-free smoke test)
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD subgraph Legacy["Legacy V1 on-disk format"] A["args: {}"] B["uiState: { graphs: GraphPageState[] }"] end subgraph DataModel["DataModelBuilder (dataModel.ts)"] C[".upgradeLegacy()\nextract uiState.graphs"] D[".init()\ngraphs: []"] E[".from<BlockData>('v1')"] end subgraph V3["BlockModelV3 (index.ts)"] F[".args<BlockArgs>(() => ({}))"] G[".sections(ctx => ctx.data.graphs.map(...))"] H[".outputWithStatus('pFrame', createPFrameForGraphs)"] I[".done()"] end subgraph UI["Vue UI"] J["defineAppV3(platforma)"] K["app.model.data.graphs"] L["GraphPage.vue\nstate + settings"] M["MainPage.vue\nnewId + addSection"] end B -->|"first load"| C C --> E D -->|"new block"| E E --> F F --> G G --> H H --> I I --> J J --> K K --> L K --> M H -->|"pFrame output"| L%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD subgraph Legacy["Legacy V1 on-disk format"] A["args: {}"] B["uiState: { graphs: GraphPageState[] }"] end subgraph DataModel["DataModelBuilder (dataModel.ts)"] C[".upgradeLegacy()\nextract uiState.graphs"] D[".init()\ngraphs: []"] E[".from<BlockData>('v1')"] end subgraph V3["BlockModelV3 (index.ts)"] F[".args<BlockArgs>(() => ({}))"] G[".sections(ctx => ctx.data.graphs.map(...))"] H[".outputWithStatus('pFrame', createPFrameForGraphs)"] I[".done()"] end subgraph UI["Vue UI"] J["defineAppV3(platforma)"] K["app.model.data.graphs"] L["GraphPage.vue\nstate + settings"] M["MainPage.vue\nnewId + addSection"] end B -->|"first load"| C C --> E D -->|"new block"| E E --> F F --> G G --> H H --> I I --> J J --> K K --> L K --> M H -->|"pFrame output"| LPrompt To Fix All With AI
Reviews (1): Last reviewed commit: "Add changeset for structurer + V3 migrat..." | Re-trigger Greptile
Context used: