ironflow_api/entities/
run.rs1use std::collections::HashMap;
4
5use chrono::{DateTime, Utc};
6use ironflow_store::models::{Run, RunStatus, TriggerKind};
7use rust_decimal::Decimal;
8use serde::{Deserialize, Serialize};
9use uuid::Uuid;
10
11use super::StepResponse;
12
13#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
24#[derive(Debug, Serialize, Deserialize)]
25pub struct RunResponse {
26 pub id: Uuid,
28 pub workflow_name: String,
30 pub status: RunStatus,
32 pub trigger: TriggerKind,
34 pub error: Option<String>,
36 pub retry_count: u32,
38 pub max_retries: u32,
40 #[cfg_attr(feature = "openapi", schema(value_type = f64))]
42 pub cost_usd: Decimal,
43 pub duration_ms: u64,
45 pub created_at: DateTime<Utc>,
47 pub updated_at: DateTime<Utc>,
49 pub started_at: Option<DateTime<Utc>>,
51 pub completed_at: Option<DateTime<Utc>>,
53 pub handler_version: Option<String>,
55 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
57 pub labels: HashMap<String, String>,
58 #[serde(default, skip_serializing_if = "Option::is_none")]
60 pub scheduled_at: Option<DateTime<Utc>>,
61}
62
63impl From<Run> for RunResponse {
64 fn from(run: Run) -> Self {
65 RunResponse {
66 id: run.id,
67 workflow_name: run.workflow_name,
68 status: run.status.state,
69 trigger: run.trigger,
70 error: run.error,
71 retry_count: run.retry_count,
72 max_retries: run.max_retries,
73 cost_usd: run.cost_usd,
74 duration_ms: run.duration_ms,
75 created_at: run.created_at,
76 updated_at: run.updated_at,
77 started_at: run.started_at,
78 completed_at: run.completed_at,
79 handler_version: run.handler_version,
80 labels: run.labels,
81 scheduled_at: run.scheduled_at,
82 }
83 }
84}
85
86#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
88#[derive(Debug, Serialize)]
89pub struct RunDetailResponse {
90 pub run: RunResponse,
92 pub steps: Vec<StepResponse>,
94 pub payload: serde_json::Value,
96}
97
98#[cfg_attr(feature = "openapi", derive(utoipa::IntoParams, utoipa::ToSchema))]
100#[derive(Debug, Deserialize)]
101pub struct ListRunsQuery {
102 pub workflow: Option<String>,
104 pub status: Option<RunStatus>,
106 pub has_steps: Option<bool>,
111 pub label: Option<String>,
113 pub page: Option<u32>,
115 pub per_page: Option<u32>,
117}
118
119impl ListRunsQuery {
120 pub fn parse_labels(&self) -> Option<HashMap<String, String>> {
122 self.label.as_ref().and_then(|raw| {
123 let mut map = HashMap::new();
124 for entry in raw.split(',') {
125 let entry = entry.trim();
126 if let Some((k, v)) = entry.split_once(':') {
127 map.insert(k.to_string(), v.to_string());
128 }
129 }
130 if map.is_empty() { None } else { Some(map) }
131 })
132 }
133}