systemprompt_models/artifacts/dashboard/
section_data.rs1use super::super::chart::ChartDataset;
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
13pub struct MetricsCardsData {
14 pub cards: Vec<MetricCard>,
15}
16
17impl MetricsCardsData {
18 pub const fn new(cards: Vec<MetricCard>) -> Self {
19 Self { cards }
20 }
21
22 pub fn add_card(mut self, card: MetricCard) -> Self {
23 self.cards.push(card);
24 self
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
29pub struct MetricCard {
30 pub title: String,
31 pub value: String,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub subtitle: Option<String>,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub icon: Option<String>,
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub status: Option<MetricStatus>,
38}
39
40#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, Default)]
41#[serde(rename_all = "lowercase")]
42pub enum MetricStatus {
43 Success,
44 Warning,
45 Error,
46 #[default]
47 Info,
48}
49
50impl std::str::FromStr for MetricStatus {
51 type Err = String;
52
53 fn from_str(s: &str) -> Result<Self, Self::Err> {
54 match s.to_lowercase().as_str() {
55 "success" | "healthy" | "ok" | "active" => Ok(Self::Success),
56 "warning" | "degraded" => Ok(Self::Warning),
57 "error" | "failed" | "critical" => Ok(Self::Error),
58 "info" | "unknown" => Ok(Self::Info),
59 _ => Err(format!("Invalid metric status: {s}")),
60 }
61 }
62}
63
64impl MetricCard {
65 pub fn new(title: impl Into<String>, value: impl Into<String>) -> Self {
66 Self {
67 title: title.into(),
68 value: value.into(),
69 subtitle: None,
70 icon: None,
71 status: None,
72 }
73 }
74
75 pub fn with_subtitle(mut self, subtitle: impl Into<String>) -> Self {
76 self.subtitle = Some(subtitle.into());
77 self
78 }
79
80 pub fn with_icon(mut self, icon: impl Into<String>) -> Self {
81 self.icon = Some(icon.into());
82 self
83 }
84
85 pub const fn with_status(mut self, status: MetricStatus) -> Self {
86 self.status = Some(status);
87 self
88 }
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
92pub struct ChartSectionData {
93 pub chart_type: String,
94 pub labels: Vec<String>,
95 pub datasets: Vec<ChartDataset>,
96}
97
98impl ChartSectionData {
99 pub fn new(
100 chart_type: impl Into<String>,
101 labels: Vec<String>,
102 datasets: Vec<ChartDataset>,
103 ) -> Self {
104 Self {
105 chart_type: chart_type.into(),
106 labels,
107 datasets,
108 }
109 }
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
113pub struct TableSectionData {
114 pub columns: Vec<String>,
115 pub rows: Vec<serde_json::Value>,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub sortable: Option<bool>,
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub default_sort: Option<SortConfig>,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
123pub struct SortConfig {
124 pub column: String,
125 pub order: String,
126}
127
128impl TableSectionData {
129 pub const fn new(columns: Vec<String>, rows: Vec<serde_json::Value>) -> Self {
130 Self {
131 columns,
132 rows,
133 sortable: None,
134 default_sort: None,
135 }
136 }
137
138 pub const fn with_sortable(mut self, sortable: bool) -> Self {
139 self.sortable = Some(sortable);
140 self
141 }
142
143 pub fn with_default_sort(
144 mut self,
145 column: impl Into<String>,
146 order: impl Into<String>,
147 ) -> Self {
148 self.default_sort = Some(SortConfig {
149 column: column.into(),
150 order: order.into(),
151 });
152 self
153 }
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
157pub struct StatusSectionData {
158 pub services: Vec<ServiceStatus>,
159 #[serde(skip_serializing_if = "Option::is_none")]
160 pub database: Option<DatabaseStatus>,
161 #[serde(skip_serializing_if = "Option::is_none")]
162 pub recent_errors: Option<ErrorCounts>,
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
166pub struct ServiceStatus {
167 pub name: String,
168 pub status: String,
169 #[serde(skip_serializing_if = "Option::is_none")]
170 pub uptime: Option<String>,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
174pub struct DatabaseStatus {
175 pub size_mb: f64,
176 pub status: String,
177}
178
179#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
180pub struct ErrorCounts {
181 pub critical: i32,
182 pub error: i32,
183 pub warn: i32,
184}
185
186impl StatusSectionData {
187 pub const fn new(services: Vec<ServiceStatus>) -> Self {
188 Self {
189 services,
190 database: None,
191 recent_errors: None,
192 }
193 }
194
195 pub fn with_database(mut self, status: DatabaseStatus) -> Self {
196 self.database = Some(status);
197 self
198 }
199
200 pub const fn with_error_counts(mut self, counts: ErrorCounts) -> Self {
201 self.recent_errors = Some(counts);
202 self
203 }
204}
205
206impl ServiceStatus {
207 pub fn new(name: impl Into<String>, status: impl Into<String>) -> Self {
208 Self {
209 name: name.into(),
210 status: status.into(),
211 uptime: None,
212 }
213 }
214
215 pub fn with_uptime(mut self, uptime: impl Into<String>) -> Self {
216 self.uptime = Some(uptime.into());
217 self
218 }
219}
220
221impl DatabaseStatus {
222 pub fn new(size_mb: f64, status: impl Into<String>) -> Self {
223 Self {
224 size_mb,
225 status: status.into(),
226 }
227 }
228}
229
230impl ErrorCounts {
231 pub const fn new(critical: i32, error: i32, warn: i32) -> Self {
232 Self {
233 critical,
234 error,
235 warn,
236 }
237 }
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
241pub struct ListSectionData {
242 pub lists: Vec<ItemList>,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
246pub struct ItemList {
247 pub title: String,
248 pub items: Vec<ListItem>,
249}
250
251#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
252pub struct ListItem {
253 pub rank: i32,
254 pub label: String,
255 pub value: String,
256 #[serde(skip_serializing_if = "Option::is_none")]
257 pub badge: Option<String>,
258}
259
260impl ListSectionData {
261 pub const fn new(lists: Vec<ItemList>) -> Self {
262 Self { lists }
263 }
264}
265
266impl ItemList {
267 pub fn new(title: impl Into<String>, items: Vec<ListItem>) -> Self {
268 Self {
269 title: title.into(),
270 items,
271 }
272 }
273}
274
275impl ListItem {
276 pub fn new(rank: i32, label: impl Into<String>, value: impl Into<String>) -> Self {
277 Self {
278 rank,
279 label: label.into(),
280 value: value.into(),
281 badge: None,
282 }
283 }
284
285 pub fn with_badge(mut self, badge: impl Into<String>) -> Self {
286 self.badge = Some(badge.into());
287 self
288 }
289}