slack_messaging/blocks/elements/multi_select_menus/
conversations.rs

1use crate::composition_objects::{ConfirmationDialog, ConversationFilter, Plain, Text};
2use crate::validators::*;
3
4use serde::Serialize;
5use slack_messaging_derive::Builder;
6
7/// [Multi select menu of conversation list](https://docs.slack.dev/reference/block-kit/block-elements/multi-select-menu-element#conversation_multi_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/multi-select-menu-element#conversation_multi_select).
14///
15/// | Field | Type | Required | Validation |
16/// |-------|------|----------|------------|
17/// | action_id | String | No | Max length 255 characters |
18/// | initial_conversations | `Vec<String>` | No | N/A |
19/// | default_to_current_conversation | bool | No | N/A |
20/// | confirm | [ConfirmationDialog] | No | N/A |
21/// | max_selected_items | i64 | No | Min value 1 |
22/// | filter | [ConversationFilter] | No | N/A |
23/// | focus_on_load | bool | No | N/A |
24/// | placeholder | [Text]<[Plain]> | No | Max length 150 characters |
25///
26/// # Example
27///
28/// ```
29/// use slack_messaging::plain_text;
30/// use slack_messaging::blocks::elements::MultiSelectMenuConversations;
31/// # use std::error::Error;
32///
33/// # fn try_main() -> Result<(), Box<dyn Error>> {
34/// let menu = MultiSelectMenuConversations::builder()
35///     .action_id("text1234")
36///     .placeholder(plain_text!("Select conversations")?)
37///     .build()?;
38///
39/// let expected = serde_json::json!({
40///     "type": "multi_conversations_select",
41///     "action_id": "text1234",
42///     "placeholder": {
43///         "type": "plain_text",
44///         "text": "Select conversations"
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 = MultiSelectMenuConversations::builder()
54///     .action_id("text1234")
55///     .placeholder(plain_text!("Select conversations")?)
56///     .max_selected_items(0)
57///     .build();
58///
59/// assert!(menu.is_err());
60/// #     Ok(())
61/// # }
62/// # fn main() {
63/// #     try_main().unwrap()
64/// # }
65/// ```
66#[derive(Debug, Default, Clone, Serialize, PartialEq, Builder)]
67#[serde(tag = "type", rename = "multi_conversations_select")]
68pub struct MultiSelectMenuConversations {
69    #[serde(skip_serializing_if = "Option::is_none")]
70    #[builder(validate("text::max_255"))]
71    pub(crate) action_id: Option<String>,
72
73    #[serde(skip_serializing_if = "Option::is_none")]
74    #[builder(push_item = "initial_conversation")]
75    pub(crate) initial_conversations: Option<Vec<String>>,
76
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub(crate) default_to_current_conversation: Option<bool>,
79
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub(crate) confirm: Option<ConfirmationDialog>,
82
83    #[serde(skip_serializing_if = "Option::is_none")]
84    #[builder(validate("integer::min_1"))]
85    pub(crate) max_selected_items: Option<i64>,
86
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub(crate) filter: Option<ConversationFilter>,
89
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub(crate) focus_on_load: Option<bool>,
92
93    #[serde(skip_serializing_if = "Option::is_none")]
94    #[builder(validate("text_object::max_150"))]
95    pub(crate) placeholder: Option<Text<Plain>>,
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101    use crate::composition_objects::test_helpers::*;
102    use crate::errors::*;
103
104    #[test]
105    fn it_implements_builder() {
106        let expected = MultiSelectMenuConversations {
107            action_id: Some("multi_select_0".into()),
108            initial_conversations: Some(vec!["foo".into(), "bar".into()]),
109            default_to_current_conversation: Some(false),
110            confirm: Some(confirm()),
111            max_selected_items: Some(2),
112            filter: Some(conversation_filter()),
113            focus_on_load: Some(true),
114            placeholder: Some(plain_text("Select items")),
115        };
116
117        let val = MultiSelectMenuConversations::builder()
118            .set_action_id(Some("multi_select_0"))
119            .set_initial_conversations(Some(vec!["foo".into(), "bar".into()]))
120            .set_default_to_current_conversation(Some(false))
121            .set_confirm(Some(confirm()))
122            .set_max_selected_items(Some(2))
123            .set_filter(Some(conversation_filter()))
124            .set_focus_on_load(Some(true))
125            .set_placeholder(Some(plain_text("Select items")))
126            .build()
127            .unwrap();
128
129        assert_eq!(val, expected);
130
131        let val = MultiSelectMenuConversations::builder()
132            .action_id("multi_select_0")
133            .initial_conversations(vec!["foo".into(), "bar".into()])
134            .default_to_current_conversation(false)
135            .confirm(confirm())
136            .max_selected_items(2)
137            .filter(conversation_filter())
138            .focus_on_load(true)
139            .placeholder(plain_text("Select items"))
140            .build()
141            .unwrap();
142
143        assert_eq!(val, expected);
144    }
145
146    #[test]
147    fn it_implements_push_item_method() {
148        let expected = MultiSelectMenuConversations {
149            action_id: None,
150            initial_conversations: Some(vec!["foo".into(), "bar".into()]),
151            default_to_current_conversation: None,
152            confirm: None,
153            max_selected_items: None,
154            filter: None,
155            focus_on_load: None,
156            placeholder: None,
157        };
158
159        let val = MultiSelectMenuConversations::builder()
160            .initial_conversation("foo")
161            .initial_conversation("bar")
162            .build()
163            .unwrap();
164
165        assert_eq!(val, expected);
166    }
167
168    #[test]
169    fn it_requires_action_id_less_than_255_characters_long() {
170        let err = MultiSelectMenuConversations::builder()
171            .action_id("a".repeat(256))
172            .build()
173            .unwrap_err();
174        assert_eq!(err.object(), "MultiSelectMenuConversations");
175
176        let errors = err.field("action_id");
177        assert!(errors.includes(ValidationErrorKind::MaxTextLength(255)));
178    }
179
180    #[test]
181    fn it_requires_max_selected_items_greater_than_1() {
182        let err = MultiSelectMenuConversations::builder()
183            .max_selected_items(0)
184            .build()
185            .unwrap_err();
186        assert_eq!(err.object(), "MultiSelectMenuConversations");
187
188        let errors = err.field("max_selected_items");
189        assert!(errors.includes(ValidationErrorKind::MinIntegerValue(1)));
190    }
191
192    #[test]
193    fn it_requires_placeholder_text_less_than_150_characters_long() {
194        let err = MultiSelectMenuConversations::builder()
195            .placeholder(plain_text("a".repeat(151)))
196            .build()
197            .unwrap_err();
198        assert_eq!(err.object(), "MultiSelectMenuConversations");
199
200        let errors = err.field("placeholder");
201        assert!(errors.includes(ValidationErrorKind::MaxTextLength(150)));
202    }
203}