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
This commit is contained in:
parent
e42950b4be
commit
7f10a4258e
|
|
@ -369,13 +369,8 @@ impl NodeNetworkInterface {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
// TODO: Get downstream connections from all outputs
|
// TODO: Get downstream connections from all outputs
|
||||||
let Some(downstream_connections) = outward_wires.get(&OutputConnector::node(*node_id, 0)) else {
|
let mut downstream_connections = outward_wires.get(&OutputConnector::node(*node_id, 0)).map_or([].iter(), |outputs| outputs.iter());
|
||||||
log::error!("Could not get outward wires in copy_nodes");
|
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)));
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let has_selected_node_downstream = downstream_connections
|
|
||||||
.iter()
|
|
||||||
.any(|input_connector| input_connector.node_id().is_some_and(|upstream_id| new_ids.keys().any(|key| *key == upstream_id)));
|
|
||||||
// If the copied node does not have a downstream connection to another copied node, then set the position to absolute
|
// If the copied node does not have a downstream connection to another copied node, then set the position to absolute
|
||||||
if !has_selected_node_downstream {
|
if !has_selected_node_downstream {
|
||||||
let Some(position) = self.position(node_id, network_path) else {
|
let Some(position) = self.position(node_id, network_path) else {
|
||||||
|
|
@ -6916,3 +6911,34 @@ pub enum TransactionStatus {
|
||||||
#[default]
|
#[default]
|
||||||
Finished,
|
Finished,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod network_interface_tests {
|
||||||
|
use crate::test_utils::test_prelude::*;
|
||||||
|
#[tokio::test]
|
||||||
|
async fn copy_isolated_node() {
|
||||||
|
let mut editor = EditorTestUtils::create();
|
||||||
|
editor.new_document().await;
|
||||||
|
let rectangle = editor.create_node_by_name("Rectangle").await;
|
||||||
|
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![rectangle] }).await;
|
||||||
|
let frontend_messages = editor.handle_message(NodeGraphMessage::Copy).await;
|
||||||
|
let serialized_nodes = frontend_messages
|
||||||
|
.into_iter()
|
||||||
|
.find_map(|msg| match msg {
|
||||||
|
FrontendMessage::TriggerTextCopy { copy_text } => Some(copy_text),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.expect("copy message should be dispatched")
|
||||||
|
.strip_prefix("graphite/nodes: ")
|
||||||
|
.expect("should start with magic string")
|
||||||
|
.to_string();
|
||||||
|
println!("Serialized: {serialized_nodes}");
|
||||||
|
editor.handle_message(NodeGraphMessage::PasteNodes { serialized_nodes }).await;
|
||||||
|
let nodes = &mut editor.active_document_mut().network_interface.network_mut(&[]).unwrap().nodes;
|
||||||
|
let orignal = nodes.remove(&rectangle).expect("original node should exist");
|
||||||
|
assert!(
|
||||||
|
nodes.values().any(|other| *other == orignal),
|
||||||
|
"duplicated node should exist\nother nodes: {nodes:#?}\norignal {orignal:#?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use glam::{DVec2, UVec2};
|
||||||
use graph_craft::document::DocumentNode;
|
use graph_craft::document::DocumentNode;
|
||||||
use graphene_std::InputAccessor;
|
use graphene_std::InputAccessor;
|
||||||
use graphene_std::raster::color::Color;
|
use graphene_std::raster::color::Color;
|
||||||
|
use graphene_std::uuid::NodeId;
|
||||||
|
|
||||||
/// A set of utility functions to make the writing of editor test more declarative
|
/// A set of utility functions to make the writing of editor test more declarative
|
||||||
pub struct EditorTestUtils {
|
pub struct EditorTestUtils {
|
||||||
|
|
@ -68,13 +69,15 @@ impl EditorTestUtils {
|
||||||
run(&mut self.editor, &mut self.runtime)
|
run(&mut self.editor, &mut self.runtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_message(&mut self, message: impl Into<Message>) {
|
pub async fn handle_message(&mut self, message: impl Into<Message>) -> Vec<FrontendMessage> {
|
||||||
self.editor.handle_message(message);
|
let frontend_messages_from_msg = self.editor.handle_message(message);
|
||||||
|
|
||||||
// Required to process any buffered messages
|
// Required to process any buffered messages
|
||||||
if let Err(e) = self.eval_graph().await {
|
if let Err(e) = self.eval_graph().await {
|
||||||
panic!("Failed to evaluate graph: {e}");
|
panic!("Failed to evaluate graph: {e}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frontend_messages_from_msg
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new_document(&mut self) {
|
pub async fn new_document(&mut self) {
|
||||||
|
|
@ -222,7 +225,7 @@ impl EditorTestUtils {
|
||||||
ToolType::Rectangle => self.handle_message(Message::Tool(ToolMessage::ActivateToolShapeRectangle)).await,
|
ToolType::Rectangle => self.handle_message(Message::Tool(ToolMessage::ActivateToolShapeRectangle)).await,
|
||||||
ToolType::Ellipse => self.handle_message(Message::Tool(ToolMessage::ActivateToolShapeEllipse)).await,
|
ToolType::Ellipse => self.handle_message(Message::Tool(ToolMessage::ActivateToolShapeEllipse)).await,
|
||||||
_ => self.handle_message(Message::Tool(ToolMessage::ActivateTool { tool_type })).await,
|
_ => self.handle_message(Message::Tool(ToolMessage::ActivateTool { tool_type })).await,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn select_primary_color(&mut self, color: Color) {
|
pub async fn select_primary_color(&mut self, color: Color) {
|
||||||
|
|
@ -303,6 +306,18 @@ impl EditorTestUtils {
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn create_node_by_name(&mut self, name: impl Into<String>) -> NodeId {
|
||||||
|
let node_id = NodeId::new();
|
||||||
|
self.handle_message(NodeGraphMessage::CreateNodeFromContextMenu {
|
||||||
|
node_id: Some(node_id),
|
||||||
|
node_type: name.into(),
|
||||||
|
xy: None,
|
||||||
|
add_transaction: true,
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
node_id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FrontendMessageTestUtils {
|
pub trait FrontendMessageTestUtils {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue