slack_messaging/blocks/elements/select_menus/
external_data_source.rs

1use crate::composition_objects::{ConfirmationDialog, Opt, Plain, Text};
2use crate::validators::*;
3
4use serde::Serialize;
5use slack_messaging_derive::Builder;
6
7/// [Select menu of external data source](https://docs.slack.dev/reference/block-kit/block-elements/select-menu-element#external_select)
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/select-menu-element#external_select).
14///
15/// | Field | Type | Required | Validation |
16/// |-------|------|----------|------------|
17/// | action_id | String | No | Max length 255 characters |
18/// | min_query_length | i64 | No | N/A |
19/// | initial_option | [Opt] | No | N/A |
20/// | confirm | [ConfirmationDialog] | No | N/A |
21/// | focus_on_load | bool | No | N/A |
22/// | placeholder | [Text]<[Plain]> | No | Max length 150 characters |
23///
24/// # Example
25///
26/// ```
27/// use slack_messaging::plain_text;
28/// use slack_messaging::blocks::elements::SelectMenuExternalDataSource;
29/// # use std::error::Error;
30///
31/// # fn try_main() -> Result<(), Box<dyn Error>> {
32/// let menu = SelectMenuExternalDataSource::builder()
33///     .action_id("text1234")
34///     .min_query_length(3)
35///     .placeholder(plain_text!("Select an item")?)
36///     .build()?;
37///
38/// let expected = serde_json::json!({
39///     "type": "external_select",
40///     "action_id": "text1234",
41///     "min_query_length": 3,
42///     "placeholder": {
43///         "type": "plain_text",
44///         "text": "Select an item"
45///     }
46/// });
47///
48/// let json = serde_json::to_value(menu).unwrap();
49///
50/// assert_eq!(json, expected);
51///
52/// // If your object has any validation errors, the build method returns Result::Err
53/// let menu = SelectMenuExternalDataSource::builder()
54///     .action_id("text1234")
55///     .placeholder(plain_text!("{}", "verrrrry long text".repeat(100))?)
56///     .build();
57///
58/// assert!(menu.is_err());
59/// #     Ok(())
60/// # }
61/// # fn main() {
62/// #     try_main().unwrap()
63/// # }
64/// ```
65#[derive(Debug, Default, Clone, Serialize, PartialEq, Builder)]
66#[serde(tag = "type", rename = "external_select")]
67pub struct SelectMenuExternalDataSource {
68    #[serde(skip_serializing_if = "Option::is_none")]
69    #[builder(validate("text::max_255"))]
70    pub(crate) action_id: Option<String>,
71
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub(crate) min_query_length: Option<i64>,
74
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub(crate) initial_option: Option<Opt>,
77
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub(crate) confirm: Option<ConfirmationDialog>,
80
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub(crate) focus_on_load: Option<bool>,
83
84    #[serde(skip_serializing_if = "Option::is_none")]
85    #[builder(validate("text_object::max_150"))]
86    pub(crate) placeholder: Option<Text<Plain>>,
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use crate::composition_objects::test_helpers::*;
93    use crate::errors::*;
94
95    #[test]
96    fn it_implements_builder() {
97        let expected = SelectMenuExternalDataSource {
98            action_id: Some("select_0".into()),
99            min_query_length: Some(3),
100            initial_option: Some(option("opt0", "val0")),
101            confirm: Some(confirm()),
102            focus_on_load: Some(true),
103            placeholder: Some(plain_text("Select item")),
104        };
105
106        let val = SelectMenuExternalDataSource::builder()
107            .set_action_id(Some("select_0"))
108            .set_min_query_length(Some(3))
109            .set_initial_option(Some(option("opt0", "val0")))
110            .set_confirm(Some(confirm()))
111            .set_focus_on_load(Some(true))
112            .set_placeholder(Some(plain_text("Select item")))
113            .build()
114            .unwrap();
115
116        assert_eq!(val, expected);
117
118        let val = SelectMenuExternalDataSource::builder()
119            .action_id("select_0")
120            .min_query_length(3)
121            .initial_option(option("opt0", "val0"))
122            .confirm(confirm())
123            .focus_on_load(true)
124            .placeholder(plain_text("Select item"))
125            .build()
126            .unwrap();
127
128        assert_eq!(val, expected);
129    }
130
131    #[test]
132    fn it_requires_action_id_less_than_255_characters_long() {
133        let err = SelectMenuExternalDataSource::builder()
134            .action_id("a".repeat(256))
135            .build()
136            .unwrap_err();
137        assert_eq!(err.object(), "SelectMenuExternalDataSource");
138
139        let errors = err.field("action_id");
140        assert!(errors.includes(ValidationErrorKind::MaxTextLength(255)));
141    }
142
143    #[test]
144    fn it_requires_placeholder_text_less_than_150_characters_long() {
145        let err = SelectMenuExternalDataSource::builder()
146            .placeholder(plain_text("a".repeat(151)))
147            .build()
148            .unwrap_err();
149        assert_eq!(err.object(), "SelectMenuExternalDataSource");
150
151        let errors = err.field("placeholder");
152        assert!(errors.includes(ValidationErrorKind::MaxTextLength(150)));
153    }
154}