From cc0b5cd8ecbd95507c09d263d97914a4d295f3bb Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 20 Nov 2025 17:25:30 -0800 Subject: [PATCH 1/3] Separate error popup from node --- .../src/messages/frontend/frontend_message.rs | 5 +- .../node_graph/node_graph_message_handler.rs | 51 +++--- .../document/node_graph/utility_types.rs | 30 +++- frontend/src/components/views/Graph.svelte | 154 ++++++++++-------- frontend/src/messages.ts | 12 +- frontend/src/state-providers/node-graph.ts | 9 + 6 files changed, 167 insertions(+), 94 deletions(-) diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index c3324a16ff..6fa77698ab 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -2,7 +2,7 @@ use super::utility_types::{DocumentDetails, MouseCursorIcon, OpenDocument}; use crate::messages::app_window::app_window_message_handler::AppWindowPlatform; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::node_graph::utility_types::{ - BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, Transform, + BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphError, Transform }; use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer}; use crate::messages::portfolio::document::utility_types::wires::{WirePath, WirePathUpdate}; @@ -289,6 +289,9 @@ pub enum FrontendMessage { UpdateNodeGraphNodes { nodes: Vec, }, + UpdateNodeGraphError { + error: Option, + }, UpdateVisibleNodes { nodes: Vec, }, diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index a52fbd0765..2a84d8751a 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -6,7 +6,7 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::document_message_handler::navigation_controls; use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext; use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext; -use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType}; +use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType, NodeGraphError}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::misc::GroupFolderType; use crate::messages::portfolio::document::utility_types::network_interface::{ @@ -793,10 +793,9 @@ impl<'a> MessageHandler> for NodeG DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x }; - let context_menu_coordinates = ((node_graph_point.x + node_graph_shift.x) as i32, (node_graph_point.y + node_graph_shift.y) as i32); - + let context_menu_coordinates = node_graph_point + node_graph_shift; self.context_menu = Some(ContextMenuInformation { - context_menu_coordinates, + context_menu_coordinates: context_menu_coordinates.into(), context_menu_data, }); @@ -1220,9 +1219,10 @@ impl<'a> MessageHandler> for NodeG let node_graph_shift = DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x; let compatible_type = network_interface.output_type(&output_connector, selection_network_path).add_node_string(); + let context_menu_coordinates = point + node_graph_shift; self.context_menu = Some(ContextMenuInformation { - context_menu_coordinates: ((point.x + node_graph_shift.x) as i32, (point.y + node_graph_shift.y) as i32), + context_menu_coordinates: context_menu_coordinates.into(), context_menu_data: ContextMenuData::CreateNode { compatible_type }, }); @@ -1646,6 +1646,8 @@ impl<'a> MessageHandler> for NodeG responses.add(FrontendMessage::UpdateNodeGraphNodes { nodes }); responses.add(NodeGraphMessage::UpdateVisibleNodes); + let error = self.node_graph_error(network_interface, breadcrumb_network_path); + responses.add(FrontendMessage::UpdateNodeGraphError { error }); let (layer_widths, chain_widths, has_left_input_wire) = network_interface.collect_layer_widths(breadcrumb_network_path); responses.add(NodeGraphMessage::UpdateImportsExports); @@ -2509,8 +2511,6 @@ impl NodeGraphMessageHandler { }; let mut nodes = Vec::new(); for (node_id, visible) in network.nodes.iter().map(|(node_id, node)| (*node_id, node.visible)).collect::>() { - let node_id_path = [breadcrumb_network_path, &[node_id]].concat(); - let primary_input_connector = InputConnector::node(node_id, 0); let primary_input = if network_interface @@ -2552,20 +2552,6 @@ impl NodeGraphMessageHandler { let locked = network_interface.is_locked(&node_id, breadcrumb_network_path); - let errors = network_interface - .resolved_types - .node_graph_errors - .iter() - .find(|error| error.node_path == node_id_path) - .map(|error| format!("{:?}", error.error.clone())) - .or_else(|| { - if network_interface.resolved_types.node_graph_errors.iter().any(|error| error.node_path.starts_with(&node_id_path)) { - Some("Node graph type error within this node".to_string()) - } else { - None - } - }); - nodes.push(FrontendNode { id: node_id, is_layer: network_interface @@ -2584,7 +2570,6 @@ impl NodeGraphMessageHandler { previewed, visible, locked, - errors, }); } @@ -2606,6 +2591,28 @@ impl NodeGraphMessageHandler { Some(subgraph_names) } + fn node_graph_error(&self, network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId]) -> Option { + let error = network_interface + .resolved_types + .node_graph_errors + .iter() + .filter(|error| error.node_path.starts_with(breadcrumb_network_path) && error.node_path.len() > breadcrumb_network_path.len()) + .next()?; + let error_node = error.node_path[breadcrumb_network_path.len()]; + let error = if error.node_path.len() == breadcrumb_network_path.len() + 1 { + format!("{:?}", error.error) + } else { + "Node graph type error within this node".to_string() + }; + let mut position = network_interface.position(&error_node, breadcrumb_network_path)?; + // Convert to graph space + position *= 24; + if network_interface.is_layer(&error_node, breadcrumb_network_path) { + position += IVec2::new(12, -12) + } + Some(NodeGraphError { position: position.into(), error }) + } + fn update_layer_panel(network_interface: &NodeNetworkInterface, selection_network_path: &[NodeId], collapsed: &CollapsedLayers, layers_panel_open: bool, responses: &mut VecDeque) { if !layers_panel_open { return; diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index 79918d2220..0b285e78b1 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -1,4 +1,4 @@ -use glam::IVec2; +use glam::{DVec2, IVec2}; use graph_craft::document::NodeId; use graph_craft::document::value::TaggedValue; use graphene_std::Type; @@ -98,7 +98,6 @@ pub struct FrontendNode { pub visible: bool, pub locked: bool, pub previewed: bool, - pub errors: Option, } #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] @@ -172,11 +171,17 @@ pub enum ContextMenuData { pub struct ContextMenuInformation { // Stores whether the context menu is open and its position in graph coordinates #[serde(rename = "contextMenuCoordinates")] - pub context_menu_coordinates: (i32, i32), + pub context_menu_coordinates: FrontendXY, #[serde(rename = "contextMenuData")] pub context_menu_data: ContextMenuData, } +#[derive(Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct NodeGraphError { + pub position: FrontendXY, + pub error: String, +} + #[derive(Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)] pub struct FrontendClickTargets { #[serde(rename = "nodeClickTargets")] @@ -200,3 +205,22 @@ pub enum Direction { Left, Right, } + +/// Stores node graph coordinates which are then transformed in svelte based on the node graph transform +#[derive(Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendXY { + pub x: i32, + pub y: i32, +} + +impl From for FrontendXY { + fn from(v: DVec2) -> Self { + FrontendXY { x: v.x as i32, y: v.y as i32 } + } +} + +impl From for FrontendXY { + fn from(v: IVec2) -> Self { + FrontendXY { x: v.x as i32, y: v.y as i32 } + } +} diff --git a/frontend/src/components/views/Graph.svelte b/frontend/src/components/views/Graph.svelte index 468d7f3fd2..e8368aa757 100644 --- a/frontend/src/components/views/Graph.svelte +++ b/frontend/src/components/views/Graph.svelte @@ -257,6 +257,27 @@ {/if} + {#if $nodeGraph.error} +
+ {$nodeGraph.error.error} + {$nodeGraph.error.error} +
+ {/if} + {#if $nodeGraph.clickTargets}
@@ -508,10 +529,6 @@ title={`${node.displayName}\n\n${description || ""}`.trim() + (editor.handle.inDevelopmentMode() ? `\n\nNode ID: ${node.id}` : "")} data-node={node.id} > - {#if node.errors} - {node.errors} - {node.errors} - {/if}
{#if $nodeGraph.thumbnails.has(node.id)} {@html $nodeGraph.thumbnails.get(node.id)} @@ -775,7 +792,6 @@
- {#if $nodeGraph.box}
{ if (data.obj.contextMenuInformation === undefined) return undefined; - const contextMenuCoordinates = { x: data.obj.contextMenuInformation.contextMenuCoordinates[0], y: data.obj.contextMenuInformation.contextMenuCoordinates[1] }; + const contextMenuCoordinates = data.obj.contextMenuInformation.contextMenuCoordinates; let contextMenuData = data.obj.contextMenuInformation.contextMenuData; if (contextMenuData.ToggleLayer !== undefined) { contextMenuData = { nodeId: contextMenuData.ToggleLayer.nodeId, currentlyIsNode: contextMenuData.ToggleLayer.currentlyIsNode }; @@ -94,6 +94,15 @@ export class UpdateNodeGraphNodes extends JsMessage { readonly nodes!: FrontendNode[]; } +export class UpdateNodeGraphError extends JsMessage { + readonly error!: NodeGraphError | undefined; +} + +export class NodeGraphError { + readonly position!: XY; + readonly error!: string; +} + export class UpdateVisibleNodes extends JsMessage { readonly nodes!: bigint[]; } @@ -1700,6 +1709,7 @@ export const messageMakers: Record = { UpdateMouseCursor, UpdateNodeGraphControlBarLayout, UpdateNodeGraphNodes, + UpdateNodeGraphError, UpdateNodeGraphSelection, UpdateNodeGraphTransform, UpdateNodeGraphWires, diff --git a/frontend/src/state-providers/node-graph.ts b/frontend/src/state-providers/node-graph.ts index fd6c7c5724..cdb28f47e3 100644 --- a/frontend/src/state-providers/node-graph.ts +++ b/frontend/src/state-providers/node-graph.ts @@ -1,6 +1,7 @@ import { writable } from "svelte/store"; import { type Editor } from "@graphite/editor"; +import type { NodeGraphError } from "@graphite/messages"; import { type Box, type FrontendClickTargets, @@ -25,6 +26,7 @@ import { UpdateNodeGraphTransform, UpdateNodeThumbnail, UpdateWirePathInProgress, + UpdateNodeGraphError, } from "@graphite/messages"; export function createNodeGraphState(editor: Editor) { @@ -32,6 +34,7 @@ export function createNodeGraphState(editor: Editor) { box: undefined as Box | undefined, clickTargets: undefined as FrontendClickTargets | undefined, contextMenuInformation: undefined as ContextMenuInformation | undefined, + error: undefined as NodeGraphError | undefined, layerWidths: new Map(), chainWidths: new Map(), hasLeftInputWire: new Map(), @@ -118,6 +121,12 @@ export function createNodeGraphState(editor: Editor) { return state; }); }); + editor.subscriptions.subscribeJsMessage(UpdateNodeGraphError, (updateNodeGraphError) => { + update((state) => { + state.error = updateNodeGraphError.error; + return state; + }); + }); editor.subscriptions.subscribeJsMessage(UpdateVisibleNodes, (updateVisibleNodes) => { update((state) => { state.visibleNodes = new Set(updateVisibleNodes.nodes); From 19405fea53ddea1fe14f2793a7ab1fba16fea970 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 15 Nov 2025 17:36:14 -0800 Subject: [PATCH 2/3] Improve context menu data --- .../src/messages/frontend/frontend_message.rs | 2 +- .../node_graph/node_graph_message_handler.rs | 17 ++++++---- .../document/node_graph/utility_types.rs | 10 +++--- editor/src/test_utils.rs | 9 ++---- frontend/src/components/views/Graph.svelte | 31 +++++-------------- frontend/src/messages.ts | 15 +-------- 6 files changed, 29 insertions(+), 55 deletions(-) diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index 6fa77698ab..22348c8cc9 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -2,7 +2,7 @@ use super::utility_types::{DocumentDetails, MouseCursorIcon, OpenDocument}; use crate::messages::app_window::app_window_message_handler::AppWindowPlatform; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::node_graph::utility_types::{ - BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphError, Transform + BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphError, Transform, }; use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer}; use crate::messages::portfolio::document::utility_types::wires::{WirePath, WirePathUpdate}; diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 2a84d8751a..034a1070ba 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -776,8 +776,13 @@ impl<'a> MessageHandler> for NodeG } let context_menu_data = if let Some(node_id) = clicked_id { - let currently_is_node = !network_interface.is_layer(&node_id, selection_network_path); - ContextMenuData::ToggleLayer { node_id, currently_is_node } + let currently_is_node = !network_interface.is_layer(&node_id, breadcrumb_network_path); + let can_be_layer = network_interface.is_eligible_to_be_layer(&node_id, breadcrumb_network_path); + ContextMenuData::ModifyNode { + can_be_layer, + currently_is_node, + node_id, + } } else { ContextMenuData::CreateNode { compatible_type: None } }; @@ -2592,18 +2597,18 @@ impl NodeGraphMessageHandler { } fn node_graph_error(&self, network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId]) -> Option { - let error = network_interface + let graph_error = network_interface .resolved_types .node_graph_errors .iter() .filter(|error| error.node_path.starts_with(breadcrumb_network_path) && error.node_path.len() > breadcrumb_network_path.len()) .next()?; - let error_node = error.node_path[breadcrumb_network_path.len()]; - let error = if error.node_path.len() == breadcrumb_network_path.len() + 1 { - format!("{:?}", error.error) + let error = if graph_error.node_path.len() == breadcrumb_network_path.len() + 1 { + format!("{:?}", graph_error.error) } else { "Node graph type error within this node".to_string() }; + let error_node = graph_error.node_path[breadcrumb_network_path.len()]; let mut position = network_interface.position(&error_node, breadcrumb_network_path)?; // Convert to graph space position *= 24; diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index 0b285e78b1..5b2704447d 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -153,16 +153,18 @@ pub struct BoxSelection { } #[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +#[serde(tag = "type", content = "data")] pub enum ContextMenuData { - ToggleLayer { - #[serde(rename = "nodeId")] - node_id: NodeId, + ModifyNode { + #[serde(rename = "canBeLayer")] + can_be_layer: bool, #[serde(rename = "currentlyIsNode")] currently_is_node: bool, + #[serde(rename = "nodeId")] + node_id: NodeId, }, CreateNode { #[serde(rename = "compatibleType")] - #[serde(default)] compatible_type: Option, }, } diff --git a/editor/src/test_utils.rs b/editor/src/test_utils.rs index 3b8a568d04..1a4e521af6 100644 --- a/editor/src/test_utils.rs +++ b/editor/src/test_utils.rs @@ -326,12 +326,9 @@ pub trait FrontendMessageTestUtils { impl FrontendMessageTestUtils for FrontendMessage { fn check_node_graph_error(&self) { - let FrontendMessage::UpdateNodeGraphNodes { nodes, .. } = self else { return }; - - for node in nodes { - if let Some(error) = &node.errors { - panic!("error on {}: {}", node.display_name, error); - } + let FrontendMessage::UpdateNodeGraphError { error } = self else { return }; + if let Some(error) = error { + panic!("error: {:?}", error); } } } diff --git a/frontend/src/components/views/Graph.svelte b/frontend/src/components/views/Graph.svelte index e8368aa757..45cecd87bc 100644 --- a/frontend/src/components/views/Graph.svelte +++ b/frontend/src/components/views/Graph.svelte @@ -27,9 +27,6 @@ let graph: HTMLDivElement | undefined; - // Key value is node id + input/output index - // Imports/Export are stored at a key value of 0 - $: gridSpacing = calculateGridSpacing($nodeGraph.transform.scale); $: gridDotRadius = 1 + Math.floor($nodeGraph.transform.scale - 0.5 + 0.001) / 2; @@ -115,15 +112,6 @@ return iconMap[icon] || "NodeNodes"; } - function toggleLayerDisplay(displayAsLayer: boolean, toggleId: bigint) { - let node = $nodeGraph.nodes.get(toggleId); - if (node) editor.handle.setToNodeOrLayer(node.id, displayAsLayer); - } - - function canBeToggledBetweenNodeAndLayer(toggleDisplayAsLayerNodeId: bigint) { - return $nodeGraph.nodes.get(toggleDisplayAsLayerNodeId)?.canBeLayer || false; - } - function createNode(nodeType: string) { if ($nodeGraph.contextMenuInformation === undefined) return; @@ -224,29 +212,26 @@ top: `${$nodeGraph.contextMenuInformation.contextMenuCoordinates.y * $nodeGraph.transform.scale + $nodeGraph.transform.y}px`, }} > - {#if typeof $nodeGraph.contextMenuInformation.contextMenuData === "string" && $nodeGraph.contextMenuInformation.contextMenuData === "CreateNode"} - createNode(e.detail)} /> - {:else if $nodeGraph.contextMenuInformation.contextMenuData && "compatibleType" in $nodeGraph.contextMenuInformation.contextMenuData} - createNode(e.detail)} /> - {:else} - {@const contextMenuData = $nodeGraph.contextMenuInformation.contextMenuData} + {#if $nodeGraph.contextMenuInformation.contextMenuData.type == "CreateNode"} + createNode(e.detail)} /> + {:else if $nodeGraph.contextMenuInformation.contextMenuData.type == "ModifyNode"} Display as toggleLayerDisplay(false, contextMenuData.nodeId), + action: () => editor.handle.setToNodeOrLayer($nodeGraph.contextMenuInformation.contextMenuData.data.nodeId, false), }, { value: "layer", label: "Layer", - action: () => toggleLayerDisplay(true, contextMenuData.nodeId), + action: () => editor.handle.setToNodeOrLayer($nodeGraph.contextMenuInformation.contextMenuData.data.nodeId, true), }, ]} - disabled={!canBeToggledBetweenNodeAndLayer(contextMenuData.nodeId)} + disabled={!$nodeGraph.contextMenuInformation.contextMenuData.data.canBeLayer} /> @@ -264,7 +249,6 @@ style={`left: ${$nodeGraph.error.position.x}px; top: ${$nodeGraph.error.position.y}px;`} transition:fade={FADE_TRANSITION} - title="" data-node-error>{$nodeGraph.error.error} {$nodeGraph.error.error}
diff --git a/frontend/src/messages.ts b/frontend/src/messages.ts index 528cf459bb..f99fb84e65 100644 --- a/frontend/src/messages.ts +++ b/frontend/src/messages.ts @@ -33,20 +33,7 @@ export class UpdateClickTargets extends JsMessage { readonly clickTargets!: FrontendClickTargets | undefined; } -const ContextTupleToVec2 = Transform((data) => { - if (data.obj.contextMenuInformation === undefined) return undefined; - const contextMenuCoordinates = data.obj.contextMenuInformation.contextMenuCoordinates; - let contextMenuData = data.obj.contextMenuInformation.contextMenuData; - if (contextMenuData.ToggleLayer !== undefined) { - contextMenuData = { nodeId: contextMenuData.ToggleLayer.nodeId, currentlyIsNode: contextMenuData.ToggleLayer.currentlyIsNode }; - } else if (contextMenuData.CreateNode !== undefined) { - contextMenuData = { type: "CreateNode", compatibleType: contextMenuData.CreateNode.compatibleType }; - } - return { contextMenuCoordinates, contextMenuData }; -}); - export class UpdateContextMenuInformation extends JsMessage { - @ContextTupleToVec2 readonly contextMenuInformation!: ContextMenuInformation | undefined; } @@ -182,7 +169,7 @@ export type FrontendClickTargets = { export type ContextMenuInformation = { contextMenuCoordinates: XY; - contextMenuData: "CreateNode" | { type: "CreateNode"; compatibleType: string } | { nodeId: bigint; currentlyIsNode: boolean }; + contextMenuData: { type: "CreateNode"; data: { compatibleType: string | undefined } } | { type: "ModifyNode"; data: { canBeLayer: boolean; currentlyIsNode: boolean; nodeId: bigint } }; }; export type FrontendGraphDataType = "General" | "Number" | "Artboard" | "Graphic" | "Raster" | "Vector" | "Color" | "Invalid"; From 956370d5092729a0cd723c181dd59a6107c9e913 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Mon, 24 Nov 2025 00:27:58 -0800 Subject: [PATCH 3/3] Code review --- .../src/messages/frontend/frontend_message.rs | 6 +-- .../node_graph/node_graph_message_handler.rs | 19 +++++---- .../document/node_graph/utility_types.rs | 16 ++++---- editor/src/test_utils.rs | 2 +- frontend/src/components/views/Graph.svelte | 40 ++++++++----------- frontend/src/messages.ts | 20 +++++----- frontend/src/state-providers/node-graph.ts | 6 +-- 7 files changed, 49 insertions(+), 60 deletions(-) diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index 22348c8cc9..0195180f1b 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -2,7 +2,7 @@ use super::utility_types::{DocumentDetails, MouseCursorIcon, OpenDocument}; use crate::messages::app_window::app_window_message_handler::AppWindowPlatform; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::node_graph::utility_types::{ - BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphError, Transform, + BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphErrorDiagnostic, Transform, }; use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer}; use crate::messages::portfolio::document::utility_types::wires::{WirePath, WirePathUpdate}; @@ -289,8 +289,8 @@ pub enum FrontendMessage { UpdateNodeGraphNodes { nodes: Vec, }, - UpdateNodeGraphError { - error: Option, + UpdateNodeGraphErrorDiagnostic { + error: Option, }, UpdateVisibleNodes { nodes: Vec, diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 034a1070ba..85c7fde361 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -6,7 +6,7 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::document_message_handler::navigation_controls; use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext; use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext; -use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType, NodeGraphError}; +use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType, NodeGraphErrorDiagnostic}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::misc::GroupFolderType; use crate::messages::portfolio::document::utility_types::network_interface::{ @@ -798,9 +798,8 @@ impl<'a> MessageHandler> for NodeG DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x }; - let context_menu_coordinates = node_graph_point + node_graph_shift; self.context_menu = Some(ContextMenuInformation { - context_menu_coordinates: context_menu_coordinates.into(), + context_menu_coordinates: (node_graph_point + node_graph_shift).into(), context_menu_data, }); @@ -1224,10 +1223,9 @@ impl<'a> MessageHandler> for NodeG let node_graph_shift = DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x; let compatible_type = network_interface.output_type(&output_connector, selection_network_path).add_node_string(); - let context_menu_coordinates = point + node_graph_shift; self.context_menu = Some(ContextMenuInformation { - context_menu_coordinates: context_menu_coordinates.into(), + context_menu_coordinates: (point + node_graph_shift).into(), context_menu_data: ContextMenuData::CreateNode { compatible_type }, }); @@ -1652,7 +1650,7 @@ impl<'a> MessageHandler> for NodeG responses.add(NodeGraphMessage::UpdateVisibleNodes); let error = self.node_graph_error(network_interface, breadcrumb_network_path); - responses.add(FrontendMessage::UpdateNodeGraphError { error }); + responses.add(FrontendMessage::UpdateNodeGraphErrorDiagnostic { error }); let (layer_widths, chain_widths, has_left_input_wire) = network_interface.collect_layer_widths(breadcrumb_network_path); responses.add(NodeGraphMessage::UpdateImportsExports); @@ -2596,26 +2594,27 @@ impl NodeGraphMessageHandler { Some(subgraph_names) } - fn node_graph_error(&self, network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId]) -> Option { + fn node_graph_error(&self, network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId]) -> Option { let graph_error = network_interface .resolved_types .node_graph_errors .iter() - .filter(|error| error.node_path.starts_with(breadcrumb_network_path) && error.node_path.len() > breadcrumb_network_path.len()) - .next()?; + .find(|error| error.node_path.starts_with(breadcrumb_network_path) && error.node_path.len() > breadcrumb_network_path.len())?; let error = if graph_error.node_path.len() == breadcrumb_network_path.len() + 1 { format!("{:?}", graph_error.error) } else { "Node graph type error within this node".to_string() }; let error_node = graph_error.node_path[breadcrumb_network_path.len()]; + let mut position = network_interface.position(&error_node, breadcrumb_network_path)?; // Convert to graph space position *= 24; if network_interface.is_layer(&error_node, breadcrumb_network_path) { position += IVec2::new(12, -12) } - Some(NodeGraphError { position: position.into(), error }) + + Some(NodeGraphErrorDiagnostic { position: position.into(), error }) } fn update_layer_panel(network_interface: &NodeNetworkInterface, selection_network_path: &[NodeId], collapsed: &CollapsedLayers, layers_panel_open: bool, responses: &mut VecDeque) { diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index 5b2704447d..60869acadc 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -90,14 +90,14 @@ pub struct FrontendNode { pub primary_output: Option, #[serde(rename = "exposedOutputs")] pub exposed_outputs: Vec, - #[serde(rename = "primaryOutputConnectedToLayer")] - pub primary_output_connected_to_layer: bool, #[serde(rename = "primaryInputConnectedToLayer")] pub primary_input_connected_to_layer: bool, + #[serde(rename = "primaryOutputConnectedToLayer")] + pub primary_output_connected_to_layer: bool, pub position: IVec2, + pub previewed: bool, pub visible: bool, pub locked: bool, - pub previewed: bool, } #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] @@ -156,12 +156,12 @@ pub struct BoxSelection { #[serde(tag = "type", content = "data")] pub enum ContextMenuData { ModifyNode { + #[serde(rename = "nodeId")] + node_id: NodeId, #[serde(rename = "canBeLayer")] can_be_layer: bool, #[serde(rename = "currentlyIsNode")] currently_is_node: bool, - #[serde(rename = "nodeId")] - node_id: NodeId, }, CreateNode { #[serde(rename = "compatibleType")] @@ -179,7 +179,7 @@ pub struct ContextMenuInformation { } #[derive(Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)] -pub struct NodeGraphError { +pub struct NodeGraphErrorDiagnostic { pub position: FrontendXY, pub error: String, } @@ -208,7 +208,7 @@ pub enum Direction { Right, } -/// Stores node graph coordinates which are then transformed in svelte based on the node graph transform +/// Stores node graph coordinates which are then transformed in Svelte based on the node graph transform #[derive(Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)] pub struct FrontendXY { pub x: i32, @@ -223,6 +223,6 @@ impl From for FrontendXY { impl From for FrontendXY { fn from(v: IVec2) -> Self { - FrontendXY { x: v.x as i32, y: v.y as i32 } + FrontendXY { x: v.x, y: v.y } } } diff --git a/editor/src/test_utils.rs b/editor/src/test_utils.rs index 1a4e521af6..230f82121c 100644 --- a/editor/src/test_utils.rs +++ b/editor/src/test_utils.rs @@ -326,7 +326,7 @@ pub trait FrontendMessageTestUtils { impl FrontendMessageTestUtils for FrontendMessage { fn check_node_graph_error(&self) { - let FrontendMessage::UpdateNodeGraphError { error } = self else { return }; + let FrontendMessage::UpdateNodeGraphErrorDiagnostic { error } = self else { return }; if let Some(error) = error { panic!("error: {:?}", error); } diff --git a/frontend/src/components/views/Graph.svelte b/frontend/src/components/views/Graph.svelte index 45cecd87bc..509dfbd96e 100644 --- a/frontend/src/components/views/Graph.svelte +++ b/frontend/src/components/views/Graph.svelte @@ -212,9 +212,9 @@ top: `${$nodeGraph.contextMenuInformation.contextMenuCoordinates.y * $nodeGraph.transform.scale + $nodeGraph.transform.y}px`, }} > - {#if $nodeGraph.contextMenuInformation.contextMenuData.type == "CreateNode"} + {#if $nodeGraph.contextMenuInformation.contextMenuData.type === "CreateNode"} createNode(e.detail)} /> - {:else if $nodeGraph.contextMenuInformation.contextMenuData.type == "ModifyNode"} + {:else if $nodeGraph.contextMenuInformation.contextMenuData.type === "ModifyNode"} Display as editor.handle.setToNodeOrLayer($nodeGraph.contextMenuInformation.contextMenuData.data.nodeId, false), + action: () => + $nodeGraph.contextMenuInformation?.contextMenuData.type === "ModifyNode" && + editor.handle.setToNodeOrLayer($nodeGraph.contextMenuInformation.contextMenuData.data.nodeId, false), }, { value: "layer", label: "Layer", - action: () => editor.handle.setToNodeOrLayer($nodeGraph.contextMenuInformation.contextMenuData.data.nodeId, true), + action: () => + $nodeGraph.contextMenuInformation?.contextMenuData.type === "ModifyNode" && + editor.handle.setToNodeOrLayer($nodeGraph.contextMenuInformation.contextMenuData.data.nodeId, true), }, ]} disabled={!$nodeGraph.contextMenuInformation.contextMenuData.data.canBeLayer} @@ -244,20 +248,12 @@ {#if $nodeGraph.error}
- {$nodeGraph.error.error} - {$nodeGraph.error.error} + + {$nodeGraph.error.error} + + + {$nodeGraph.error.error} +
{/if} @@ -337,7 +333,7 @@ style:--offset-left={($nodeGraph.updateImportsExports.importPosition.x - 8) / 24} style:--offset-top={($nodeGraph.updateImportsExports.importPosition.y - 8) / 24 + index} > - {#if editingNameImportIndex == index} + {#if editingNameImportIndex === index} - {#if node.errors} - {node.errors} - {node.errors} - {/if}
diff --git a/frontend/src/messages.ts b/frontend/src/messages.ts index f99fb84e65..d1a24ccd61 100644 --- a/frontend/src/messages.ts +++ b/frontend/src/messages.ts @@ -33,10 +33,6 @@ export class UpdateClickTargets extends JsMessage { readonly clickTargets!: FrontendClickTargets | undefined; } -export class UpdateContextMenuInformation extends JsMessage { - readonly contextMenuInformation!: ContextMenuInformation | undefined; -} - export class UpdateImportsExports extends JsMessage { readonly imports!: (FrontendGraphOutput | undefined)[]; @@ -81,7 +77,7 @@ export class UpdateNodeGraphNodes extends JsMessage { readonly nodes!: FrontendNode[]; } -export class UpdateNodeGraphError extends JsMessage { +export class UpdateNodeGraphErrorDiagnostic extends JsMessage { readonly error!: NodeGraphError | undefined; } @@ -172,6 +168,10 @@ export type ContextMenuInformation = { contextMenuData: { type: "CreateNode"; data: { compatibleType: string | undefined } } | { type: "ModifyNode"; data: { canBeLayer: boolean; currentlyIsNode: boolean; nodeId: bigint } }; }; +export class UpdateContextMenuInformation extends JsMessage { + readonly contextMenuInformation!: ContextMenuInformation | undefined; +} + export type FrontendGraphDataType = "General" | "Number" | "Artboard" | "Graphic" | "Raster" | "Vector" | "Color" | "Invalid"; export class FrontendGraphInput { @@ -201,12 +201,12 @@ export class FrontendGraphOutput { } export class FrontendNode { + readonly id!: bigint; + readonly isLayer!: boolean; readonly canBeLayer!: boolean; - readonly id!: bigint; - readonly reference!: string | undefined; readonly displayName!: string; @@ -232,9 +232,7 @@ export class FrontendNode { readonly visible!: boolean; - readonly unlocked!: boolean; - - readonly errors!: string | undefined; + readonly locked!: boolean; } export class FrontendNodeType { @@ -1696,7 +1694,7 @@ export const messageMakers: Record = { UpdateMouseCursor, UpdateNodeGraphControlBarLayout, UpdateNodeGraphNodes, - UpdateNodeGraphError, + UpdateNodeGraphErrorDiagnostic, UpdateNodeGraphSelection, UpdateNodeGraphTransform, UpdateNodeGraphWires, diff --git a/frontend/src/state-providers/node-graph.ts b/frontend/src/state-providers/node-graph.ts index cdb28f47e3..80d35eadb8 100644 --- a/frontend/src/state-providers/node-graph.ts +++ b/frontend/src/state-providers/node-graph.ts @@ -26,7 +26,7 @@ import { UpdateNodeGraphTransform, UpdateNodeThumbnail, UpdateWirePathInProgress, - UpdateNodeGraphError, + UpdateNodeGraphErrorDiagnostic, } from "@graphite/messages"; export function createNodeGraphState(editor: Editor) { @@ -121,9 +121,9 @@ export function createNodeGraphState(editor: Editor) { return state; }); }); - editor.subscriptions.subscribeJsMessage(UpdateNodeGraphError, (updateNodeGraphError) => { + editor.subscriptions.subscribeJsMessage(UpdateNodeGraphErrorDiagnostic, (updateNodeGraphErrorDiagnostic) => { update((state) => { - state.error = updateNodeGraphError.error; + state.error = updateNodeGraphErrorDiagnostic.error; return state; }); });