Skip to main content

slack_messaging/blocks/elements/
rich_text_input.rs

1use crate::blocks::RichText;
2use crate::composition_objects::{DispatchActionConfiguration, Plain, Text};
3use crate::validators::*;
4
5use serde::Serialize;
6use slack_messaging_derive::Builder;
7
8/// [Rich text input element](https://docs.slack.dev/reference/block-kit/block-elements/rich-text-input-element)
9/// representation.
10///
11/// # Fields and Validations
12///
13/// For more details, see the [official
14/// documentation](https://docs.slack.dev/reference/block-kit/block-elements/rich-text-input-element).
15///
16/// | Field | Type | Required | Validation |
17/// |-------|------|----------|------------|
18/// | action_id | String | Yes | Max length 255 characters |
19/// | initial_value | [RichText] | No | N/A |
20/// | dispatch_action_config | [DispatchActionConfiguration] | No | N/A |
21/// | focus_on_load | bool | No | N/A |
22/// | placeholder | [Text]<[Plain]> | No | Max length 150 characters |
23///
24/// # Example
25///
26/// ```
27/// use slack_messaging::blocks::elements::RichTextInput;
28/// use slack_messaging::blocks::rich_text::prelude::*;
29/// # use std::error::Error;
30///
31/// # fn try_main() -> Result<(), Box<dyn Error>> {
32/// let rich_text = RichTextInput::builder()
33///     .action_id("rich_text_input-action")
34///     .initial_value(
35///         RichText::builder()
36///             .element(
37///                 RichTextSection::builder()
38///                     .element(
39///                         RichTextElementText::builder()
40///                             .text("Hello")
41///                             .build()?
42///                     )
43///                     .build()?
44///             )
45///             .build()?
46///     )
47///     .build()?;
48///
49/// let expected = serde_json::json!({
50///     "type": "rich_text_input",
51///     "action_id": "rich_text_input-action",
52///     "initial_value": {
53///         "type": "rich_text",
54///         "elements": [
55///             {
56///                 "type": "rich_text_section",
57///                 "elements": [
58///                     {
59///                         "type": "text",
60///                         "text": "Hello"
61///                     }
62///                 ]
63///             }
64///         ]
65///     }
66/// });
67///
68/// let json = serde_json::to_value(rich_text).unwrap();
69///
70/// assert_eq!(json, expected);
71///
72/// // If your object has any validation errors, the build method returns Result::Err
73/// let rich_text = RichTextInput::builder().build();
74///
75/// assert!(rich_text.is_err());
76/// #     Ok(())
77/// # }
78/// # fn main() {
79/// #     try_main().unwrap()
80/// # }
81/// ```
82#[derive(Debug, Clone, Serialize, PartialEq, Builder)]
83#[serde(tag = "type", rename = "rich_text_input")]
84pub struct RichTextInput {
85    #[serde(skip_serializing_if = "Option::is_none")]
86    #[builder(validate("required", "text::max_255"))]
87    pub(super) action_id: Option<String>,
88
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub(super) initial_value: Option<RichText>,
91
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub(super) dispatch_action_config: Option<DispatchActionConfiguration>,
94
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub(super) focus_on_load: Option<bool>,
97
98    #[serde(skip_serializing_if = "Option::is_none")]
99    #[builder(validate("text_object::max_150"))]
100    pub(super) placeholder: Option<Text<Plain>>,
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106    use crate::blocks::test_helpers::*;
107    use crate::composition_objects::test_helpers::*;
108    use crate::errors::*;
109
110    #[test]
111    fn it_implements_builder() {
112        let expected = RichTextInput {
113            action_id: Some("rich_text_input_0".into()),
114            initial_value: Some(rich_text()),
115            dispatch_action_config: Some(dispatch_action_config()),
116            focus_on_load: Some(true),
117            placeholder: Some(plain_text("Input text")),
118        };
119
120        let val = RichTextInput::builder()
121            .set_action_id(Some("rich_text_input_0"))
122            .set_initial_value(Some(rich_text()))
123            .set_dispatch_action_config(Some(dispatch_action_config()))
124            .set_focus_on_load(Some(true))
125            .set_placeholder(Some(plain_text("Input text")))
126            .build()
127            .unwrap();
128
129        assert_eq!(val, expected);
130
131        let val = RichTextInput::builder()
132            .action_id("rich_text_input_0")
133            .initial_value(rich_text())
134            .dispatch_action_config(dispatch_action_config())
135            .focus_on_load(true)
136            .placeholder(plain_text("Input text"))
137            .build()
138            .unwrap();
139
140        assert_eq!(val, expected);
141    }
142
143    #[test]
144    fn it_requries_action_id_field() {
145        let err = RichTextInput::builder().build().unwrap_err();
146        assert_eq!(err.object(), "RichTextInput");
147
148        let errors = err.field("action_id");
149        assert!(errors.includes(ValidationErrorKind::Required));
150    }
151
152    #[test]
153    fn it_requires_action_id_less_than_255_characters_long() {
154        let err = RichTextInput::builder()
155            .action_id("a".repeat(256))
156            .build()
157            .unwrap_err();
158        assert_eq!(err.object(), "RichTextInput");
159
160        let errors = err.field("action_id");
161        assert!(errors.includes(ValidationErrorKind::MaxTextLength(255)));
162    }
163
164    #[test]
165    fn it_requires_placeholder_less_than_150_characters_long() {
166        let err = RichTextInput::builder()
167            .action_id("rich_text_input_0")
168            .placeholder(plain_text("a".repeat(151)))
169            .build()
170            .unwrap_err();
171        assert_eq!(err.object(), "RichTextInput");
172
173        let errors = err.field("placeholder");
174        assert!(errors.includes(ValidationErrorKind::MaxTextLength(150)));
175    }
176}