Skip to content

fix: the palette creates in every product, and copy writes what paste reads - #119

Open
endrix wants to merge 2 commits into
mainfrom
fix/palette-create-gate-and-clipboard-shape
Open

endrix wants to merge 2 commits into
mainfrom
fix/palette-create-gate-and-clipboard-shape

Conversation

@endrix

@endrix endrix commented Nov 8, 2026 •

Copy link
Copy Markdown
Owner

Phase 2 of the declutter plan: the two likely bugs the review found, each pinned by a test, plus what the review of this PR turned up.

The palette never created a node outside Python

create-node-handler.ts and entity-port-crud-handler.ts returned no command unless the model's source ended in .py. In a SystemVerilog, VHDL or NDF diagram a palette drop, and the property panel's "add port", did nothing, silently.

The other thirteen handlers that write to the source ask only that the model has one (the profile's openability already decided which files open), so these two now do the same. The first version of this PR added a sourceExtensions gate instead; the review pointed out that this grew infrastructure around the odd one out, and it is gone again.

create-in-every-product.test.ts resolves the real handlers through the toolkit DI module and checks a .sv, .vhd, .md and .py source all get a command, and a model with no source does not.

Copy then paste pasted nothing

RequestClipboardData built one payload shape (entityName, sourceRange, text) while the toolkit's paste parsed another (name, typeName, portType, edge endpoints). Cut and duplicate already produced the second shape, so cut+paste worked and copy+paste created a node with type: undefined.

  • The payload type, the format constant, parseClipboardPayload and clipboardDataFromPayload move to @dialogram/shared (clipboard-payload.ts): one shape for the server, the toolkit and the webview. Types are DiagramClipboardItem and DiagramClipboardPayload, clear of the DOM global.
  • clipboard/clipboard.ts keeps only buildClipboardPayload (the former buildPyClipboardPayload, with the blank-name check the old builder had) and re-exports the shared pieces; py-clipboard.ts and the client's clipboard-payload.ts are deleted.
  • Copy, cut, duplicate and paste import from clipboard/clipboard; post-edit-selection-service.ts reads item.name.

Found by the review of this PR

  • A pasted or duplicated connection kept the names of the entities it was copied from, so copying add with its wire re-wired the original and left add2 unwired. Paste and duplicate now carry a renamed map and connect the copies.
  • The webview predicted the pasted name with a suffix from 1 while the toolkit wrote a suffix from 2, so the post-paste selection never matched. One rule, nextFreeName in shared, on both sides.
  • A paste whose payload has no items now says so instead of returning a silent no-op edit.
  • Dead await on the now-synchronous builder in cut and duplicate removed.

Tests: paste-handler.test.ts (names, remapped wire, empty payload), the server copy handler round-trips through parseClipboardPayload, the webview's prepareForPaste plans exactly add2/a2, nextFreeName pinned.

No product repo changes. Typecheck 5/5, neutrality 5/5, server 446, client 363, toolkit touched suites green (the full toolkit run has the known local timeout in variant-node-create-wizard.test.ts, which passes in CI).

https://claude.ai/code/session_01EToj6RJRMSSHQiqGNMU9wv

… reads

Two bugs the declutter review turned up.

The create-node and entity-port handlers accepted only a `.py` source, so
a palette drop in a Verilog, VHDL or NDF diagram did nothing. The gate now
asks the profile's source extensions: the runtime config carries
`sourceExtensions`, `SidecarRuntimeService` and `SidecarInvoker` answer
`handlesSource(uri)`, and the profile fills the list from its input. A
config that names no extension accepts every source.

Copy wrote the entity's name as `entityName` with its source text, while
paste looked for `name` and `typeName`, so a copied node pasted as nothing;
cut and duplicate already wrote the paste shape. One payload now lives in
`@dialogram/shared` and is written by copy, cut and duplicate and read by
paste and the webview's post-paste selection. The server's
`clipboard/py-clipboard` module and the client's `clipboard-payload` are
gone; the builder is `buildClipboardPayload` in `clipboard/clipboard`.

Claude-Session: https://claude.ai/code/session_01EToj6RJRMSSHQiqGNMU9wv
The `.py` gate goes instead of growing: the other handlers that write to
the source ask only that the model has one, so create-node and
entity-port do the same. The `sourceExtensions` runtime field and
`handlesSource` are gone again.

A pasted or duplicated connection now joins the pasted copies, not the
entities it was copied from. The pasted name follows one rule,
`nextFreeName` in shared, on the sidecar side and in the webview, which
predicted `add1` where the toolkit wrote `add2` and so never selected the
pasted node. A paste with nothing to paste says so.

The shared types are `DiagramClipboardItem` and `DiagramClipboardPayload`,
clear of the DOM's `ClipboardItem`. Copy drops a blank name as it did
before; cut and duplicate no longer await a synchronous builder.

Claude-Session: https://claude.ai/code/session_01EToj6RJRMSSHQiqGNMU9wv
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant