Skip to main content

slack_web_api/blocks/
element.rs

1use serde::{Deserialize, Serialize};
2
3use super::composition::{
4    ButtonStyle, ConfirmationDialog, DispatchActionConfig, Mrkdwn, OptionObject, PlainText,
5    SlackFile, TextObject, Workflow,
6};
7use super::rich_text::RichTextBlock;
8use super::select::{
9    ChannelsSelectElement, ConversationsSelectElement, ExternalSelectElement,
10    MultiChannelsSelectElement, MultiConversationsSelectElement, MultiExternalSelectElement,
11    MultiStaticSelectElement, MultiUsersSelectElement, StaticSelectElement, UsersSelectElement,
12};
13use super::tag::{tagged_enum, Tag, Tagged};
14
15tagged_enum! {
16    /// An element allowed in an actions block. <https://docs.slack.dev/reference/block-kit/blocks/actions-block>
17    pub enum ActionsElement("type") {
18        Button(ButtonElement),
19        Checkboxes(CheckboxesElement),
20        DatePicker(DatePickerElement),
21        DatetimePicker(DatetimePickerElement),
22        MultiStaticSelect(MultiStaticSelectElement),
23        MultiExternalSelect(MultiExternalSelectElement),
24        MultiUsersSelect(MultiUsersSelectElement),
25        MultiConversationsSelect(MultiConversationsSelectElement),
26        MultiChannelsSelect(MultiChannelsSelectElement),
27        Overflow(OverflowElement),
28        RadioButtons(RadioButtonsElement),
29        RichTextInput(RichTextInputElement),
30        StaticSelect(StaticSelectElement),
31        ExternalSelect(ExternalSelectElement),
32        UsersSelect(UsersSelectElement),
33        ConversationsSelect(ConversationsSelectElement),
34        ChannelsSelect(ChannelsSelectElement),
35        TimePicker(TimePickerElement),
36        WorkflowButton(WorkflowButtonElement),
37    }
38}
39
40tagged_enum! {
41    /// An element allowed as the `accessory` of a section block. <https://docs.slack.dev/reference/block-kit/blocks/section-block>
42    pub enum SectionAccessory("type") {
43        Button(ButtonElement),
44        Checkboxes(CheckboxesElement),
45        DatePicker(DatePickerElement),
46        Image(ImageElement),
47        MultiStaticSelect(MultiStaticSelectElement),
48        MultiExternalSelect(MultiExternalSelectElement),
49        MultiUsersSelect(MultiUsersSelectElement),
50        MultiConversationsSelect(MultiConversationsSelectElement),
51        MultiChannelsSelect(MultiChannelsSelectElement),
52        Overflow(OverflowElement),
53        RadioButtons(RadioButtonsElement),
54        StaticSelect(StaticSelectElement),
55        ExternalSelect(ExternalSelectElement),
56        UsersSelect(UsersSelectElement),
57        ConversationsSelect(ConversationsSelectElement),
58        ChannelsSelect(ChannelsSelectElement),
59        TimePicker(TimePickerElement),
60        WorkflowButton(WorkflowButtonElement),
61    }
62}
63
64tagged_enum! {
65    /// An element allowed in an input block. <https://docs.slack.dev/reference/block-kit/blocks/input-block>
66    pub enum InputElement("type") {
67        Checkboxes(CheckboxesElement),
68        DatePicker(DatePickerElement),
69        DatetimePicker(DatetimePickerElement),
70        EmailInput(EmailInputElement),
71        FileInput(FileInputElement),
72        MultiStaticSelect(MultiStaticSelectElement),
73        MultiExternalSelect(MultiExternalSelectElement),
74        MultiUsersSelect(MultiUsersSelectElement),
75        MultiConversationsSelect(MultiConversationsSelectElement),
76        MultiChannelsSelect(MultiChannelsSelectElement),
77        NumberInput(NumberInputElement),
78        PlainTextInput(PlainTextInputElement),
79        RadioButtons(RadioButtonsElement),
80        RichTextInput(RichTextInputElement),
81        StaticSelect(StaticSelectElement),
82        ExternalSelect(ExternalSelectElement),
83        UsersSelect(UsersSelectElement),
84        ConversationsSelect(ConversationsSelectElement),
85        ChannelsSelect(ChannelsSelectElement),
86        TimePicker(TimePickerElement),
87        UrlInput(UrlInputElement),
88    }
89}
90
91tagged_enum! {
92    /// An element allowed in a context block (images and text). <https://docs.slack.dev/reference/block-kit/blocks/context-block>
93    pub enum ContextElement("type") {
94        Image(ImageElement),
95        PlainText(PlainText),
96        Mrkdwn(Mrkdwn),
97    }
98}
99
100tagged_enum! {
101    /// An element allowed in a context actions block. <https://docs.slack.dev/reference/block-kit/blocks/context-actions-block>
102    pub enum ContextActionsElement("type") {
103        FeedbackButtons(FeedbackButtonsElement),
104        IconButton(IconButtonElement),
105    }
106}
107
108/// A button. <https://docs.slack.dev/reference/block-kit/block-elements/button-element>
109#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
110pub struct ButtonElement {
111    r#type: Tag<Self>,
112    pub text: TextObject,
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub action_id: Option<String>,
115    #[serde(skip_serializing_if = "Option::is_none")]
116    pub url: Option<String>,
117    #[serde(skip_serializing_if = "Option::is_none")]
118    pub value: Option<String>,
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub style: Option<ButtonStyle>,
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub confirm: Option<ConfirmationDialog>,
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub accessibility_label: Option<String>,
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub agent_prompt: Option<String>,
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub agent_prompt_display: Option<String>,
129    #[serde(default, skip_serializing_if = "Vec::is_empty")]
130    pub visible_to_user_ids: Vec<String>,
131}
132
133impl Tagged for ButtonElement {
134    const TAG: &'static str = "button";
135}
136
137impl ButtonElement {
138    pub fn new(text: impl Into<TextObject>) -> Self {
139        Self {
140            r#type: Tag::default(),
141            text: text.into(),
142            action_id: None,
143            url: None,
144            value: None,
145            style: None,
146            confirm: None,
147            accessibility_label: None,
148            agent_prompt: None,
149            agent_prompt_display: None,
150            visible_to_user_ids: Vec::new(),
151        }
152    }
153
154    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
155        self.action_id = Some(action_id.into());
156        self
157    }
158
159    pub fn url(mut self, url: impl Into<String>) -> Self {
160        self.url = Some(url.into());
161        self
162    }
163
164    pub fn value(mut self, value: impl Into<String>) -> Self {
165        self.value = Some(value.into());
166        self
167    }
168
169    pub fn style(mut self, style: ButtonStyle) -> Self {
170        self.style = Some(style);
171        self
172    }
173
174    pub fn confirm(mut self, confirm: ConfirmationDialog) -> Self {
175        self.confirm = Some(confirm);
176        self
177    }
178
179    pub fn accessibility_label(mut self, accessibility_label: impl Into<String>) -> Self {
180        self.accessibility_label = Some(accessibility_label.into());
181        self
182    }
183
184    pub fn agent_prompt(mut self, agent_prompt: impl Into<String>) -> Self {
185        self.agent_prompt = Some(agent_prompt.into());
186        self
187    }
188
189    pub fn agent_prompt_display(mut self, agent_prompt_display: impl Into<String>) -> Self {
190        self.agent_prompt_display = Some(agent_prompt_display.into());
191        self
192    }
193
194    pub fn visible_to_user_ids(mut self, visible_to_user_ids: Vec<String>) -> Self {
195        self.visible_to_user_ids = visible_to_user_ids;
196        self
197    }
198}
199
200/// A group of checkboxes. <https://docs.slack.dev/reference/block-kit/block-elements/checkboxes-element>
201#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
202pub struct CheckboxesElement {
203    r#type: Tag<Self>,
204    #[serde(skip_serializing_if = "Option::is_none")]
205    pub action_id: Option<String>,
206    pub options: Vec<OptionObject>,
207    #[serde(default, skip_serializing_if = "Vec::is_empty")]
208    pub initial_options: Vec<OptionObject>,
209    #[serde(skip_serializing_if = "Option::is_none")]
210    pub confirm: Option<ConfirmationDialog>,
211    #[serde(skip_serializing_if = "Option::is_none")]
212    pub focus_on_load: Option<bool>,
213    #[serde(default, skip_serializing_if = "Vec::is_empty")]
214    pub visible_to_user_ids: Vec<String>,
215}
216
217impl Tagged for CheckboxesElement {
218    const TAG: &'static str = "checkboxes";
219}
220
221impl CheckboxesElement {
222    pub fn new(options: Vec<OptionObject>) -> Self {
223        Self {
224            r#type: Tag::default(),
225            action_id: None,
226            options,
227            initial_options: Vec::new(),
228            confirm: None,
229            focus_on_load: None,
230            visible_to_user_ids: Vec::new(),
231        }
232    }
233
234    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
235        self.action_id = Some(action_id.into());
236        self
237    }
238
239    pub fn initial_options(mut self, initial_options: Vec<OptionObject>) -> Self {
240        self.initial_options = initial_options;
241        self
242    }
243
244    pub fn confirm(mut self, confirm: ConfirmationDialog) -> Self {
245        self.confirm = Some(confirm);
246        self
247    }
248
249    pub fn focus_on_load(mut self, focus_on_load: bool) -> Self {
250        self.focus_on_load = Some(focus_on_load);
251        self
252    }
253
254    pub fn visible_to_user_ids(mut self, visible_to_user_ids: Vec<String>) -> Self {
255        self.visible_to_user_ids = visible_to_user_ids;
256        self
257    }
258}
259
260/// A date picker. <https://docs.slack.dev/reference/block-kit/block-elements/date-picker-element>
261#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
262pub struct DatePickerElement {
263    r#type: Tag<Self>,
264    #[serde(skip_serializing_if = "Option::is_none")]
265    pub action_id: Option<String>,
266    #[serde(skip_serializing_if = "Option::is_none")]
267    pub initial_date: Option<String>,
268    #[serde(skip_serializing_if = "Option::is_none")]
269    pub confirm: Option<ConfirmationDialog>,
270    #[serde(skip_serializing_if = "Option::is_none")]
271    pub focus_on_load: Option<bool>,
272    #[serde(skip_serializing_if = "Option::is_none")]
273    pub placeholder: Option<TextObject>,
274}
275
276impl Tagged for DatePickerElement {
277    const TAG: &'static str = "datepicker";
278}
279
280impl DatePickerElement {
281    pub fn new() -> Self {
282        Self::default()
283    }
284
285    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
286        self.action_id = Some(action_id.into());
287        self
288    }
289
290    pub fn initial_date(mut self, initial_date: impl Into<String>) -> Self {
291        self.initial_date = Some(initial_date.into());
292        self
293    }
294
295    pub fn confirm(mut self, confirm: ConfirmationDialog) -> Self {
296        self.confirm = Some(confirm);
297        self
298    }
299
300    pub fn focus_on_load(mut self, focus_on_load: bool) -> Self {
301        self.focus_on_load = Some(focus_on_load);
302        self
303    }
304
305    pub fn placeholder(mut self, placeholder: impl Into<TextObject>) -> Self {
306        self.placeholder = Some(placeholder.into());
307        self
308    }
309}
310
311/// A date and time picker. <https://docs.slack.dev/reference/block-kit/block-elements/datetime-picker-element>
312#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
313pub struct DatetimePickerElement {
314    r#type: Tag<Self>,
315    #[serde(skip_serializing_if = "Option::is_none")]
316    pub action_id: Option<String>,
317    #[serde(skip_serializing_if = "Option::is_none")]
318    pub initial_date_time: Option<i64>,
319    #[serde(skip_serializing_if = "Option::is_none")]
320    pub confirm: Option<ConfirmationDialog>,
321    #[serde(skip_serializing_if = "Option::is_none")]
322    pub focus_on_load: Option<bool>,
323}
324
325impl Tagged for DatetimePickerElement {
326    const TAG: &'static str = "datetimepicker";
327}
328
329impl DatetimePickerElement {
330    pub fn new() -> Self {
331        Self::default()
332    }
333
334    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
335        self.action_id = Some(action_id.into());
336        self
337    }
338
339    pub fn initial_date_time(mut self, initial_date_time: i64) -> Self {
340        self.initial_date_time = Some(initial_date_time);
341        self
342    }
343
344    pub fn confirm(mut self, confirm: ConfirmationDialog) -> Self {
345        self.confirm = Some(confirm);
346        self
347    }
348
349    pub fn focus_on_load(mut self, focus_on_load: bool) -> Self {
350        self.focus_on_load = Some(focus_on_load);
351        self
352    }
353}
354
355/// An email input. <https://docs.slack.dev/reference/block-kit/block-elements/email-input-element>
356#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
357pub struct EmailInputElement {
358    r#type: Tag<Self>,
359    #[serde(skip_serializing_if = "Option::is_none")]
360    pub action_id: Option<String>,
361    #[serde(skip_serializing_if = "Option::is_none")]
362    pub initial_value: Option<String>,
363    #[serde(skip_serializing_if = "Option::is_none")]
364    pub dispatch_action_config: Option<DispatchActionConfig>,
365    #[serde(skip_serializing_if = "Option::is_none")]
366    pub focus_on_load: Option<bool>,
367    #[serde(skip_serializing_if = "Option::is_none")]
368    pub placeholder: Option<TextObject>,
369}
370
371impl Tagged for EmailInputElement {
372    const TAG: &'static str = "email_text_input";
373}
374
375impl EmailInputElement {
376    pub fn new() -> Self {
377        Self::default()
378    }
379
380    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
381        self.action_id = Some(action_id.into());
382        self
383    }
384
385    pub fn initial_value(mut self, initial_value: impl Into<String>) -> Self {
386        self.initial_value = Some(initial_value.into());
387        self
388    }
389
390    pub fn dispatch_action_config(mut self, dispatch_action_config: DispatchActionConfig) -> Self {
391        self.dispatch_action_config = Some(dispatch_action_config);
392        self
393    }
394
395    pub fn focus_on_load(mut self, focus_on_load: bool) -> Self {
396        self.focus_on_load = Some(focus_on_load);
397        self
398    }
399
400    pub fn placeholder(mut self, placeholder: impl Into<TextObject>) -> Self {
401        self.placeholder = Some(placeholder.into());
402        self
403    }
404}
405
406/// Positive and negative feedback buttons. <https://docs.slack.dev/reference/block-kit/block-elements/feedback-buttons-element>
407#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
408pub struct FeedbackButtonsElement {
409    r#type: Tag<Self>,
410    pub positive_button: FeedbackButton,
411    pub negative_button: FeedbackButton,
412    #[serde(skip_serializing_if = "Option::is_none")]
413    pub action_id: Option<String>,
414}
415
416impl Tagged for FeedbackButtonsElement {
417    const TAG: &'static str = "feedback_buttons";
418}
419
420impl FeedbackButtonsElement {
421    pub fn new(positive_button: FeedbackButton, negative_button: FeedbackButton) -> Self {
422        Self {
423            r#type: Tag::default(),
424            positive_button,
425            negative_button,
426            action_id: None,
427        }
428    }
429
430    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
431        self.action_id = Some(action_id.into());
432        self
433    }
434}
435
436/// One of the feedback buttons. <https://docs.slack.dev/reference/block-kit/block-elements/feedback-buttons-element>
437#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
438pub struct FeedbackButton {
439    pub text: TextObject,
440    pub value: String,
441    #[serde(skip_serializing_if = "Option::is_none")]
442    pub accessibility_label: Option<String>,
443}
444
445impl FeedbackButton {
446    pub fn new(text: impl Into<TextObject>, value: impl Into<String>) -> Self {
447        Self {
448            text: text.into(),
449            value: value.into(),
450            accessibility_label: None,
451        }
452    }
453
454    pub fn accessibility_label(mut self, accessibility_label: impl Into<String>) -> Self {
455        self.accessibility_label = Some(accessibility_label.into());
456        self
457    }
458}
459
460/// A file upload input. <https://docs.slack.dev/reference/block-kit/block-elements/file-input-element>
461#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
462pub struct FileInputElement {
463    r#type: Tag<Self>,
464    #[serde(skip_serializing_if = "Option::is_none")]
465    pub action_id: Option<String>,
466    #[serde(default, skip_serializing_if = "Vec::is_empty")]
467    pub filetypes: Vec<String>,
468    #[serde(skip_serializing_if = "Option::is_none")]
469    pub max_files: Option<u32>,
470}
471
472impl Tagged for FileInputElement {
473    const TAG: &'static str = "file_input";
474}
475
476impl FileInputElement {
477    pub fn new() -> Self {
478        Self::default()
479    }
480
481    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
482        self.action_id = Some(action_id.into());
483        self
484    }
485
486    pub fn filetypes(mut self, filetypes: Vec<String>) -> Self {
487        self.filetypes = filetypes;
488        self
489    }
490
491    pub fn max_files(mut self, max_files: u32) -> Self {
492        self.max_files = Some(max_files);
493        self
494    }
495}
496
497/// An icon button. <https://docs.slack.dev/reference/block-kit/block-elements/icon-button-element>
498#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
499pub struct IconButtonElement {
500    r#type: Tag<Self>,
501    pub icon: String,
502    pub text: TextObject,
503    #[serde(skip_serializing_if = "Option::is_none")]
504    pub action_id: Option<String>,
505    #[serde(skip_serializing_if = "Option::is_none")]
506    pub value: Option<String>,
507    #[serde(skip_serializing_if = "Option::is_none")]
508    pub confirm: Option<ConfirmationDialog>,
509    #[serde(skip_serializing_if = "Option::is_none")]
510    pub accessibility_label: Option<String>,
511    #[serde(default, skip_serializing_if = "Vec::is_empty")]
512    pub visible_to_user_ids: Vec<String>,
513}
514
515impl Tagged for IconButtonElement {
516    const TAG: &'static str = "icon_button";
517}
518
519impl IconButtonElement {
520    pub fn new(icon: impl Into<String>, text: impl Into<TextObject>) -> Self {
521        Self {
522            r#type: Tag::default(),
523            icon: icon.into(),
524            text: text.into(),
525            action_id: None,
526            value: None,
527            confirm: None,
528            accessibility_label: None,
529            visible_to_user_ids: Vec::new(),
530        }
531    }
532
533    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
534        self.action_id = Some(action_id.into());
535        self
536    }
537
538    pub fn value(mut self, value: impl Into<String>) -> Self {
539        self.value = Some(value.into());
540        self
541    }
542
543    pub fn confirm(mut self, confirm: ConfirmationDialog) -> Self {
544        self.confirm = Some(confirm);
545        self
546    }
547
548    pub fn accessibility_label(mut self, accessibility_label: impl Into<String>) -> Self {
549        self.accessibility_label = Some(accessibility_label.into());
550        self
551    }
552
553    pub fn visible_to_user_ids(mut self, visible_to_user_ids: Vec<String>) -> Self {
554        self.visible_to_user_ids = visible_to_user_ids;
555        self
556    }
557}
558
559/// An image element (either `image_url` or `slack_file`). <https://docs.slack.dev/reference/block-kit/block-elements/image-element>
560#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
561pub struct ImageElement {
562    r#type: Tag<Self>,
563    pub alt_text: String,
564    #[serde(skip_serializing_if = "Option::is_none")]
565    pub image_url: Option<String>,
566    #[serde(skip_serializing_if = "Option::is_none")]
567    pub slack_file: Option<SlackFile>,
568}
569
570impl Tagged for ImageElement {
571    const TAG: &'static str = "image";
572}
573
574impl ImageElement {
575    pub fn new(image_url: impl Into<String>, alt_text: impl Into<String>) -> Self {
576        Self {
577            r#type: Tag::default(),
578            alt_text: alt_text.into(),
579            image_url: Some(image_url.into()),
580            slack_file: None,
581        }
582    }
583
584    pub fn from_slack_file(slack_file: SlackFile, alt_text: impl Into<String>) -> Self {
585        Self {
586            r#type: Tag::default(),
587            alt_text: alt_text.into(),
588            image_url: None,
589            slack_file: Some(slack_file),
590        }
591    }
592
593    pub fn image_url(mut self, image_url: impl Into<String>) -> Self {
594        self.image_url = Some(image_url.into());
595        self
596    }
597
598    pub fn slack_file(mut self, slack_file: SlackFile) -> Self {
599        self.slack_file = Some(slack_file);
600        self
601    }
602}
603
604/// A number input. <https://docs.slack.dev/reference/block-kit/block-elements/number-input-element>
605#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
606pub struct NumberInputElement {
607    r#type: Tag<Self>,
608    pub is_decimal_allowed: bool,
609    #[serde(skip_serializing_if = "Option::is_none")]
610    pub action_id: Option<String>,
611    #[serde(skip_serializing_if = "Option::is_none")]
612    pub initial_value: Option<String>,
613    #[serde(skip_serializing_if = "Option::is_none")]
614    pub min_value: Option<String>,
615    #[serde(skip_serializing_if = "Option::is_none")]
616    pub max_value: Option<String>,
617    #[serde(skip_serializing_if = "Option::is_none")]
618    pub dispatch_action_config: Option<DispatchActionConfig>,
619    #[serde(skip_serializing_if = "Option::is_none")]
620    pub focus_on_load: Option<bool>,
621    #[serde(skip_serializing_if = "Option::is_none")]
622    pub placeholder: Option<TextObject>,
623}
624
625impl Tagged for NumberInputElement {
626    const TAG: &'static str = "number_input";
627}
628
629impl NumberInputElement {
630    pub fn new(is_decimal_allowed: bool) -> Self {
631        Self {
632            r#type: Tag::default(),
633            is_decimal_allowed,
634            action_id: None,
635            initial_value: None,
636            min_value: None,
637            max_value: None,
638            dispatch_action_config: None,
639            focus_on_load: None,
640            placeholder: None,
641        }
642    }
643
644    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
645        self.action_id = Some(action_id.into());
646        self
647    }
648
649    pub fn initial_value(mut self, initial_value: impl Into<String>) -> Self {
650        self.initial_value = Some(initial_value.into());
651        self
652    }
653
654    pub fn min_value(mut self, min_value: impl Into<String>) -> Self {
655        self.min_value = Some(min_value.into());
656        self
657    }
658
659    pub fn max_value(mut self, max_value: impl Into<String>) -> Self {
660        self.max_value = Some(max_value.into());
661        self
662    }
663
664    pub fn dispatch_action_config(mut self, dispatch_action_config: DispatchActionConfig) -> Self {
665        self.dispatch_action_config = Some(dispatch_action_config);
666        self
667    }
668
669    pub fn focus_on_load(mut self, focus_on_load: bool) -> Self {
670        self.focus_on_load = Some(focus_on_load);
671        self
672    }
673
674    pub fn placeholder(mut self, placeholder: impl Into<TextObject>) -> Self {
675        self.placeholder = Some(placeholder.into());
676        self
677    }
678}
679
680/// An overflow menu. <https://docs.slack.dev/reference/block-kit/block-elements/overflow-menu-element>
681#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
682pub struct OverflowElement {
683    r#type: Tag<Self>,
684    #[serde(skip_serializing_if = "Option::is_none")]
685    pub action_id: Option<String>,
686    pub options: Vec<OptionObject>,
687    #[serde(skip_serializing_if = "Option::is_none")]
688    pub confirm: Option<ConfirmationDialog>,
689}
690
691impl Tagged for OverflowElement {
692    const TAG: &'static str = "overflow";
693}
694
695impl OverflowElement {
696    pub fn new(options: Vec<OptionObject>) -> Self {
697        Self {
698            r#type: Tag::default(),
699            action_id: None,
700            options,
701            confirm: None,
702        }
703    }
704
705    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
706        self.action_id = Some(action_id.into());
707        self
708    }
709
710    pub fn confirm(mut self, confirm: ConfirmationDialog) -> Self {
711        self.confirm = Some(confirm);
712        self
713    }
714}
715
716/// A plain-text input. <https://docs.slack.dev/reference/block-kit/block-elements/plain-text-input-element>
717#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
718pub struct PlainTextInputElement {
719    r#type: Tag<Self>,
720    #[serde(skip_serializing_if = "Option::is_none")]
721    pub action_id: Option<String>,
722    #[serde(skip_serializing_if = "Option::is_none")]
723    pub initial_value: Option<String>,
724    #[serde(skip_serializing_if = "Option::is_none")]
725    pub multiline: Option<bool>,
726    #[serde(skip_serializing_if = "Option::is_none")]
727    pub min_length: Option<u32>,
728    #[serde(skip_serializing_if = "Option::is_none")]
729    pub max_length: Option<u32>,
730    #[serde(skip_serializing_if = "Option::is_none")]
731    pub dispatch_action_config: Option<DispatchActionConfig>,
732    #[serde(skip_serializing_if = "Option::is_none")]
733    pub focus_on_load: Option<bool>,
734    #[serde(skip_serializing_if = "Option::is_none")]
735    pub placeholder: Option<TextObject>,
736}
737
738impl Tagged for PlainTextInputElement {
739    const TAG: &'static str = "plain_text_input";
740}
741
742impl PlainTextInputElement {
743    pub fn new() -> Self {
744        Self::default()
745    }
746
747    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
748        self.action_id = Some(action_id.into());
749        self
750    }
751
752    pub fn initial_value(mut self, initial_value: impl Into<String>) -> Self {
753        self.initial_value = Some(initial_value.into());
754        self
755    }
756
757    pub fn multiline(mut self, multiline: bool) -> Self {
758        self.multiline = Some(multiline);
759        self
760    }
761
762    pub fn min_length(mut self, min_length: u32) -> Self {
763        self.min_length = Some(min_length);
764        self
765    }
766
767    pub fn max_length(mut self, max_length: u32) -> Self {
768        self.max_length = Some(max_length);
769        self
770    }
771
772    pub fn dispatch_action_config(mut self, dispatch_action_config: DispatchActionConfig) -> Self {
773        self.dispatch_action_config = Some(dispatch_action_config);
774        self
775    }
776
777    pub fn focus_on_load(mut self, focus_on_load: bool) -> Self {
778        self.focus_on_load = Some(focus_on_load);
779        self
780    }
781
782    pub fn placeholder(mut self, placeholder: impl Into<TextObject>) -> Self {
783        self.placeholder = Some(placeholder.into());
784        self
785    }
786}
787
788/// A radio button group. <https://docs.slack.dev/reference/block-kit/block-elements/radio-button-group-element>
789#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
790pub struct RadioButtonsElement {
791    r#type: Tag<Self>,
792    #[serde(skip_serializing_if = "Option::is_none")]
793    pub action_id: Option<String>,
794    pub options: Vec<OptionObject>,
795    #[serde(skip_serializing_if = "Option::is_none")]
796    pub initial_option: Option<OptionObject>,
797    #[serde(skip_serializing_if = "Option::is_none")]
798    pub confirm: Option<ConfirmationDialog>,
799    #[serde(skip_serializing_if = "Option::is_none")]
800    pub focus_on_load: Option<bool>,
801}
802
803impl Tagged for RadioButtonsElement {
804    const TAG: &'static str = "radio_buttons";
805}
806
807impl RadioButtonsElement {
808    pub fn new(options: Vec<OptionObject>) -> Self {
809        Self {
810            r#type: Tag::default(),
811            action_id: None,
812            options,
813            initial_option: None,
814            confirm: None,
815            focus_on_load: None,
816        }
817    }
818
819    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
820        self.action_id = Some(action_id.into());
821        self
822    }
823
824    pub fn initial_option(mut self, initial_option: OptionObject) -> Self {
825        self.initial_option = Some(initial_option);
826        self
827    }
828
829    pub fn confirm(mut self, confirm: ConfirmationDialog) -> Self {
830        self.confirm = Some(confirm);
831        self
832    }
833
834    pub fn focus_on_load(mut self, focus_on_load: bool) -> Self {
835        self.focus_on_load = Some(focus_on_load);
836        self
837    }
838}
839
840/// A rich text input. <https://docs.slack.dev/reference/block-kit/block-elements/rich-text-input-element>
841#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
842pub struct RichTextInputElement {
843    r#type: Tag<Self>,
844    pub action_id: String,
845    #[serde(skip_serializing_if = "Option::is_none")]
846    pub initial_value: Option<RichTextBlock>,
847    #[serde(skip_serializing_if = "Option::is_none")]
848    pub dispatch_action_config: Option<DispatchActionConfig>,
849    #[serde(skip_serializing_if = "Option::is_none")]
850    pub focus_on_load: Option<bool>,
851    #[serde(skip_serializing_if = "Option::is_none")]
852    pub placeholder: Option<TextObject>,
853    #[serde(skip_serializing_if = "Option::is_none")]
854    pub min_lines: Option<u32>,
855    #[serde(skip_serializing_if = "Option::is_none")]
856    pub max_lines: Option<u32>,
857}
858
859impl Tagged for RichTextInputElement {
860    const TAG: &'static str = "rich_text_input";
861}
862
863impl RichTextInputElement {
864    pub fn new(action_id: impl Into<String>) -> Self {
865        Self {
866            r#type: Tag::default(),
867            action_id: action_id.into(),
868            initial_value: None,
869            dispatch_action_config: None,
870            focus_on_load: None,
871            placeholder: None,
872            min_lines: None,
873            max_lines: None,
874        }
875    }
876
877    pub fn initial_value(mut self, initial_value: RichTextBlock) -> Self {
878        self.initial_value = Some(initial_value);
879        self
880    }
881
882    pub fn dispatch_action_config(mut self, dispatch_action_config: DispatchActionConfig) -> Self {
883        self.dispatch_action_config = Some(dispatch_action_config);
884        self
885    }
886
887    pub fn focus_on_load(mut self, focus_on_load: bool) -> Self {
888        self.focus_on_load = Some(focus_on_load);
889        self
890    }
891
892    pub fn placeholder(mut self, placeholder: impl Into<TextObject>) -> Self {
893        self.placeholder = Some(placeholder.into());
894        self
895    }
896
897    pub fn min_lines(mut self, min_lines: u32) -> Self {
898        self.min_lines = Some(min_lines);
899        self
900    }
901
902    pub fn max_lines(mut self, max_lines: u32) -> Self {
903        self.max_lines = Some(max_lines);
904        self
905    }
906}
907
908/// A time picker. <https://docs.slack.dev/reference/block-kit/block-elements/time-picker-element>
909#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
910pub struct TimePickerElement {
911    r#type: Tag<Self>,
912    #[serde(skip_serializing_if = "Option::is_none")]
913    pub action_id: Option<String>,
914    #[serde(skip_serializing_if = "Option::is_none")]
915    pub initial_time: Option<String>,
916    #[serde(skip_serializing_if = "Option::is_none")]
917    pub confirm: Option<ConfirmationDialog>,
918    #[serde(skip_serializing_if = "Option::is_none")]
919    pub focus_on_load: Option<bool>,
920    #[serde(skip_serializing_if = "Option::is_none")]
921    pub placeholder: Option<TextObject>,
922    #[serde(skip_serializing_if = "Option::is_none")]
923    pub timezone: Option<String>,
924}
925
926impl Tagged for TimePickerElement {
927    const TAG: &'static str = "timepicker";
928}
929
930impl TimePickerElement {
931    pub fn new() -> Self {
932        Self::default()
933    }
934
935    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
936        self.action_id = Some(action_id.into());
937        self
938    }
939
940    pub fn initial_time(mut self, initial_time: impl Into<String>) -> Self {
941        self.initial_time = Some(initial_time.into());
942        self
943    }
944
945    pub fn confirm(mut self, confirm: ConfirmationDialog) -> Self {
946        self.confirm = Some(confirm);
947        self
948    }
949
950    pub fn focus_on_load(mut self, focus_on_load: bool) -> Self {
951        self.focus_on_load = Some(focus_on_load);
952        self
953    }
954
955    pub fn placeholder(mut self, placeholder: impl Into<TextObject>) -> Self {
956        self.placeholder = Some(placeholder.into());
957        self
958    }
959
960    pub fn timezone(mut self, timezone: impl Into<String>) -> Self {
961        self.timezone = Some(timezone.into());
962        self
963    }
964}
965
966/// A URL input. <https://docs.slack.dev/reference/block-kit/block-elements/url-input-element>
967#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
968pub struct UrlInputElement {
969    r#type: Tag<Self>,
970    #[serde(skip_serializing_if = "Option::is_none")]
971    pub action_id: Option<String>,
972    #[serde(skip_serializing_if = "Option::is_none")]
973    pub initial_value: Option<String>,
974    #[serde(skip_serializing_if = "Option::is_none")]
975    pub dispatch_action_config: Option<DispatchActionConfig>,
976    #[serde(skip_serializing_if = "Option::is_none")]
977    pub focus_on_load: Option<bool>,
978    #[serde(skip_serializing_if = "Option::is_none")]
979    pub placeholder: Option<TextObject>,
980}
981
982impl Tagged for UrlInputElement {
983    const TAG: &'static str = "url_text_input";
984}
985
986impl UrlInputElement {
987    pub fn new() -> Self {
988        Self::default()
989    }
990
991    pub fn action_id(mut self, action_id: impl Into<String>) -> Self {
992        self.action_id = Some(action_id.into());
993        self
994    }
995
996    pub fn initial_value(mut self, initial_value: impl Into<String>) -> Self {
997        self.initial_value = Some(initial_value.into());
998        self
999    }
1000
1001    pub fn dispatch_action_config(mut self, dispatch_action_config: DispatchActionConfig) -> Self {
1002        self.dispatch_action_config = Some(dispatch_action_config);
1003        self
1004    }
1005
1006    pub fn focus_on_load(mut self, focus_on_load: bool) -> Self {
1007        self.focus_on_load = Some(focus_on_load);
1008        self
1009    }
1010
1011    pub fn placeholder(mut self, placeholder: impl Into<TextObject>) -> Self {
1012        self.placeholder = Some(placeholder.into());
1013        self
1014    }
1015}
1016
1017/// A button that runs a workflow. <https://docs.slack.dev/reference/block-kit/block-elements/workflow-button-element>
1018#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1019pub struct WorkflowButtonElement {
1020    r#type: Tag<Self>,
1021    pub text: TextObject,
1022    pub workflow: Workflow,
1023    pub action_id: String,
1024    #[serde(skip_serializing_if = "Option::is_none")]
1025    pub style: Option<ButtonStyle>,
1026    #[serde(skip_serializing_if = "Option::is_none")]
1027    pub accessibility_label: Option<String>,
1028}
1029
1030impl Tagged for WorkflowButtonElement {
1031    const TAG: &'static str = "workflow_button";
1032}
1033
1034impl WorkflowButtonElement {
1035    pub fn new(
1036        text: impl Into<TextObject>,
1037        workflow: Workflow,
1038        action_id: impl Into<String>,
1039    ) -> Self {
1040        Self {
1041            r#type: Tag::default(),
1042            text: text.into(),
1043            workflow,
1044            action_id: action_id.into(),
1045            style: None,
1046            accessibility_label: None,
1047        }
1048    }
1049
1050    pub fn style(mut self, style: ButtonStyle) -> Self {
1051        self.style = Some(style);
1052        self
1053    }
1054
1055    pub fn accessibility_label(mut self, accessibility_label: impl Into<String>) -> Self {
1056        self.accessibility_label = Some(accessibility_label.into());
1057        self
1058    }
1059}
1060
1061/// A URL source shown in a task card block. <https://docs.slack.dev/reference/block-kit/block-elements/url-source-element>
1062#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1063pub struct UrlSourceElement {
1064    r#type: Tag<Self>,
1065    pub url: String,
1066    pub text: String,
1067}
1068
1069impl Tagged for UrlSourceElement {
1070    const TAG: &'static str = "url";
1071}
1072
1073impl UrlSourceElement {
1074    pub fn new(url: impl Into<String>, text: impl Into<String>) -> Self {
1075        Self {
1076            r#type: Tag::default(),
1077            url: url.into(),
1078            text: text.into(),
1079        }
1080    }
1081}