1use std::collections::HashMap;
8
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "snake_case")]
15pub enum BlockKind {
16 Agent,
17 Condition,
18 Api,
19 Response,
20 Variables,
21}
22
23impl BlockKind {
24 pub fn parse(s: &str) -> Option<Self> {
25 match s {
26 "agent" => Some(Self::Agent),
27 "condition" => Some(Self::Condition),
28 "api" => Some(Self::Api),
29 "response" => Some(Self::Response),
30 "variables" => Some(Self::Variables),
31 _ => None,
32 }
33 }
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct FlowNode {
41 pub id: String,
42 #[serde(default)]
44 pub position: NodePosition,
45 pub data: serde_json::Value,
47 #[serde(default, rename = "type", skip_serializing_if = "String::is_empty")]
49 pub node_type: String,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, Default)]
53pub struct NodePosition {
54 pub x: f64,
55 pub y: f64,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
64#[serde(rename_all = "camelCase")]
65pub struct FlowEdge {
66 pub id: String,
67 pub source: String,
68 pub target: String,
69 #[serde(default, skip_serializing_if = "Option::is_none")]
70 pub source_handle: Option<String>,
71 #[serde(default, skip_serializing_if = "Option::is_none")]
72 pub target_handle: Option<String>,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize, Default)]
77pub struct DroneGraph {
78 #[serde(default)]
79 pub nodes: Vec<FlowNode>,
80 #[serde(default)]
81 pub edges: Vec<FlowEdge>,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct DroneViewport {
86 pub x: f64,
87 pub y: f64,
88 pub zoom: f64,
89}
90
91impl Default for DroneViewport {
92 fn default() -> Self {
93 Self { x: 0.0, y: 0.0, zoom: 1.0 }
94 }
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct DroneDefinition {
100 pub id: String,
101 pub name: String,
102 #[serde(default)]
103 pub description: String,
104 #[serde(default)]
105 pub graph: DroneGraph,
106 #[serde(default)]
107 pub viewport: DroneViewport,
108 pub created_at: i64,
109 pub updated_at: i64,
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
113#[serde(rename_all = "snake_case")]
114pub enum RunStatus {
115 Running,
116 Done,
117 Failed,
118}
119
120impl RunStatus {
121 pub fn as_str(&self) -> &'static str {
122 match self {
123 Self::Running => "running",
124 Self::Done => "done",
125 Self::Failed => "failed",
126 }
127 }
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct DroneRun {
133 pub id: String,
134 pub drone_id: String,
135 pub status: String,
136 pub started_at: i64,
137 pub ended_at: i64,
138 #[serde(default)]
140 pub block_states: HashMap<String, BlockState>,
141 #[serde(default)]
143 pub output: String,
144 #[serde(default)]
146 pub error: String,
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct BlockState {
151 pub status: String, #[serde(default, skip_serializing_if = "Option::is_none")]
153 pub output: Option<serde_json::Value>,
154 #[serde(default, skip_serializing_if = "Option::is_none")]
155 pub error: Option<String>,
156 #[serde(default, skip_serializing_if = "Option::is_none")]
157 pub started_at: Option<i64>,
158 #[serde(default, skip_serializing_if = "Option::is_none")]
159 pub completed_at: Option<i64>,
160}
161
162impl BlockState {
163 pub fn pending() -> Self {
164 Self {
165 status: "pending".to_string(),
166 output: None,
167 error: None,
168 started_at: None,
169 completed_at: None,
170 }
171 }
172}