slack_messaging/blocks/rich_text/
list.rs

1use super::RichTextSection;
2use crate::validators::*;
3
4use serde::Serialize;
5use slack_messaging_derive::Builder;
6
7/// [Rich text list element](https://docs.slack.dev/reference/block-kit/blocks/rich-text-block#rich_text_list)
8/// representation.
9///
10/// # Fields and Validations
11///
12/// For more details, see the [official
13/// documentation](https://docs.slack.dev/reference/block-kit/blocks/rich-text-block#rich_text_list).
14///
15/// | Field | Type | Required | Validation |
16/// |-------|------|----------|------------|
17/// | style | [ListStyle] | Yes | N/A |
18/// | elements | Vec<[RichTextSection]> | Yes | N/A |
19/// | indent | i64 | No | N/A |
20/// | offset | i64 | No | N/A |
21/// | border | i64 | No | N/A |
22///
23/// # Example
24///
25/// ```
26/// use slack_messaging::blocks::rich_text::{RichTextList, ListStyle, RichTextSection};
27/// use slack_messaging::blocks::rich_text::types::RichTextElementText;
28/// # use std::error::Error;
29///
30/// # fn try_main() -> Result<(), Box<dyn Error>> {
31/// let list = RichTextList::builder()
32///     .element(
33///         RichTextSection::builder()
34///             .element(
35///                 RichTextElementText::builder()
36///                     .text("Huddles")
37///                     .build()?
38///             )
39///             .build()?
40///     )
41///     .element(
42///         RichTextSection::builder()
43///             .element(
44///                 RichTextElementText::builder()
45///                     .text("Canvas")
46///                     .build()?
47///             )
48///             .build()?
49///     )
50///     .style(ListStyle::Bullet)
51///     .indent(0)
52///     .border(1)
53///     .build()?;
54///
55/// let expected = serde_json::json!({
56///     "type": "rich_text_list",
57///     "elements": [
58///         {
59///             "type": "rich_text_section",
60///             "elements": [
61///                 {
62///                     "type": "text",
63///                     "text": "Huddles",
64///                 }
65///             ]
66///         },
67///         {
68///             "type": "rich_text_section",
69///             "elements": [
70///                 {
71///                     "type": "text",
72///                     "text": "Canvas",
73///                 }
74///             ]
75///         }
76///     ],
77///     "style": "bullet",
78///     "indent": 0,
79///     "border": 1
80/// });
81///
82/// let json = serde_json::to_value(list).unwrap();
83///
84/// assert_eq!(json, expected);
85///
86/// // If your object has any validation errors, the build method returns Result::Err
87/// let list = RichTextList::builder().build();
88/// assert!(list.is_err());
89/// #     Ok(())
90/// # }
91/// # fn main() {
92/// #     try_main().unwrap()
93/// # }
94/// ```
95#[derive(Debug, Clone, Serialize, PartialEq, Builder)]
96#[serde(tag = "type", rename = "rich_text_list")]
97pub struct RichTextList {
98    #[builder(validate("required"))]
99    pub(crate) style: Option<ListStyle>,
100
101    #[builder(push_item = "element", validate("required"))]
102    pub(crate) elements: Option<Vec<RichTextSection>>,
103
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub(crate) indent: Option<i64>,
106
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub(crate) offset: Option<i64>,
109
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub(crate) border: Option<i64>,
112}
113
114/// List style for [`RichTextList`].
115#[derive(Debug, Clone, Serialize, PartialEq)]
116#[serde(rename_all = "snake_case")]
117pub enum ListStyle {
118    /// Bullet list style.
119    Bullet,
120    /// Ordered list style.
121    Ordered,
122}
123
124#[cfg(test)]
125mod tests {
126    use super::*;
127    use crate::blocks::rich_text::{test_helpers::*, types::test_helpers::*};
128    use crate::errors::*;
129
130    #[test]
131    fn it_implements_builder() {
132        let expected = RichTextList {
133            style: Some(ListStyle::Bullet),
134            elements: Some(vec![
135                section(vec![el_text("foo")]),
136                section(vec![el_text("bar")]),
137            ]),
138            indent: Some(1),
139            offset: Some(2),
140            border: Some(3),
141        };
142
143        let val = RichTextList::builder()
144            .set_style(Some(ListStyle::Bullet))
145            .set_elements(Some(vec![
146                section(vec![el_text("foo")]),
147                section(vec![el_text("bar")]),
148            ]))
149            .set_indent(Some(1))
150            .set_offset(Some(2))
151            .set_border(Some(3))
152            .build()
153            .unwrap();
154
155        assert_eq!(val, expected);
156
157        let val = RichTextList::builder()
158            .style(ListStyle::Bullet)
159            .elements(vec![
160                section(vec![el_text("foo")]),
161                section(vec![el_text("bar")]),
162            ])
163            .indent(1)
164            .offset(2)
165            .border(3)
166            .build()
167            .unwrap();
168
169        assert_eq!(val, expected);
170    }
171
172    #[test]
173    fn it_implements_push_item_method() {
174        let expected = RichTextList {
175            style: Some(ListStyle::Ordered),
176            elements: Some(vec![
177                section(vec![el_text("foo")]),
178                section(vec![el_text("bar")]),
179            ]),
180            indent: None,
181            offset: None,
182            border: None,
183        };
184
185        let val = RichTextList::builder()
186            .style(ListStyle::Ordered)
187            .element(section(vec![el_text("foo")]))
188            .element(section(vec![el_text("bar")]))
189            .build()
190            .unwrap();
191
192        assert_eq!(val, expected);
193    }
194
195    #[test]
196    fn it_requires_style_field() {
197        let err = RichTextList::builder()
198            .element(section(vec![el_text("foo")]))
199            .build()
200            .unwrap_err();
201        assert_eq!(err.object(), "RichTextList");
202
203        let errors = err.field("style");
204        assert!(errors.includes(ValidationErrorKind::Required));
205    }
206
207    #[test]
208    fn it_requires_elements_field() {
209        let err = RichTextList::builder()
210            .style(ListStyle::Ordered)
211            .build()
212            .unwrap_err();
213        assert_eq!(err.object(), "RichTextList");
214
215        let errors = err.field("elements");
216        assert!(errors.includes(ValidationErrorKind::Required));
217    }
218}