Skip to main content

slack_web_api/blocks/
view.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5use super::block::Block;
6use super::composition::TextObject;
7
8/// A view for views.open / publish / update / push (the later fields are only returned by Slack). <https://docs.slack.dev/reference/views>
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub struct View {
11    pub r#type: ViewType,
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub title: Option<TextObject>,
14    pub blocks: Vec<Block>,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub close: Option<TextObject>,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub submit: Option<TextObject>,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub private_metadata: Option<String>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub callback_id: Option<String>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub clear_on_close: Option<bool>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub notify_on_close: Option<bool>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub external_id: Option<String>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub submit_disabled: Option<bool>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub id: Option<String>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub team_id: Option<String>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub state: Option<ViewState>,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub hash: Option<String>,
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub previous_view_id: Option<String>,
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub root_view_id: Option<String>,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub app_id: Option<String>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub app_installed_team_id: Option<String>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub bot_id: Option<String>,
49}
50
51impl View {
52    pub fn modal(title: impl Into<TextObject>, blocks: Vec<Block>) -> Self {
53        Self {
54            title: Some(title.into()),
55            ..Self::with_type(ViewType::Modal, blocks)
56        }
57    }
58
59    pub fn home(blocks: Vec<Block>) -> Self {
60        Self::with_type(ViewType::Home, blocks)
61    }
62
63    pub fn workflow_step(blocks: Vec<Block>) -> Self {
64        Self::with_type(ViewType::WorkflowStep, blocks)
65    }
66
67    fn with_type(r#type: ViewType, blocks: Vec<Block>) -> Self {
68        Self {
69            r#type,
70            title: None,
71            blocks,
72            close: None,
73            submit: None,
74            private_metadata: None,
75            callback_id: None,
76            clear_on_close: None,
77            notify_on_close: None,
78            external_id: None,
79            submit_disabled: None,
80            id: None,
81            team_id: None,
82            state: None,
83            hash: None,
84            previous_view_id: None,
85            root_view_id: None,
86            app_id: None,
87            app_installed_team_id: None,
88            bot_id: None,
89        }
90    }
91
92    pub fn title(mut self, title: impl Into<TextObject>) -> Self {
93        self.title = Some(title.into());
94        self
95    }
96
97    pub fn close(mut self, close: impl Into<TextObject>) -> Self {
98        self.close = Some(close.into());
99        self
100    }
101
102    pub fn submit(mut self, submit: impl Into<TextObject>) -> Self {
103        self.submit = Some(submit.into());
104        self
105    }
106
107    pub fn private_metadata(mut self, private_metadata: impl Into<String>) -> Self {
108        self.private_metadata = Some(private_metadata.into());
109        self
110    }
111
112    pub fn callback_id(mut self, callback_id: impl Into<String>) -> Self {
113        self.callback_id = Some(callback_id.into());
114        self
115    }
116
117    pub fn clear_on_close(mut self, clear_on_close: bool) -> Self {
118        self.clear_on_close = Some(clear_on_close);
119        self
120    }
121
122    pub fn notify_on_close(mut self, notify_on_close: bool) -> Self {
123        self.notify_on_close = Some(notify_on_close);
124        self
125    }
126
127    pub fn external_id(mut self, external_id: impl Into<String>) -> Self {
128        self.external_id = Some(external_id.into());
129        self
130    }
131
132    pub fn submit_disabled(mut self, submit_disabled: bool) -> Self {
133        self.submit_disabled = Some(submit_disabled);
134        self
135    }
136}
137
138/// The type of a view. Unknown values go to `Other`.
139#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
140#[serde(rename_all = "snake_case")]
141pub enum ViewType {
142    Modal,
143    Home,
144    WorkflowStep,
145    #[serde(untagged)]
146    Other(String),
147}
148
149/// Current input values (`block_id` -> `action_id` -> value). Kept as raw JSON because the shape differs by element type.
150#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
151pub struct ViewState {
152    pub values: BTreeMap<String, BTreeMap<String, serde_json::Value>>,
153}