jellyflow_runtime/runtime/delete/
planner.rs1use keyboard_types::Code as KeyCode;
2
3use crate::io::{NodeGraphInteractionState, NodeGraphViewState};
4use crate::rules::{DeletePlan, plan_delete_elements_with_policy};
5use jellyflow_core::core::Graph;
6use jellyflow_core::ops::{GraphOp, GraphTransaction};
7
8use super::types::{
9 DELETE_SELECTION_TRANSACTION_LABEL, DeleteElements, DeleteSelectionError, PreDeleteRequest,
10};
11
12pub fn plan_delete_selection(
14 graph: &Graph,
15 view_state: &NodeGraphViewState,
16 interaction: &NodeGraphInteractionState,
17) -> DeletePlan {
18 let elements = delete_selection_elements(view_state);
19 plan_delete_elements(graph, interaction, &elements)
20}
21
22pub fn plan_delete_selection_for_key(
24 graph: &Graph,
25 view_state: &NodeGraphViewState,
26 interaction: &NodeGraphInteractionState,
27 key: KeyCode,
28) -> Option<DeletePlan> {
29 let keyboard = interaction.keyboard_interaction();
30 if keyboard.disable_keyboard_a11y || !keyboard.delete_key.matches(key) {
31 return None;
32 }
33
34 Some(plan_delete_selection(graph, view_state, interaction))
35}
36
37pub fn delete_selection_elements(view_state: &NodeGraphViewState) -> DeleteElements {
39 DeleteElements::new(
40 view_state.selected_nodes.iter().copied(),
41 view_state.selected_edges.iter().copied(),
42 )
43}
44
45pub fn plan_delete_elements(
47 graph: &Graph,
48 interaction: &NodeGraphInteractionState,
49 elements: &DeleteElements,
50) -> DeletePlan {
51 plan_delete_elements_with_policy(
52 graph,
53 elements.nodes().iter().copied(),
54 elements.edges().iter().copied(),
55 interaction,
56 )
57}
58
59pub fn prepare_delete_selection(
61 graph: &Graph,
62 view_state: &NodeGraphViewState,
63 interaction: &NodeGraphInteractionState,
64) -> Result<Option<PreDeleteRequest>, DeleteSelectionError> {
65 let requested = delete_selection_elements(view_state);
66 prepare_delete_elements(graph, interaction, requested)
67}
68
69pub fn prepare_delete_selection_for_key(
71 graph: &Graph,
72 view_state: &NodeGraphViewState,
73 interaction: &NodeGraphInteractionState,
74 key: KeyCode,
75) -> Result<Option<PreDeleteRequest>, DeleteSelectionError> {
76 let keyboard = interaction.keyboard_interaction();
77 if keyboard.disable_keyboard_a11y || !keyboard.delete_key.matches(key) {
78 return Ok(None);
79 }
80
81 prepare_delete_selection(graph, view_state, interaction)
82}
83
84pub fn prepare_delete_elements(
86 graph: &Graph,
87 interaction: &NodeGraphInteractionState,
88 requested: DeleteElements,
89) -> Result<Option<PreDeleteRequest>, DeleteSelectionError> {
90 let plan = plan_delete_elements(graph, interaction, &requested);
91 if plan.is_reject() {
92 return Err(DeleteSelectionError::Rejected {
93 diagnostics: plan.diagnostics,
94 });
95 }
96
97 let planned = delete_elements_from_plan(&plan);
98 if planned.is_empty() {
99 return Ok(None);
100 }
101
102 Ok(Some(PreDeleteRequest::new(requested, planned)))
103}
104
105pub fn delete_elements_from_plan(plan: &DeletePlan) -> DeleteElements {
107 let mut nodes = Vec::new();
108 let mut edges = Vec::new();
109
110 for op in plan.ops() {
111 match op {
112 GraphOp::RemoveNode {
113 id,
114 edges: removed_edges,
115 ..
116 } => {
117 nodes.push(*id);
118 edges.extend(removed_edges.iter().map(|(edge_id, _)| *edge_id));
119 }
120 GraphOp::RemovePort {
121 edges: removed_edges,
122 ..
123 } => {
124 edges.extend(removed_edges.iter().map(|(edge_id, _)| *edge_id));
125 }
126 GraphOp::RemoveEdge { id, .. } => edges.push(*id),
127 _ => {}
128 }
129 }
130
131 DeleteElements::new(nodes, edges)
132}
133
134pub fn delete_selection_transaction(plan: &DeletePlan) -> Option<GraphTransaction> {
136 if !plan.is_accept() || plan.ops().is_empty() {
137 return None;
138 }
139
140 Some(
141 GraphTransaction::from_ops(plan.ops().iter().cloned())
142 .with_label(DELETE_SELECTION_TRANSACTION_LABEL),
143 )
144}
145
146pub fn delete_selection_transaction_from_plan(plan: DeletePlan) -> Option<GraphTransaction> {
148 if !plan.is_accept() || plan.ops().is_empty() {
149 return None;
150 }
151
152 Some(GraphTransaction::from_ops(plan.into_ops()).with_label(DELETE_SELECTION_TRANSACTION_LABEL))
153}