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