Make the Data panel able to display data from selected nodes living in subgraphs (#4064)

Enable the Data panel to display data from selected nodes living in subgraphs
This commit is contained in:
Keavon Chambers
2026-04-28 12:55:13 -07:00
committed by GitHub
parent df8c2125d9
commit cf150b5cff
5 changed files with 98 additions and 42 deletions
@@ -27,7 +27,9 @@ pub struct DataPanelMessageContext<'a> {
/// The data panel allows for graph data to be previewed.
#[derive(Default, Debug, Clone, ExtractField)]
pub struct DataPanelMessageHandler {
introspected_node: Option<NodeId>,
/// Full path from the root network to the introspected node, with the node itself as the last element.
/// Empty when nothing is being introspected.
introspected_node_path: Vec<NodeId>,
introspected_data: Option<Arc<dyn Any + Send + Sync>>,
element_path: Vec<PathStep>,
active_vector_table_tab: VectorTableTab,
@@ -38,12 +40,12 @@ impl MessageHandler<DataPanelMessage, DataPanelMessageContext<'_>> for DataPanel
fn process_message(&mut self, message: DataPanelMessage, responses: &mut VecDeque<Message>, context: DataPanelMessageContext) {
match message {
DataPanelMessage::UpdateLayout { mut inspect_result } => {
self.introspected_node = Some(inspect_result.inspect_node);
self.introspected_data = inspect_result.take_data();
self.introspected_node_path = inspect_result.inspect_node_path;
self.update_layout(responses, context);
}
DataPanelMessage::ClearLayout => {
self.introspected_node = None;
self.introspected_node_path.clear();
self.introspected_data = None;
self.element_path.clear();
self.active_vector_table_tab = VectorTableTab::default();
@@ -93,8 +95,9 @@ impl DataPanelMessageHandler {
let mut widgets = Vec::new();
// Selected layer/node name
if let Some(node_id) = self.introspected_node {
let is_layer = network_interface.is_layer(&node_id, &[]);
if let Some((node_id, parent_path)) = self.introspected_node_path.split_last() {
let node_id = *node_id;
let is_layer = network_interface.is_layer(&node_id, parent_path);
widgets.extend([
if is_layer {
@@ -103,7 +106,7 @@ impl DataPanelMessageHandler {
IconLabel::new("Node").tooltip_description("Name of the selected node.").widget_instance()
},
Separator::new(SeparatorStyle::Related).widget_instance(),
TextInput::new(network_interface.display_name(&node_id, &[]))
TextInput::new(network_interface.display_name(&node_id, parent_path))
.tooltip_description(if is_layer { "Name of the selected layer." } else { "Name of the selected node." })
.on_update(move |text_input| {
NodeGraphMessage::SetDisplayName {
@@ -1686,6 +1686,12 @@ impl DocumentMessageHandler {
self.network_interface.document_metadata()
}
/// Path to the subnetwork that the user's selection is currently scoped to.
/// Empty when the selection lives in the root document network.
pub fn selection_network_path(&self) -> &[NodeId] {
&self.selection_network_path
}
pub fn serialize_document(&self) -> String {
let val = serde_json::to_string(self);
// We fully expect the serialization to succeed
@@ -1868,22 +1868,31 @@ impl PortfolioMessageHandler {
}
}
/// Get the ID of the selected node that should be used as the current source for the Data panel.
pub fn node_to_inspect(&self) -> Option<NodeId> {
/// Returns the full path from the root network to the selected node that should drive the Data panel.
/// The last element is the node itself; preceding elements identify the nested subnetwork it lives in
/// so the Data panel can introspect nodes inside subgraphs. An empty `Vec` signals "nothing to inspect".
pub fn node_to_inspect(&self) -> Vec<NodeId> {
// Skip if the Data panel is not open
if !self.workspace_panel_layout.is_panel_visible(PanelType::Data) || self.workspace_panel_layout.focus_document {
return None;
return Vec::new();
}
let document = self.document(self.active_document_id?)?;
let selected_nodes = document.network_interface.selected_nodes().0;
let Some(document) = self.active_document_id.and_then(|id| self.document(id)) else {
return Vec::new();
};
let network_path = document.selection_network_path();
let Some(selected_nodes) = document.network_interface.selected_nodes_in_nested_network(network_path) else {
return Vec::new();
};
// Skip if there is not exactly one selected node
if selected_nodes.len() != 1 {
return None;
}
let [node_id] = selected_nodes.0.as_slice() else {
return Vec::new();
};
selected_nodes.first().copied()
let mut path = network_path.to_vec();
path.push(*node_id);
path
}
/// Remove a dockable panel type from whichever panel group currently contains it. Does not prune empty groups.