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