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