diff --git a/block-kit/README.md b/block-kit/README.md index 9785597..e230230 100644 --- a/block-kit/README.md +++ b/block-kit/README.md @@ -10,6 +10,7 @@ Read the [docs](https://docs.slack.dev/block-kit/) to learn concepts behind thes - **[Actions](https://docs.slack.dev/reference/block-kit/blocks/actions-block)**: Holds multiple interactive elements. [Implementation](./src/blocks/actions.py). - **[Alert](https://docs.slack.dev/reference/block-kit/blocks/alert-block)**: Displays alerts, warnings, and informational messages. [Implementation](./src/blocks/alert.py). +- **[Container](https://docs.slack.dev/reference/block-kit/blocks/container-block)**: A general-purpose wrapper for grouping child blocks together, with a configurable size. [Implementation](./src/blocks/container.py). - **[Context](https://docs.slack.dev/reference/block-kit/blocks/context-block)**: Provides contextual info, which can include both images and text. [Implementation](./src/blocks/context.py). - **[Context actions](https://docs.slack.dev/reference/block-kit/blocks/context-actions-block)**: Displays actions as contextual info, which can include both feedback buttons and icon buttons. [Implementation](./src/blocks/context_actions.py). - **[Divider](https://docs.slack.dev/reference/block-kit/blocks/divider-block)**: Visually separates pieces of info inside of a message. [Implementation](./src/blocks/divider.py). diff --git a/block-kit/src/blocks/container.py b/block-kit/src/blocks/container.py new file mode 100644 index 0000000..4187e24 --- /dev/null +++ b/block-kit/src/blocks/container.py @@ -0,0 +1,63 @@ +from slack_sdk.models.blocks import ( + ActionsBlock, + ContainerBlock, + ContextBlock, + DividerBlock, + SectionBlock, +) +from slack_sdk.models.blocks.basic_components import MarkdownTextObject, PlainTextObject +from slack_sdk.models.blocks.block_elements import ButtonElement + + +def example01() -> ContainerBlock: + """ + A general-purpose wrapper for grouping child blocks together, with a configurable size. + https://docs.slack.dev/reference/block-kit/blocks/container-block/ + + A collapsible container with sections, a divider, context, and actions. + """ + block = ContainerBlock( + block_id="bkb_container_bulk_update", + title=PlainTextObject(text="Bulk update: 2 records selected"), + subtitle=PlainTextObject(text="Review changes before confirming"), + is_collapsible=True, + child_blocks=[ + SectionBlock( + block_id="record-row-1", + text=MarkdownTextObject( + text="*DCW-1024*\nStatus: Open → Closed\nAssignee: @princessdonut → @carl" + ), + ), + DividerBlock(block_id="bulk-div-1"), + SectionBlock( + block_id="record-row-2", + text=MarkdownTextObject( + text="*DCW-1025*\nStatus: In Progress → Closed\nAssignee: @mordecai → @carl" + ), + ), + DividerBlock(block_id="bulk-div-2"), + ContextBlock( + block_id="bulk-status-bar", + elements=[ + MarkdownTextObject( + text=":white_check_mark: 2 records will be updated • Status → Closed • Assignee → @carl" + ), + ], + ), + ActionsBlock( + block_id="bulk-actions", + elements=[ + ButtonElement( + text=PlainTextObject(text="Confirm All", emoji=True), + style="primary", + action_id="bulk_confirm", + ), + ButtonElement( + text=PlainTextObject(text="Cancel", emoji=True), + action_id="bulk_cancel", + ), + ], + ), + ], + ) + return block diff --git a/block-kit/tests/blocks/test_container.py b/block-kit/tests/blocks/test_container.py new file mode 100644 index 0000000..a4ef1ce --- /dev/null +++ b/block-kit/tests/blocks/test_container.py @@ -0,0 +1,83 @@ +import json + +from src.blocks import container + + +def test_example01(): + block = container.example01() + actual = block.to_dict() + expected = { + "type": "container", + "block_id": "bkb_container_bulk_update", + "title": { + "type": "plain_text", + "text": "Bulk update: 2 records selected", + }, + "subtitle": { + "type": "plain_text", + "text": "Review changes before confirming", + }, + "is_collapsible": True, + "child_blocks": [ + { + "type": "section", + "block_id": "record-row-1", + "text": { + "type": "mrkdwn", + "text": "*DCW-1024*\nStatus: Open → Closed\nAssignee: @princessdonut → @carl", + }, + }, + { + "type": "divider", + "block_id": "bulk-div-1", + }, + { + "type": "section", + "block_id": "record-row-2", + "text": { + "type": "mrkdwn", + "text": "*DCW-1025*\nStatus: In Progress → Closed\nAssignee: @mordecai → @carl", + }, + }, + { + "type": "divider", + "block_id": "bulk-div-2", + }, + { + "type": "context", + "block_id": "bulk-status-bar", + "elements": [ + { + "type": "mrkdwn", + "text": ":white_check_mark: 2 records will be updated • Status → Closed • Assignee → @carl", + }, + ], + }, + { + "type": "actions", + "block_id": "bulk-actions", + "elements": [ + { + "type": "button", + "text": { + "type": "plain_text", + "text": "Confirm All", + "emoji": True, + }, + "style": "primary", + "action_id": "bulk_confirm", + }, + { + "type": "button", + "text": { + "type": "plain_text", + "text": "Cancel", + "emoji": True, + }, + "action_id": "bulk_cancel", + }, + ], + }, + ], + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True)