1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use strum::{Display, EnumString};
4
5#[cfg(feature = "display")]
6use crossterm::style::Stylize;
7#[cfg(feature = "display")]
8use std::fmt::Write;
9
10use super::deployment::DeploymentState;
11
12#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
13#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
14#[typeshare::typeshare]
15pub struct ProjectCreateRequest {
16 #[cfg_attr(feature = "utoipa", schema(pattern = "^[a-z0-9-]{1,32}$"))]
17 pub name: String,
18}
19
20#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
21#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
22#[typeshare::typeshare]
23pub struct ProjectResponse {
24 pub id: String,
25 pub name: String,
27 pub user_id: String,
29 pub team_id: Option<String>,
31 pub created_at: DateTime<Utc>,
32 pub compute_tier: Option<ComputeTier>,
33 pub deployment_state: Option<DeploymentState>,
35 pub uris: Vec<String>,
37}
38
39impl ProjectResponse {
40 #[cfg(feature = "display")]
41 pub fn to_string_colored(&self) -> String {
42 let mut s = String::new();
43 writeln!(&mut s, "{}", "Project info:".bold()).unwrap();
44 writeln!(&mut s, " Project ID: {}", self.id).unwrap();
45 writeln!(&mut s, " Project Name: {}", self.name).unwrap();
46 writeln!(&mut s, " Owner: {}", self.user_id).unwrap();
47 writeln!(
48 &mut s,
49 " Team: {}",
50 self.team_id.as_deref().unwrap_or("N/A")
51 )
52 .unwrap();
53 writeln!(
54 &mut s,
55 " Created: {}",
56 self.created_at
57 .to_rfc3339_opts(chrono::SecondsFormat::Secs, true)
58 )
59 .unwrap();
60 writeln!(&mut s, " URIs:").unwrap();
61 for uri in &self.uris {
62 writeln!(&mut s, " - {uri}").unwrap();
63 }
64
65 s
66 }
67}
68
69#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
70#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
71#[typeshare::typeshare]
72pub struct ProjectListResponse {
73 pub projects: Vec<ProjectResponse>,
74}
75
76#[derive(Debug, Default, Deserialize, Serialize, Clone)]
78#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
79#[typeshare::typeshare]
80pub struct ProjectUpdateRequest {
81 #[cfg_attr(feature = "utoipa", schema(pattern = "^[a-z0-9-]{1,32}$"))]
83 pub name: Option<String>,
84 #[cfg_attr(feature = "utoipa", schema(pattern = "^user_[A-Z0-9]{26}$"))]
86 pub user_id: Option<String>,
87 #[cfg_attr(feature = "utoipa", schema(pattern = "^team_[A-Z0-9]{26}$"))]
89 pub team_id: Option<String>,
90 pub remove_from_team: Option<bool>,
92 pub config: Option<serde_json::Value>,
94}
95
96#[derive(Debug, Default, Clone, PartialEq, Eq, Display, Serialize, Deserialize, EnumString)]
97#[serde(rename_all = "lowercase")]
98#[strum(serialize_all = "lowercase")]
99#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
100#[typeshare::typeshare]
101pub enum ComputeTier {
102 #[default]
103 XS,
104 S,
105 M,
106 L,
107 XL,
108 XXL,
109
110 #[cfg(feature = "unknown-variants")]
112 #[doc(hidden)]
113 #[typeshare(skip)]
114 #[serde(untagged, skip_serializing)]
115 #[strum(default, to_string = "Unknown: {0}")]
116 Unknown(String),
117}
118
119#[derive(Debug, Default, Deserialize, Serialize, Clone)]
121#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
122#[typeshare::typeshare]
123pub struct ProjectUsageResponse {
124 pub build_minutes: ProjectUsageBuild,
126
127 pub vcpu: ProjectUsageVCPU,
129}
130
131#[derive(Debug, Default, Deserialize, Serialize, Clone)]
133#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
134#[typeshare::typeshare]
135pub struct ProjectUsageBuild {
136 pub used: u32,
138
139 pub limit: u32,
141}
142
143#[derive(Debug, Default, Deserialize, Serialize, Clone)]
145#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
146#[typeshare::typeshare]
147pub struct ProjectUsageVCPU {
148 pub reserved: f32,
150
151 pub billable_hours: f32,
153}