1use serde::{Deserialize, Serialize};
2
3use super::tag::{tagged_enum, Tag, Tagged};
4
5tagged_enum! {
6 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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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}