1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::constants::{FilterCondition, SortDirection};
7
8pub type GridRecord = Value;
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
11#[serde(rename_all = "camelCase")]
12pub enum GridColumnType {
13 #[default]
14 String,
15 Number,
16 Boolean,
17 Date,
18 Object,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
22#[serde(rename_all = "camelCase")]
23pub struct GridFilterFlags {
24 #[serde(default)]
25 pub case_sensitive: bool,
26 #[serde(default)]
27 pub date: bool,
28}
29
30#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
31#[serde(rename_all = "camelCase")]
32pub struct GridFilterDescriptor {
33 #[serde(default)]
34 pub term: Option<Value>,
35 #[serde(default)]
36 pub condition: Option<FilterCondition>,
37 #[serde(default)]
38 pub flags: GridFilterFlags,
39 #[serde(default)]
40 pub raw_term: bool,
41 #[serde(default)]
42 pub no_term: bool,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
46#[serde(rename_all = "camelCase")]
47pub struct GridSortDescriptor {
48 #[serde(default)]
49 pub direction: Option<SortDirection>,
50 #[serde(default)]
51 pub priority: Option<u32>,
52 #[serde(default)]
53 pub ignore_sort: bool,
54}
55
56#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
57#[serde(rename_all = "camelCase")]
58pub struct GridColumnDef {
59 pub name: String,
60 #[serde(default)]
61 pub display_name: Option<String>,
62 #[serde(default)]
63 pub field: Option<String>,
64 #[serde(default)]
65 pub r#type: GridColumnType,
66 #[serde(default = "default_true")]
67 pub visible: bool,
68 #[serde(default = "default_true")]
69 pub sortable: bool,
70 #[serde(default = "default_true")]
71 pub filterable: bool,
72 #[serde(default = "default_true")]
73 pub enable_sorting: bool,
74 #[serde(default = "default_true")]
75 pub enable_filtering: bool,
76 #[serde(default = "default_true")]
77 pub enable_grouping: bool,
78 #[serde(default)]
79 pub enable_cell_edit: bool,
80 #[serde(default)]
81 pub enable_cell_edit_on_focus: bool,
82 #[serde(default)]
83 pub sort: Option<GridSortDescriptor>,
84 #[serde(default)]
85 pub filter: Option<GridFilterDescriptor>,
86}
87
88fn default_true() -> bool {
89 true
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
93#[serde(rename_all = "camelCase")]
94pub struct GridGroupingOptions {
95 #[serde(default)]
96 pub group_by: Vec<String>,
97 #[serde(default)]
98 pub start_collapsed: bool,
99}
100
101#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
102#[serde(rename_all = "camelCase")]
103pub struct GridOptions {
104 pub id: String,
105 #[serde(default)]
106 pub title: Option<String>,
107 #[serde(default)]
108 pub data: Vec<GridRecord>,
109 #[serde(default)]
110 pub column_defs: Vec<GridColumnDef>,
111 #[serde(default = "default_true")]
112 pub enable_sorting: bool,
113 #[serde(default = "default_true")]
114 pub enable_filtering: bool,
115 #[serde(default)]
116 pub enable_grouping: bool,
117 #[serde(default)]
118 pub enable_cell_edit: bool,
119 #[serde(default)]
120 pub enable_cell_edit_on_focus: bool,
121 #[serde(default = "default_true")]
122 pub enable_virtualization: bool,
123 #[serde(default)]
124 pub enable_pagination: bool,
125 #[serde(default)]
126 pub use_external_pagination: bool,
127 #[serde(default)]
128 pub pagination_page_sizes: Vec<usize>,
129 #[serde(default)]
130 pub pagination_page_size: Option<usize>,
131 #[serde(default)]
132 pub pagination_current_page: Option<usize>,
133 #[serde(default)]
134 pub total_items: Option<usize>,
135 #[serde(default)]
136 pub enable_expandable: bool,
137 #[serde(default)]
138 pub expandable_row_height: Option<usize>,
139 #[serde(default)]
140 pub enable_tree_view: bool,
141 #[serde(default)]
142 pub tree_children_field: Option<String>,
143 #[serde(default)]
144 pub virtualization_threshold: Option<usize>,
145 #[serde(default)]
146 pub grouping: Option<GridGroupingOptions>,
147 #[serde(default)]
148 pub row_id_field: Option<String>,
149}
150
151impl Default for GridOptions {
152 fn default() -> Self {
153 Self {
154 id: String::new(),
155 title: None,
156 data: Vec::new(),
157 column_defs: Vec::new(),
158 enable_sorting: true,
159 enable_filtering: true,
160 enable_grouping: false,
161 enable_cell_edit: false,
162 enable_cell_edit_on_focus: false,
163 enable_virtualization: true,
164 enable_pagination: false,
165 use_external_pagination: false,
166 pagination_page_sizes: Vec::new(),
167 pagination_page_size: None,
168 pagination_current_page: None,
169 total_items: None,
170 enable_expandable: false,
171 expandable_row_height: None,
172 enable_tree_view: false,
173 tree_children_field: None,
174 virtualization_threshold: Some(40),
175 grouping: None,
176 row_id_field: Some("id".to_string()),
177 }
178 }
179}
180
181#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
182#[serde(rename_all = "camelCase")]
183pub struct GridCellPosition {
184 pub row_id: String,
185 pub column_name: String,
186}
187
188#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
189#[serde(rename_all = "camelCase")]
190pub struct SortState {
191 #[serde(default)]
192 pub column_name: Option<String>,
193 #[serde(default)]
194 pub direction: SortDirection,
195}
196
197#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
198#[serde(rename_all = "camelCase")]
199pub struct GridSavedPaginationState {
200 pub pagination_current_page: usize,
201 pub pagination_page_size: usize,
202}
203
204#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
205#[serde(rename_all = "camelCase")]
206pub struct GridSavedState {
207 #[serde(default)]
208 pub column_order: Vec<String>,
209 #[serde(default)]
210 pub filters: BTreeMap<String, String>,
211 #[serde(default)]
212 pub sort: Option<SortState>,
213 #[serde(default)]
214 pub grouping: Vec<String>,
215 #[serde(default)]
216 pub pagination: Option<GridSavedPaginationState>,
217 #[serde(default)]
218 pub expandable: BTreeMap<String, bool>,
219 #[serde(default)]
220 pub tree_view: BTreeMap<String, bool>,
221}
222
223#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
224#[serde(rename_all = "camelCase")]
225pub struct GridRow {
226 pub id: String,
227 pub entity: GridRecord,
228 pub index: usize,
229 pub height: usize,
230 #[serde(default)]
231 pub invisible_reasons: Vec<String>,
232 #[serde(default = "default_true")]
233 pub visible: bool,
234 #[serde(default)]
235 pub is_selected: bool,
236 #[serde(default)]
237 pub tree_level: usize,
238 #[serde(default)]
239 pub parent_id: Option<String>,
240 #[serde(default)]
241 pub has_children: bool,
242 #[serde(default)]
243 pub child_count: usize,
244 #[serde(default)]
245 pub expanded: bool,
246 #[serde(default)]
247 pub expanded_row_height: usize,
248}
249
250impl GridRow {
251 pub fn new(id: String, entity: GridRecord, index: usize, height: usize) -> Self {
252 Self {
253 id,
254 entity,
255 index,
256 height,
257 invisible_reasons: Vec::new(),
258 visible: true,
259 is_selected: false,
260 tree_level: 0,
261 parent_id: None,
262 has_children: false,
263 child_count: 0,
264 expanded: false,
265 expanded_row_height: 0,
266 }
267 }
268
269 pub fn set_this_row_invisible(&mut self, reason: impl Into<String>) {
270 let reason = reason.into();
271 if !self
272 .invisible_reasons
273 .iter()
274 .any(|existing| existing == &reason)
275 {
276 self.invisible_reasons.push(reason);
277 }
278 self.visible = false;
279 }
280
281 pub fn clear_this_row_invisible(&mut self, reason: &str) {
282 self.invisible_reasons.retain(|existing| existing != reason);
283 self.visible = self.invisible_reasons.is_empty();
284 }
285}
286
287#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
288#[serde(rename_all = "camelCase")]
289pub struct GroupItem {
290 pub id: String,
291 pub depth: usize,
292 pub field: String,
293 pub label: String,
294 pub count: usize,
295 pub collapsed: bool,
296}
297
298#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
299#[serde(rename_all = "camelCase")]
300pub struct RowItem {
301 pub id: String,
302 pub row: GridRow,
303 pub visible_index: usize,
304}
305
306#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
307#[serde(rename_all = "camelCase")]
308pub struct ExpandableItem {
309 pub id: String,
310 pub row: GridRow,
311}
312
313#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
314#[serde(tag = "kind", rename_all = "camelCase")]
315pub enum DisplayItem {
316 Group(GroupItem),
317 Row(RowItem),
318 Expandable(ExpandableItem),
319}
320
321#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
322#[serde(rename_all = "camelCase")]
323pub struct BuildGridPipelineContext {
324 pub options: GridOptions,
325 #[serde(default)]
326 pub columns: Vec<GridColumnDef>,
327 #[serde(default)]
328 pub active_filters: BTreeMap<String, String>,
329 #[serde(default)]
330 pub sort_state: SortState,
331 #[serde(default)]
332 pub group_by_columns: Vec<String>,
333 #[serde(default)]
334 pub collapsed_groups: BTreeMap<String, bool>,
335 #[serde(default)]
336 pub hidden_row_reasons: BTreeMap<String, Vec<String>>,
337 #[serde(default)]
338 pub expanded_rows: BTreeMap<String, bool>,
339 #[serde(default)]
340 pub expanded_tree_rows: BTreeMap<String, bool>,
341 #[serde(default = "default_current_page")]
342 pub current_page: usize,
343 #[serde(default)]
344 pub page_size: usize,
345 #[serde(default = "default_row_size")]
346 pub row_size: usize,
347}
348
349fn default_current_page() -> usize {
350 1
351}
352
353fn default_row_size() -> usize {
354 44
355}
356
357#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
358#[serde(rename_all = "camelCase")]
359pub struct PipelineResult {
360 #[serde(default)]
361 pub visible_rows: Vec<GridRow>,
362 #[serde(default)]
363 pub display_items: Vec<DisplayItem>,
364 #[serde(default)]
365 pub virtualization_enabled: bool,
366 #[serde(default)]
367 pub pipeline_ms: f64,
368 #[serde(default)]
369 pub total_items: usize,
370}