Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement copy, paste, cut, and select all functionality for node/edge management #382

Merged
merged 10 commits into from
Feb 20, 2025

Conversation

stone-lyl
Copy link
Collaborator

@stone-lyl stone-lyl commented Feb 19, 2025

  • Keyboard Shortcut Support: We've successfully implemented support for Ctrl+C, Ctrl+V, and Ctrl+X, allowing users to easily copy, paste, and cut nodes.
  • Multi-selection Copy: Users can select multiple nodes by holding down the Ctrl key, and when copying, both the selected nodes and their corresponding edges will be copied together.
  • Duplicate Component id Issue: The copied Component id is currently not unique, leading to repetition that needs to be addressed.
  • Inadequate node Selection Feedback: Especially for table type nodes, the selection feedback is not clearly visible, which could be improved for a better user experience.
  • Select All Functionality: Currently, there's no capability to select all content on the page at once.
2025-02-19-21-28-47.mp4

Todo:

  • System Clipboard Support: The copied content does not appear in the system clipboard, preventing cross-panel copying and sharing of diagram information.
  • Text Content Copy: We cannot copy text content beyond nodes, which interferes with copying text in the Sidebar and Resource and DataStory text on the page.

Copy link

vercel bot commented Feb 19, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
data-story-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Feb 20, 2025 9:10am

@ajthinking
Copy link
Owner

After creating a Signal + Table, then copying them, and running:

image

Note how they both get 600 items instead of 300 (expected)

{"nodes":[{"id":"Signal.aLnKNC68Aa","name":"Signal","label":"Signal","inputs":[],"outputs":[{"id":"Signal.aLnKNC68Aa.output","name":"output","schema":{"id":"any"}}],"params":[{"name":"period","type":"StringableParam","label":"period","help":"How many ms between each signal?","multiline":false,"canInterpolate":true,"interpolate":true,"casts":[{"type":"numberCast","label":"Number"}],"value":{"value":50,"Cast":"numberCast"}},{"name":"count","type":"StringableParam","label":"count","help":"How many times to send the signal?","multiline":false,"canInterpolate":true,"interpolate":true,"casts":[{"type":"numberCast","label":"Number"}],"value":{"value":300,"Cast":"numberCast"}},{"name":"expression","type":"StringableParam","label":"Template expression","help":"Use this field to customize the signal. ${{i}} is available as a variable.","multiline":true,"canInterpolate":true,"interpolate":true,"evaluations":[{"type":"HJSON","label":"HJSON","selected":true},{"type":"JSON","label":"JSON"},{"type":"JS_FUNCTION","label":"JS Function"},{"type":"JS_EXPRESSION","label":"JS Expression"}],"casts":[{"type":"numberCast","label":"Number"},{"type":"stringCast","label":"String"}],"value":{"value":"{\n  id: ${{i}}\n}","Evaluation":"HJSON"}}],"position":{"x":-137.61858549287962,"y":-217.4627781766346}},{"id":"Table.GsgFk6AtZR","name":"Table","label":"Table","inputs":[{"id":"Table.GsgFk6AtZR.input","name":"input","schema":{}}],"outputs":[],"params":[{"name":"only","type":"StringListParam","label":"only","help":"If set, only the specified paths will be shown. Use comma separation","value":""},{"name":"drop","type":"StringListParam","label":"drop","help":"If set, the specified paths will be dropped. Use comma separation","value":""},{"name":"destructObjects","type":"StringableParam","label":"destructObjects","help":"If set, objects will be destructured","multiline":false,"canInterpolate":true,"interpolate":true,"casts":[{"type":"stringCast","label":"String"}],"value":{"value":"true","Cast":"stringCast"}}],"position":{"x":244.17556530498086,"y":-165.68207489897105}},{"id":"Signal.aLnKNC68Aa-1739974029454","name":"Signal","label":"Signal","inputs":[],"outputs":[{"id":"Signal.aLnKNC68Aa.output","name":"output","schema":{"id":"any"}}],"params":[{"name":"period","type":"StringableParam","label":"period","help":"How many ms between each signal?","multiline":false,"canInterpolate":true,"interpolate":true,"casts":[{"type":"numberCast","label":"Number"}],"value":{"value":50,"Cast":"numberCast"}},{"name":"count","type":"StringableParam","label":"count","help":"How many times to send the signal?","multiline":false,"canInterpolate":true,"interpolate":true,"casts":[{"type":"numberCast","label":"Number"}],"value":{"value":300,"Cast":"numberCast"}},{"name":"expression","type":"StringableParam","label":"Template expression","help":"Use this field to customize the signal. ${{i}} is available as a variable.","multiline":true,"canInterpolate":true,"interpolate":true,"evaluations":[{"type":"HJSON","label":"HJSON","selected":true},{"type":"JSON","label":"JSON"},{"type":"JS_FUNCTION","label":"JS Function"},{"type":"JS_EXPRESSION","label":"JS Expression"}],"casts":[{"type":"numberCast","label":"Number"},{"type":"stringCast","label":"String"}],"value":{"value":"{\n  id: ${{i}}\n}","Evaluation":"HJSON"}}],"position":{"x":-149.0646894644835,"y":-1.7420892318882508}},{"id":"Table.GsgFk6AtZR-1739974029454","name":"Table","label":"Table","inputs":[{"id":"Table.GsgFk6AtZR.input","name":"input","schema":{}}],"outputs":[],"params":[{"name":"only","type":"StringListParam","label":"only","help":"If set, only the specified paths will be shown. Use comma separation","value":""},{"name":"drop","type":"StringListParam","label":"drop","help":"If set, the specified paths will be dropped. Use comma separation","value":""},{"name":"destructObjects","type":"StringableParam","label":"destructObjects","help":"If set, objects will be destructured","multiline":false,"canInterpolate":true,"interpolate":true,"casts":[{"type":"stringCast","label":"String"}],"value":{"value":"true","Cast":"stringCast"}}],"position":{"x":124.37272727272726,"y":21.290909090909075}}],"links":[{"id":"3hZwXsc5mm","sourcePortId":"Signal.aLnKNC68Aa.output","targetPortId":"Table.GsgFk6AtZR.input","label":600,"labelBgStyle":{"opacity":0.6}},{"id":"3hZwXsc5mm-1739974029454","sourcePortId":"Signal.aLnKNC68Aa.output","targetPortId":"Table.GsgFk6AtZR.input","label":600,"labelBgStyle":{"opacity":0.6}}],"params":[],"viewport":{"x":0,"y":0,"zoom":1}}

