1use serde::{Deserialize, Serialize};
2
3use super::tag::{tagged_enum, Tag, Tagged};
4
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7pub struct DataVisualizationBlock {
8 r#type: Tag<Self>,
9 pub title: String,
10 pub chart: Chart,
11 #[serde(skip_serializing_if = "Option::is_none")]
12 pub block_id: Option<String>,
13}
14
15impl Tagged for DataVisualizationBlock {
16 const TAG: &'static str = "data_visualization";
17}
18
19impl DataVisualizationBlock {
20 pub fn new(title: impl Into<String>, chart: impl Into<Chart>) -> Self {
21 Self {
22 r#type: Tag::default(),
23 title: title.into(),
24 chart: chart.into(),
25 block_id: None,
26 }
27 }
28
29 pub fn block_id(mut self, block_id: impl Into<String>) -> Self {
30 self.block_id = Some(block_id.into());
31 self
32 }
33}
34
35tagged_enum! {
36 pub enum Chart("type") {
38 Pie(PieChart),
39 Bar(BarChart),
40 Area(AreaChart),
41 Line(LineChart),
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
47pub struct PieChart {
48 r#type: Tag<Self>,
49 pub segments: Vec<Segment>,
50}
51
52impl Tagged for PieChart {
53 const TAG: &'static str = "pie";
54}
55
56impl PieChart {
57 pub fn new(segments: Vec<Segment>) -> Self {
58 Self {
59 r#type: Tag::default(),
60 segments,
61 }
62 }
63}
64
65#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
67pub struct BarChart {
68 r#type: Tag<Self>,
69 pub series: Vec<DataSeries>,
70 pub axis_config: AxisConfig,
71}
72
73impl Tagged for BarChart {
74 const TAG: &'static str = "bar";
75}
76
77impl BarChart {
78 pub fn new(series: Vec<DataSeries>, axis_config: AxisConfig) -> Self {
79 Self {
80 r#type: Tag::default(),
81 series,
82 axis_config,
83 }
84 }
85}
86
87#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
89pub struct AreaChart {
90 r#type: Tag<Self>,
91 pub series: Vec<DataSeries>,
92 pub axis_config: AxisConfig,
93}
94
95impl Tagged for AreaChart {
96 const TAG: &'static str = "area";
97}
98
99impl AreaChart {
100 pub fn new(series: Vec<DataSeries>, axis_config: AxisConfig) -> Self {
101 Self {
102 r#type: Tag::default(),
103 series,
104 axis_config,
105 }
106 }
107}
108
109#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
111pub struct LineChart {
112 r#type: Tag<Self>,
113 pub series: Vec<DataSeries>,
114 pub axis_config: AxisConfig,
115}
116
117impl Tagged for LineChart {
118 const TAG: &'static str = "line";
119}
120
121impl LineChart {
122 pub fn new(series: Vec<DataSeries>, axis_config: AxisConfig) -> Self {
123 Self {
124 r#type: Tag::default(),
125 series,
126 axis_config,
127 }
128 }
129}
130
131#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
133pub struct Segment {
134 pub label: String,
135 pub value: f64,
136}
137
138impl Segment {
139 pub fn new(label: impl Into<String>, value: f64) -> Self {
140 Self {
141 label: label.into(),
142 value,
143 }
144 }
145}
146
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
149pub struct DataSeries {
150 pub name: String,
151 pub data: Vec<DataPoint>,
152}
153
154impl DataSeries {
155 pub fn new(name: impl Into<String>, data: Vec<DataPoint>) -> Self {
156 Self {
157 name: name.into(),
158 data,
159 }
160 }
161}
162
163#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
165pub struct DataPoint {
166 pub label: String,
167 pub value: f64,
168}
169
170impl DataPoint {
171 pub fn new(label: impl Into<String>, value: f64) -> Self {
172 Self {
173 label: label.into(),
174 value,
175 }
176 }
177}
178
179#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
181pub struct AxisConfig {
182 pub categories: Vec<String>,
183 #[serde(skip_serializing_if = "Option::is_none")]
184 pub x_label: Option<String>,
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub y_label: Option<String>,
187}
188
189impl AxisConfig {
190 pub fn new(categories: Vec<String>) -> Self {
191 Self {
192 categories,
193 x_label: None,
194 y_label: None,
195 }
196 }
197
198 pub fn x_label(mut self, x_label: impl Into<String>) -> Self {
199 self.x_label = Some(x_label.into());
200 self
201 }
202
203 pub fn y_label(mut self, y_label: impl Into<String>) -> Self {
204 self.y_label = Some(y_label.into());
205 self
206 }
207}