slack_messaging/blocks/elements/
radio_button_group.rs

1use crate::composition_objects::{ConfirmationDialog, Opt, TextContent};
2use crate::validators::*;
3
4use serde::Serialize;
5use slack_messaging_derive::Builder;
6
7/// [Radio buton group element](https://docs.slack.dev/reference/block-kit/block-elements/radio-button-group-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/radio-button-group-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_option | [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::RadioButtonGroup;
28/// use slack_messaging::composition_objects::{Opt, Text};
29/// # use std::error::Error;
30///
31/// # fn try_main() -> Result<(), Box<dyn Error>> {
32/// let radio = RadioButtonGroup::builder()
33///     .action_id("radio_button_group")
34///     .option(
35///         Opt::builder()
36///             .text(mrkdwn!("**Radio 1**")?)
37///             .value("A1")
38///             .build()?
39///     )
40///     .option(
41///         Opt::builder()
42///             .text(mrkdwn!("**Radio 2**")?)
43///             .value("A2")
44///             .build()?
45///     )
46///     .build()?;
47///
48/// let expected = serde_json::json!({
49///     "type": "radio_buttons",
50///     "action_id": "radio_button_group",
51///     "options": [
52///         {
53///             "value": "A1",
54///             "text": {
55///                 "type": "mrkdwn",
56///                 "text": "**Radio 1**"
57///             }
58///         },
59///         {
60///             "value": "A2",
61///             "text": {
62///                 "type": "mrkdwn",
63///                 "text": "**Radio 2**"
64///             }
65///         }
66///     ]
67/// });
68///
69/// let json = serde_json::to_value(radio).unwrap();
70///
71/// assert_eq!(json, expected);
72///
73/// // If your object has any validation errors, the build method returns Result::Err
74/// let radio = RadioButtonGroup::builder()
75///     .action_id("radio_button_group")
76///     .build();
77///
78/// assert!(radio.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 = "radio_buttons")]
87pub struct RadioButtonGroup {
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    pub(crate) initial_option: Option<Opt<TextContent>>,
97
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub(crate) confirm: Option<ConfirmationDialog>,
100
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub(crate) focus_on_load: Option<bool>,
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108    use crate::composition_objects::test_helpers::*;
109    use crate::errors::*;
110
111    #[test]
112    fn it_implements_builder() {
113        let expected = RadioButtonGroup {
114            action_id: Some("radio_button_group_0".into()),
115            options: Some(vec![option_t("opt0", "val0"), option_t("opt1", "val1")]),
116            initial_option: Some(option_t("opt0", "val0")),
117            confirm: Some(confirm()),
118            focus_on_load: Some(true),
119        };
120
121        let val = RadioButtonGroup::builder()
122            .set_action_id(Some("radio_button_group_0"))
123            .set_options(Some(vec![
124                option_t("opt0", "val0"),
125                option_t("opt1", "val1"),
126            ]))
127            .set_initial_option(Some(option_t("opt0", "val0")))
128            .set_confirm(Some(confirm()))
129            .set_focus_on_load(Some(true))
130            .build()
131            .unwrap();
132
133        assert_eq!(val, expected);
134
135        let val = RadioButtonGroup::builder()
136            .action_id("radio_button_group_0")
137            .options(vec![option_t("opt0", "val0"), option_t("opt1", "val1")])
138            .initial_option(option_t("opt0", "val0"))
139            .confirm(confirm())
140            .focus_on_load(true)
141            .build()
142            .unwrap();
143
144        assert_eq!(val, expected);
145    }
146
147    #[test]
148    fn it_implements_push_item_method() {
149        let expected = RadioButtonGroup {
150            action_id: None,
151            options: Some(vec![option_t("opt0", "val0"), option_t("opt1", "val1")]),
152            initial_option: None,
153            confirm: None,
154            focus_on_load: None,
155        };
156
157        let val = RadioButtonGroup::builder()
158            .option(option_t("opt0", "val0"))
159            .option(option_t("opt1", "val1"))
160            .build()
161            .unwrap();
162
163        assert_eq!(val, expected);
164    }
165
166    #[test]
167    fn it_requires_action_id_less_than_255_characters_long() {
168        let err = RadioButtonGroup::builder()
169            .option(option_t("opt0", "val0"))
170            .action_id("a".repeat(256))
171            .build()
172            .unwrap_err();
173        assert_eq!(err.object(), "RadioButtonGroup");
174
175        let errors = err.field("action_id");
176        assert!(errors.includes(ValidationErrorKind::MaxTextLength(255)));
177    }
178
179    #[test]
180    fn it_requires_options_field() {
181        let err = RadioButtonGroup::builder().build().unwrap_err();
182        assert_eq!(err.object(), "RadioButtonGroup");
183
184        let errors = err.field("options");
185        assert!(errors.includes(ValidationErrorKind::Required));
186    }
187
188    #[test]
189    fn it_requires_options_item_size_less_than_10() {
190        let options: Vec<Opt<TextContent>> = (0..11).map(|_| option_t("opt", "val")).collect();
191        let err = RadioButtonGroup::builder()
192            .options(options)
193            .build()
194            .unwrap_err();
195        assert_eq!(err.object(), "RadioButtonGroup");
196
197        let errors = err.field("options");
198        assert!(errors.includes(ValidationErrorKind::MaxArraySize(10)));
199    }
200}