@ajthinking
Copy link
Owner

Does these checkboxes indicate that the problem is solved, or that there is still an issue?
image

@ajthinking
Copy link
Owner

Second row is copy pasted.
image

When closing and reopening, the lower link has gone missing.

image

@ajthinking
Copy link
Owner

Second row is copied.

image

When CTRL-X:ing the the last Ignore, the link of the first row is also removed.

Copy link
Owner

@ajthinking ajthinking left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good 👍 Lets address the issues commented before. Feels like things related to ids not being unique?

@stone-lyl
Copy link
Collaborator Author

stone-lyl commented Feb 19, 2025

Does these checkboxes indicate that the problem is solved, or that there is still an issue?

The issues have been resolved.

@stone-lyl
Copy link
Collaborator Author

Very good 👍 Lets address the issues commented before. Feels like things related to ids not being unique?

These issues are likely related to the IDs, but they are indeed unique.
One potential reason could be that other parts of the project need to adapt to the new ID generation rules.

@stone-lyl
Copy link
Collaborator Author

In addition to the issues mentioned above, I tested the new feature, identified, and fixed the following problems:

When modifying the parameters of a copied signal node, the parameters of the original node also change.

before:

2025-02-20-15-34-57.mp4

after:
image

Since we've modified the edge, we can't use the original code of (selectedEdges).includes(edge) in the useCopyPaste hooks of xyFlow.

image

@stone-lyl stone-lyl merged commit 67bf682 into ajthinking:main Feb 20, 2025
3 checks passed
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.

2 participants