Skip to content

Commit 7f10a42

Browse files
authored
Fix copying nodes sometimes failing when no OutputConnector exists (#3365)
* Fix copy nodes sometimes failing when no OutputConnector exists * Add test for copying a node
1 parent e42950b commit 7f10a42

File tree

2 files changed

+51
-10
lines changed

2 files changed

+51
-10
lines changed

editor/src/messages/portfolio/document/utility_types/network_interface.rs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -369,13 +369,8 @@ impl NodeNetworkInterface {
369369
return None;
370370
};
371371
// TODO: Get downstream connections from all outputs
372-
let Some(downstream_connections) = outward_wires.get(&OutputConnector::node(*node_id, 0)) else {
373-
log::error!("Could not get outward wires in copy_nodes");
374-
return None;
375-
};
376-
let has_selected_node_downstream = downstream_connections
377-
.iter()
378-
.any(|input_connector| input_connector.node_id().is_some_and(|upstream_id| new_ids.keys().any(|key| *key == upstream_id)));
372+
let mut downstream_connections = outward_wires.get(&OutputConnector::node(*node_id, 0)).map_or([].iter(), |outputs| outputs.iter());
373+
let has_selected_node_downstream = downstream_connections.any(|input_connector| input_connector.node_id().is_some_and(|upstream_id| new_ids.keys().any(|key| *key == upstream_id)));
379374
// If the copied node does not have a downstream connection to another copied node, then set the position to absolute
380375
if !has_selected_node_downstream {
381376
let Some(position) = self.position(node_id, network_path) else {
@@ -6916,3 +6911,34 @@ pub enum TransactionStatus {
69166911
#[default]
69176912
Finished,
69186913
}
6914+
6915+
#[cfg(test)]
6916+
mod network_interface_tests {
6917+
use crate::test_utils::test_prelude::*;
6918+
#[tokio::test]
6919+
async fn copy_isolated_node() {
6920+
let mut editor = EditorTestUtils::create();
6921+
editor.new_document().await;
6922+
let rectangle = editor.create_node_by_name("Rectangle").await;
6923+
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![rectangle] }).await;
6924+
let frontend_messages = editor.handle_message(NodeGraphMessage::Copy).await;
6925+
let serialized_nodes = frontend_messages
6926+
.into_iter()
6927+
.find_map(|msg| match msg {
6928+
FrontendMessage::TriggerTextCopy { copy_text } => Some(copy_text),
6929+
_ => None,
6930+
})
6931+
.expect("copy message should be dispatched")
6932+
.strip_prefix("graphite/nodes: ")
6933+
.expect("should start with magic string")
6934+
.to_string();
6935+
println!("Serialized: {serialized_nodes}");
6936+
editor.handle_message(NodeGraphMessage::PasteNodes { serialized_nodes }).await;
6937+
let nodes = &mut editor.active_document_mut().network_interface.network_mut(&[]).unwrap().nodes;
6938+
let orignal = nodes.remove(&rectangle).expect("original node should exist");
6939+
assert!(
6940+
nodes.values().any(|other| *other == orignal),
6941+
"duplicated node should exist\nother nodes: {nodes:#?}\norignal {orignal:#?}"
6942+
);
6943+
}
6944+
}

editor/src/test_utils.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use glam::{DVec2, UVec2};
1313
use graph_craft::document::DocumentNode;
1414
use graphene_std::InputAccessor;
1515
use graphene_std::raster::color::Color;
16+
use graphene_std::uuid::NodeId;
1617

1718
/// A set of utility functions to make the writing of editor test more declarative
1819
pub struct EditorTestUtils {
@@ -68,13 +69,15 @@ impl EditorTestUtils {
6869
run(&mut self.editor, &mut self.runtime)
6970
}
7071

71-
pub async fn handle_message(&mut self, message: impl Into<Message>) {
72-
self.editor.handle_message(message);
72+
pub async fn handle_message(&mut self, message: impl Into<Message>) -> Vec<FrontendMessage> {
73+
let frontend_messages_from_msg = self.editor.handle_message(message);
7374

7475
// Required to process any buffered messages
7576
if let Err(e) = self.eval_graph().await {
7677
panic!("Failed to evaluate graph: {e}");
7778
}
79+
80+
frontend_messages_from_msg
7881
}
7982

8083
pub async fn new_document(&mut self) {
@@ -222,7 +225,7 @@ impl EditorTestUtils {
222225
ToolType::Rectangle => self.handle_message(Message::Tool(ToolMessage::ActivateToolShapeRectangle)).await,
223226
ToolType::Ellipse => self.handle_message(Message::Tool(ToolMessage::ActivateToolShapeEllipse)).await,
224227
_ => self.handle_message(Message::Tool(ToolMessage::ActivateTool { tool_type })).await,
225-
}
228+
};
226229
}
227230

228231
pub async fn select_primary_color(&mut self, color: Color) {
@@ -303,6 +306,18 @@ impl EditorTestUtils {
303306
})
304307
.await;
305308
}
309+
310+
pub async fn create_node_by_name(&mut self, name: impl Into<String>) -> NodeId {
311+
let node_id = NodeId::new();
312+
self.handle_message(NodeGraphMessage::CreateNodeFromContextMenu {
313+
node_id: Some(node_id),
314+
node_type: name.into(),
315+
xy: None,
316+
add_transaction: true,
317+
})
318+
.await;
319+
node_id
320+
}
306321
}
307322

308323
pub trait FrontendMessageTestUtils {

0 commit comments

Comments
 (0)