Skip to main content

slack_web_api/blocks/
composition.rs

1use serde::{Deserialize, Serialize};
2
3use super::tag::{tagged_enum, Tag, Tagged};
4
5tagged_enum! {
6    /// A text object (`plain_text` or `mrkdwn`). <https://docs.slack.dev/reference/block-kit/composition-objects/text-object>
7    pub enum TextObject("type") {
8        PlainText(PlainText),
9        Mrkdwn(Mrkdwn),
10    }
11}
12
13impl TextObject {
14    pub fn plain(text: impl Into<String>) -> Self {
15        PlainText::new(text).into()
16    }
17
18    pub fn mrkdwn(text: impl Into<String>) -> Self {
19        Mrkdwn::new(text).into()
20    }
21}
22
23/// A `plain_text` text object. <https://docs.slack.dev/reference/block-kit/composition-objects/text-object>
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25pub struct PlainText {
26    r#type: Tag<Self>,
27    pub text: String,
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub emoji: Option<bool>,
30}
31
32impl Tagged for PlainText {
33    const TAG: &'static str = "plain_text";
34}
35
36impl PlainText {
37    pub fn new(text: impl Into<String>) -> Self {
38        Self {
39            r#type: Tag::default(),
40            text: text.into(),
41            emoji: None,
42        }
43    }
44
45    pub fn emoji(mut self, emoji: bool) -> Self {
46        self.emoji = Some(emoji);
47        self
48    }
49}
50
51/// A `mrkdwn` text object. <https://docs.slack.dev/reference/block-kit/composition-objects/text-object>
52#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
53pub struct Mrkdwn {
54    r#type: Tag<Self>,
55    pub text: String,
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub verbatim: Option<bool>,
58}
59
60impl Tagged for Mrkdwn {
61    const TAG: &'static str = "mrkdwn";
62}
63
64impl Mrkdwn {
65    pub fn new(text: impl Into<String>) -> Self {
66        Self {
67            r#type: Tag::default(),
68            text: text.into(),
69            verbatim: None,
70        }
71    }
72
73    pub fn verbatim(mut self, verbatim: bool) -> Self {
74        self.verbatim = Some(verbatim);
75        self
76    }
77}
78
79/// A confirmation dialog. <https://docs.slack.dev/reference/block-kit/composition-objects/confirmation-dialog-object>
80#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
81pub struct ConfirmationDialog {
82    pub title: TextObject,
83    pub text: TextObject,
84    pub confirm: TextObject,
85    pub deny: TextObject,
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub style: Option<ButtonStyle>,
88}
89
90impl ConfirmationDialog {
91    pub fn new(
92        title: impl Into<TextObject>,
93        text: impl Into<TextObject>,
94        confirm: impl Into<TextObject>,
95        deny: impl Into<TextObject>,
96    ) -> Self {
97        Self {
98            title: title.into(),
99            text: text.into(),
100            confirm: confirm.into(),
101            deny: deny.into(),
102            style: None,
103        }
104    }
105
106    pub fn style(mut self, style: ButtonStyle) -> Self {
107        self.style = Some(style);
108        self
109    }
110}
111
112/// An option. <https://docs.slack.dev/reference/block-kit/composition-objects/option-object>
113#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
114pub struct OptionObject {
115    pub text: TextObject,
116    pub value: String,
117    #[serde(skip_serializing_if = "Option::is_none")]
118    pub description: Option<TextObject>,
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub url: Option<String>,
121}
122
123impl OptionObject {
124    pub fn new(text: impl Into<TextObject>, value: impl Into<String>) -> Self {
125        Self {
126            text: text.into(),
127            value: value.into(),
128            description: None,
129            url: None,
130        }
131    }
132
133    pub fn description(mut self, description: impl Into<TextObject>) -> Self {
134        self.description = Some(description.into());
135        self
136    }
137
138    pub fn url(mut self, url: impl Into<String>) -> Self {
139        self.url = Some(url.into());
140        self
141    }
142}
143
144/// A group of options. <https://docs.slack.dev/reference/block-kit/composition-objects/option-group-object>
145#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
146pub struct OptionGroup {
147    pub label: TextObject,
148    pub options: Vec<OptionObject>,
149}
150
151impl OptionGroup {
152    pub fn new(label: impl Into<TextObject>, options: Vec<OptionObject>) -> Self {
153        Self {
154            label: label.into(),
155            options,
156        }
157    }
158}
159
160/// A filter for conversation select menus. <https://docs.slack.dev/reference/block-kit/composition-objects/conversation-filter-object>
161#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
162pub struct ConversationFilter {
163    #[serde(default, skip_serializing_if = "Vec::is_empty")]
164    pub include: Vec<ConversationType>,
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub exclude_external_shared_channels: Option<bool>,
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub exclude_bot_users: Option<bool>,
169}
170
171impl ConversationFilter {
172    pub fn new() -> Self {
173        Self::default()
174    }
175
176    pub fn include(mut self, include: Vec<ConversationType>) -> Self {
177        self.include = include;
178        self
179    }
180
181    pub fn exclude_external_shared_channels(
182        mut self,
183        exclude_external_shared_channels: bool,
184    ) -> Self {
185        self.exclude_external_shared_channels = Some(exclude_external_shared_channels);
186        self
187    }
188
189    pub fn exclude_bot_users(mut self, exclude_bot_users: bool) -> Self {
190        self.exclude_bot_users = Some(exclude_bot_users);
191        self
192    }
193}
194
195/// Configures when typing in an input dispatches a `block_actions` payload. <https://docs.slack.dev/reference/block-kit/composition-objects/dispatch-action-configuration-object>
196#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
197pub struct DispatchActionConfig {
198    #[serde(default, skip_serializing_if = "Vec::is_empty")]
199    pub trigger_actions_on: Vec<TriggerAction>,
200}
201
202impl DispatchActionConfig {
203    pub fn new() -> Self {
204        Self::default()
205    }
206
207    pub fn trigger_actions_on(mut self, trigger_actions_on: Vec<TriggerAction>) -> Self {
208        self.trigger_actions_on = trigger_actions_on;
209        self
210    }
211}
212
213/// A Slack file used as an image (either `url` or `id`). <https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object>
214#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
215pub struct SlackFile {
216    #[serde(skip_serializing_if = "Option::is_none")]
217    pub url: Option<String>,
218    #[serde(skip_serializing_if = "Option::is_none")]
219    pub id: Option<String>,
220}
221
222impl SlackFile {
223    pub fn from_url(url: impl Into<String>) -> Self {
224        Self {
225            url: Some(url.into()),
226            id: None,
227        }
228    }
229
230    pub fn from_id(id: impl Into<String>) -> Self {
231        Self {
232            url: None,
233            id: Some(id.into()),
234        }
235    }
236
237    pub fn url(mut self, url: impl Into<String>) -> Self {
238        self.url = Some(url.into());
239        self
240    }
241
242    pub fn id(mut self, id: impl Into<String>) -> Self {
243        self.id = Some(id.into());
244        self
245    }
246}
247
248/// A built-in Slack icon. <https://docs.slack.dev/reference/block-kit/composition-objects/slack-icon-object>
249#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
250pub struct SlackIcon {
251    r#type: Tag<Self>,
252    pub name: String,
253}
254
255impl Tagged for SlackIcon {
256    const TAG: &'static str = "icon";
257}
258
259impl SlackIcon {
260    pub fn new(name: impl Into<String>) -> Self {
261        Self {
262            r#type: Tag::default(),
263            name: name.into(),
264        }
265    }
266}
267
268/// The workflow run by a workflow button. <https://docs.slack.dev/reference/block-kit/composition-objects/workflow-object>
269#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
270pub struct Workflow {
271    pub trigger: Trigger,
272}
273
274impl Workflow {
275    pub fn new(trigger: Trigger) -> Self {
276        Self { trigger }
277    }
278}
279
280/// A workflow link trigger. <https://docs.slack.dev/reference/block-kit/composition-objects/trigger-object>
281#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
282pub struct Trigger {
283    pub url: String,
284    #[serde(default, skip_serializing_if = "Vec::is_empty")]
285    pub customizable_input_parameters: Vec<InputParameter>,
286}
287
288impl Trigger {
289    pub fn new(url: impl Into<String>) -> Self {
290        Self {
291            url: url.into(),
292            customizable_input_parameters: Vec::new(),
293        }
294    }
295
296    pub fn customizable_input_parameters(
297        mut self,
298        customizable_input_parameters: Vec<InputParameter>,
299    ) -> Self {
300        self.customizable_input_parameters = customizable_input_parameters;
301        self
302    }
303}
304
305/// An input parameter passed to a trigger. <https://docs.slack.dev/reference/block-kit/composition-objects/trigger-object>
306#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
307pub struct InputParameter {
308    pub name: String,
309    pub value: String,
310}
311
312impl InputParameter {
313    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
314        Self {
315            name: name.into(),
316            value: value.into(),
317        }
318    }
319}
320
321/// The color scheme of a button. Unknown values go to `Other`.
322#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
323#[serde(rename_all = "snake_case")]
324pub enum ButtonStyle {
325    Primary,
326    Danger,
327    #[serde(untagged)]
328    Other(String),
329}
330
331/// A conversation type. Unknown values go to `Other`.
332#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
333#[serde(rename_all = "snake_case")]
334pub enum ConversationType {
335    Im,
336    Mpim,
337    Private,
338    Public,
339    #[serde(untagged)]
340    Other(String),
341}
342
343/// An event that dispatches a `block_actions` payload. Unknown values go to `Other`.
344#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
345#[serde(rename_all = "snake_case")]
346pub enum TriggerAction {
347    OnEnterPressed,
348    OnCharacterEntered,
349    #[serde(untagged)]
350    Other(String),
351}