mcai_models/
workflow.rs

1use super::{NotificationHook, StartParameter, Step, WorkflowDefinition, WorkflowInstance};
2use crate::common::Job;
3use mcai_graph::{Graph, GraphConfiguration, ToGraph};
4use semver::Version;
5use std::collections::HashMap;
6
7#[derive(PartialEq)]
8pub enum SchemaVersion {
9  _1_8,
10  _1_9,
11  _1_10,
12  _1_11,
13}
14
15#[derive(Clone, PartialEq)]
16pub enum Workflow {
17  Definition(WorkflowDefinition),
18  Instance(WorkflowInstance),
19}
20
21impl Workflow {
22  pub fn is_definition(&self) -> bool {
23    match self {
24      Workflow::Definition(_) => true,
25      Workflow::Instance(_) => false,
26    }
27  }
28
29  pub fn schema_version(&self) -> SchemaVersion {
30    match self {
31      Workflow::Definition(workflow) => workflow.schema_version(),
32      Workflow::Instance(workflow) => workflow.schema_version(),
33    }
34  }
35
36  pub fn identifier(&self) -> &str {
37    match self {
38      Workflow::Definition(workflow) => workflow.identifier(),
39      Workflow::Instance(workflow) => &workflow.identifier,
40    }
41  }
42
43  pub fn label(&self) -> &str {
44    match self {
45      Workflow::Definition(workflow) => workflow.label(),
46      Workflow::Instance(workflow) => &workflow.label,
47    }
48  }
49
50  pub fn version(&self) -> Version {
51    match self {
52      Workflow::Definition(workflow) => workflow.version(),
53      Workflow::Instance(workflow) => Version::new(
54        workflow.version_major as u64,
55        workflow.version_minor as u64,
56        workflow.version_micro as u64,
57      ),
58    }
59  }
60
61  pub fn is_live(&self) -> bool {
62    match self {
63      Workflow::Definition(workflow) => workflow.is_live(),
64      Workflow::Instance(workflow) => workflow.is_live,
65    }
66  }
67
68  pub fn tags(&self) -> &Vec<String> {
69    match self {
70      Workflow::Definition(workflow) => workflow.tags(),
71      Workflow::Instance(workflow) => &workflow.tags,
72    }
73  }
74
75  pub fn reference(&self) -> Option<String> {
76    match self {
77      Workflow::Definition(_) => None,
78      Workflow::Instance(workflow) => workflow.reference.clone(),
79    }
80  }
81
82  pub fn jobs(&self) -> Option<&Vec<Job>> {
83    match self {
84      Workflow::Definition(_) => None,
85      Workflow::Instance(workflow) => Some(&workflow.jobs),
86    }
87  }
88
89  pub fn steps(&self) -> &Vec<Step> {
90    match self {
91      Workflow::Definition(workflow) => workflow.steps(),
92      Workflow::Instance(workflow) => &workflow.steps,
93    }
94  }
95
96  pub fn get_start_parameters(&self) -> &Vec<StartParameter> {
97    match self {
98      Workflow::Definition(workflow) => workflow.get_start_parameters(),
99      Workflow::Instance(workflow) => &workflow.start_parameters,
100    }
101  }
102
103  pub fn get_notification_hooks(&self) -> Option<&Vec<NotificationHook>> {
104    match self {
105      Workflow::Definition(workflow) => workflow.get_notification_hooks(),
106      Workflow::Instance(_workflow) => None,
107    }
108  }
109
110  pub fn update_steps_coordinates_from_graph(&mut self, graph: &Graph) {
111    if let Workflow::Definition(workflow_definition) = self {
112      for (id, node) in graph.nodes() {
113        if let Some(step) = workflow_definition.get_mut_step(id) {
114          step.coordinates = Some(node.borrow().coordinates().clone());
115        }
116        continue;
117      }
118    }
119  }
120}
121
122impl ToGraph for Workflow {
123  fn to_graph(&self, configuration: GraphConfiguration) -> Graph {
124    let steps = self.steps().clone();
125
126    let mut graph = Graph::new(configuration.clone());
127
128    let mut nodes = HashMap::with_capacity(steps.len());
129    let mut node_level = HashMap::with_capacity(steps.len());
130
131    let mut level = 0;
132    let mut column = 0;
133
134    for step in self.steps().iter() {
135      // Add node from step coordinates
136      if let Some(coordinates) = &step.coordinates {
137        let node = graph.add_node(step.id, coordinates.clone());
138        nodes.insert(step.id, node);
139        node_level.insert(step.id, level);
140        continue;
141      }
142
143      // Add node from step without parents
144      if step.parent_ids.is_empty() {
145        let node = graph.add_node(
146          step.id,
147          configuration
148            .node_configuration()
149            .get_coordinates(level, column),
150        );
151        nodes.insert(step.id, node);
152        node_level.insert(step.id, level);
153
154        column += 1;
155      }
156    }
157
158    loop {
159      column = 0;
160      if nodes.len() == steps.len() {
161        break;
162      }
163      level += 1;
164
165      // Add nodes from step with parents
166      for step in steps.iter() {
167        if nodes.contains_key(&step.id) {
168          continue;
169        }
170
171        if let Some(latest_level) = step
172          .parent_ids
173          .iter()
174          .filter_map(|parent_id| node_level.get(parent_id))
175          .max()
176        {
177          let step_level = latest_level + 1;
178          if step_level == level {
179            let node = graph.add_node(
180              step.id,
181              configuration
182                .node_configuration()
183                .get_coordinates(step_level, column),
184            );
185
186            nodes.insert(step.id, node);
187            node_level.insert(step.id, step_level);
188
189            column += 1;
190          }
191        }
192      }
193    }
194
195    // Set step parents and required steps
196    for step in steps.iter() {
197      let parents = step
198        .parent_ids
199        .iter()
200        .filter_map(|parent_id| nodes.get(parent_id).cloned())
201        .collect();
202
203      let required_to_start = step
204        .required_to_start
205        .iter()
206        .filter_map(|required_step_id| nodes.get(required_step_id).cloned())
207        .collect();
208
209      if let Some(node) = nodes.get(&step.id) {
210        node.borrow_mut().set_parents(parents);
211        node.borrow_mut().set_required_nodes(required_to_start);
212      }
213    }
214
215    graph
216  }
217}