slack_morphism/models/blocks/
kit.rs

1use rsb_derive::Builder;
2use rvstruct::ValueStruct;
3use serde::{Deserialize, Serialize};
4use serde_with::skip_serializing_none;
5use url::Url;
6
7use crate::*;
8
9#[skip_serializing_none]
10#[derive(Debug, PartialEq, Clone, Eq, Hash, Serialize, Deserialize, ValueStruct)]
11pub struct SlackBlockId(pub String);
12
13#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
14#[serde(tag = "type")]
15pub enum SlackBlock {
16    #[serde(rename = "section")]
17    Section(SlackSectionBlock),
18    #[serde(rename = "header")]
19    Header(SlackHeaderBlock),
20    #[serde(rename = "divider")]
21    Divider(SlackDividerBlock),
22    #[serde(rename = "image")]
23    Image(SlackImageBlock),
24    #[serde(rename = "actions")]
25    Actions(SlackActionsBlock),
26    #[serde(rename = "context")]
27    Context(SlackContextBlock),
28    #[serde(rename = "input")]
29    Input(SlackInputBlock),
30    #[serde(rename = "file")]
31    File(SlackFileBlock),
32    #[serde(rename = "video")]
33    Video(SlackVideoBlock),
34    #[serde(rename = "markdown")]
35    Markdown(SlackMarkdownBlock),
36
37    // This block is still undocumented, so we don't define any structure yet we can return it back,
38    #[serde(rename = "rich_text")]
39    RichText(serde_json::Value),
40    #[serde(rename = "event")]
41    Event(serde_json::Value),
42}
43
44#[skip_serializing_none]
45#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
46pub struct SlackSectionBlock {
47    pub block_id: Option<SlackBlockId>,
48    pub text: Option<SlackBlockText>,
49    pub fields: Option<Vec<SlackBlockText>>,
50    pub accessory: Option<SlackSectionBlockElement>,
51}
52
53impl From<SlackSectionBlock> for SlackBlock {
54    fn from(block: SlackSectionBlock) -> Self {
55        SlackBlock::Section(block)
56    }
57}
58
59#[skip_serializing_none]
60#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
61pub struct SlackHeaderBlock {
62    pub block_id: Option<SlackBlockId>,
63    pub text: SlackBlockPlainTextOnly,
64}
65
66impl From<SlackHeaderBlock> for SlackBlock {
67    fn from(block: SlackHeaderBlock) -> Self {
68        SlackBlock::Header(block)
69    }
70}
71
72#[skip_serializing_none]
73#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
74pub struct SlackDividerBlock {
75    pub block_id: Option<SlackBlockId>,
76}
77
78impl From<SlackDividerBlock> for SlackBlock {
79    fn from(block: SlackDividerBlock) -> Self {
80        SlackBlock::Divider(block)
81    }
82}
83
84#[skip_serializing_none]
85#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
86pub struct SlackImageBlock {
87    pub block_id: Option<SlackBlockId>,
88    #[serde(flatten)]
89    pub image_url_or_file: SlackImageUrlOrFile,
90    pub alt_text: String,
91    pub title: Option<SlackBlockPlainTextOnly>,
92}
93
94impl From<SlackImageBlock> for SlackBlock {
95    fn from(block: SlackImageBlock) -> Self {
96        SlackBlock::Image(block)
97    }
98}
99
100#[skip_serializing_none]
101#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
102pub struct SlackActionsBlock {
103    pub block_id: Option<SlackBlockId>,
104    pub elements: Vec<SlackActionBlockElement>,
105}
106
107impl From<SlackActionsBlock> for SlackBlock {
108    fn from(block: SlackActionsBlock) -> Self {
109        SlackBlock::Actions(block)
110    }
111}
112
113#[skip_serializing_none]
114#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
115pub struct SlackContextBlock {
116    pub block_id: Option<SlackBlockId>,
117    pub elements: Vec<SlackContextBlockElement>,
118}
119
120impl From<SlackContextBlock> for SlackBlock {
121    fn from(block: SlackContextBlock) -> Self {
122        SlackBlock::Context(block)
123    }
124}
125
126#[skip_serializing_none]
127#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
128pub struct SlackInputBlock {
129    pub block_id: Option<SlackBlockId>,
130    pub label: SlackBlockPlainTextOnly,
131    pub element: SlackInputBlockElement,
132    pub hint: Option<SlackBlockPlainTextOnly>,
133    pub optional: Option<bool>,
134    pub dispatch_action: Option<bool>,
135}
136
137impl From<SlackInputBlock> for SlackBlock {
138    fn from(block: SlackInputBlock) -> Self {
139        SlackBlock::Input(block)
140    }
141}
142
143const SLACK_FILE_BLOCK_SOURCE_DEFAULT: &str = "remote";
144
145#[skip_serializing_none]
146#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
147pub struct SlackFileBlock {
148    pub block_id: Option<SlackBlockId>,
149    pub external_id: String,
150    #[default = "SLACK_FILE_BLOCK_SOURCE_DEFAULT.into()"]
151    pub source: String,
152}
153
154impl From<SlackFileBlock> for SlackBlock {
155    fn from(block: SlackFileBlock) -> Self {
156        SlackBlock::File(block)
157    }
158}
159
160#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
161#[serde(tag = "type")]
162pub enum SlackSectionBlockElement {
163    #[serde(rename = "image")]
164    Image(SlackBlockImageElement),
165    #[serde(rename = "button")]
166    Button(SlackBlockButtonElement),
167    #[serde(rename = "static_select")]
168    StaticSelect(SlackBlockStaticSelectElement),
169    #[serde(rename = "multi_static_select")]
170    MultiStaticSelect(SlackBlockMultiStaticSelectElement),
171    #[serde(rename = "external_select")]
172    ExternalSelect(SlackBlockExternalSelectElement),
173    #[serde(rename = "multi_external_select")]
174    MultiExternalSelect(SlackBlockMultiExternalSelectElement),
175    #[serde(rename = "users_select")]
176    UsersSelect(SlackBlockUsersSelectElement),
177    #[serde(rename = "multi_users_select")]
178    MultiUsersSelect(SlackBlockMultiUsersSelectElement),
179    #[serde(rename = "conversations_select")]
180    ConversationsSelect(SlackBlockConversationsSelectElement),
181    #[serde(rename = "multi_conversations_select")]
182    MultiConversationsSelect(SlackBlockMultiConversationsSelectElement),
183    #[serde(rename = "channels_select")]
184    ChannelsSelect(SlackBlockChannelsSelectElement),
185    #[serde(rename = "multi_channels_select")]
186    MultiChannelsSelect(SlackBlockMultiChannelsSelectElement),
187    #[serde(rename = "overflow")]
188    Overflow(SlackBlockOverflowElement),
189    #[serde(rename = "datepicker")]
190    DatePicker(SlackBlockDatePickerElement),
191    #[serde(rename = "timepicker")]
192    TimePicker(SlackBlockTimePickerElement),
193    #[serde(rename = "plain_text_input")]
194    PlainTextInput(SlackBlockPlainTextInputElement),
195    #[serde(rename = "number_input")]
196    NumberInput(SlackBlockNumberInputElement),
197    #[serde(rename = "url_text_input")]
198    UrlInput(SlackBlockUrlInputElement),
199    #[serde(rename = "radio_buttons")]
200    RadioButtons(SlackBlockRadioButtonsElement),
201    #[serde(rename = "checkboxes")]
202    Checkboxes(SlackBlockCheckboxesElement),
203}
204
205#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
206#[serde(tag = "type")]
207pub enum SlackActionBlockElement {
208    #[serde(rename = "button")]
209    Button(SlackBlockButtonElement),
210    #[serde(rename = "overflow")]
211    Overflow(SlackBlockOverflowElement),
212    #[serde(rename = "datepicker")]
213    DatePicker(SlackBlockDatePickerElement),
214    #[serde(rename = "timepicker")]
215    TimePicker(SlackBlockTimePickerElement),
216    #[serde(rename = "datetimepicker")]
217    DateTimePicker(SlackBlockDateTimePickerElement),
218    #[serde(rename = "plain_text_input")]
219    PlainTextInput(SlackBlockPlainTextInputElement),
220    #[serde(rename = "number_input")]
221    NumberInput(SlackBlockNumberInputElement),
222    #[serde(rename = "url_text_input")]
223    UrlInput(SlackBlockUrlInputElement),
224    #[serde(rename = "radio_buttons")]
225    RadioButtons(SlackBlockRadioButtonsElement),
226    #[serde(rename = "checkboxes")]
227    Checkboxes(SlackBlockCheckboxesElement),
228    #[serde(rename = "static_select")]
229    StaticSelect(SlackBlockStaticSelectElement),
230    #[serde(rename = "external_select")]
231    ExternalSelect(SlackBlockExternalSelectElement),
232    #[serde(rename = "users_select")]
233    UsersSelect(SlackBlockUsersSelectElement),
234    #[serde(rename = "conversations_select")]
235    ConversationsSelect(SlackBlockConversationsSelectElement),
236    #[serde(rename = "channels_select")]
237    ChannelsSelect(SlackBlockChannelsSelectElement),
238}
239
240#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
241#[serde(tag = "type")]
242pub enum SlackContextBlockElement {
243    #[serde(rename = "image")]
244    Image(SlackBlockImageElement),
245    #[serde(rename = "plain_text")]
246    Plain(SlackBlockPlainText),
247    #[serde(rename = "mrkdwn")]
248    MarkDown(SlackBlockMarkDownText),
249}
250
251#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
252#[serde(tag = "type")]
253pub enum SlackInputBlockElement {
254    #[serde(rename = "static_select")]
255    StaticSelect(SlackBlockStaticSelectElement),
256    #[serde(rename = "multi_static_select")]
257    MultiStaticSelect(SlackBlockMultiStaticSelectElement),
258    #[serde(rename = "external_select")]
259    ExternalSelect(SlackBlockExternalSelectElement),
260    #[serde(rename = "multi_external_select")]
261    MultiExternalSelect(SlackBlockMultiExternalSelectElement),
262    #[serde(rename = "users_select")]
263    UsersSelect(SlackBlockUsersSelectElement),
264    #[serde(rename = "multi_users_select")]
265    MultiUsersSelect(SlackBlockMultiUsersSelectElement),
266    #[serde(rename = "conversations_select")]
267    ConversationsSelect(SlackBlockConversationsSelectElement),
268    #[serde(rename = "multi_conversations_select")]
269    MultiConversationsSelect(SlackBlockMultiConversationsSelectElement),
270    #[serde(rename = "channels_select")]
271    ChannelsSelect(SlackBlockChannelsSelectElement),
272    #[serde(rename = "multi_channels_select")]
273    MultiChannelsSelect(SlackBlockMultiChannelsSelectElement),
274    #[serde(rename = "datepicker")]
275    DatePicker(SlackBlockDatePickerElement),
276    #[serde(rename = "timepicker")]
277    TimePicker(SlackBlockTimePickerElement),
278    #[serde(rename = "datetimepicker")]
279    DateTimePicker(SlackBlockDateTimePickerElement),
280    #[serde(rename = "plain_text_input")]
281    PlainTextInput(SlackBlockPlainTextInputElement),
282    #[serde(rename = "number_input")]
283    NumberInput(SlackBlockNumberInputElement),
284    #[serde(rename = "url_text_input")]
285    UrlInput(SlackBlockUrlInputElement),
286    #[serde(rename = "radio_buttons")]
287    RadioButtons(SlackBlockRadioButtonsElement),
288    #[serde(rename = "checkboxes")]
289    Checkboxes(SlackBlockCheckboxesElement),
290    #[serde(rename = "email_text_input")]
291    EmailInput(SlackBlockEmailInputElement),
292}
293
294#[skip_serializing_none]
295#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
296pub struct SlackBlockImageElement {
297    #[serde(flatten)]
298    pub image_url_or_file: SlackImageUrlOrFile,
299    pub alt_text: String,
300}
301
302impl From<SlackBlockImageElement> for SlackSectionBlockElement {
303    fn from(element: SlackBlockImageElement) -> Self {
304        SlackSectionBlockElement::Image(element)
305    }
306}
307
308impl From<SlackBlockImageElement> for SlackContextBlockElement {
309    fn from(element: SlackBlockImageElement) -> Self {
310        SlackContextBlockElement::Image(element)
311    }
312}
313
314#[skip_serializing_none]
315#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
316pub struct SlackBlockButtonElement {
317    pub action_id: SlackActionId,
318    pub text: SlackBlockPlainTextOnly,
319    pub url: Option<Url>,
320    pub value: Option<String>,
321    pub style: Option<String>,
322    pub confirm: Option<SlackBlockConfirmItem>,
323}
324
325impl From<SlackBlockButtonElement> for SlackSectionBlockElement {
326    fn from(element: SlackBlockButtonElement) -> Self {
327        SlackSectionBlockElement::Button(element)
328    }
329}
330
331impl From<SlackBlockButtonElement> for SlackActionBlockElement {
332    fn from(element: SlackBlockButtonElement) -> Self {
333        SlackActionBlockElement::Button(element)
334    }
335}
336
337#[skip_serializing_none]
338#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
339pub struct SlackBlockConfirmItem {
340    pub title: SlackBlockPlainTextOnly,
341    pub text: SlackBlockText,
342    pub confirm: SlackBlockPlainTextOnly,
343    pub deny: SlackBlockPlainTextOnly,
344    pub style: Option<String>,
345}
346
347#[skip_serializing_none]
348#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
349pub struct SlackBlockChoiceItem<T: Into<SlackBlockText>> {
350    pub text: T,
351    pub value: String,
352    pub url: Option<Url>,
353}
354
355#[skip_serializing_none]
356#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
357pub struct SlackBlockOptionGroup<T: Into<SlackBlockText>> {
358    pub label: SlackBlockPlainTextOnly,
359    pub options: Vec<SlackBlockChoiceItem<T>>,
360}
361
362#[skip_serializing_none]
363#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
364pub struct SlackBlockStaticSelectElement {
365    pub action_id: SlackActionId,
366    pub placeholder: Option<SlackBlockPlainTextOnly>,
367    pub options: Option<Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>>,
368    pub option_groups: Option<Vec<SlackBlockOptionGroup<SlackBlockPlainTextOnly>>>,
369    pub initial_option: Option<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>,
370    pub confirm: Option<SlackBlockConfirmItem>,
371    pub focus_on_load: Option<bool>,
372}
373
374impl From<SlackBlockStaticSelectElement> for SlackSectionBlockElement {
375    fn from(element: SlackBlockStaticSelectElement) -> Self {
376        SlackSectionBlockElement::StaticSelect(element)
377    }
378}
379
380impl From<SlackBlockStaticSelectElement> for SlackInputBlockElement {
381    fn from(element: SlackBlockStaticSelectElement) -> Self {
382        SlackInputBlockElement::StaticSelect(element)
383    }
384}
385
386impl From<SlackBlockStaticSelectElement> for SlackActionBlockElement {
387    fn from(element: SlackBlockStaticSelectElement) -> Self {
388        SlackActionBlockElement::StaticSelect(element)
389    }
390}
391
392#[skip_serializing_none]
393#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
394pub struct SlackBlockMultiStaticSelectElement {
395    pub action_id: SlackActionId,
396    pub placeholder: Option<SlackBlockPlainTextOnly>,
397    pub options: Option<Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>>,
398    pub option_groups: Option<Vec<SlackBlockOptionGroup<SlackBlockPlainTextOnly>>>,
399    pub initial_options: Option<Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>>,
400    pub confirm: Option<SlackBlockConfirmItem>,
401    pub max_selected_items: Option<u64>,
402    pub focus_on_load: Option<bool>,
403}
404
405impl From<SlackBlockMultiStaticSelectElement> for SlackSectionBlockElement {
406    fn from(element: SlackBlockMultiStaticSelectElement) -> Self {
407        SlackSectionBlockElement::MultiStaticSelect(element)
408    }
409}
410
411impl From<SlackBlockMultiStaticSelectElement> for SlackInputBlockElement {
412    fn from(element: SlackBlockMultiStaticSelectElement) -> Self {
413        SlackInputBlockElement::MultiStaticSelect(element)
414    }
415}
416
417#[skip_serializing_none]
418#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
419pub struct SlackBlockExternalSelectElement {
420    pub action_id: SlackActionId,
421    pub placeholder: Option<SlackBlockPlainTextOnly>,
422    pub initial_option: Option<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>,
423    pub confirm: Option<SlackBlockConfirmItem>,
424    pub focus_on_load: Option<bool>,
425    pub min_query_length: Option<u64>,
426}
427
428impl From<SlackBlockExternalSelectElement> for SlackSectionBlockElement {
429    fn from(element: SlackBlockExternalSelectElement) -> Self {
430        SlackSectionBlockElement::ExternalSelect(element)
431    }
432}
433
434impl From<SlackBlockExternalSelectElement> for SlackInputBlockElement {
435    fn from(element: SlackBlockExternalSelectElement) -> Self {
436        SlackInputBlockElement::ExternalSelect(element)
437    }
438}
439
440impl From<SlackBlockExternalSelectElement> for SlackActionBlockElement {
441    fn from(element: SlackBlockExternalSelectElement) -> Self {
442        SlackActionBlockElement::ExternalSelect(element)
443    }
444}
445
446#[skip_serializing_none]
447#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
448pub struct SlackBlockMultiExternalSelectElement {
449    pub action_id: SlackActionId,
450    pub placeholder: Option<SlackBlockPlainTextOnly>,
451    pub initial_options: Option<Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>>,
452    pub confirm: Option<SlackBlockConfirmItem>,
453    pub max_selected_items: Option<u64>,
454    pub focus_on_load: Option<bool>,
455    pub min_query_length: Option<u64>,
456}
457
458impl From<SlackBlockMultiExternalSelectElement> for SlackSectionBlockElement {
459    fn from(element: SlackBlockMultiExternalSelectElement) -> Self {
460        SlackSectionBlockElement::MultiExternalSelect(element)
461    }
462}
463
464impl From<SlackBlockMultiExternalSelectElement> for SlackInputBlockElement {
465    fn from(element: SlackBlockMultiExternalSelectElement) -> Self {
466        SlackInputBlockElement::MultiExternalSelect(element)
467    }
468}
469
470#[skip_serializing_none]
471#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
472pub struct SlackBlockUsersSelectElement {
473    pub action_id: SlackActionId,
474    pub placeholder: Option<SlackBlockPlainTextOnly>,
475    pub initial_user: Option<String>,
476    pub confirm: Option<SlackBlockConfirmItem>,
477    pub focus_on_load: Option<bool>,
478}
479
480impl From<SlackBlockUsersSelectElement> for SlackSectionBlockElement {
481    fn from(element: SlackBlockUsersSelectElement) -> Self {
482        SlackSectionBlockElement::UsersSelect(element)
483    }
484}
485
486impl From<SlackBlockUsersSelectElement> for SlackInputBlockElement {
487    fn from(element: SlackBlockUsersSelectElement) -> Self {
488        SlackInputBlockElement::UsersSelect(element)
489    }
490}
491
492impl From<SlackBlockUsersSelectElement> for SlackActionBlockElement {
493    fn from(element: SlackBlockUsersSelectElement) -> Self {
494        SlackActionBlockElement::UsersSelect(element)
495    }
496}
497
498#[skip_serializing_none]
499#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
500pub struct SlackBlockMultiUsersSelectElement {
501    pub action_id: SlackActionId,
502    pub placeholder: Option<SlackBlockPlainTextOnly>,
503    pub initial_users: Option<Vec<String>>,
504    pub confirm: Option<SlackBlockConfirmItem>,
505    pub max_selected_items: Option<u64>,
506    pub focus_on_load: Option<bool>,
507}
508
509impl From<SlackBlockMultiUsersSelectElement> for SlackSectionBlockElement {
510    fn from(element: SlackBlockMultiUsersSelectElement) -> Self {
511        SlackSectionBlockElement::MultiUsersSelect(element)
512    }
513}
514
515impl From<SlackBlockMultiUsersSelectElement> for SlackInputBlockElement {
516    fn from(element: SlackBlockMultiUsersSelectElement) -> Self {
517        SlackInputBlockElement::MultiUsersSelect(element)
518    }
519}
520
521#[skip_serializing_none]
522#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
523pub struct SlackBlockConversationsSelectElement {
524    pub action_id: SlackActionId,
525    pub placeholder: Option<SlackBlockPlainTextOnly>,
526    pub initial_conversation: Option<SlackConversationId>,
527    pub default_to_current_conversation: Option<bool>,
528    pub confirm: Option<SlackBlockConfirmItem>,
529    pub response_url_enabled: Option<bool>,
530    pub focus_on_load: Option<bool>,
531}
532
533impl From<SlackBlockConversationsSelectElement> for SlackSectionBlockElement {
534    fn from(element: SlackBlockConversationsSelectElement) -> Self {
535        SlackSectionBlockElement::ConversationsSelect(element)
536    }
537}
538
539impl From<SlackBlockConversationsSelectElement> for SlackInputBlockElement {
540    fn from(element: SlackBlockConversationsSelectElement) -> Self {
541        SlackInputBlockElement::ConversationsSelect(element)
542    }
543}
544
545impl From<SlackBlockConversationsSelectElement> for SlackActionBlockElement {
546    fn from(element: SlackBlockConversationsSelectElement) -> Self {
547        SlackActionBlockElement::ConversationsSelect(element)
548    }
549}
550
551#[skip_serializing_none]
552#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
553pub struct SlackBlockMultiConversationsSelectElement {
554    pub action_id: SlackActionId,
555    pub placeholder: Option<SlackBlockPlainTextOnly>,
556    pub initial_conversations: Option<Vec<SlackConversationId>>,
557    pub default_to_current_conversation: Option<bool>,
558    pub confirm: Option<SlackBlockConfirmItem>,
559    pub max_selected_items: Option<u64>,
560    pub focus_on_load: Option<bool>,
561}
562
563impl From<SlackBlockMultiConversationsSelectElement> for SlackSectionBlockElement {
564    fn from(element: SlackBlockMultiConversationsSelectElement) -> Self {
565        SlackSectionBlockElement::MultiConversationsSelect(element)
566    }
567}
568
569impl From<SlackBlockMultiConversationsSelectElement> for SlackInputBlockElement {
570    fn from(element: SlackBlockMultiConversationsSelectElement) -> Self {
571        SlackInputBlockElement::MultiConversationsSelect(element)
572    }
573}
574
575#[skip_serializing_none]
576#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
577pub struct SlackBlockChannelsSelectElement {
578    pub action_id: SlackActionId,
579    pub placeholder: Option<SlackBlockPlainTextOnly>,
580    pub initial_channel: Option<SlackChannelId>,
581    pub confirm: Option<SlackBlockConfirmItem>,
582    pub response_url_enabled: Option<bool>,
583    pub focus_on_load: Option<bool>,
584}
585
586impl From<SlackBlockChannelsSelectElement> for SlackSectionBlockElement {
587    fn from(element: SlackBlockChannelsSelectElement) -> Self {
588        SlackSectionBlockElement::ChannelsSelect(element)
589    }
590}
591
592impl From<SlackBlockChannelsSelectElement> for SlackInputBlockElement {
593    fn from(element: SlackBlockChannelsSelectElement) -> Self {
594        SlackInputBlockElement::ChannelsSelect(element)
595    }
596}
597
598impl From<SlackBlockChannelsSelectElement> for SlackActionBlockElement {
599    fn from(element: SlackBlockChannelsSelectElement) -> Self {
600        SlackActionBlockElement::ChannelsSelect(element)
601    }
602}
603
604#[skip_serializing_none]
605#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
606pub struct SlackBlockMultiChannelsSelectElement {
607    pub action_id: SlackActionId,
608    pub placeholder: Option<SlackBlockPlainTextOnly>,
609    pub initial_channels: Option<Vec<SlackChannelId>>,
610    pub confirm: Option<SlackBlockConfirmItem>,
611    pub max_selected_items: Option<u64>,
612    pub focus_on_load: Option<bool>,
613}
614
615impl From<SlackBlockMultiChannelsSelectElement> for SlackSectionBlockElement {
616    fn from(element: SlackBlockMultiChannelsSelectElement) -> Self {
617        SlackSectionBlockElement::MultiChannelsSelect(element)
618    }
619}
620
621impl From<SlackBlockMultiChannelsSelectElement> for SlackInputBlockElement {
622    fn from(element: SlackBlockMultiChannelsSelectElement) -> Self {
623        SlackInputBlockElement::MultiChannelsSelect(element)
624    }
625}
626
627#[skip_serializing_none]
628#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
629pub struct SlackBlockOverflowElement {
630    pub action_id: SlackActionId,
631    pub options: Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>,
632    pub confirm: Option<SlackBlockConfirmItem>,
633}
634
635impl From<SlackBlockOverflowElement> for SlackSectionBlockElement {
636    fn from(element: SlackBlockOverflowElement) -> Self {
637        SlackSectionBlockElement::Overflow(element)
638    }
639}
640
641impl From<SlackBlockOverflowElement> for SlackActionBlockElement {
642    fn from(element: SlackBlockOverflowElement) -> Self {
643        SlackActionBlockElement::Overflow(element)
644    }
645}
646
647#[skip_serializing_none]
648#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
649pub struct SlackBlockDatePickerElement {
650    pub action_id: SlackActionId,
651    pub placeholder: Option<SlackBlockPlainTextOnly>,
652    pub initial_date: Option<String>,
653    pub confirm: Option<SlackBlockConfirmItem>,
654    pub focus_on_load: Option<bool>,
655}
656
657impl From<SlackBlockDatePickerElement> for SlackSectionBlockElement {
658    fn from(element: SlackBlockDatePickerElement) -> Self {
659        SlackSectionBlockElement::DatePicker(element)
660    }
661}
662
663impl From<SlackBlockDatePickerElement> for SlackInputBlockElement {
664    fn from(element: SlackBlockDatePickerElement) -> Self {
665        SlackInputBlockElement::DatePicker(element)
666    }
667}
668
669impl From<SlackBlockDatePickerElement> for SlackActionBlockElement {
670    fn from(element: SlackBlockDatePickerElement) -> Self {
671        SlackActionBlockElement::DatePicker(element)
672    }
673}
674
675#[skip_serializing_none]
676#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
677pub struct SlackBlockTimePickerElement {
678    pub action_id: SlackActionId,
679    pub initial_time: Option<String>,
680    pub confirm: Option<SlackBlockConfirmItem>,
681    pub focus_on_load: Option<bool>,
682    pub placeholder: Option<SlackBlockPlainTextOnly>,
683    pub timezone: Option<String>,
684}
685
686impl From<SlackBlockTimePickerElement> for SlackSectionBlockElement {
687    fn from(element: SlackBlockTimePickerElement) -> Self {
688        SlackSectionBlockElement::TimePicker(element)
689    }
690}
691
692impl From<SlackBlockTimePickerElement> for SlackInputBlockElement {
693    fn from(element: SlackBlockTimePickerElement) -> Self {
694        SlackInputBlockElement::TimePicker(element)
695    }
696}
697
698impl From<SlackBlockTimePickerElement> for SlackActionBlockElement {
699    fn from(element: SlackBlockTimePickerElement) -> Self {
700        SlackActionBlockElement::TimePicker(element)
701    }
702}
703
704#[skip_serializing_none]
705#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
706pub struct SlackBlockDateTimePickerElement {
707    pub action_id: SlackActionId,
708    pub initial_date_time: Option<SlackDateTime>,
709    pub confirm: Option<SlackBlockConfirmItem>,
710    pub focus_on_load: Option<bool>,
711}
712
713impl From<SlackBlockDateTimePickerElement> for SlackInputBlockElement {
714    fn from(element: SlackBlockDateTimePickerElement) -> Self {
715        SlackInputBlockElement::DateTimePicker(element)
716    }
717}
718
719impl From<SlackBlockDateTimePickerElement> for SlackActionBlockElement {
720    fn from(element: SlackBlockDateTimePickerElement) -> Self {
721        SlackActionBlockElement::DateTimePicker(element)
722    }
723}
724
725#[skip_serializing_none]
726#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
727pub struct SlackBlockPlainTextInputElement {
728    pub action_id: SlackActionId,
729    pub placeholder: Option<SlackBlockPlainTextOnly>,
730    pub initial_value: Option<String>,
731    pub multiline: Option<bool>,
732    pub min_length: Option<u64>,
733    pub max_length: Option<u64>,
734    pub focus_on_load: Option<bool>,
735}
736
737impl From<SlackBlockPlainTextInputElement> for SlackSectionBlockElement {
738    fn from(element: SlackBlockPlainTextInputElement) -> Self {
739        SlackSectionBlockElement::PlainTextInput(element)
740    }
741}
742
743impl From<SlackBlockPlainTextInputElement> for SlackInputBlockElement {
744    fn from(element: SlackBlockPlainTextInputElement) -> Self {
745        SlackInputBlockElement::PlainTextInput(element)
746    }
747}
748
749impl From<SlackBlockPlainTextInputElement> for SlackActionBlockElement {
750    fn from(element: SlackBlockPlainTextInputElement) -> Self {
751        SlackActionBlockElement::PlainTextInput(element)
752    }
753}
754
755#[skip_serializing_none]
756#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
757pub struct SlackBlockNumberInputElement {
758    pub action_id: SlackActionId,
759    pub is_decimal_allowed: bool,
760    pub focus_on_load: Option<bool>,
761    pub placeholder: Option<SlackBlockPlainTextOnly>,
762    pub initial_value: Option<String>,
763    pub min_value: Option<String>,
764    pub max_value: Option<String>,
765}
766
767impl From<SlackBlockNumberInputElement> for SlackSectionBlockElement {
768    fn from(element: SlackBlockNumberInputElement) -> Self {
769        SlackSectionBlockElement::NumberInput(element)
770    }
771}
772
773impl From<SlackBlockNumberInputElement> for SlackInputBlockElement {
774    fn from(element: SlackBlockNumberInputElement) -> Self {
775        SlackInputBlockElement::NumberInput(element)
776    }
777}
778
779impl From<SlackBlockNumberInputElement> for SlackActionBlockElement {
780    fn from(element: SlackBlockNumberInputElement) -> Self {
781        SlackActionBlockElement::NumberInput(element)
782    }
783}
784
785#[skip_serializing_none]
786#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
787pub struct SlackBlockUrlInputElement {
788    pub action_id: SlackActionId,
789    pub placeholder: Option<SlackBlockPlainTextOnly>,
790    pub initial_value: Option<String>,
791}
792
793impl From<SlackBlockUrlInputElement> for SlackSectionBlockElement {
794    fn from(element: SlackBlockUrlInputElement) -> Self {
795        SlackSectionBlockElement::UrlInput(element)
796    }
797}
798
799impl From<SlackBlockUrlInputElement> for SlackInputBlockElement {
800    fn from(element: SlackBlockUrlInputElement) -> Self {
801        SlackInputBlockElement::UrlInput(element)
802    }
803}
804
805impl From<SlackBlockUrlInputElement> for SlackActionBlockElement {
806    fn from(element: SlackBlockUrlInputElement) -> Self {
807        SlackActionBlockElement::UrlInput(element)
808    }
809}
810
811#[skip_serializing_none]
812#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
813pub struct SlackBlockEmailInputElement {
814    pub action_id: SlackActionId,
815    pub focus_on_load: Option<bool>,
816    pub placeholder: Option<SlackBlockPlainTextOnly>,
817    pub initial_value: Option<EmailAddress>,
818}
819
820impl From<SlackBlockEmailInputElement> for SlackInputBlockElement {
821    fn from(element: SlackBlockEmailInputElement) -> Self {
822        SlackInputBlockElement::EmailInput(element)
823    }
824}
825
826#[skip_serializing_none]
827#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
828pub struct SlackBlockRadioButtonsElement {
829    pub action_id: SlackActionId,
830    pub options: Vec<SlackBlockChoiceItem<SlackBlockText>>,
831    pub initial_option: Option<SlackBlockChoiceItem<SlackBlockText>>,
832    pub confirm: Option<SlackBlockConfirmItem>,
833    pub focus_on_load: Option<bool>,
834}
835
836impl From<SlackBlockRadioButtonsElement> for SlackSectionBlockElement {
837    fn from(element: SlackBlockRadioButtonsElement) -> Self {
838        SlackSectionBlockElement::RadioButtons(element)
839    }
840}
841
842impl From<SlackBlockRadioButtonsElement> for SlackInputBlockElement {
843    fn from(element: SlackBlockRadioButtonsElement) -> Self {
844        SlackInputBlockElement::RadioButtons(element)
845    }
846}
847
848impl From<SlackBlockRadioButtonsElement> for SlackActionBlockElement {
849    fn from(element: SlackBlockRadioButtonsElement) -> Self {
850        SlackActionBlockElement::RadioButtons(element)
851    }
852}
853
854#[skip_serializing_none]
855#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
856pub struct SlackBlockCheckboxesElement {
857    pub action_id: SlackActionId,
858    pub options: Vec<SlackBlockChoiceItem<SlackBlockText>>,
859    pub initial_options: Option<Vec<SlackBlockChoiceItem<SlackBlockText>>>,
860    pub confirm: Option<SlackBlockConfirmItem>,
861    pub focus_on_load: Option<bool>,
862}
863
864impl From<SlackBlockCheckboxesElement> for SlackSectionBlockElement {
865    fn from(element: SlackBlockCheckboxesElement) -> Self {
866        SlackSectionBlockElement::Checkboxes(element)
867    }
868}
869
870impl From<SlackBlockCheckboxesElement> for SlackInputBlockElement {
871    fn from(element: SlackBlockCheckboxesElement) -> Self {
872        SlackInputBlockElement::Checkboxes(element)
873    }
874}
875
876impl From<SlackBlockCheckboxesElement> for SlackActionBlockElement {
877    fn from(element: SlackBlockCheckboxesElement) -> Self {
878        SlackActionBlockElement::Checkboxes(element)
879    }
880}
881
882/**
883 * 'plain_text' type of https://api.slack.com/reference/block-kit/composition-objects#text
884 */
885#[skip_serializing_none]
886#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
887pub struct SlackBlockPlainText {
888    pub text: String,
889    pub emoji: Option<bool>,
890}
891
892/**
893 * 'mrkdwn' type of https://api.slack.com/reference/block-kit/composition-objects#text
894 */
895#[skip_serializing_none]
896#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
897pub struct SlackBlockMarkDownText {
898    pub text: String,
899    pub verbatim: Option<bool>,
900}
901
902/**
903 * https://api.slack.com/reference/block-kit/composition-objects#text
904 */
905#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
906#[serde(tag = "type")]
907pub enum SlackBlockText {
908    #[serde(rename = "plain_text")]
909    Plain(SlackBlockPlainText),
910    #[serde(rename = "mrkdwn")]
911    MarkDown(SlackBlockMarkDownText),
912}
913
914#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
915#[serde(tag = "type", rename = "plain_text")]
916pub struct SlackBlockPlainTextOnly {
917    #[serde(flatten)]
918    value: SlackBlockPlainText,
919}
920
921impl SlackBlockPlainText {
922    pub fn as_block_text(&self) -> SlackBlockText {
923        SlackBlockText::Plain(self.clone())
924    }
925}
926
927impl From<String> for SlackBlockPlainText {
928    fn from(value: String) -> Self {
929        SlackBlockPlainText::new(value)
930    }
931}
932
933impl From<&str> for SlackBlockPlainText {
934    fn from(value: &str) -> Self {
935        SlackBlockPlainText::new(String::from(value))
936    }
937}
938
939impl SlackBlockMarkDownText {
940    pub fn as_block_text(&self) -> SlackBlockText {
941        SlackBlockText::MarkDown(self.clone())
942    }
943}
944
945impl From<String> for SlackBlockMarkDownText {
946    fn from(value: String) -> Self {
947        SlackBlockMarkDownText::new(value)
948    }
949}
950
951impl From<&str> for SlackBlockMarkDownText {
952    fn from(value: &str) -> Self {
953        SlackBlockMarkDownText::new(String::from(value))
954    }
955}
956
957impl From<SlackBlockPlainText> for SlackBlockPlainTextOnly {
958    fn from(pt: SlackBlockPlainText) -> Self {
959        SlackBlockPlainTextOnly { value: pt }
960    }
961}
962
963impl From<SlackBlockPlainText> for SlackBlockText {
964    fn from(text: SlackBlockPlainText) -> Self {
965        SlackBlockText::Plain(text)
966    }
967}
968
969impl From<SlackBlockMarkDownText> for SlackBlockText {
970    fn from(text: SlackBlockMarkDownText) -> Self {
971        SlackBlockText::MarkDown(text)
972    }
973}
974
975impl From<SlackBlockPlainText> for SlackContextBlockElement {
976    fn from(text: SlackBlockPlainText) -> Self {
977        SlackContextBlockElement::Plain(text)
978    }
979}
980
981impl From<SlackBlockMarkDownText> for SlackContextBlockElement {
982    fn from(text: SlackBlockMarkDownText) -> Self {
983        SlackContextBlockElement::MarkDown(text)
984    }
985}
986
987impl From<SlackBlockPlainTextOnly> for SlackBlockText {
988    fn from(text: SlackBlockPlainTextOnly) -> Self {
989        SlackBlockText::Plain(text.value)
990    }
991}
992
993impl From<String> for SlackBlockPlainTextOnly {
994    fn from(value: String) -> Self {
995        SlackBlockPlainTextOnly {
996            value: value.into(),
997        }
998    }
999}
1000
1001impl From<&str> for SlackBlockPlainTextOnly {
1002    fn from(value: &str) -> Self {
1003        SlackBlockPlainTextOnly {
1004            value: value.into(),
1005        }
1006    }
1007}
1008
1009/**
1010 * https://api.slack.com/reference/block-kit/blocks#video
1011 */
1012#[skip_serializing_none]
1013#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
1014pub struct SlackVideoBlock {
1015    pub alt_text: String,
1016    pub author_name: Option<String>,
1017    pub block_id: Option<SlackBlockId>,
1018    pub description: Option<SlackBlockPlainTextOnly>,
1019    pub provider_icon_url: Option<Url>,
1020    pub provider_name: Option<String>,
1021    pub title: SlackBlockPlainTextOnly,
1022    pub title_url: Option<Url>,
1023    pub thumbnail_url: Url,
1024    pub video_url: Url,
1025}
1026
1027impl From<SlackVideoBlock> for SlackBlock {
1028    fn from(block: SlackVideoBlock) -> Self {
1029        SlackBlock::Video(block)
1030    }
1031}
1032
1033/**
1034 * https://api.slack.com/reference/block-kit/blocks#markdown
1035 */
1036#[skip_serializing_none]
1037#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
1038pub struct SlackMarkdownBlock {
1039    pub block_id: Option<SlackBlockId>,
1040    pub text: String,
1041}
1042
1043impl From<SlackMarkdownBlock> for SlackBlock {
1044    fn from(block: SlackMarkdownBlock) -> Self {
1045        SlackBlock::Markdown(block)
1046    }
1047}
1048
1049#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1050#[serde(untagged)]
1051pub enum SlackImageUrlOrFile {
1052    ImageUrl { image_url: Url },
1053    SlackFile { slack_file: SlackFileIdOrUrl },
1054}
1055
1056impl SlackImageUrlOrFile {
1057    pub fn image_url(&self) -> Option<&Url> {
1058        match self {
1059            SlackImageUrlOrFile::ImageUrl { image_url } => Some(image_url),
1060            SlackImageUrlOrFile::SlackFile { slack_file } => match slack_file {
1061                SlackFileIdOrUrl::Url { url } => Some(url),
1062                _ => None,
1063            },
1064        }
1065    }
1066}
1067
1068impl From<Url> for SlackImageUrlOrFile {
1069    fn from(value: Url) -> Self {
1070        SlackImageUrlOrFile::ImageUrl { image_url: value }
1071    }
1072}
1073
1074#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1075#[serde(untagged)]
1076pub enum SlackFileIdOrUrl {
1077    Id { id: SlackFileId },
1078    Url { url: Url },
1079}
1080
1081impl From<SlackFileId> for SlackFileIdOrUrl {
1082    fn from(value: SlackFileId) -> Self {
1083        SlackFileIdOrUrl::Id { id: value }
1084    }
1085}
1086
1087#[cfg(test)]
1088mod test {
1089    use super::*;
1090    use crate::blocks::SlackHomeView;
1091
1092    #[test]
1093    fn test_slack_image_block_deserialize() -> Result<(), Box<dyn std::error::Error>> {
1094        let payload = include_str!("./fixtures/slack_image_blocks.json");
1095        let content: SlackMessageContent = serde_json::from_str(payload)?;
1096        let blocks = content.blocks.expect("Blocks should not be empty");
1097        match blocks.first() {
1098            Some(SlackBlock::Section(section)) => match &section.accessory {
1099                Some(SlackSectionBlockElement::Image(image)) => {
1100                    assert_eq!(image.alt_text, "alt text for image");
1101                    match &image.image_url_or_file {
1102                        SlackImageUrlOrFile::ImageUrl { image_url } => {
1103                            assert_eq!(image_url.as_str(), "https://s3-media3.fl.yelpcdn.com/bphoto/c7ed05m9lC2EmA3Aruue7A/o.jpg");
1104                        }
1105                        SlackImageUrlOrFile::SlackFile { slack_file } => {
1106                            panic!("Expected an image URL, not a Slack file: {:?}", slack_file);
1107                        }
1108                    }
1109                }
1110                _ => panic!("Expected a section block with an image accessory"),
1111            },
1112            _ => panic!("Expected a section block"),
1113        }
1114        Ok(())
1115    }
1116}