slack_messaging/blocks/elements/
checkboxes.rs

1use crate::composition_objects::{ConfirmationDialog, Opt, TextContent};
2use crate::validators::*;
3
4use serde::Serialize;
5use slack_messaging_derive::Builder;
6
7/// [Checkboxes](https://docs.slack.dev/reference/block-kit/block-elements/checkboxes-element)
8/// representation.
9///
10/// # Fields and Validations
11///
12/// For more details, see the [official
13/// documentation](https://docs.slack.dev/reference/block-kit/block-elements/checkboxes-element).
14///
15/// | Field | Type | Required | Validation |
16/// |-------|------|----------|------------|
17/// | action_id | String | No | Max length 255 characters |
18/// | options | Vec<[Opt]<[TextContent]>> | Yes | Max 10 items |
19/// | initial_options | Vec<[Opt]<[TextContent]>> | No | N/A |
20/// | confirm | [ConfirmationDialog] | No | N/A |
21/// | focus_on_load | bool | No | N/A |
22///
23/// # Example
24///
25/// ```
26/// use slack_messaging::mrkdwn;
27/// use slack_messaging::blocks::elements::Checkboxes;
28/// use slack_messaging::composition_objects::Opt;
29/// # use std::error::Error;
30///
31/// # fn try_main() -> Result<(), Box<dyn Error>> {
32/// let checkboxes = Checkboxes::builder()
33///     .action_id("group-0")
34///     .option(
35///         Opt::builder()
36///             .text(mrkdwn!("option-0")?)
37///             .value("value-0")
38///             .build()?
39///     )
40///     .option(
41///         Opt::builder()
42///             .text(mrkdwn!("option-1")?)
43///             .value("value-1")
44///             .build()?
45///     )
46///     .build()?;
47///
48/// let expected = serde_json::json!({
49///     "type": "checkboxes",
50///     "action_id": "group-0",
51///     "options": [
52///         {
53///             "value": "value-0",
54///             "text": {
55///                 "type": "mrkdwn",
56///                 "text": "option-0"
57///             }
58///         },
59///         {
60///             "value": "value-1",
61///             "text": {
62///                 "type": "mrkdwn",
63///                 "text": "option-1"
64///             }
65///         }
66///     ]
67/// });
68///
69/// let json = serde_json::to_value(checkboxes).unwrap();
70///
71/// assert_eq!(json, expected);
72///
73/// // If your object has any validation errors, the build method returns Result::Err
74/// let checkboxes = Checkboxes::builder()
75///     .action_id("group-0")
76///     .build();
77///
78/// assert!(checkboxes.is_err());
79/// #     Ok(())
80/// # }
81/// # fn main() {
82/// #     try_main().unwrap()
83/// # }
84/// ```
85#[derive(Debug, Clone, Serialize, PartialEq, Builder)]
86#[serde(tag = "type", rename = "checkboxes")]
87pub struct Checkboxes {
88    #[serde(skip_serializing_if = "Option::is_none")]
89    #[builder(validate("text::max_255"))]
90    pub(crate) action_id: Option<String>,
91
92    #[builder(push_item = "option", validate("required", "list::max_item_10"))]
93    pub(crate) options: Option<Vec<Opt<TextContent>>>,
94
95    #[serde(skip_serializing_if = "Option::is_none")]
96    #[builder(push_item = "initial_option")]
97    pub(crate) initial_options: Option<Vec<Opt<TextContent>>>,
98
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub(crate) confirm: Option<ConfirmationDialog>,
101
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub(crate) focus_on_load: Option<bool>,
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109    use crate::composition_objects::test_helpers::*;
110    use crate::errors::*;
111
112    #[test]
113    fn it_implements_builder() {
114        let expected = Checkboxes {
115            action_id: Some("checkboxes_0".into()),
116            options: Some(vec![
117                option_t("opt_0", "val_0"),
118                option_t("opt_1", "val_1"),
119                option_t("opt_2", "val_2"),
120            ]),
121            initial_options: Some(vec![option_t("opt_0", "val_0"), option_t("opt_1", "val_1")]),
122            confirm: Some(confirm()),
123            focus_on_load: Some(true),
124        };
125
126        let val = Checkboxes::builder()
127            .set_action_id(Some("checkboxes_0"))
128            .set_options(Some(vec![
129                option_t("opt_0", "val_0"),
130                option_t("opt_1", "val_1"),
131                option_t("opt_2", "val_2"),
132            ]))
133            .set_initial_options(Some(vec![
134                option_t("opt_0", "val_0"),
135                option_t("opt_1", "val_1"),
136            ]))
137            .set_confirm(Some(confirm()))
138            .set_focus_on_load(Some(true))
139            .build()
140            .unwrap();
141
142        assert_eq!(val, expected);
143
144        let val = Checkboxes::builder()
145            .action_id("checkboxes_0")
146            .options(vec![
147                option_t("opt_0", "val_0"),
148                option_t("opt_1", "val_1"),
149                option_t("opt_2", "val_2"),
150            ])
151            .initial_options(vec![option_t("opt_0", "val_0"), option_t("opt_1", "val_1")])
152            .confirm(confirm())
153            .focus_on_load(true)
154            .build()
155            .unwrap();
156
157        assert_eq!(val, expected);
158    }
159
160    #[test]
161    fn it_implements_push_item_method() {
162        let expected = Checkboxes {
163            action_id: None,
164            options: Some(vec![
165                option_t("opt_0", "val_0"),
166                option_t("opt_1", "val_1"),
167                option_t("opt_2", "val_2"),
168            ]),
169            initial_options: Some(vec![option_t("opt_0", "val_0"), option_t("opt_1", "val_1")]),
170            confirm: None,
171            focus_on_load: None,
172        };
173
174        let val = Checkboxes::builder()
175            .option(option_t("opt_0", "val_0"))
176            .option(option_t("opt_1", "val_1"))
177            .option(option_t("opt_2", "val_2"))
178            .initial_option(option_t("opt_0", "val_0"))
179            .initial_option(option_t("opt_1", "val_1"))
180            .build()
181            .unwrap();
182
183        assert_eq!(val, expected);
184    }
185
186    #[test]
187    fn it_requires_action_id_less_than_255_chracters_long() {
188        let err = Checkboxes::builder()
189            .action_id("a".repeat(256))
190            .option(option_t("opt_0", "val_0"))
191            .build()
192            .unwrap_err();
193        assert_eq!(err.object(), "Checkboxes");
194
195        let errors = err.field("action_id");
196        assert!(errors.includes(ValidationErrorKind::MaxTextLength(255)));
197    }
198
199    #[test]
200    fn it_requires_options_field() {
201        let err = Checkboxes::builder().build().unwrap_err();
202        assert_eq!(err.object(), "Checkboxes");
203
204        let errors = err.field("options");
205        assert!(errors.includes(ValidationErrorKind::Required));
206    }
207
208    #[test]
209    fn it_requires_options_item_size_less_than_10() {
210        let options: Vec<Opt<TextContent>> = (0..11).map(|_| option_t("opt", "val")).collect();
211        let err = Checkboxes::builder().options(options).build().unwrap_err();
212        assert_eq!(err.object(), "Checkboxes");
213
214        let errors = err.field("options");
215        assert!(errors.includes(ValidationErrorKind::MaxArraySize(10)));
216    }
217}