pmx-canvas 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/extensions/pmx-canvas/extension.mjs +3 -1
- package/.github/extensions/pmx-canvas/runtime.json +1 -1
- package/.github/extensions/pmx-canvas/tools.json +440 -18
- package/CHANGELOG.md +37 -0
- package/dist/amp-plugin/pmx-canvas/LICENSE +21 -0
- package/dist/amp-plugin/pmx-canvas/THIRD_PARTY_LICENSES.txt +331 -0
- package/dist/amp-plugin/pmx-canvas/index.js +5445 -0
- package/dist/amp-plugin/pmx-canvas/runtime.json +3 -0
- package/dist/amp-plugin/pmx-canvas/shared-runtime.mjs +194 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/SKILL.md +251 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/evals.json +1086 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/jwt.ts +17 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/login.ts +12 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/middleware.ts +13 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/routes/auth.ts +13 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/investigation-board/src/handlers/users.ts +27 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/mcp.json +36 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/ax-html-control-surface.md +101 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/codex-app-adapter.md +151 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/excalidraw-diagram-authoring.md +150 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/full-reference.md +1785 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/github-copilot-app-adapter.md +223 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/html-primitives.md +139 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/importing-context.md +132 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/installing-pmx-canvas.md +251 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/tours-and-recording.md +111 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/workbench-workflows.md +900 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas-orchestration/SKILL.md +141 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas-testing/SKILL.md +266 -0
- package/dist/amp-plugin/pmx-canvas/start-mcp.mjs +14857 -0
- package/dist/amp-plugin/pmx-canvas/tools.json +10963 -0
- package/dist/canvas/chunks/{abnfDiagram-N423BO3Z-p8dtp6va.js → abnfDiagram-N423BO3Z-cwtsds5d.js} +1 -1
- package/dist/canvas/chunks/architecture-TIHT7OUA-x63cwejs.js +1 -0
- package/dist/canvas/chunks/{architectureDiagram-T3A2C74G-5jhmxrzf.js → architectureDiagram-T3A2C74G-b4xc9tpz.js} +3 -3
- package/dist/canvas/chunks/{blockDiagram-VBNYF7ZC-pw1fa9yb.js → blockDiagram-VBNYF7ZC-ahp3yxxs.js} +7 -7
- package/dist/canvas/chunks/{c4Diagram-5PPSVZJV-x07nq0tt.js → c4Diagram-5PPSVZJV-nappnay7.js} +4 -4
- package/dist/canvas/chunks/classDiagram-JCYQIIEL-k1j2xc1t.js +1 -0
- package/dist/canvas/chunks/classDiagram-v2-OCEON4UE-33x08xf2.js +1 -0
- package/dist/canvas/chunks/{cose-bilkent-JH36ORCC-nm39npq0.js → cose-bilkent-JH36ORCC-a428syda.js} +1 -1
- package/dist/canvas/chunks/cynefin-VYW2F7L2-8v6jxfz8.js +1 -0
- package/dist/canvas/chunks/{cynefinDiagram-MW4NZA55-vdxrwahz.js → cynefinDiagram-MW4NZA55-nspsqebj.js} +1 -1
- package/dist/canvas/chunks/{dagre-VZM6K2ZE-bqdm7wpd.js → dagre-VZM6K2ZE-8y6177fh.js} +2 -2
- package/dist/canvas/chunks/{diagram-7IWD3JNH-gs5gpr93.js → diagram-7IWD3JNH-vym028wn.js} +4 -4
- package/dist/canvas/chunks/{diagram-B4RE2ZJO-cgwjg47s.js → diagram-B4RE2ZJO-jddqb8sy.js} +1 -1
- package/dist/canvas/chunks/{diagram-LBJQPF4R-w3vahpav.js → diagram-LBJQPF4R-bjwbpkrn.js} +1 -1
- package/dist/canvas/chunks/{diagram-Q27KOJAE-42837z6h.js → diagram-Q27KOJAE-j6ph6hcx.js} +2 -2
- package/dist/canvas/chunks/{diagram-UB23O5K3-4fz83q59.js → diagram-UB23O5K3-p09w8jej.js} +1 -1
- package/dist/canvas/chunks/{ebnfDiagram-BXEA7PRR-zphtgegj.js → ebnfDiagram-BXEA7PRR-j975ycq5.js} +1 -1
- package/dist/canvas/chunks/{erDiagram-JOGREHBK-zvbbdxp4.js → erDiagram-JOGREHBK-sxp6hjn8.js} +5 -5
- package/dist/canvas/chunks/eventmodeling-45OFAUF4-xzfgn6xg.js +1 -0
- package/dist/canvas/chunks/flowDiagram-UKHOOZJN-2nsmkskb.js +1 -0
- package/dist/canvas/chunks/{ganttDiagram-PKOTCBZU-282jzycm.js → ganttDiagram-PKOTCBZU-4tv230y2.js} +2 -2
- package/dist/canvas/chunks/gitGraph-TEB2WS4Q-macbhand.js +1 -0
- package/dist/canvas/chunks/{gitGraphDiagram-DS77QQ5N-vqqy6p1b.js → gitGraphDiagram-DS77QQ5N-mqgmnw9g.js} +1 -1
- package/dist/canvas/chunks/{index-wgv7en21.js → index-037z5dz2.js} +2 -2
- package/dist/canvas/chunks/{index-w2mra17t.js → index-081n3har.js} +1 -1
- package/dist/canvas/chunks/{index-353m7b0p.js → index-5n03dmb9.js} +1 -1
- package/dist/canvas/chunks/{index-yw8h9vha.js → index-60pgzdqe.js} +1 -1
- package/dist/canvas/chunks/index-8g1vb57n.js +2 -0
- package/dist/canvas/chunks/{index-vv56h019.js → index-8rjes9r6.js} +1 -1
- package/dist/canvas/chunks/{index-nprm96xp.js → index-9022d1n9.js} +1 -1
- package/dist/canvas/chunks/{index-194m3hc3.js → index-9b02042t.js} +1 -1
- package/dist/canvas/chunks/{index-0rk4gp1g.js → index-ap4q4vez.js} +1 -1
- package/dist/canvas/chunks/{index-rh7nv68n.js → index-dyp2nhd3.js} +1 -1
- package/dist/canvas/chunks/index-frvta4tm.js +2 -0
- package/dist/canvas/chunks/{index-s4j678gj.js → index-h9ycj8n2.js} +1 -1
- package/dist/canvas/chunks/{index-fjtdggjn.js → index-mergmj97.js} +2 -2
- package/dist/canvas/chunks/index-nwsya6dj.js +301 -0
- package/dist/canvas/chunks/{index-3cy1bzwh.js → index-nz8qbd1p.js} +1 -1
- package/dist/canvas/chunks/{index-d3b3gqe9.js → index-qhfrazv3.js} +1 -1
- package/dist/canvas/chunks/{index-6qmsnxwy.js → index-v119nznk.js} +4 -4
- package/dist/canvas/chunks/{index-r2fyc9w1.js → index-vpt37m3d.js} +6 -6
- package/dist/canvas/chunks/{index-qj8fxwsf.js → index-y9ma6azy.js} +1 -1
- package/dist/canvas/chunks/{index-tb1wf525.js → index-zx0j3a2z.js} +26 -26
- package/dist/canvas/chunks/info-DKCQHKI2-a0ykzs9z.js +1 -0
- package/dist/canvas/chunks/{infoDiagram-6WML65LV-v1yvggqj.js → infoDiagram-6WML65LV-qv97qq6a.js} +2 -2
- package/dist/canvas/chunks/ishikawaDiagram-WSZJBQD7-p9306gh0.js +70 -0
- package/dist/canvas/chunks/{journeyDiagram-NVQOT4AX-zjcffveh.js → journeyDiagram-NVQOT4AX-sv67zats.js} +5 -5
- package/dist/canvas/chunks/{kanban-definition-27J2QSJJ-dakqtfp1.js → kanban-definition-27J2QSJJ-k2pfam6p.js} +1 -1
- package/dist/canvas/chunks/{mermaid.core-j2geswrd.js → mermaid.core-83r0fdce.js} +4 -4
- package/dist/canvas/chunks/{mindmap-definition-FAOFIHXS-142xhr3k.js → mindmap-definition-FAOFIHXS-vg2newm1.js} +1 -1
- package/dist/canvas/chunks/packet-7NZHBO7P-tqnabcdv.js +1 -0
- package/dist/canvas/chunks/{pegDiagram-VL7TDLO6-5wvk7vsd.js → pegDiagram-VL7TDLO6-k2h7zc5n.js} +1 -1
- package/dist/canvas/chunks/pie-RZYD4A2V-wke6gyhe.js +1 -0
- package/dist/canvas/chunks/{pieDiagram-7S7Q4E2Y-ztdhwycc.js → pieDiagram-7S7Q4E2Y-hg169p1v.js} +2 -2
- package/dist/canvas/chunks/{quadrantDiagram-CIZ2JOQS-c5p9gmg6.js → quadrantDiagram-CIZ2JOQS-bxtvsq0b.js} +5 -5
- package/dist/canvas/chunks/radar-I7S5WNFK-w7ka0drw.js +1 -0
- package/dist/canvas/chunks/railroad-3IZDKUUU-y3vg318x.js +1 -0
- package/dist/canvas/chunks/railroad-abnf-AHOZXSZD-6hqvcz3c.js +1 -0
- package/dist/canvas/chunks/railroad-ebnf-EBAXGLYW-vcae260m.js +1 -0
- package/dist/canvas/chunks/railroad-peg-LSFZ7HO6-0dbyme23.js +1 -0
- package/dist/canvas/chunks/{railroadDiagram-AXF67PYL-xkmqkjwf.js → railroadDiagram-AXF67PYL-njyhcp4p.js} +1 -1
- package/dist/canvas/chunks/{requirementDiagram-LRYGKXZP-9wm2dyaw.js → requirementDiagram-LRYGKXZP-2z6v09gm.js} +4 -4
- package/dist/canvas/chunks/{sankeyDiagram-W5VNT64P-2w19etgb.js → sankeyDiagram-W5VNT64P-15mzam0e.js} +1 -1
- package/dist/canvas/chunks/{sequenceDiagram-SI44F4Z6-0jn0vwmz.js → sequenceDiagram-SI44F4Z6-rbshyd2c.js} +12 -12
- package/dist/canvas/chunks/{sizeCapture-X5ZJPWSS-x75epwdq.js → sizeCapture-X5ZJPWSS-sg26xwts.js} +1 -1
- package/dist/canvas/chunks/{stateDiagram-OKZ733FA-schjpy6d.js → stateDiagram-OKZ733FA-6eahp98e.js} +1 -1
- package/dist/canvas/chunks/stateDiagram-v2-UEYNNEHI-tty0ggn5.js +1 -0
- package/dist/canvas/chunks/{swimlanes-SLNWSIFB-gkw4xce3.js → swimlanes-SLNWSIFB-ze5db10t.js} +1 -1
- package/dist/canvas/chunks/swimlanesDiagram-ULZ7WXOC-thze75gq.js +8 -0
- package/dist/canvas/chunks/{timeline-definition-Z64GVDOM-x7nkcy01.js → timeline-definition-Z64GVDOM-vnp7jyy8.js} +3 -3
- package/dist/canvas/chunks/treeView-QDETBFTQ-6ysffnm6.js +1 -0
- package/dist/canvas/chunks/treemap-6X3UGDF4-m3h9p066.js +1 -0
- package/dist/canvas/chunks/vennDiagram-T6HMQDX7-0qrnb7mj.js +34 -0
- package/dist/canvas/chunks/wardley-OPB4EBWU-dp37drwx.js +1 -0
- package/dist/canvas/chunks/{wardleyDiagram-T6FBY63Y-t1j52t9r.js → wardleyDiagram-T6FBY63Y-8nxg8wqt.js} +4 -4
- package/dist/canvas/chunks/{xychartDiagram-ELKLHX3M-38t16pme.js → xychartDiagram-ELKLHX3M-nj921e7s.js} +5 -5
- package/dist/canvas/global.css +94 -1
- package/dist/canvas/index.js +154 -145
- package/dist/canvas/mcp-app.html +600 -498
- package/dist/json-render/index.css +1 -1
- package/dist/types/client/canvas/BoardMoveDialog.d.ts +2 -0
- package/dist/types/client/canvas/EdgeEditor.d.ts +19 -0
- package/dist/types/client/canvas/GroupNavigation.d.ts +2 -0
- package/dist/types/client/canvas/TextPrompt.d.ts +4 -0
- package/dist/types/client/nodes/PromptNode.d.ts +1 -0
- package/dist/types/client/nodes/ViewerFrame.d.ts +1 -1
- package/dist/types/client/nodes/WorkCard.d.ts +7 -0
- package/dist/types/client/nodes/use-ax-surface-bridge.d.ts +1 -0
- package/dist/types/client/state/canvas-store.d.ts +15 -0
- package/dist/types/client/state/human-store.d.ts +2 -0
- package/dist/types/client/state/intent-bridge.d.ts +4 -2
- package/dist/types/client/state/relation-store.d.ts +11 -0
- package/dist/types/client/types.d.ts +1 -1
- package/dist/types/json-render/catalog.d.ts +2 -2
- package/dist/types/server/agent-presence.d.ts +1 -0
- package/dist/types/server/ax-interaction.d.ts +1 -0
- package/dist/types/server/ax-state-manager.d.ts +10 -2
- package/dist/types/server/board-local.d.ts +4 -0
- package/dist/types/server/board-move.d.ts +38 -0
- package/dist/types/server/canvas-db.d.ts +12 -2
- package/dist/types/server/canvas-operations.d.ts +5 -6
- package/dist/types/server/canvas-provenance.d.ts +1 -1
- package/dist/types/server/canvas-serialization.d.ts +1 -0
- package/dist/types/server/canvas-state.d.ts +84 -20
- package/dist/types/server/card-relocation.d.ts +6 -0
- package/dist/types/server/context-reads.d.ts +3 -1
- package/dist/types/server/human-presence.d.ts +1 -1
- package/dist/types/server/index.d.ts +16 -5
- package/dist/types/server/intent-registry.d.ts +8 -4
- package/dist/types/server/knowledge-lifecycle.d.ts +4 -2
- package/dist/types/server/mutation-history.d.ts +7 -5
- package/dist/types/server/operations/registry.d.ts +2 -0
- package/dist/types/server/trace-manager.d.ts +1 -0
- package/dist/types/shared/ax-kinds.d.ts +6 -0
- package/dist/types/shared/ax-surface-protocol.d.ts +8 -0
- package/dist/types/shared/human-presence.d.ts +1 -0
- package/dist/types/shared/lifecycle-status.d.ts +2 -0
- package/docs/RELEASE.md +21 -14
- package/docs/agent-plugin.md +16 -2
- package/docs/amp-plugin.md +271 -0
- package/docs/cli.md +42 -3
- package/docs/design/GuestName.dc.html +50 -0
- package/docs/design/PluginLogo.svg +7 -0
- package/docs/design/WorkCards.dc.html +39 -0
- package/docs/design/canvas.json +16 -0
- package/docs/design/plugin-logo.png +0 -0
- package/docs/design.md +111 -8
- package/docs/evals/agents-md-sections.md +38 -0
- package/docs/http-api.md +128 -10
- package/docs/mcp.md +61 -9
- package/docs/node-types.md +71 -1
- package/docs/plans/plan-009-tech-debt-backlog.md +1 -1
- package/docs/plans/plan-019-post-0.9-roadmap.md +44 -20
- package/docs/plans/plan-020-wave-5-work-planning.md +553 -0
- package/docs/product-vision-2026-09.md +33 -17
- package/docs/sdk.md +18 -0
- package/package.json +6 -3
- package/plugins/pmx-canvas/assets/preview.png +0 -0
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/extension.mjs +3 -1
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +1 -1
- package/plugins/pmx-canvas/plugin.json +2 -2
- package/plugins/pmx-canvas/runtime.json +1 -1
- package/plugins/pmx-canvas/tools.json +440 -18
- package/skills/data-analysis/SKILL.md +13 -26
- package/skills/frontend-design/LICENSE.txt +177 -0
- package/skills/frontend-design/SKILL.md +3 -0
- package/skills/pmx-canvas/SKILL.md +232 -842
- package/skills/pmx-canvas/evals/evals.json +26 -3
- package/skills/pmx-canvas/references/full-reference.md +80 -20
- package/skills/pmx-canvas/references/html-primitives.md +7 -0
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +6 -6
- package/skills/pmx-canvas/references/tours-and-recording.md +29 -2
- package/skills/pmx-canvas/references/workbench-workflows.md +900 -0
- package/skills/pmx-canvas-testing/SKILL.md +7 -5
- package/skills/published-consumer-e2e/SKILL.md +25 -8
- package/skills/published-consumer-e2e/scripts/run-published-consumer-e2e.sh +51 -75
- package/skills/web-artifacts-builder/LICENSE.txt +202 -0
- package/skills/web-artifacts-builder/SKILL.md +6 -0
- package/skills/web-artifacts-builder/scripts/init-artifact.sh +2 -2
- package/src/cli/commands/apps.ts +1 -0
- package/src/cli/commands/boards.ts +30 -0
- package/src/client/App.tsx +20 -4
- package/src/client/canvas/AttentionHistory.tsx +10 -2
- package/src/client/canvas/BoardMoveDialog.tsx +225 -0
- package/src/client/canvas/CanvasNode.tsx +45 -2
- package/src/client/canvas/CanvasViewport.tsx +38 -9
- package/src/client/canvas/ContextMenu.tsx +34 -12
- package/src/client/canvas/EdgeEditor.tsx +149 -0
- package/src/client/canvas/EdgeLayer.tsx +87 -16
- package/src/client/canvas/ExpandedNodeOverlay.tsx +4 -0
- package/src/client/canvas/GroupNavigation.tsx +85 -0
- package/src/client/canvas/RelationsPanel.tsx +9 -0
- package/src/client/canvas/SelectionBar.tsx +21 -0
- package/src/client/canvas/SessionPanel.tsx +35 -1
- package/src/client/canvas/TextPrompt.tsx +18 -1
- package/src/client/canvas/TopBar.tsx +30 -0
- package/src/client/canvas/canvas-area.ts +1 -1
- package/src/client/nodes/ExtAppFrame.tsx +26 -10
- package/src/client/nodes/MarkdownNode.tsx +6 -7
- package/src/client/nodes/PromptNode.tsx +32 -3
- package/src/client/nodes/StatusNode.tsx +12 -0
- package/src/client/nodes/StatusSummary.tsx +11 -0
- package/src/client/nodes/ViewerFrame.tsx +21 -10
- package/src/client/nodes/WorkCard.tsx +175 -0
- package/src/client/nodes/use-ax-surface-bridge.ts +18 -14
- package/src/client/state/attention-bridge.ts +5 -0
- package/src/client/state/attention-store.ts +1 -0
- package/src/client/state/canvas-store.ts +185 -15
- package/src/client/state/human-store.ts +22 -2
- package/src/client/state/intent-bridge.ts +19 -5
- package/src/client/state/relation-store.ts +127 -1
- package/src/client/theme/global.css +94 -1
- package/src/client/types.ts +1 -0
- package/src/mcp/server.ts +13 -3
- package/src/server/agent-presence.ts +43 -23
- package/src/server/ax-flow-loop.ts +6 -0
- package/src/server/ax-gate-ttl.ts +8 -1
- package/src/server/ax-interaction.ts +16 -10
- package/src/server/ax-state-manager.ts +17 -4
- package/src/server/ax-wait.ts +20 -6
- package/src/server/board-export.ts +19 -6
- package/src/server/board-local.ts +20 -0
- package/src/server/board-move.ts +297 -0
- package/src/server/canvas-db.ts +249 -158
- package/src/server/canvas-operations.ts +139 -109
- package/src/server/canvas-schema.ts +21 -0
- package/src/server/canvas-serialization.ts +2 -0
- package/src/server/canvas-state.ts +792 -159
- package/src/server/card-relocation.ts +53 -0
- package/src/server/code-graph.ts +4 -3
- package/src/server/context-reads.ts +83 -55
- package/src/server/demo-state.json +35 -15
- package/src/server/file-watcher.ts +30 -10
- package/src/server/human-presence.ts +18 -5
- package/src/server/index.ts +35 -15
- package/src/server/intent-registry.ts +43 -5
- package/src/server/knowledge-lifecycle.ts +32 -9
- package/src/server/lifecycle-status.ts +29 -1
- package/src/server/mcp-app-runtime.ts +26 -7
- package/src/server/mutation-history.ts +37 -8
- package/src/server/operations/composites.ts +6 -3
- package/src/server/operations/mcp-contracts.ts +15 -0
- package/src/server/operations/mcp.ts +36 -9
- package/src/server/operations/ops/annotation.ts +22 -1
- package/src/server/operations/ops/ax-await.ts +1 -0
- package/src/server/operations/ops/ax-timeline.ts +28 -2
- package/src/server/operations/ops/batch.ts +25 -11
- package/src/server/operations/ops/boards.ts +44 -3
- package/src/server/operations/ops/nodes.ts +70 -0
- package/src/server/operations/ops/query.ts +32 -3
- package/src/server/operations/ops/snapshots.ts +1 -0
- package/src/server/operations/registry.ts +49 -4
- package/src/server/server.ts +62 -16
- package/src/server/tour-control.ts +37 -12
- package/src/server/trace-manager.ts +4 -0
- package/src/server/web-artifacts/scripts/init-artifact.sh +2 -2
- package/src/shared/agent-context.ts +7 -1
- package/src/shared/auto-arrange.ts +5 -4
- package/src/shared/ax-kinds.ts +13 -0
- package/src/shared/ax-surface-protocol.ts +22 -0
- package/src/shared/human-presence.ts +1 -0
- package/src/shared/lifecycle-status.ts +2 -0
- package/dist/canvas/chunks/architecture-TIHT7OUA-9tffvpsv.js +0 -1
- package/dist/canvas/chunks/classDiagram-JCYQIIEL-nc6g5x1r.js +0 -1
- package/dist/canvas/chunks/classDiagram-v2-OCEON4UE-0qnbpwvh.js +0 -1
- package/dist/canvas/chunks/cynefin-VYW2F7L2-ys8p46ts.js +0 -1
- package/dist/canvas/chunks/eventmodeling-45OFAUF4-v9q6dn4c.js +0 -1
- package/dist/canvas/chunks/flowDiagram-UKHOOZJN-yrr5z8tc.js +0 -1
- package/dist/canvas/chunks/gitGraph-TEB2WS4Q-kdwb8m0a.js +0 -1
- package/dist/canvas/chunks/index-1r72hdzb.js +0 -301
- package/dist/canvas/chunks/index-g3pwnqeb.js +0 -2
- package/dist/canvas/chunks/index-rft2hcz5.js +0 -2
- package/dist/canvas/chunks/info-DKCQHKI2-wpzs6sz3.js +0 -1
- package/dist/canvas/chunks/ishikawaDiagram-WSZJBQD7-5hnq1a9p.js +0 -70
- package/dist/canvas/chunks/packet-7NZHBO7P-xn439f0s.js +0 -1
- package/dist/canvas/chunks/pie-RZYD4A2V-0kf16rwh.js +0 -1
- package/dist/canvas/chunks/radar-I7S5WNFK-0g2pz36t.js +0 -1
- package/dist/canvas/chunks/railroad-3IZDKUUU-fcaran6j.js +0 -1
- package/dist/canvas/chunks/railroad-abnf-AHOZXSZD-wgdya41q.js +0 -1
- package/dist/canvas/chunks/railroad-ebnf-EBAXGLYW-gy07a4ka.js +0 -1
- package/dist/canvas/chunks/railroad-peg-LSFZ7HO6-ewk6wtkh.js +0 -1
- package/dist/canvas/chunks/stateDiagram-v2-UEYNNEHI-k8sfp2e7.js +0 -1
- package/dist/canvas/chunks/swimlanesDiagram-ULZ7WXOC-nqysw67j.js +0 -8
- package/dist/canvas/chunks/treeView-QDETBFTQ-cesw6gp0.js +0 -1
- package/dist/canvas/chunks/treemap-6X3UGDF4-zdv4knp9.js +0 -1
- package/dist/canvas/chunks/vennDiagram-T6HMQDX7-x8dqn9yf.js +0 -34
- package/dist/canvas/chunks/wardley-OPB4EBWU-44pdddez.js +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef } from 'preact/hooks';
|
|
1
2
|
import {
|
|
2
3
|
attentionHistory,
|
|
3
4
|
attentionHistoryOpen,
|
|
@@ -20,13 +21,19 @@ function handleOpenUpdates(): void {
|
|
|
20
21
|
|
|
21
22
|
export function AttentionHistory() {
|
|
22
23
|
const entries = attentionHistory.value;
|
|
23
|
-
if (entries.length === 0) return null;
|
|
24
|
-
|
|
25
24
|
const isOpen = attentionHistoryOpen.value;
|
|
26
25
|
const unread = attentionHistoryUnread.value;
|
|
26
|
+
const toggleRef = useRef<HTMLButtonElement>(null);
|
|
27
|
+
const wasOpen = useRef(isOpen);
|
|
28
|
+
useLayoutEffect(() => {
|
|
29
|
+
if (isOpen !== wasOpen.current) toggleRef.current?.focus({ preventScroll: true });
|
|
30
|
+
wasOpen.current = isOpen;
|
|
31
|
+
}, [isOpen]);
|
|
32
|
+
if (entries.length === 0) return null;
|
|
27
33
|
if (!isOpen) {
|
|
28
34
|
return (
|
|
29
35
|
<button
|
|
36
|
+
ref={toggleRef}
|
|
30
37
|
type="button"
|
|
31
38
|
class="attention-history-tab"
|
|
32
39
|
onClick={handleOpenUpdates}
|
|
@@ -67,6 +74,7 @@ export function AttentionHistory() {
|
|
|
67
74
|
<span class="attention-history-subtitle">Focus and meaning shifts</span>
|
|
68
75
|
</div>
|
|
69
76
|
<button
|
|
77
|
+
ref={toggleRef}
|
|
70
78
|
type="button"
|
|
71
79
|
class="attention-history-close"
|
|
72
80
|
onClick={closeAttentionHistory}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { signal } from '@preact/signals';
|
|
2
|
+
import { useRef, useState } from 'preact/hooks';
|
|
3
|
+
import type { BoardMoveInput, BoardMovePreview, BoardMoveResult } from '../../server/board-move.js';
|
|
4
|
+
import { activeBoardId, boardIncarnation, claimNavigation, openBoard } from '../state/boards-store';
|
|
5
|
+
import { nodes } from '../state/canvas-store';
|
|
6
|
+
import { requestJson } from '../state/intent-bridge';
|
|
7
|
+
import { hasUnsavedMarkdown } from '../nodes/MarkdownNode';
|
|
8
|
+
import { hasUnsavedPrompt } from '../nodes/PromptNode';
|
|
9
|
+
import { hasUnsavedWorkCard } from '../nodes/WorkCard';
|
|
10
|
+
import { useFocusTrap } from './use-focus-trap';
|
|
11
|
+
import { submitWithoutNavigation } from './submit-without-navigation';
|
|
12
|
+
|
|
13
|
+
type MoveSelection = {
|
|
14
|
+
sourceBoardId: string;
|
|
15
|
+
nodeIds: string[];
|
|
16
|
+
requestId: string;
|
|
17
|
+
incarnation: number;
|
|
18
|
+
canNavigate: () => boolean;
|
|
19
|
+
};
|
|
20
|
+
const selection = signal<MoveSelection | null>(null);
|
|
21
|
+
|
|
22
|
+
export function openBoardMove(nodeIds: string[]): void {
|
|
23
|
+
if (!activeBoardId.value || !nodeIds.length) return;
|
|
24
|
+
selection.value = {
|
|
25
|
+
sourceBoardId: activeBoardId.value,
|
|
26
|
+
nodeIds: [...nodeIds],
|
|
27
|
+
requestId: crypto.randomUUID(),
|
|
28
|
+
incarnation: boardIncarnation,
|
|
29
|
+
canNavigate: claimNavigation(),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function BoardMoveDialog() {
|
|
34
|
+
const current = selection.value;
|
|
35
|
+
return current ? <MoveForm key={current.requestId} selected={current} /> : null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function MoveForm({ selected }: { selected: MoveSelection }) {
|
|
39
|
+
const dialogRef = useRef<HTMLDivElement>(null);
|
|
40
|
+
const nameRef = useRef<HTMLInputElement>(null);
|
|
41
|
+
const [name, setName] = useState('New board');
|
|
42
|
+
const [preview, setPreview] = useState<BoardMovePreview | null>(null);
|
|
43
|
+
const [input, setInput] = useState<BoardMoveInput | null>(null);
|
|
44
|
+
const [busy, setBusy] = useState(false);
|
|
45
|
+
const [attempted, setAttempted] = useState(false);
|
|
46
|
+
const [refused, setRefused] = useState(false);
|
|
47
|
+
const [error, setError] = useState('');
|
|
48
|
+
const close = () => {
|
|
49
|
+
if (selection.value === selected) selection.value = null;
|
|
50
|
+
};
|
|
51
|
+
const current = () =>
|
|
52
|
+
selection.value === selected &&
|
|
53
|
+
selected.incarnation === boardIncarnation &&
|
|
54
|
+
activeBoardId.value === selected.sourceBoardId;
|
|
55
|
+
useFocusTrap(dialogRef, true, { initial: nameRef, onEscape: close });
|
|
56
|
+
|
|
57
|
+
const unsaved = (ids: string[]) =>
|
|
58
|
+
ids.filter(
|
|
59
|
+
(id) =>
|
|
60
|
+
hasUnsavedMarkdown(selected.sourceBoardId, id) ||
|
|
61
|
+
hasUnsavedWorkCard(selected.sourceBoardId, id) ||
|
|
62
|
+
hasUnsavedPrompt(selected.sourceBoardId, id),
|
|
63
|
+
);
|
|
64
|
+
const submit = async (event: Event) => {
|
|
65
|
+
event.preventDefault();
|
|
66
|
+
if (busy || refused || !name.trim()) return;
|
|
67
|
+
if (!current()) return setError('The board changed. Close this dialog and select the cards again.');
|
|
68
|
+
setBusy(true);
|
|
69
|
+
setError('');
|
|
70
|
+
if (!preview) {
|
|
71
|
+
const board = await requestJson<{ ok: boolean; contentRevision: number } | null>(
|
|
72
|
+
'moveRevision',
|
|
73
|
+
`/api/canvas/boards/${encodeURIComponent(selected.sourceBoardId)}`,
|
|
74
|
+
null,
|
|
75
|
+
);
|
|
76
|
+
if (!current()) {
|
|
77
|
+
setBusy(false);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (!board?.ok) {
|
|
81
|
+
setError('Could not read the source board. Try again.');
|
|
82
|
+
setBusy(false);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const next = {
|
|
86
|
+
sourceBoardId: selected.sourceBoardId,
|
|
87
|
+
nodeIds: selected.nodeIds,
|
|
88
|
+
requestId: selected.requestId,
|
|
89
|
+
name: name.trim(),
|
|
90
|
+
expectedRevision: board.contentRevision,
|
|
91
|
+
};
|
|
92
|
+
const result = await requestJson<{ ok: boolean; preview?: BoardMovePreview; error?: string } | null>(
|
|
93
|
+
'previewMove',
|
|
94
|
+
'/api/canvas/boards/move-selection',
|
|
95
|
+
null,
|
|
96
|
+
{
|
|
97
|
+
method: 'POST',
|
|
98
|
+
headers: { 'Content-Type': 'application/json' },
|
|
99
|
+
body: JSON.stringify({ ...next, preview: true }),
|
|
100
|
+
},
|
|
101
|
+
);
|
|
102
|
+
if (current()) {
|
|
103
|
+
if (result?.ok && result.preview) {
|
|
104
|
+
setInput(next);
|
|
105
|
+
setPreview(result.preview);
|
|
106
|
+
if (unsaved(result.preview.nodeIds).length)
|
|
107
|
+
setError('Save or clear the selected cards’ drafts before moving. Close and preview again.');
|
|
108
|
+
} else setError(result?.error ?? 'Could not preview the move. Try again.');
|
|
109
|
+
}
|
|
110
|
+
} else if (input && !preview.blockers.length) {
|
|
111
|
+
if (unsaved(preview.nodeIds).length) {
|
|
112
|
+
setBusy(false);
|
|
113
|
+
return setError('Save or clear the selected cards’ drafts before moving. Close and preview again.');
|
|
114
|
+
}
|
|
115
|
+
setAttempted(true);
|
|
116
|
+
const result = await requestJson<
|
|
117
|
+
({ ok: true } & BoardMoveResult) | { ok: false; error?: string; blockers?: string[] } | null
|
|
118
|
+
>('moveSelection', '/api/canvas/boards/move-selection', null, {
|
|
119
|
+
method: 'POST',
|
|
120
|
+
headers: { 'Content-Type': 'application/json' },
|
|
121
|
+
body: JSON.stringify(input),
|
|
122
|
+
});
|
|
123
|
+
if (result?.ok) {
|
|
124
|
+
const navigate = current() && selected.canNavigate();
|
|
125
|
+
close();
|
|
126
|
+
if (navigate) await openBoard(result.destinationBoardId);
|
|
127
|
+
} else if (selection.value === selected) {
|
|
128
|
+
if (result) {
|
|
129
|
+
setRefused(true);
|
|
130
|
+
setError(`${result.error ?? 'Move refused.'} ${result.blockers?.join(' ') ?? ''} Close and preview again.`);
|
|
131
|
+
} else {
|
|
132
|
+
setError('No reply received. Retry uses the same request and cannot create a second board.');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
setBusy(false);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const blocked = !!preview?.blockers.length;
|
|
140
|
+
return (
|
|
141
|
+
<div class="text-prompt-backdrop board-move-backdrop" onMouseDown={close}>
|
|
142
|
+
<div
|
|
143
|
+
ref={dialogRef}
|
|
144
|
+
class="text-prompt board-move-dialog"
|
|
145
|
+
role="dialog"
|
|
146
|
+
aria-modal="true"
|
|
147
|
+
aria-labelledby="board-move-title"
|
|
148
|
+
onMouseDown={(event) => event.stopPropagation()}
|
|
149
|
+
onKeyDown={(event) => {
|
|
150
|
+
event.stopPropagation();
|
|
151
|
+
if (event.key === 'Escape') {
|
|
152
|
+
event.preventDefault();
|
|
153
|
+
close();
|
|
154
|
+
}
|
|
155
|
+
}}
|
|
156
|
+
>
|
|
157
|
+
<form onClick={submitWithoutNavigation} onSubmit={submit}>
|
|
158
|
+
<h2 id="board-move-title">Move to new board</h2>
|
|
159
|
+
<p>Move the original cards, including group contents. Leave a portal on this board.</p>
|
|
160
|
+
<label class="board-copy-field">
|
|
161
|
+
New board name
|
|
162
|
+
<input
|
|
163
|
+
ref={nameRef}
|
|
164
|
+
class="text-prompt-input"
|
|
165
|
+
maxLength={120}
|
|
166
|
+
required
|
|
167
|
+
value={name}
|
|
168
|
+
readOnly={!!preview || busy}
|
|
169
|
+
onInput={(event) => setName(event.currentTarget.value)}
|
|
170
|
+
/>
|
|
171
|
+
</label>
|
|
172
|
+
{preview && (
|
|
173
|
+
<>
|
|
174
|
+
<p>
|
|
175
|
+
{preview.nodeIds.length} cards · {preview.pinnedNodeIds.length} pinned ·{' '}
|
|
176
|
+
{preview.affectedBoardIds.length + 1} affected boards
|
|
177
|
+
</p>
|
|
178
|
+
<ul class="board-move-cards">
|
|
179
|
+
{preview.nodeIds.map((id) => (
|
|
180
|
+
<li key={id}>{String(nodes.value.get(id)?.data.title ?? id)}</li>
|
|
181
|
+
))}
|
|
182
|
+
</ul>
|
|
183
|
+
{preview.readmeNodeId && <p>The README moves with the cards.</p>}
|
|
184
|
+
{!!preview.liveTaskNodeIds.length && (
|
|
185
|
+
<p>{preview.liveTaskNodeIds.length} live task cards keep their original task owner.</p>
|
|
186
|
+
)}
|
|
187
|
+
<p>Content, relations and review history are preserved. Moving does not validate or read content.</p>
|
|
188
|
+
<p class="board-move-warning">
|
|
189
|
+
⚠ History boundary: pre-move Undo/Redo is cleared on affected boards. Older snapshots remain
|
|
190
|
+
inspectable, but cannot be restored across the move.
|
|
191
|
+
</p>
|
|
192
|
+
<p>Board-space annotations stay here. The new board opens after the move.</p>
|
|
193
|
+
{blocked && (
|
|
194
|
+
<div role="alert" class="board-move-warning">
|
|
195
|
+
<strong>⚠ Cannot move this selection</strong>
|
|
196
|
+
<ul>
|
|
197
|
+
{preview.blockers.map((reason) => (
|
|
198
|
+
<li key={reason}>{reason}</li>
|
|
199
|
+
))}
|
|
200
|
+
</ul>
|
|
201
|
+
<p>No cards moved. Close, resolve the listed bindings and preview again.</p>
|
|
202
|
+
</div>
|
|
203
|
+
)}
|
|
204
|
+
</>
|
|
205
|
+
)}
|
|
206
|
+
{error && (
|
|
207
|
+
<p role="alert" class="board-move-warning">
|
|
208
|
+
⚠ {error}
|
|
209
|
+
</p>
|
|
210
|
+
)}
|
|
211
|
+
<div class="text-prompt-actions">
|
|
212
|
+
<button type="button" class="text-prompt-cancel" onClick={close}>
|
|
213
|
+
{blocked || refused ? 'Close' : 'Cancel'}
|
|
214
|
+
</button>
|
|
215
|
+
{!blocked && !refused && (
|
|
216
|
+
<button type="submit" class="text-prompt-confirm" disabled={busy || !name.trim()}>
|
|
217
|
+
{busy ? 'Working…' : attempted ? 'Retry move' : preview ? 'Move and open' : 'Preview move'}
|
|
218
|
+
</button>
|
|
219
|
+
)}
|
|
220
|
+
</div>
|
|
221
|
+
</form>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
@@ -4,6 +4,7 @@ import { knowledgeLifecycleEnabled } from '../state/workspace-settings';
|
|
|
4
4
|
import { relationHighlight } from '../state/relation-store';
|
|
5
5
|
import { LifecycleFooter } from './LifecycleChrome';
|
|
6
6
|
import { BarHint } from './BarHint';
|
|
7
|
+
import { openBoardMove } from './BoardMoveDialog';
|
|
7
8
|
import { CrossBoardReferences } from './CrossBoardReferences';
|
|
8
9
|
import { BoardPinButton } from './BoardPinButton';
|
|
9
10
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks';
|
|
@@ -36,6 +37,8 @@ import {
|
|
|
36
37
|
updateNodeData,
|
|
37
38
|
viewport,
|
|
38
39
|
canvasTool,
|
|
40
|
+
groupContents,
|
|
41
|
+
openGroup,
|
|
39
42
|
} from '../state/canvas-store';
|
|
40
43
|
import {
|
|
41
44
|
addToGroupFromClient,
|
|
@@ -275,7 +278,10 @@ export function CanvasNode({ node, children, onContextMenu }: CanvasNodeProps) {
|
|
|
275
278
|
reportHumanGrab(node.id);
|
|
276
279
|
noteNearAtGrab(node.id);
|
|
277
280
|
takeOverNode(node.id, typeof node.data.title === 'string' && node.data.title ? node.data.title : node.type);
|
|
278
|
-
buildSnapCache(
|
|
281
|
+
buildSnapCache(
|
|
282
|
+
node.id,
|
|
283
|
+
[...nodes.value.values()].filter((candidate) => !groupContents.value || groupContents.value.has(candidate.id)),
|
|
284
|
+
);
|
|
279
285
|
if (node.type !== 'group') {
|
|
280
286
|
const onKey = (ev: KeyboardEvent) => {
|
|
281
287
|
if (ev.key === 'Escape') suppressDropForDrag();
|
|
@@ -333,12 +339,21 @@ export function CanvasNode({ node, children, onContextMenu }: CanvasNodeProps) {
|
|
|
333
339
|
const dir = ARROW_DIRS[e.key];
|
|
334
340
|
if (dir) {
|
|
335
341
|
e.preventDefault();
|
|
336
|
-
const next = nearestNodeInDirection(
|
|
342
|
+
const next = nearestNodeInDirection(
|
|
343
|
+
node,
|
|
344
|
+
dir,
|
|
345
|
+
[...nodes.value.values()].filter(
|
|
346
|
+
(candidate) => !groupContents.value || groupContents.value.has(candidate.id),
|
|
347
|
+
),
|
|
348
|
+
);
|
|
337
349
|
if (!next) return;
|
|
338
350
|
bringToFront(next.id);
|
|
339
351
|
requestAnimationFrame(() => {
|
|
340
352
|
document.querySelector<HTMLElement>(`.canvas-node[data-node-id="${CSS.escape(next.id)}"]`)?.focus();
|
|
341
353
|
});
|
|
354
|
+
} else if (e.key === 'Enter' && e.target === e.currentTarget && node.type === 'group') {
|
|
355
|
+
e.preventDefault();
|
|
356
|
+
openGroup(node.id);
|
|
342
357
|
} else if (e.key === 'Enter' && e.target === e.currentTarget && EXPANDABLE_TYPES.has(node.type)) {
|
|
343
358
|
e.preventDefault();
|
|
344
359
|
expandNode(node.id);
|
|
@@ -380,6 +395,8 @@ export function CanvasNode({ node, children, onContextMenu }: CanvasNodeProps) {
|
|
|
380
395
|
if (!body) return;
|
|
381
396
|
|
|
382
397
|
const observer = new ResizeObserver(() => {
|
|
398
|
+
// Focus-mode return can remount an open work draft. Never save its temporary form height.
|
|
399
|
+
if (body.querySelector('.work-card-editor')) hasAutoFit.current = true;
|
|
383
400
|
if (hasAutoFit.current) {
|
|
384
401
|
observer.disconnect();
|
|
385
402
|
return;
|
|
@@ -492,8 +509,12 @@ export function CanvasNode({ node, children, onContextMenu }: CanvasNodeProps) {
|
|
|
492
509
|
// Collapsed group: a compact chip. Children keep their positions for restore.
|
|
493
510
|
return (
|
|
494
511
|
<div
|
|
512
|
+
ref={shellRef}
|
|
495
513
|
class={`${nodeClass} group-chip`}
|
|
496
514
|
data-node-type={node.type}
|
|
515
|
+
data-node-id={node.id}
|
|
516
|
+
tabIndex={isActive ? 0 : -1}
|
|
517
|
+
onKeyDown={handleNodeKeyDown}
|
|
497
518
|
style={{ ...nodeStyle, width: 'auto', height: 'auto' }}
|
|
498
519
|
onPointerDown={handlePointerDown}
|
|
499
520
|
onDblClick={handleDblClick}
|
|
@@ -671,6 +692,28 @@ export function CanvasNode({ node, children, onContextMenu }: CanvasNodeProps) {
|
|
|
671
692
|
</button>
|
|
672
693
|
{groupMenuOpen && (
|
|
673
694
|
<div class="group-menu" role="menu" onPointerDown={(e) => e.stopPropagation()}>
|
|
695
|
+
<button
|
|
696
|
+
type="button"
|
|
697
|
+
role="menuitem"
|
|
698
|
+
onClick={(e) => {
|
|
699
|
+
e.stopPropagation();
|
|
700
|
+
setGroupMenuOpen(false);
|
|
701
|
+
openGroup(node.id);
|
|
702
|
+
}}
|
|
703
|
+
>
|
|
704
|
+
Open group
|
|
705
|
+
</button>
|
|
706
|
+
<button
|
|
707
|
+
type="button"
|
|
708
|
+
role="menuitem"
|
|
709
|
+
onClick={(e) => {
|
|
710
|
+
e.stopPropagation();
|
|
711
|
+
setGroupMenuOpen(false);
|
|
712
|
+
openBoardMove([node.id]);
|
|
713
|
+
}}
|
|
714
|
+
>
|
|
715
|
+
Move to new board
|
|
716
|
+
</button>
|
|
674
717
|
<button
|
|
675
718
|
type="button"
|
|
676
719
|
role="menuitem"
|
|
@@ -37,6 +37,9 @@ import {
|
|
|
37
37
|
dragDropTarget,
|
|
38
38
|
hiddenByCollapsedGroup,
|
|
39
39
|
canvasTool,
|
|
40
|
+
groupContents,
|
|
41
|
+
groupViewNodes,
|
|
42
|
+
canvasInteractionEpoch,
|
|
40
43
|
} from '../state/canvas-store';
|
|
41
44
|
import { createEdgeFromClient, createNodeFromClient } from '../state/intent-bridge';
|
|
42
45
|
import type { AnnotationTool, CanvasAnnotation, CanvasNodeState } from '../types';
|
|
@@ -50,6 +53,7 @@ import { ScopeFenceLayer } from './ScopeFenceLayer';
|
|
|
50
53
|
import { CanvasNode } from './CanvasNode';
|
|
51
54
|
import { BoardNode } from '../nodes/BoardNode';
|
|
52
55
|
import { EdgeLayer } from './EdgeLayer';
|
|
56
|
+
import { GroupOutsideLinks } from './GroupNavigation';
|
|
53
57
|
import { AnnotationLayer } from './AnnotationLayer';
|
|
54
58
|
import { activeGuides } from './snap-guides';
|
|
55
59
|
import { usePanZoom } from './use-pan-zoom';
|
|
@@ -104,19 +108,30 @@ function renderNodeContent(node: CanvasNodeState) {
|
|
|
104
108
|
*/
|
|
105
109
|
class WorldNode extends Component<{
|
|
106
110
|
node: CanvasNodeState;
|
|
111
|
+
hidden: boolean;
|
|
107
112
|
onContextMenu?: (e: MouseEvent, nodeId: string) => void;
|
|
108
113
|
}> {
|
|
109
|
-
shouldComponentUpdate(next: {
|
|
110
|
-
|
|
114
|
+
shouldComponentUpdate(next: {
|
|
115
|
+
node: CanvasNodeState;
|
|
116
|
+
hidden: boolean;
|
|
117
|
+
onContextMenu?: (e: MouseEvent, nodeId: string) => void;
|
|
118
|
+
}) {
|
|
119
|
+
return (
|
|
120
|
+
next.node !== this.props.node ||
|
|
121
|
+
next.hidden !== this.props.hidden ||
|
|
122
|
+
next.onContextMenu !== this.props.onContextMenu
|
|
123
|
+
);
|
|
111
124
|
}
|
|
112
125
|
|
|
113
126
|
render() {
|
|
114
|
-
const { node, onContextMenu } = this.props;
|
|
127
|
+
const { node, hidden, onContextMenu } = this.props;
|
|
115
128
|
const viewer = ['html', 'mcp-app', 'json-render', 'graph', 'webpage', 'mermaid'].includes(node.type);
|
|
116
129
|
return (
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
<div style={{ display: hidden ? 'none' : 'contents' }}>
|
|
131
|
+
<CanvasNode node={node} onContextMenu={onContextMenu}>
|
|
132
|
+
{viewer ? <ViewerHost node={node}>{renderNodeContent(node)}</ViewerHost> : renderNodeContent(node)}
|
|
133
|
+
</CanvasNode>
|
|
134
|
+
</div>
|
|
120
135
|
);
|
|
121
136
|
}
|
|
122
137
|
}
|
|
@@ -572,6 +587,7 @@ export function CanvasViewport({
|
|
|
572
587
|
// Find intersecting nodes (AABB intersection)
|
|
573
588
|
const hits: string[] = [];
|
|
574
589
|
for (const node of nodes.value.values()) {
|
|
590
|
+
if (groupContents.value && !groupContents.value.has(node.id)) continue;
|
|
575
591
|
const nx = node.position.x;
|
|
576
592
|
const ny = node.position.y;
|
|
577
593
|
if (nx + node.size.width > worldMinX && nx < worldMaxX && ny + node.size.height > worldMinY && ny < worldMaxY) {
|
|
@@ -622,6 +638,7 @@ export function CanvasViewport({
|
|
|
622
638
|
let hit: string | null = null;
|
|
623
639
|
for (const node of nodes.value.values()) {
|
|
624
640
|
if (node.id === exceptId || node.type === 'group') continue;
|
|
641
|
+
if (groupContents.value && !groupContents.value.has(node.id)) continue;
|
|
625
642
|
if (
|
|
626
643
|
wx >= node.position.x &&
|
|
627
644
|
wx <= node.position.x + node.size.width &&
|
|
@@ -807,11 +824,17 @@ export function CanvasViewport({
|
|
|
807
824
|
// reorder DOM children when bringToFront() changes zIndex, causing browsers to
|
|
808
825
|
// detach/reattach iframe elements (which forces them to reload/reconnect).
|
|
809
826
|
// Group nodes render first (behind) so they serve as visual containers.
|
|
827
|
+
const mounted = useRef({ epoch: canvasInteractionEpoch.value, ids: new Set<string>() });
|
|
828
|
+
if (mounted.current.epoch !== canvasInteractionEpoch.value)
|
|
829
|
+
mounted.current = { epoch: canvasInteractionEpoch.value, ids: new Set() };
|
|
830
|
+
for (const id of mounted.current.ids) if (!nodes.value.has(id)) mounted.current.ids.delete(id);
|
|
831
|
+
const collapsed = hiddenByCollapsedGroup.value;
|
|
810
832
|
const worldNodes = getRenderableWorldNodes(
|
|
811
833
|
nodes.value.values(),
|
|
812
834
|
expandedNodeId.value,
|
|
813
|
-
new Set(
|
|
835
|
+
new Set([...collapsed.keys()].filter((id) => !mounted.current.ids.has(id))),
|
|
814
836
|
);
|
|
837
|
+
for (const node of worldNodes) mounted.current.ids.add(node.id);
|
|
815
838
|
const lowestZ = worldNodes.reduce((lowest, node) => Math.min(lowest, Math.floor(node.zIndex)), 0);
|
|
816
839
|
const highestZ = worldNodes.reduce((highest, node) => Math.max(highest, Math.ceil(node.zIndex)), 0);
|
|
817
840
|
// Keep group-body hit order without changing the frames' visual stacking.
|
|
@@ -895,7 +918,8 @@ export function CanvasViewport({
|
|
|
895
918
|
<IntentLayer />
|
|
896
919
|
<AgentPresenceLayer />
|
|
897
920
|
<HumanPresenceLayer />
|
|
898
|
-
<EdgeLayer nodes={
|
|
921
|
+
<EdgeLayer nodes={groupViewNodes} edges={edges} />
|
|
922
|
+
<GroupOutsideLinks />
|
|
899
923
|
{draggingEdge.value && (
|
|
900
924
|
<div
|
|
901
925
|
class="edge-hint-pill"
|
|
@@ -930,7 +954,12 @@ export function CanvasViewport({
|
|
|
930
954
|
<AnnotationLayer annotations={Array.from(annotations.value.values())} />
|
|
931
955
|
{draftAnnotation && draftAnnotation.points.length >= 2 && <AnnotationLayer annotations={[draftAnnotation]} />}
|
|
932
956
|
{worldNodes.map((node) => (
|
|
933
|
-
<WorldNode
|
|
957
|
+
<WorldNode
|
|
958
|
+
key={node.id}
|
|
959
|
+
node={node}
|
|
960
|
+
hidden={collapsed.has(node.id) || (groupContents.value !== null && !groupContents.value.has(node.id))}
|
|
961
|
+
onContextMenu={onNodeContextMenu}
|
|
962
|
+
/>
|
|
934
963
|
))}
|
|
935
964
|
{/* Snap alignment guide lines */}
|
|
936
965
|
{activeGuides.value && (
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
expandNode,
|
|
8
8
|
focusNode,
|
|
9
9
|
nodes,
|
|
10
|
+
openGroup,
|
|
10
11
|
pendingConnection,
|
|
11
12
|
persistLayout,
|
|
12
13
|
removeNode,
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
import { canOpenAsSite, openNodeAsSite } from '../nodes/surface-url';
|
|
31
32
|
import { canCopyPrimitiveJson, copyPrimitiveJson } from '../nodes/primitive-copy';
|
|
32
33
|
import { askText } from './TextPrompt';
|
|
34
|
+
import { openBoardMove } from './BoardMoveDialog';
|
|
33
35
|
import { activeBoard, boardIncarnation, setBoardReadme } from '../state/boards-store';
|
|
34
36
|
import { openLifecycle } from '../state/knowledge-store';
|
|
35
37
|
import { RELATION_KINDS, relationKind } from '../../shared/relations.js';
|
|
@@ -468,6 +470,23 @@ async function createPromptedNode(opts: {
|
|
|
468
470
|
|
|
469
471
|
function buildCanvasMenuItems(canvasX: number, canvasY: number): MenuItem[] {
|
|
470
472
|
return [
|
|
473
|
+
{
|
|
474
|
+
label: 'New work card',
|
|
475
|
+
action: () => {
|
|
476
|
+
const width = 360;
|
|
477
|
+
const height = 200;
|
|
478
|
+
const position = centeredPosition(canvasX, canvasY, width, height);
|
|
479
|
+
void createNodeFromClient({
|
|
480
|
+
type: 'status',
|
|
481
|
+
title: 'New work card',
|
|
482
|
+
data: { workState: 'todo' },
|
|
483
|
+
x: position.x,
|
|
484
|
+
y: position.y,
|
|
485
|
+
width,
|
|
486
|
+
height,
|
|
487
|
+
});
|
|
488
|
+
},
|
|
489
|
+
},
|
|
471
490
|
{
|
|
472
491
|
label: 'New note',
|
|
473
492
|
action: () => {
|
|
@@ -567,18 +586,19 @@ function buildNodeMenuItems(node: CanvasNodeState): MenuItem[] {
|
|
|
567
586
|
action: () => focusNode(node.id),
|
|
568
587
|
});
|
|
569
588
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
589
|
+
if (!(node.type === 'status' && typeof node.data.workItemId === 'string'))
|
|
590
|
+
items.push({
|
|
591
|
+
label: 'Rename…',
|
|
592
|
+
action: () => {
|
|
593
|
+
void askText('Rename node', 'Node title', {
|
|
594
|
+
initial: typeof node.data.title === 'string' ? node.data.title : '',
|
|
595
|
+
confirm: 'Save',
|
|
596
|
+
}).then((title) => {
|
|
597
|
+
if (!title?.trim()) return;
|
|
598
|
+
void updateNodeFromClient(node.id, { title: title.trim() });
|
|
599
|
+
});
|
|
600
|
+
},
|
|
601
|
+
});
|
|
582
602
|
|
|
583
603
|
// Expand into full-viewport overlay for focused work
|
|
584
604
|
if (EXPANDABLE_TYPES.has(node.type)) {
|
|
@@ -757,6 +777,8 @@ function buildNodeMenuItems(node: CanvasNodeState): MenuItem[] {
|
|
|
757
777
|
if (node.type === 'group') {
|
|
758
778
|
const childIds = (node.data.children as string[]) ?? [];
|
|
759
779
|
items.push({ separator: true });
|
|
780
|
+
items.push({ label: 'Open group', action: () => openGroup(node.id) });
|
|
781
|
+
items.push({ label: 'Move to new board', action: () => openBoardMove([node.id]) });
|
|
760
782
|
items.push({
|
|
761
783
|
render: (onClose) => renderGroupColorSection(node, onClose),
|
|
762
784
|
});
|