pipedash_plugin_api/
types.rs

1use std::collections::HashMap;
2
3use chrono::{
4    DateTime,
5    Utc,
6};
7use serde::{
8    Deserialize,
9    Serialize,
10};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "lowercase")]
14pub enum PipelineStatus {
15    Success,
16    Failed,
17    Running,
18    Pending,
19    Cancelled,
20    Skipped,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct AvailablePipeline {
25    pub id: String,
26    pub name: String,
27    pub description: Option<String>,
28    pub organization: Option<String>,
29    pub repository: Option<String>,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct Pipeline {
34    pub id: String,
35    pub provider_id: i64,
36    pub provider_type: String,
37    pub name: String,
38    pub status: PipelineStatus,
39    pub last_run: Option<DateTime<Utc>>,
40    pub last_updated: DateTime<Utc>,
41    pub repository: String,
42    pub branch: Option<String>,
43    pub workflow_file: Option<String>,
44    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
45    pub metadata: HashMap<String, serde_json::Value>,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct PipelineRun {
50    pub id: String,
51    pub pipeline_id: String,
52    pub run_number: i64,
53    pub status: PipelineStatus,
54    pub started_at: DateTime<Utc>,
55    pub concluded_at: Option<DateTime<Utc>>,
56    pub duration_seconds: Option<i64>,
57    pub logs_url: String,
58    pub commit_sha: Option<String>,
59    pub commit_message: Option<String>,
60    pub branch: Option<String>,
61    pub actor: Option<String>,
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub inputs: Option<serde_json::Value>,
64    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
65    pub metadata: HashMap<String, serde_json::Value>,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct TriggerParams {
70    pub workflow_id: String,
71    pub inputs: Option<serde_json::Value>,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct BuildAgent {
76    pub id: String,
77    pub name: String,
78    pub hostname: String,
79    pub status: String,
80    pub job_id: Option<String>,
81    pub last_seen: DateTime<Utc>,
82    pub metadata: HashMap<String, String>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct BuildQueue {
87    pub id: String,
88    pub waiting: usize,
89    pub running: usize,
90    pub avg_wait_time: Option<i64>,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct BuildArtifact {
95    pub id: String,
96    pub run_id: String,
97    pub filename: String,
98    pub size_bytes: i64,
99    pub download_url: String,
100    pub content_type: Option<String>,
101    pub created_at: DateTime<Utc>,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct Organization {
106    pub id: String,
107    pub name: String,
108    pub description: Option<String>,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
112#[serde(tag = "type", rename_all = "lowercase")]
113pub enum WorkflowParameterType {
114    String {
115        #[serde(default)]
116        default: Option<String>,
117    },
118    Boolean {
119        #[serde(default)]
120        default: bool,
121    },
122    Choice {
123        options: Vec<String>,
124        #[serde(default)]
125        default: Option<String>,
126    },
127    Number {
128        #[serde(default)]
129        default: Option<f64>,
130    },
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct WorkflowParameter {
135    pub name: String,
136    pub label: Option<String>,
137    pub description: Option<String>,
138    #[serde(flatten)]
139    pub param_type: WorkflowParameterType,
140    #[serde(default)]
141    pub required: bool,
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct PaginationParams {
146    pub page: usize,
147    pub page_size: usize,
148}
149
150impl PaginationParams {
151    pub fn validate(&self) -> Result<(), String> {
152        if self.page == 0 {
153            return Err("Page must be >= 1".to_string());
154        }
155        if self.page_size == 0 {
156            return Err("Page size must be >= 1".to_string());
157        }
158        if self.page_size > 200 {
159            return Err("Page size must be <= 200".to_string());
160        }
161        Ok(())
162    }
163
164    pub fn calculate_offset(&self) -> Result<usize, String> {
165        self.page
166            .checked_sub(1)
167            .and_then(|p| p.checked_mul(self.page_size))
168            .ok_or_else(|| "Pagination offset overflow".to_string())
169    }
170}
171
172impl Default for PaginationParams {
173    fn default() -> Self {
174        Self {
175            page: 1,
176            page_size: 100,
177        }
178    }
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct PaginatedResponse<T> {
183    pub items: Vec<T>,
184    pub page: usize,
185    pub page_size: usize,
186    pub total_count: usize,
187    pub total_pages: usize,
188    pub has_more: bool,
189}
190
191impl<T> PaginatedResponse<T> {
192    pub fn new(items: Vec<T>, page: usize, page_size: usize, total_count: usize) -> Self {
193        let items_count = items.len();
194        let total_pages = if page_size > 0 {
195            total_count.div_ceil(page_size)
196        } else {
197            1
198        };
199        let has_more = items_count == page_size;
200
201        Self {
202            items,
203            page,
204            page_size,
205            total_count,
206            total_pages,
207            has_more,
208        }
209    }
210
211    pub fn empty() -> Self {
212        Self {
213            items: Vec::new(),
214            page: 1,
215            page_size: 100,
216            total_count: 0,
217            total_pages: 0,
218            has_more: false,
219        }
220    }
221}
222
223pub type PaginatedAvailablePipelines = PaginatedResponse<AvailablePipeline>;
224
225#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
226pub struct Permission {
227    pub name: String,
228    pub description: String,
229    pub required: bool,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize)]
233pub struct PermissionCheck {
234    pub permission: Permission,
235    pub granted: bool,
236}
237
238#[derive(Debug, Clone, Serialize, Deserialize)]
239pub struct PermissionStatus {
240    pub permissions: Vec<PermissionCheck>,
241    pub all_granted: bool,
242    pub checked_at: DateTime<Utc>,
243    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
244    pub metadata: HashMap<String, String>,
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize)]
248pub struct Feature {
249    pub id: String,
250    pub name: String,
251    pub description: String,
252    pub required_permissions: Vec<String>,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct FeatureAvailability {
257    pub feature: Feature,
258    pub available: bool,
259    pub missing_permissions: Vec<String>,
260}