Skip to main content

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