Skip to main content

ui_grid_core/
export.rs

1use crate::{
2    display::format_grid_cell_display_value,
3    models::{GridColumnDef, GridRow},
4    state::sanitize_download_filename,
5    utils::{titleize, to_csv_value},
6};
7
8pub const GRID_CSV_MIME_TYPE: &str = "text/csv;charset=utf-8";
9
10#[derive(Debug, Clone, PartialEq)]
11pub struct GridExportContext<'a> {
12    pub grid_id: &'a str,
13    pub columns: &'a [GridColumnDef],
14    pub rows: &'a [GridRow],
15}
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct GridExportPayload {
19    pub filename: String,
20    pub mime_type: String,
21    pub contents: String,
22}
23
24pub fn header_label(column: &GridColumnDef) -> String {
25    column
26        .display_name
27        .clone()
28        .unwrap_or_else(|| titleize(&column.name))
29}
30
31pub fn build_grid_export_context<'a>(
32    grid_id: &'a str,
33    columns: &'a [GridColumnDef],
34    rows: &'a [GridRow],
35) -> GridExportContext<'a> {
36    GridExportContext {
37        grid_id,
38        columns,
39        rows,
40    }
41}
42
43pub fn build_grid_export_payload(
44    filename: impl Into<String>,
45    mime_type: impl Into<String>,
46    contents: impl Into<String>,
47) -> GridExportPayload {
48    GridExportPayload {
49        filename: filename.into(),
50        mime_type: mime_type.into(),
51        contents: contents.into(),
52    }
53}
54
55pub fn default_csv_export_filename(grid_id: &str) -> String {
56    format!("{}.csv", sanitize_download_filename(grid_id))
57}
58
59pub fn export_csv_rows_with<F>(
60    columns: &[GridColumnDef],
61    rows: &[GridRow],
62    format_cell: F,
63) -> String
64where
65    F: Fn(&GridRow, &GridColumnDef) -> String,
66{
67    let header = columns
68        .iter()
69        .map(|column| to_csv_value(&header_label(column)))
70        .collect::<Vec<_>>()
71        .join(",");
72
73    let body = rows
74        .iter()
75        .map(|row| {
76            columns
77                .iter()
78                .map(|column| to_csv_value(&format_cell(row, column)))
79                .collect::<Vec<_>>()
80                .join(",")
81        })
82        .collect::<Vec<_>>();
83
84    std::iter::once(header)
85        .chain(body)
86        .collect::<Vec<_>>()
87        .join("\n")
88}
89
90pub fn export_csv_rows(columns: &[GridColumnDef], rows: &[GridRow]) -> String {
91    export_csv_rows_with(columns, rows, |row, column| {
92        format_grid_cell_display_value(row, column)
93    })
94}
95
96pub fn build_csv_export_payload(context: &GridExportContext<'_>) -> GridExportPayload {
97    build_grid_export_payload(
98        default_csv_export_filename(context.grid_id),
99        GRID_CSV_MIME_TYPE,
100        export_csv_rows(context.columns, context.rows),
101    )
102}
103
104pub fn build_csv_export_payload_with<F>(
105    context: &GridExportContext<'_>,
106    format_cell: F,
107) -> GridExportPayload
108where
109    F: Fn(&GridRow, &GridColumnDef) -> String,
110{
111    build_grid_export_payload(
112        default_csv_export_filename(context.grid_id),
113        GRID_CSV_MIME_TYPE,
114        export_csv_rows_with(context.columns, context.rows, format_cell),
115    )
116}