lib_client_slack/
blocks.rs1use serde::Serialize;
2
3#[derive(Debug, Clone, Serialize)]
5#[serde(tag = "type", rename_all = "snake_case")]
6pub enum Block {
7 Section(SectionBlock),
8 Divider,
9 Header(HeaderBlock),
10 Context(ContextBlock),
11 Actions(ActionsBlock),
12 Image(ImageBlock),
13}
14
15#[derive(Debug, Clone, Serialize)]
17pub struct SectionBlock {
18 pub text: TextObject,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub accessory: Option<BlockElement>,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub fields: Option<Vec<TextObject>>,
23}
24
25#[derive(Debug, Clone, Serialize)]
27pub struct HeaderBlock {
28 pub text: TextObject,
29}
30
31#[derive(Debug, Clone, Serialize)]
33pub struct ContextBlock {
34 pub elements: Vec<ContextElement>,
35}
36
37#[derive(Debug, Clone, Serialize)]
39pub struct ActionsBlock {
40 pub elements: Vec<BlockElement>,
41}
42
43#[derive(Debug, Clone, Serialize)]
45pub struct ImageBlock {
46 pub image_url: String,
47 pub alt_text: String,
48 #[serde(skip_serializing_if = "Option::is_none")]
49 pub title: Option<TextObject>,
50}
51
52#[derive(Debug, Clone, Serialize)]
54pub struct TextObject {
55 #[serde(rename = "type")]
56 pub text_type: TextType,
57 pub text: String,
58 #[serde(skip_serializing_if = "Option::is_none")]
59 pub emoji: Option<bool>,
60}
61
62#[derive(Debug, Clone, Serialize)]
63#[serde(rename_all = "snake_case")]
64pub enum TextType {
65 PlainText,
66 Mrkdwn,
67}
68
69impl TextObject {
70 pub fn plain(text: impl Into<String>) -> Self {
71 Self {
72 text_type: TextType::PlainText,
73 text: text.into(),
74 emoji: Some(true),
75 }
76 }
77
78 pub fn mrkdwn(text: impl Into<String>) -> Self {
79 Self {
80 text_type: TextType::Mrkdwn,
81 text: text.into(),
82 emoji: None,
83 }
84 }
85}
86
87#[derive(Debug, Clone, Serialize)]
89#[serde(untagged)]
90pub enum ContextElement {
91 Text(TextObject),
92 Image { type_: String, image_url: String, alt_text: String },
93}
94
95#[derive(Debug, Clone, Serialize)]
97#[serde(tag = "type", rename_all = "snake_case")]
98pub enum BlockElement {
99 Button(ButtonElement),
100 StaticSelect(StaticSelectElement),
101 Overflow(OverflowElement),
102}
103
104#[derive(Debug, Clone, Serialize)]
106pub struct ButtonElement {
107 pub text: TextObject,
108 pub action_id: String,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub value: Option<String>,
111 #[serde(skip_serializing_if = "Option::is_none")]
112 pub url: Option<String>,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub style: Option<ButtonStyle>,
115}
116
117#[derive(Debug, Clone, Serialize)]
118#[serde(rename_all = "lowercase")]
119pub enum ButtonStyle {
120 Primary,
121 Danger,
122}
123
124#[derive(Debug, Clone, Serialize)]
126pub struct StaticSelectElement {
127 pub placeholder: TextObject,
128 pub action_id: String,
129 pub options: Vec<SelectOption>,
130}
131
132#[derive(Debug, Clone, Serialize)]
134pub struct SelectOption {
135 pub text: TextObject,
136 pub value: String,
137}
138
139#[derive(Debug, Clone, Serialize)]
141pub struct OverflowElement {
142 pub action_id: String,
143 pub options: Vec<SelectOption>,
144}
145
146impl Block {
148 pub fn section(text: TextObject) -> Self {
149 Self::Section(SectionBlock {
150 text,
151 accessory: None,
152 fields: None,
153 })
154 }
155
156 pub fn divider() -> Self {
157 Self::Divider
158 }
159
160 pub fn header(text: impl Into<String>) -> Self {
161 Self::Header(HeaderBlock {
162 text: TextObject::plain(text),
163 })
164 }
165
166 pub fn context(elements: Vec<ContextElement>) -> Self {
167 Self::Context(ContextBlock { elements })
168 }
169}