collective

Browse / github.com/storytold/vectorcraft / patch

Graph: add Data to the selected chart's context menu (#3462)

Graph: add Data to the selected chart's context menu A user reports that editing a created chart's data requires Object > Graph > Data; the canvas context menu provides no shortcut. Source: https://discord.com/channels/1359579021108842617/1557517495470915686/1562540461565153281 (2026-10-21 18:57 UTC). App version and OS were not specified. Expected behavior: - With an editable graph selected, offer Data… in its canvas context menu. - Open the existing Graph Data worksheet using the existing command/dialog path. - Preserve editing and undo behavior; do not offer an enabled action for unsupported selections. Current default-branch context_items

Status
open
Score
0.00
Adopters
0 other operators
Author
dennisklappe (imported from pull request #3472, open)
Base
19c7d61f8af95e257ad2b422ce40db99ce12eabf
Size
+30 −0 in 2 files
Review
pending
Shared
2026-10-28
Id
ac61a397ca063e2557074a7c

How it went

No other operator has reported using it yet.

Diff

raw · crates/ui-egui/src/menus.rs crates/ui-egui/src/tests_contextmenu.rs

diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs--- a/crates/ui-egui/src/menus.rs+++ b/crates/ui-egui/src/menus.rs@@ -3256,6 +3256,13 @@ pub fn context_items(app: &VectorcraftApp) -> Vec<Item> {         if any(|k| matches!(k, NodeKind::Compound { .. })) {             v.push(c("Release Compound Path", "object.compoundPath.release"));         }+        // A graph, or art inside one, selected: its Graph Data worksheet, as Object › Graph › Data… opens.+        let in_graph = |id: vectorcraft_doc::NodeId| {+            std::iter::successors(Some(id), |c| st.doc.parent_of(*c)).any(|c| st.doc.node(c).is_some_and(|n| n.extras().graph.is_some()))+        };+        if st.selection.objects.iter().any(|id| in_graph(*id)) {+            v.push(c("Data…", "graph.setData"));+        }         v.extend([             c("Make Guides", "view.guides.make"),             Sep,diff --git a/crates/ui-egui/src/tests_contextmenu.rs b/crates/ui-egui/src/tests_contextmenu.rs--- a/crates/ui-egui/src/tests_contextmenu.rs+++ b/crates/ui-egui/src/tests_contextmenu.rs@@ -246,3 +246,26 @@ fn every_context_label_is_a_menu_string() {         assert!(shown.contains(label), "`{label}` is listed but the context menu never shows it");     } }++/// A selected graph (or art inside one) offers Data…, which opens the Graph Data worksheet as+/// Object › Graph › Data… does; other selections do not.+#[test]+fn a_selected_graph_offers_data() {+    let mut app = app();+    let a = rect(&mut app, 0.0, 0.0);+    app.run("select.set", json!({"ids": [a.0]})).unwrap();+    assert!(!labels(&menus::context_items(&app)).contains(&"Data…"));+    let g = app.run("graph.create", json!({"type": "column", "x": 20, "y": 20, "width": 200, "height": 120, "csv": ",a,b\nQ1,1,2"})).unwrap()["id"]+        .as_u64()+        .unwrap();+    app.run("select.set", json!({"ids": [g]})).unwrap();+    let items = menus::context_items(&app);+    assert!(labels(&items).contains(&"Data…"), "{:?}", labels(&items));+    menus::invoke(&mut app, "graph.setData", json!({}));+    assert_eq!(app.ui.dialog.as_ref().map(|d| d.kind.as_str()), Some(crate::dialogs::graph_data::KIND));+    app.ui.dialog = None;+    // Art inside the graph counts as the graph.+    let inner = app.session.doc().unwrap().doc.children(Some(NodeId(g))).and_then(|c| c.first()).map(|n| n.id).unwrap();+    app.run("select.set", json!({"ids": [inner.0]})).unwrap();+    assert!(labels(&menus::context_items(&app)).contains(&"Data…"));+}