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 = "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#[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#[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#[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#[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#[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 §ion.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}