diff --git a/CHANGELOG.md b/CHANGELOG.md index 4659c54..38ea266 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [0.3.0][] - 2024-04-09 + +- https://github.com/kaicoh/slack-messaging/pull/8 Builder pattern. +- https://github.com/kaicoh/slack-messaging/pull/8 Remove `Attachment` (since it's a deprecated legacy feature). +- https://github.com/kaicoh/slack-messaging/pull/8 Support `Rich text` block. + ## [0.2.2][] - 2023-03-02 - https://github.com/kaicoh/slack-messaging/pull/6 Add `mrkdwn` and `plain_text` macros. @@ -16,6 +22,7 @@ - pre-release +[0.3.0]: https://github.com/kaicoh/slack-messaging/releases/v0.3.0 [0.2.2]: https://github.com/kaicoh/slack-messaging/releases/v0.2.2 [0.2.1]: https://github.com/kaicoh/slack-messaging/releases/v0.2.1 [0.2.0]: https://github.com/kaicoh/slack-messaging/releases/v0.2.0 diff --git a/Cargo.toml b/Cargo.toml index 0d6a6ad..7c772a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "slack-messaging" -version = "0.2.2" +version = "0.3.0" authors = ["kaicoh "] edition = "2021" keywords = ["slack", "messaging", "webhook"] @@ -17,10 +17,10 @@ all-features = true chrono = { version = "0.4", optional = true } regex = { version = "1.7", optional = true } serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" [dev-dependencies] reqwest = { version = "0.11", features = ["json"] } -serde_json = "1.0" tokio = { version = "1", features = ["full"] } [features] diff --git a/LICENSE b/LICENSE index c620722..4275d6c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Kanji Tanaka +Copyright (c) 2024 Kanji Tanaka Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index e71bd62..74cd552 100644 --- a/README.md +++ b/README.md @@ -8,36 +8,42 @@ This is a library for [Rust](https://www.rust-lang.org/) to support building mes Using this, you can build any messages in type-safe way like following. ```rust -use slack_messaging::Message; +use slack_messaging::{mrkdwn, Message}; use slack_messaging::blocks::{elements::Button, Actions, Section}; #[tokio::main] async fn main() { - let message = Message::new() - .push_block( - Section::new() - .set_text_mrkdwn("You have a new request:\n**") + let message = Message::builder() + .block( + Section::builder() + .text(mrkdwn!("You have a new request:\n**")) + .build() ) - .push_block( - Section::new() - .push_field_mrkdwn("*Type:*\nComputer (laptop)") - .push_field_mrkdwn("*When:*\nSubmitted Aut 10") + .block( + Section::builder() + .field(mrkdwn!("*Type:*\nComputer (laptop)")) + .field(mrkdwn!("*When:*\nSubmitted Aug 10")) + .build() ) - .push_block( - Actions::new() - .push_element( - Button::new() + .block( + Actions::builder() + .element( + Button::builder() .text("Approve") - .set_value("approve") - .set_primary() + .value("approve") + .primary() + .build() ) - .push_element( - Button::new() + .element( + Button::builder() .text("Deny") - .set_value("deny") - .set_danger() + .value("deny") + .danger() + .build() ) - ); + .build() + ) + .build(); let req = reqwest::Client::new() .post("https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX") @@ -70,7 +76,7 @@ The message payload of the above example is following. }, { "type": "mrkdwn", - "text": "*When:*\nSubmitted Aut 10" + "text": "*When:*\nSubmitted Aug 10" } ] }, @@ -81,8 +87,7 @@ The message payload of the above example is following. "type": "button", "text": { "type": "plain_text", - "text": "Approve", - "emoji": true + "text": "Approve" }, "value": "approve", "style": "primary" @@ -91,8 +96,7 @@ The message payload of the above example is following. "type": "button", "text": { "type": "plain_text", - "text": "Deny", - "emoji": true + "text": "Deny" }, "value": "deny", "style": "danger" diff --git a/src/attachment.rs b/src/attachment.rs deleted file mode 100644 index 9f71679..0000000 --- a/src/attachment.rs +++ /dev/null @@ -1,250 +0,0 @@ -use super::blocks::Block; -use serde::Serialize; - -/// [Secondary message attachment](https://api.slack.com/reference/messaging/attachments) -/// representation. -/// -/// # Example -/// -/// See also [Context](crate::blocks::Context), [Section](crate::blocks::Section) -/// and [any other blocks](crate::blocks) to know how to build these blocks. -/// -/// ``` -/// use slack_messaging::Attachment; -/// use slack_messaging::blocks::{Context, Section}; -/// use slack_messaging::blocks::elements::{Image, Text}; -/// use serde_json::json; -/// -/// let author = Context::new() -/// .push_element( -/// Image::new() -/// .set_image_url("https://placeimg.com/16/16/people") -/// .set_alt_text("author") -/// ) -/// .push_element( -/// Text::mrkdwn("**") -/// ); -/// -/// let content = Section::new() -/// .set_text_mrkdwn("Optional `text` that appears within the attachment") -/// .push_field_mrkdwn("*A 1st field's title*\nA 1st field's value") -/// .push_field_mrkdwn("*A 2nd field's title*\nA 2nd field's value") -/// .set_accessory( -/// Image::new() -/// .set_image_url("http://placekitten.com/g/200/200") -/// .set_alt_text("cute kitten") -/// ); -/// -/// let footer = Context::new() -/// .push_element( -/// Image::new() -/// .set_image_url("https://platform.slack-edge.com/img/default_application_icon.png") -/// .set_alt_text("footer icon") -/// ) -/// .push_element( -/// Text::mrkdwn("footer | ") -/// ); -/// -/// let attachment = Attachment::new() -/// .set_color("#36a64f") -/// .push_block(author) -/// .push_block(content) -/// .push_block(footer); -/// -/// let expected = json!({ -/// "color": "#36a64f", -/// "blocks": [ -/// { -/// "type": "context", -/// "elements": [ -/// { -/// "type": "image", -/// "image_url": "https://placeimg.com/16/16/people", -/// "alt_text": "author" -/// }, -/// { -/// "type": "mrkdwn", -/// "text": "**" -/// } -/// ] -/// }, -/// { -/// "type": "section", -/// "text": { -/// "type": "mrkdwn", -/// "text": "Optional `text` that appears within the attachment" -/// }, -/// "fields": [ -/// { -/// "type": "mrkdwn", -/// "text": "*A 1st field's title*\nA 1st field's value" -/// }, -/// { -/// "type": "mrkdwn", -/// "text": "*A 2nd field's title*\nA 2nd field's value" -/// } -/// ], -/// "accessory": { -/// "type": "image", -/// "image_url": "http://placekitten.com/g/200/200", -/// "alt_text": "cute kitten" -/// } -/// }, -/// { -/// "type": "context", -/// "elements": [ -/// { -/// "type": "image", -/// "image_url": "https://platform.slack-edge.com/img/default_application_icon.png", -/// "alt_text": "footer icon" -/// }, -/// { -/// "type": "mrkdwn", -/// "text": "footer | " -/// } -/// ] -/// } -/// ] -/// }); -/// -/// let attachment_json = serde_json::to_value(attachment).unwrap(); -/// -/// assert_eq!(attachment_json, expected); -/// ``` -#[derive(Debug, Default, Clone, Serialize)] -pub struct Attachment { - #[serde(skip_serializing_if = "Vec::is_empty")] - blocks: Vec, - - #[serde(skip_serializing_if = "Option::is_none")] - color: Option, -} - -impl Attachment { - /// Constructs an Attachment. - /// - /// ``` - /// use slack_messaging::Attachment; - /// use serde_json::json; - /// - /// let attachment = Attachment::new(); - /// let expected = json!({}); - /// let attachment_json = serde_json::to_value(attachment).unwrap(); - /// - /// assert_eq!(attachment_json, expected); - /// ``` - pub fn new() -> Self { - Self::default() - } - - /// Sets color field. - /// - /// ``` - /// use slack_messaging::Attachment; - /// use serde_json::json; - /// - /// let attachment = Attachment::new().set_color("#FFFFFF"); - /// let expected = json!({ - /// "color": "#FFFFFF" - /// }); - /// let attachment_json = serde_json::to_value(attachment).unwrap(); - /// - /// assert_eq!(attachment_json, expected); - /// ``` - pub fn set_color>(self, color: T) -> Self { - Self { - color: Some(color.into()), - ..self - } - } - - /// Sets blocks field directly. The argument is a vector composed from any objects - /// that can transform into the enum [Block](crate::blocks::Block). - /// - /// ``` - /// use slack_messaging::Attachment; - /// use slack_messaging::blocks::{Context, Section}; - /// use slack_messaging::blocks::elements::Text; - /// use serde_json::json; - /// - /// let attachment = Attachment::new() - /// .set_blocks( - /// vec![ - /// Context::new().push_element(Text::mrkdwn("*title*")).into(), - /// Section::new().set_text_mrkdwn("content").into() - /// ] - /// ); - /// - /// let expected = json!({ - /// "blocks": [ - /// { - /// "type": "context", - /// "elements": [ - /// { - /// "type": "mrkdwn", - /// "text": "*title*" - /// } - /// ] - /// }, - /// { - /// "type": "section", - /// "text": { - /// "type": "mrkdwn", - /// "text": "content" - /// } - /// } - /// ] - /// }); - /// - /// let attachment_json = serde_json::to_value(attachment).unwrap(); - /// - /// assert_eq!(attachment_json, expected); - /// ``` - pub fn set_blocks(self, blocks: Vec) -> Self { - Self { blocks, ..self } - } - - /// Adds an object to blocks field. The argument is an any object - /// that can transform into the enum [Block](crate::blocks::Block). - /// - /// ``` - /// use slack_messaging::Attachment; - /// use slack_messaging::blocks::{Context, Section}; - /// use slack_messaging::blocks::elements::Text; - /// use serde_json::json; - /// - /// let attachment = Attachment::new() - /// .push_block(Context::new().push_element(Text::mrkdwn("*title*"))) - /// .push_block(Section::new().set_text_mrkdwn("content")); - /// - /// let expected = json!({ - /// "blocks": [ - /// { - /// "type": "context", - /// "elements": [ - /// { - /// "type": "mrkdwn", - /// "text": "*title*" - /// } - /// ] - /// }, - /// { - /// "type": "section", - /// "text": { - /// "type": "mrkdwn", - /// "text": "content" - /// } - /// } - /// ] - /// }); - /// - /// let attachment_json = serde_json::to_value(attachment).unwrap(); - /// - /// assert_eq!(attachment_json, expected); - /// ``` - pub fn push_block>(self, block: T) -> Self { - let Self { mut blocks, .. } = self; - blocks.push(block.into()); - Self { blocks, ..self } - } -} diff --git a/src/blocks/actions.rs b/src/blocks/actions.rs index 0fe4475..9e80e6e 100644 --- a/src/blocks/actions.rs +++ b/src/blocks/actions.rs @@ -1,8 +1,8 @@ use super::elements::{ - Button, CheckboxGroup, DatePicker, DatetimePicker, MultiSelectConversations, - MultiSelectExternals, MultiSelectPublicChannels, MultiSelectStaticOptions, MultiSelectUsers, - OverflowMenu, RadioButtonGroup, SelectConversations, SelectExternals, SelectPublicChannels, - SelectStaticOptions, SelectUsers, TimePicker, + Button, Checkboxes, DatePicker, DatetimePicker, MultiSelectConversations, MultiSelectExternals, + MultiSelectPublicChannels, MultiSelectStaticOptions, MultiSelectUsers, OverflowMenu, + RadioButtonGroup, SelectConversations, SelectExternals, SelectPublicChannels, + SelectStaticOptions, SelectUsers, TimePicker, WorkflowButton, }; use serde::Serialize; @@ -14,29 +14,35 @@ use serde::Serialize; /// The following is reproduction of [the 1st sample actions](https://api.slack.com/reference/block-kit/blocks#actions_examples). /// /// ``` -/// use slack_messaging::blocks::Actions; -/// use slack_messaging::blocks::elements::{Button, SelectStaticOptions, Opt}; -/// use serde_json::json; -/// -/// let actions = Actions::new() -/// .set_block_id("actions1") -/// .push_element( -/// SelectStaticOptions::new() -/// .set_action_id("select_2") +/// # use slack_messaging::blocks::Actions; +/// # use slack_messaging::blocks::elements::{Button, SelectStaticOptions}; +/// # use slack_messaging::composition_objects::Opt; +/// let actions = Actions::builder() +/// .block_id("actions1") +/// .element( +/// SelectStaticOptions::builder() +/// .action_id("select_2") /// .placeholder("Which witch is the witchiest witch?") -/// .push_option(Opt::plain("Matilda").set_value("matilda")) -/// .push_option(Opt::plain("Glinda").set_value("glinda")) -/// .push_option(Opt::plain("Granny Weatherwax").set_value("grannyWeatherwax")) -/// .push_option(Opt::plain("Hermione").set_value("hermione")) +/// .set_options( +/// vec![ +/// Opt::builder().text("Matilda").value("matilda").build(), +/// Opt::builder().text("Glinda").value("glinda").build(), +/// Opt::builder().text("Granny Weatherwax").value("grannyWeatherwax").build(), +/// Opt::builder().text("Hermione").value("hermione").build(), +/// ] +/// ) +/// .build() /// ) -/// .push_element( -/// Button::new() -/// .set_action_id("button_1") -/// .set_value("cancel") +/// .element( +/// Button::builder() +/// .action_id("button_1") +/// .value("cancel") /// .text("Cancel") -/// ); +/// .build() +/// ) +/// .build(); /// -/// let expected = json!({ +/// let expected = serde_json::json!({ /// "type": "actions", /// "block_id": "actions1", /// "elements": [ @@ -45,39 +51,34 @@ use serde::Serialize; /// "action_id": "select_2", /// "placeholder": { /// "type": "plain_text", -/// "text": "Which witch is the witchiest witch?", -/// "emoji": true +/// "text": "Which witch is the witchiest witch?" /// }, /// "options": [ /// { /// "text": { /// "type": "plain_text", -/// "text": "Matilda", -/// "emoji": true +/// "text": "Matilda" /// }, /// "value": "matilda" /// }, /// { /// "text": { /// "type": "plain_text", -/// "text": "Glinda", -/// "emoji": true +/// "text": "Glinda" /// }, /// "value": "glinda" /// }, /// { /// "text": { /// "type": "plain_text", -/// "text": "Granny Weatherwax", -/// "emoji": true +/// "text": "Granny Weatherwax" /// }, /// "value": "grannyWeatherwax" /// }, /// { /// "text": { /// "type": "plain_text", -/// "text": "Hermione", -/// "emoji": true +/// "text": "Hermione" /// }, /// "value": "hermione" /// } @@ -87,8 +88,7 @@ use serde::Serialize; /// "type": "button", /// "text": { /// "type": "plain_text", -/// "text": "Cancel", -/// "emoji": true +/// "text": "Cancel" /// }, /// "value": "cancel", /// "action_id": "button_1" @@ -96,43 +96,46 @@ use serde::Serialize; /// ] /// }); /// -/// let actions_json = serde_json::to_value(actions).unwrap(); +/// let json = serde_json::to_value(actions).unwrap(); /// -/// assert_eq!(actions_json, expected); +/// assert_eq!(json, expected); /// ``` /// /// And the following is the [2nd sample actions](https://api.slack.com/reference/block-kit/blocks#actions_examples). /// /// ``` -/// use slack_messaging::blocks::Actions; -/// use slack_messaging::blocks::elements::{Button, DatePicker, Opt, OverflowMenu}; -/// use serde_json::json; -/// -/// let actions = Actions::new() -/// .set_block_id("actionblock789") -/// .push_element( -/// DatePicker::new() -/// .set_action_id("datepicker123") -/// .set_initial_date("1990-04-28") +/// # use slack_messaging::blocks::Actions; +/// # use slack_messaging::blocks::elements::{Button, DatePicker, OverflowMenu}; +/// # use slack_messaging::composition_objects::Opt; +/// let actions = Actions::builder() +/// .block_id("actionblock789") +/// .element( +/// DatePicker::builder() +/// .action_id("datepicker123") +/// .initial_date("1990-04-28") /// .placeholder("Select a date") +/// .build() /// ) -/// .push_element( -/// OverflowMenu::new() -/// .set_action_id("overflow") -/// .push_option(Opt::plain("*this is plain_text text*").set_value("value-0")) -/// .push_option(Opt::plain("*this is plain_text text*").set_value("value-1")) -/// .push_option(Opt::plain("*this is plain_text text*").set_value("value-2")) -/// .push_option(Opt::plain("*this is plain_text text*").set_value("value-3")) -/// .push_option(Opt::plain("*this is plain_text text*").set_value("value-4")) +/// .element( +/// OverflowMenu::builder() +/// .action_id("overflow") +/// .option(Opt::builder().text("*this is plain_text text*").value("value-0").build()) +/// .option(Opt::builder().text("*this is plain_text text*").value("value-1").build()) +/// .option(Opt::builder().text("*this is plain_text text*").value("value-2").build()) +/// .option(Opt::builder().text("*this is plain_text text*").value("value-3").build()) +/// .option(Opt::builder().text("*this is plain_text text*").value("value-4").build()) +/// .build() /// ) -/// .push_element( -/// Button::new() -/// .set_action_id("button") -/// .set_value("click_me_123") +/// .element( +/// Button::builder() +/// .action_id("button") +/// .value("click_me_123") /// .text("Click Me") -/// ); +/// .build() +/// ) +/// .build(); /// -/// let expected = json!({ +/// let expected = serde_json::json!({ /// "type": "actions", /// "block_id": "actionblock789", /// "elements": [ @@ -142,8 +145,7 @@ use serde::Serialize; /// "initial_date": "1990-04-28", /// "placeholder": { /// "type": "plain_text", -/// "text": "Select a date", -/// "emoji": true +/// "text": "Select a date" /// } /// }, /// { @@ -153,40 +155,35 @@ use serde::Serialize; /// { /// "text": { /// "type": "plain_text", -/// "text": "*this is plain_text text*", -/// "emoji": true +/// "text": "*this is plain_text text*" /// }, /// "value": "value-0" /// }, /// { /// "text": { /// "type": "plain_text", -/// "text": "*this is plain_text text*", -/// "emoji": true +/// "text": "*this is plain_text text*" /// }, /// "value": "value-1" /// }, /// { /// "text": { /// "type": "plain_text", -/// "text": "*this is plain_text text*", -/// "emoji": true +/// "text": "*this is plain_text text*" /// }, /// "value": "value-2" /// }, /// { /// "text": { /// "type": "plain_text", -/// "text": "*this is plain_text text*", -/// "emoji": true +/// "text": "*this is plain_text text*" /// }, /// "value": "value-3" /// }, /// { /// "text": { /// "type": "plain_text", -/// "text": "*this is plain_text text*", -/// "emoji": true +/// "text": "*this is plain_text text*" /// }, /// "value": "value-4" /// } @@ -196,8 +193,7 @@ use serde::Serialize; /// "type": "button", /// "text": { /// "type": "plain_text", -/// "text": "Click Me", -/// "emoji": true +/// "text": "Click Me" /// }, /// "value": "click_me_123", /// "action_id": "button" @@ -205,212 +201,20 @@ use serde::Serialize; /// ] /// }); /// -/// let actions_json = serde_json::to_value(actions).unwrap(); +/// let json = serde_json::to_value(actions).unwrap(); /// -/// assert_eq!(actions_json, expected); +/// assert_eq!(json, expected); /// ``` /// #[derive(Debug, Clone, Serialize)] pub struct Actions { #[serde(rename = "type")] - kind: &'static str, + pub(super) kind: &'static str, - elements: Vec, + pub(super) elements: Vec, #[serde(skip_serializing_if = "Option::is_none")] - block_id: Option, -} - -impl Default for Actions { - fn default() -> Self { - Self { - kind: "actions", - elements: vec![], - block_id: None, - } - } -} - -impl Actions { - /// Constructs an Actions block. - /// - /// ``` - /// use slack_messaging::blocks::Actions; - /// use serde_json::json; - /// - /// let actions = Actions::new(); - /// - /// let expected = json!({ - /// "type": "actions", - /// "elements": [] - /// }); - /// - /// let actions_json = serde_json::to_value(actions).unwrap(); - /// - /// assert_eq!(actions_json, expected); - /// ``` - pub fn new() -> Self { - Self::default() - } - - /// Sets elements field directly. The argument is a vector composed from any objects - /// that can transform into the enum [ActionsElement]. - /// - /// ``` - /// use slack_messaging::blocks::Actions; - /// use slack_messaging::blocks::elements::{Button, SelectStaticOptions, Opt}; - /// use serde_json::json; - /// - /// let actions = Actions::new() - /// .set_elements( - /// vec![ - /// SelectStaticOptions::new() - /// .set_action_id("select_2") - /// .placeholder("Which witch is the witchiest witch?") - /// .push_option(Opt::plain("Matilda").set_value("matilda")) - /// .push_option(Opt::plain("Glinda").set_value("glinda")) - /// .into(), - /// Button::new() - /// .set_action_id("button_1") - /// .set_value("cancel") - /// .text("Cancel") - /// .into(), - /// ] - /// ); - /// - /// let expected = json!({ - /// "type": "actions", - /// "elements": [ - /// { - /// "type": "static_select", - /// "action_id": "select_2", - /// "placeholder": { - /// "type": "plain_text", - /// "text": "Which witch is the witchiest witch?", - /// "emoji": true - /// }, - /// "options": [ - /// { - /// "text": { - /// "type": "plain_text", - /// "text": "Matilda", - /// "emoji": true - /// }, - /// "value": "matilda" - /// }, - /// { - /// "text": { - /// "type": "plain_text", - /// "text": "Glinda", - /// "emoji": true - /// }, - /// "value": "glinda" - /// } - /// ] - /// }, - /// { - /// "type": "button", - /// "text": { - /// "type": "plain_text", - /// "text": "Cancel", - /// "emoji": true - /// }, - /// "value": "cancel", - /// "action_id": "button_1" - /// } - /// ] - /// }); - /// - /// let actions_json = serde_json::to_value(actions).unwrap(); - /// - /// assert_eq!(actions_json, expected); - /// ``` - pub fn set_elements(self, elements: Vec) -> Self { - Self { elements, ..self } - } - - /// Adds an object to elements field. The argument is an any object - /// that can transform into the enum [ActionsElement]. - /// - /// ``` - /// use slack_messaging::blocks::Actions; - /// use slack_messaging::blocks::elements::{Button, DatePicker}; - /// use serde_json::json; - /// - /// let actions = Actions::new() - /// .push_element( - /// DatePicker::new() - /// .set_action_id("datepicker123") - /// .set_initial_date("1990-04-28") - /// .placeholder("Select a date") - /// ) - /// .push_element( - /// Button::new() - /// .set_action_id("button") - /// .set_value("click_me_123") - /// .text("Click Me") - /// ); - /// - /// let expected = json!({ - /// "type": "actions", - /// "elements": [ - /// { - /// "type": "datepicker", - /// "action_id": "datepicker123", - /// "initial_date": "1990-04-28", - /// "placeholder": { - /// "type": "plain_text", - /// "text": "Select a date", - /// "emoji": true - /// } - /// }, - /// { - /// "type": "button", - /// "text": { - /// "type": "plain_text", - /// "text": "Click Me", - /// "emoji": true - /// }, - /// "value": "click_me_123", - /// "action_id": "button" - /// } - /// ] - /// }); - /// - /// let actions_json = serde_json::to_value(actions).unwrap(); - /// - /// assert_eq!(actions_json, expected); - /// ``` - pub fn push_element>(self, element: T) -> Self { - let mut elements = self.elements; - elements.push(element.into()); - Self { elements, ..self } - } - - /// Sets block_id field. - /// - /// ``` - /// use slack_messaging::blocks::Actions; - /// use serde_json::json; - /// - /// let actions = Actions::new().set_block_id("actions_block_1"); - /// - /// let expected = json!({ - /// "type": "actions", - /// "elements": [], - /// "block_id": "actions_block_1" - /// }); - /// - /// let actions_json = serde_json::to_value(actions).unwrap(); - /// - /// assert_eq!(actions_json, expected); - /// ``` - pub fn set_block_id>(self, block_id: T) -> Self { - Self { - block_id: Some(block_id.into()), - ..self - } - } + pub(super) block_id: Option, } /// Objects that can be an element of the [Actions]'s elements field. @@ -423,7 +227,7 @@ pub enum ActionsElement { /// [Checkbox group](https://api.slack.com/reference/block-kit/block-elements#checkboxes) /// representation - CheckboxGroup(Box), + Checkboxes(Box), /// [Date picker element](https://api.slack.com/reference/block-kit/block-elements#datepicker) /// representation @@ -484,106 +288,41 @@ pub enum ActionsElement { /// [Time picker element](https://api.slack.com/reference/block-kit/block-elements#timepicker) /// representation TimePicker(Box), -} - -impl From