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