Skip to main content

slack_web_api/blocks/
table.rs

1use serde::{Deserialize, Serialize};
2
3use super::element::ButtonElement;
4use super::rich_text::RichTextBlock;
5use super::tag::{tagged_enum, Tag, Tagged};
6
7/// A table. <https://docs.slack.dev/reference/block-kit/blocks/table-block>
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9pub struct TableBlock {
10    r#type: Tag<Self>,
11    #[serde(skip_serializing_if = "Option::is_none")]
12    pub block_id: Option<String>,
13    pub rows: Vec<Vec<TableCell>>,
14    #[serde(default, skip_serializing_if = "Vec::is_empty")]
15    pub column_settings: Vec<Option<ColumnSetting>>,
16}
17
18impl Tagged for TableBlock {
19    const TAG: &'static str = "table";
20}
21
22impl TableBlock {
23    pub fn new(rows: Vec<Vec<TableCell>>) -> Self {
24        Self {
25            r#type: Tag::default(),
26            block_id: None,
27            rows,
28            column_settings: Vec::new(),
29        }
30    }
31
32    pub fn block_id(mut self, block_id: impl Into<String>) -> Self {
33        self.block_id = Some(block_id.into());
34        self
35    }
36
37    pub fn column_settings(mut self, column_settings: Vec<Option<ColumnSetting>>) -> Self {
38        self.column_settings = column_settings;
39        self
40    }
41}
42
43tagged_enum! {
44    /// A cell in a table block. <https://docs.slack.dev/reference/block-kit/blocks/table-block>
45    pub enum TableCell("type") {
46        RawText(RawTextCell),
47        RawNumber(RawNumberCell),
48        RichText(RichTextBlock),
49    }
50}
51
52/// Settings for a table column (use `None` for a column that keeps the defaults, sent as `null`). <https://docs.slack.dev/reference/block-kit/blocks/table-block>
53#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
54pub struct ColumnSetting {
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub align: Option<ColumnAlign>,
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub is_wrapped: Option<bool>,
59}
60
61impl ColumnSetting {
62    pub fn new() -> Self {
63        Self::default()
64    }
65
66    pub fn align(mut self, align: ColumnAlign) -> Self {
67        self.align = Some(align);
68        self
69    }
70
71    pub fn is_wrapped(mut self, is_wrapped: bool) -> Self {
72        self.is_wrapped = Some(is_wrapped);
73        self
74    }
75}
76
77/// A table with pagination, sorting and filtering. <https://docs.slack.dev/reference/block-kit/blocks/data-table-block>
78#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
79pub struct DataTableBlock {
80    r#type: Tag<Self>,
81    pub rows: Vec<Vec<DataTableCell>>,
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub block_id: Option<String>,
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub page_size: Option<u32>,
86    pub caption: String,
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub row_header_column_index: Option<u32>,
89}
90
91impl Tagged for DataTableBlock {
92    const TAG: &'static str = "data_table";
93}
94
95impl DataTableBlock {
96    pub fn new(rows: Vec<Vec<DataTableCell>>, caption: impl Into<String>) -> Self {
97        Self {
98            r#type: Tag::default(),
99            rows,
100            block_id: None,
101            page_size: None,
102            caption: caption.into(),
103            row_header_column_index: None,
104        }
105    }
106
107    pub fn block_id(mut self, block_id: impl Into<String>) -> Self {
108        self.block_id = Some(block_id.into());
109        self
110    }
111
112    pub fn page_size(mut self, page_size: u32) -> Self {
113        self.page_size = Some(page_size);
114        self
115    }
116
117    pub fn row_header_column_index(mut self, row_header_column_index: u32) -> Self {
118        self.row_header_column_index = Some(row_header_column_index);
119        self
120    }
121}
122
123tagged_enum! {
124    /// A cell in a data table block. <https://docs.slack.dev/reference/block-kit/blocks/data-table-block>
125    pub enum DataTableCell("type") {
126        RawText(RawTextCell),
127        RawNumber(RawNumberCell),
128        RichText(RichTextBlock),
129        ActionCell(ActionCell),
130    }
131}
132
133/// A plain text cell. <https://docs.slack.dev/reference/block-kit/blocks/data-table-block>
134#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
135pub struct RawTextCell {
136    r#type: Tag<Self>,
137    pub text: String,
138}
139
140impl Tagged for RawTextCell {
141    const TAG: &'static str = "raw_text";
142}
143
144impl RawTextCell {
145    pub fn new(text: impl Into<String>) -> Self {
146        Self {
147            r#type: Tag::default(),
148            text: text.into(),
149        }
150    }
151}
152
153/// A numeric cell. <https://docs.slack.dev/reference/block-kit/blocks/data-table-block>
154#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
155pub struct RawNumberCell {
156    r#type: Tag<Self>,
157    pub value: f64,
158    #[serde(skip_serializing_if = "Option::is_none")]
159    pub text: Option<String>,
160}
161
162impl Tagged for RawNumberCell {
163    const TAG: &'static str = "raw_number";
164}
165
166impl RawNumberCell {
167    pub fn new(value: f64) -> Self {
168        Self {
169            r#type: Tag::default(),
170            value,
171            text: None,
172        }
173    }
174
175    pub fn text(mut self, text: impl Into<String>) -> Self {
176        self.text = Some(text.into());
177        self
178    }
179}
180
181/// A cell holding a button (data table blocks only). <https://docs.slack.dev/reference/block-kit/blocks/data-table-block>
182#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
183pub struct ActionCell {
184    r#type: Tag<Self>,
185    pub element: Box<ButtonElement>,
186    #[serde(skip_serializing_if = "Option::is_none")]
187    pub fallback: Option<ActionCellFallback>,
188}
189
190impl Tagged for ActionCell {
191    const TAG: &'static str = "action_cell";
192}
193
194impl ActionCell {
195    pub fn new(element: ButtonElement) -> Self {
196        Self {
197            r#type: Tag::default(),
198            element: Box::new(element),
199            fallback: None,
200        }
201    }
202
203    pub fn fallback(mut self, fallback: impl Into<ActionCellFallback>) -> Self {
204        self.fallback = Some(fallback.into());
205        self
206    }
207}
208
209tagged_enum! {
210    /// The cell shown instead of the button on clients that do not support action cells. <https://docs.slack.dev/reference/block-kit/blocks/data-table-block>
211    pub enum ActionCellFallback("type") {
212        RawText(RawTextCell),
213        RawNumber(RawNumberCell),
214    }
215}
216
217/// Column alignment. Unknown values go to `Other`.
218#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
219#[serde(rename_all = "snake_case")]
220pub enum ColumnAlign {
221    Left,
222    Center,
223    Right,
224    #[serde(untagged)]
225    Other(String),
226}