From 3b6498f3d46312e606145925a4fd6f2dab91f85c Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Thu, 27 Aug 2026 22:48:26 -0700 Subject: [PATCH 01/11] feat(block-kit): add composition object examples Add example projects for the Block Kit composition objects documented on docs.slack.dev, each demonstrating the full reference payload for its object hosted inside a valid block, element, or view. Every example ships a test that asserts the complete serialized JSON. Co-Authored-By: Claude --- block-kit/README.md | 12 ++++ block-kit/src/composition_objects/__init__.py | 0 .../confirmation_dialog.py | 39 +++++++++++ .../conversation_filter.py | 40 +++++++++++ .../dispatch_action_configuration.py | 26 +++++++ block-kit/src/composition_objects/option.py | 56 ++++++++++++++++ .../src/composition_objects/option_group.py | 60 +++++++++++++++++ .../src/composition_objects/slack_file.py | 33 +++++++++ block-kit/src/composition_objects/text.py | 17 +++++ block-kit/src/composition_objects/trigger.py | 42 ++++++++++++ block-kit/src/composition_objects/workflow.py | 42 ++++++++++++ .../tests/composition_objects/__init__.py | 0 .../test_confirmation_dialog.py | 38 +++++++++++ .../test_conversation_filter.py | 37 ++++++++++ .../test_dispatch_action_configuration.py | 25 +++++++ .../tests/composition_objects/test_option.py | 63 +++++++++++++++++ .../composition_objects/test_option_group.py | 67 +++++++++++++++++++ .../composition_objects/test_slack_file.py | 31 +++++++++ .../tests/composition_objects/test_text.py | 16 +++++ .../tests/composition_objects/test_trigger.py | 36 ++++++++++ .../composition_objects/test_workflow.py | 36 ++++++++++ 21 files changed, 716 insertions(+) create mode 100644 block-kit/src/composition_objects/__init__.py create mode 100644 block-kit/src/composition_objects/confirmation_dialog.py create mode 100644 block-kit/src/composition_objects/conversation_filter.py create mode 100644 block-kit/src/composition_objects/dispatch_action_configuration.py create mode 100644 block-kit/src/composition_objects/option.py create mode 100644 block-kit/src/composition_objects/option_group.py create mode 100644 block-kit/src/composition_objects/slack_file.py create mode 100644 block-kit/src/composition_objects/text.py create mode 100644 block-kit/src/composition_objects/trigger.py create mode 100644 block-kit/src/composition_objects/workflow.py create mode 100644 block-kit/tests/composition_objects/__init__.py create mode 100644 block-kit/tests/composition_objects/test_confirmation_dialog.py create mode 100644 block-kit/tests/composition_objects/test_conversation_filter.py create mode 100644 block-kit/tests/composition_objects/test_dispatch_action_configuration.py create mode 100644 block-kit/tests/composition_objects/test_option.py create mode 100644 block-kit/tests/composition_objects/test_option_group.py create mode 100644 block-kit/tests/composition_objects/test_slack_file.py create mode 100644 block-kit/tests/composition_objects/test_text.py create mode 100644 block-kit/tests/composition_objects/test_trigger.py create mode 100644 block-kit/tests/composition_objects/test_workflow.py diff --git a/block-kit/README.md b/block-kit/README.md index 9785597..2247c03 100644 --- a/block-kit/README.md +++ b/block-kit/README.md @@ -24,3 +24,15 @@ Read the [docs](https://docs.slack.dev/block-kit/) to learn concepts behind thes - **[Table](https://docs.slack.dev/reference/block-kit/blocks/table-block)**: Displays structured information in a table. [Implementation](./src/blocks/table.py). - **[Task card](https://docs.slack.dev/reference/block-kit/blocks/task-card-block)**: Displays a single task, representing a single action. [Implementation](./src/blocks/task_card.py). - **[Video](https://docs.slack.dev/reference/block-kit/blocks/video-block)**: Displays an embedded video player. [Implementation](./src/blocks/video.py). + +### Composition objects + +- **[Confirmation dialog](https://docs.slack.dev/reference/block-kit/composition-objects/confirmation-dialog-object)**: Defines a dialog that adds a confirmation step to interactive elements. [Implementation](./src/composition_objects/confirmation_dialog.py). +- **[Conversation filter](https://docs.slack.dev/reference/block-kit/composition-objects/conversation-filter-object)**: Defines a filter for the list of options in a conversation selector menu. [Implementation](./src/composition_objects/conversation_filter.py). +- **[Dispatch action configuration](https://docs.slack.dev/reference/block-kit/composition-objects/dispatch-action-configuration-object)**: Defines when a plain-text input element will return a block_actions interaction payload. [Implementation](./src/composition_objects/dispatch_action_configuration.py). +- **[Option](https://docs.slack.dev/reference/block-kit/composition-objects/option-object)**: Defines a single item in a number of item selection elements. [Implementation](./src/composition_objects/option.py). +- **[Option group](https://docs.slack.dev/reference/block-kit/composition-objects/option-group-object)**: Defines a way to group options in a menu. [Implementation](./src/composition_objects/option_group.py). +- **[Slack file](https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object)**: Defines an object containing Slack file information to be used in an image block or image element. [Implementation](./src/composition_objects/slack_file.py). +- **[Text](https://docs.slack.dev/reference/block-kit/composition-objects/text-object)**: Defines an object containing some text. [Implementation](./src/composition_objects/text.py). +- **[Trigger](https://docs.slack.dev/reference/block-kit/composition-objects/trigger-object)**: Defines an object containing trigger information. [Implementation](./src/composition_objects/trigger.py). +- **[Workflow](https://docs.slack.dev/reference/block-kit/composition-objects/workflow-object)**: Defines an object containing workflow information. [Implementation](./src/composition_objects/workflow.py). diff --git a/block-kit/src/composition_objects/__init__.py b/block-kit/src/composition_objects/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/block-kit/src/composition_objects/confirmation_dialog.py b/block-kit/src/composition_objects/confirmation_dialog.py new file mode 100644 index 0000000..d3cfea8 --- /dev/null +++ b/block-kit/src/composition_objects/confirmation_dialog.py @@ -0,0 +1,39 @@ +from slack_sdk.models.blocks import ActionsBlock +from slack_sdk.models.blocks.basic_components import ( + ConfirmObject, + MarkdownTextObject, + PlainTextObject, +) +from slack_sdk.models.blocks.block_elements import ButtonElement + + +def example01() -> ActionsBlock: + """ + Defines a dialog that adds a confirmation step to interactive elements. + https://docs.slack.dev/reference/block-kit/composition-objects/confirmation-dialog-object/ + + An actions block with a button that opens a confirmation dialog. + """ + block = ActionsBlock( + elements=[ + ButtonElement( + text=PlainTextObject(text="Approve", emoji=True), + confirm=ConfirmObject( + title=PlainTextObject(text="Are you sure?"), + text=MarkdownTextObject( + text="Would you not prefer a good game of _chess_?" + ), + confirm=PlainTextObject(text="Do it"), + deny=PlainTextObject(text="Stop, I changed my mind!"), + ), + style="primary", + value="click_me_123", + ), + ButtonElement( + text=PlainTextObject(text="Deny", emoji=True), + style="danger", + value="click_me_123", + ), + ], + ) + return block diff --git a/block-kit/src/composition_objects/conversation_filter.py b/block-kit/src/composition_objects/conversation_filter.py new file mode 100644 index 0000000..a854f4e --- /dev/null +++ b/block-kit/src/composition_objects/conversation_filter.py @@ -0,0 +1,40 @@ +from slack_sdk.models.blocks import InputBlock +from slack_sdk.models.blocks.basic_components import PlainTextObject +from slack_sdk.models.blocks.block_elements import ( + ConversationFilter, + ConversationSelectElement, +) +from slack_sdk.models.views import View + + +def example01() -> View: + """ + Defines a filter for the list of options in a conversation selector menu. + https://docs.slack.dev/reference/block-kit/composition-objects/conversation-filter-object/ + + A modal view whose conversations select filters the listed conversations. + """ + view = View( + type="modal", + title=PlainTextObject(text="My App", emoji=True), + submit=PlainTextObject(text="Submit", emoji=True), + close=PlainTextObject(text="Cancel", emoji=True), + blocks=[ + InputBlock( + element=ConversationSelectElement( + placeholder=PlainTextObject( + text="Select a conversation", emoji=True + ), + filter=ConversationFilter( + include=["public", "mpim"], + exclude_bot_users=True, + ), + ), + label=PlainTextObject( + text="Choose the conversation to publish your result to:", + emoji=True, + ), + ), + ], + ) + return view diff --git a/block-kit/src/composition_objects/dispatch_action_configuration.py b/block-kit/src/composition_objects/dispatch_action_configuration.py new file mode 100644 index 0000000..563da2c --- /dev/null +++ b/block-kit/src/composition_objects/dispatch_action_configuration.py @@ -0,0 +1,26 @@ +from slack_sdk.models.blocks import InputBlock +from slack_sdk.models.blocks.basic_components import ( + DispatchActionConfig, + PlainTextObject, +) +from slack_sdk.models.blocks.block_elements import PlainTextInputElement + + +def example01() -> InputBlock: + """ + Defines when a plain-text input element will return a block_actions interaction payload. + https://docs.slack.dev/reference/block-kit/composition-objects/dispatch-action-configuration-object/ + + An input block whose plain-text input dispatches actions on character entry. + """ + block = InputBlock( + dispatch_action=True, + element=PlainTextInputElement( + multiline=True, + dispatch_action_config=DispatchActionConfig( + trigger_actions_on=["on_character_entered"], + ), + ), + label=PlainTextObject(text="This is a multiline plain-text input", emoji=True), + ) + return block diff --git a/block-kit/src/composition_objects/option.py b/block-kit/src/composition_objects/option.py new file mode 100644 index 0000000..5938550 --- /dev/null +++ b/block-kit/src/composition_objects/option.py @@ -0,0 +1,56 @@ +from slack_sdk.models.blocks import Block, DividerBlock, SectionBlock +from slack_sdk.models.blocks.basic_components import ( + MarkdownTextObject, + Option, + PlainTextObject, +) +from slack_sdk.models.blocks.block_elements import StaticSelectElement + + +def example01() -> Option: + """ + Defines a single item in a number of item selection elements. + https://docs.slack.dev/reference/block-kit/composition-objects/option-object/ + + A single option object. + """ + option = Option( + text=PlainTextObject(text="Save it", emoji=True), + value="value-2", + ) + return option + + +def example02() -> list[Block]: + """ + Options used within a select menu accessory on a section block. + """ + blocks: list[Block] = [ + SectionBlock( + text=MarkdownTextObject(text=":mag: Search results for *Cata*"), + ), + DividerBlock(), + SectionBlock( + text=MarkdownTextObject( + text="**\nUse Case Catalogue for the following departments/roles..." + ), + accessory=StaticSelectElement( + placeholder=PlainTextObject(text="Manage", emoji=True), + options=[ + Option( + text=PlainTextObject(text="Edit it", emoji=True), + value="value-0", + ), + Option( + text=PlainTextObject(text="Read it", emoji=True), + value="value-1", + ), + Option( + text=PlainTextObject(text="Save it", emoji=True), + value="value-2", + ), + ], + ), + ), + ] + return blocks diff --git a/block-kit/src/composition_objects/option_group.py b/block-kit/src/composition_objects/option_group.py new file mode 100644 index 0000000..812387e --- /dev/null +++ b/block-kit/src/composition_objects/option_group.py @@ -0,0 +1,60 @@ +from slack_sdk.models.blocks import Block, DividerBlock, SectionBlock +from slack_sdk.models.blocks.basic_components import ( + MarkdownTextObject, + Option, + OptionGroup, + PlainTextObject, +) +from slack_sdk.models.blocks.block_elements import StaticSelectElement + + +def example01() -> list[Block]: + """ + Defines a way to group options in a menu. + https://docs.slack.dev/reference/block-kit/composition-objects/option-group-object/ + + Option groups used within a select menu accessory on a section block. + """ + blocks: list[Block] = [ + SectionBlock( + text=MarkdownTextObject(text=":mag: Search results for *Cata*"), + ), + DividerBlock(), + SectionBlock( + text=MarkdownTextObject( + text="**\nUse Case Catalogue for the following departments/roles..." + ), + accessory=StaticSelectElement( + placeholder=PlainTextObject(text="Manage", emoji=True), + option_groups=[ + OptionGroup( + label=PlainTextObject(text="Group 1"), + options=[ + Option( + text=PlainTextObject(text="*this is plain_text text*"), + value="value-0", + ), + Option( + text=PlainTextObject(text="*this is plain_text text*"), + value="value-1", + ), + Option( + text=PlainTextObject(text="*this is plain_text text*"), + value="value-2", + ), + ], + ), + OptionGroup( + label=PlainTextObject(text="Group 2"), + options=[ + Option( + text=PlainTextObject(text="*this is plain_text text*"), + value="value-3", + ), + ], + ), + ], + ), + ), + ] + return blocks diff --git a/block-kit/src/composition_objects/slack_file.py b/block-kit/src/composition_objects/slack_file.py new file mode 100644 index 0000000..a6d72a8 --- /dev/null +++ b/block-kit/src/composition_objects/slack_file.py @@ -0,0 +1,33 @@ +from slack_sdk.models.blocks import ImageBlock +from slack_sdk.models.blocks.basic_components import PlainTextObject, SlackFile + + +def example01() -> ImageBlock: + """ + Defines an object containing Slack file information to be used in an image block or image element. + https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object/ + + An image block referencing a Slack file by URL. + """ + block = ImageBlock( + title=PlainTextObject(text="Please enjoy this photo of a kitten"), + block_id="image4", + slack_file=SlackFile( + url="https://files.slack.com/files-pri/T0123456-F0123456/xyz.png" + ), + alt_text="An incredibly cute kitten.", + ) + return block + + +def example02() -> ImageBlock: + """ + An image block referencing a Slack file by ID. + """ + block = ImageBlock( + title=PlainTextObject(text="Please enjoy this photo of a kitten"), + block_id="image4", + slack_file=SlackFile(id="F0123456"), + alt_text="An incredibly cute kitten.", + ) + return block diff --git a/block-kit/src/composition_objects/text.py b/block-kit/src/composition_objects/text.py new file mode 100644 index 0000000..58977a7 --- /dev/null +++ b/block-kit/src/composition_objects/text.py @@ -0,0 +1,17 @@ +from slack_sdk.models.blocks import SectionBlock +from slack_sdk.models.blocks.basic_components import MarkdownTextObject + + +def example01() -> SectionBlock: + """ + Defines an object containing some text. + https://docs.slack.dev/reference/block-kit/composition-objects/text-object/ + + A section block containing an mrkdwn text object. + """ + block = SectionBlock( + text=MarkdownTextObject( + text="A message *with some bold text* and _some italicized text_." + ) + ) + return block diff --git a/block-kit/src/composition_objects/trigger.py b/block-kit/src/composition_objects/trigger.py new file mode 100644 index 0000000..f70e8af --- /dev/null +++ b/block-kit/src/composition_objects/trigger.py @@ -0,0 +1,42 @@ +from slack_sdk.models.blocks import SectionBlock +from slack_sdk.models.blocks.basic_components import ( + MarkdownTextObject, + PlainTextObject, + Workflow, + WorkflowTrigger, +) +from slack_sdk.models.blocks.block_elements import WorkflowButtonElement + + +def example01() -> SectionBlock: + """ + Defines an object containing trigger information. + https://docs.slack.dev/reference/block-kit/composition-objects/trigger-object/ + + A workflow button whose trigger carries a URL and customizable inputs. + """ + block = SectionBlock( + text=MarkdownTextObject( + text="A message *with some bold text* and _some italicized text_." + ), + accessory=WorkflowButtonElement( + text=PlainTextObject(text="Run Workflow"), + action_id="workflowbutton123", + workflow=Workflow( + trigger=WorkflowTrigger( + url="https://slack.com/shortcuts/Ft0123ABC456/xyz...zyx", + customizable_input_parameters=[ + { + "name": "input_parameter_a", + "value": "Value for input param A", + }, + { + "name": "input_parameter_b", + "value": "Value for input param B", + }, + ], + ), + ), + ), + ) + return block diff --git a/block-kit/src/composition_objects/workflow.py b/block-kit/src/composition_objects/workflow.py new file mode 100644 index 0000000..5fc4048 --- /dev/null +++ b/block-kit/src/composition_objects/workflow.py @@ -0,0 +1,42 @@ +from slack_sdk.models.blocks import SectionBlock +from slack_sdk.models.blocks.basic_components import ( + MarkdownTextObject, + PlainTextObject, + Workflow, + WorkflowTrigger, +) +from slack_sdk.models.blocks.block_elements import WorkflowButtonElement + + +def example01() -> SectionBlock: + """ + Defines an object containing workflow information. + https://docs.slack.dev/reference/block-kit/composition-objects/workflow-object/ + + A workflow button whose workflow references a configured trigger. + """ + block = SectionBlock( + text=MarkdownTextObject( + text="A message *with some bold text* and _some italicized text_." + ), + accessory=WorkflowButtonElement( + text=PlainTextObject(text="Run Workflow"), + action_id="workflowbutton123", + workflow=Workflow( + trigger=WorkflowTrigger( + url="https://slack.com/shortcuts/Ft0123ABC456/xyz...zyx", + customizable_input_parameters=[ + { + "name": "input_parameter_a", + "value": "Value for input param A", + }, + { + "name": "input_parameter_b", + "value": "Value for input param B", + }, + ], + ), + ), + ), + ) + return block diff --git a/block-kit/tests/composition_objects/__init__.py b/block-kit/tests/composition_objects/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/block-kit/tests/composition_objects/test_confirmation_dialog.py b/block-kit/tests/composition_objects/test_confirmation_dialog.py new file mode 100644 index 0000000..40d3713 --- /dev/null +++ b/block-kit/tests/composition_objects/test_confirmation_dialog.py @@ -0,0 +1,38 @@ +import json + +from src.composition_objects import confirmation_dialog + + +def test_example01(): + block = confirmation_dialog.example01() + actual = block.to_dict() + expected = { + "type": "actions", + "elements": [ + { + "type": "button", + "text": {"type": "plain_text", "emoji": True, "text": "Approve"}, + "confirm": { + "title": {"type": "plain_text", "text": "Are you sure?"}, + "text": { + "type": "mrkdwn", + "text": "Would you not prefer a good game of _chess_?", + }, + "confirm": {"type": "plain_text", "text": "Do it"}, + "deny": { + "type": "plain_text", + "text": "Stop, I changed my mind!", + }, + }, + "style": "primary", + "value": "click_me_123", + }, + { + "type": "button", + "text": {"type": "plain_text", "emoji": True, "text": "Deny"}, + "style": "danger", + "value": "click_me_123", + }, + ], + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_conversation_filter.py b/block-kit/tests/composition_objects/test_conversation_filter.py new file mode 100644 index 0000000..6557146 --- /dev/null +++ b/block-kit/tests/composition_objects/test_conversation_filter.py @@ -0,0 +1,37 @@ +import json + +from src.composition_objects import conversation_filter + + +def test_example01(): + view = conversation_filter.example01() + actual = view.to_dict() + expected = { + "title": {"type": "plain_text", "text": "My App", "emoji": True}, + "submit": {"type": "plain_text", "text": "Submit", "emoji": True}, + "type": "modal", + "close": {"type": "plain_text", "text": "Cancel", "emoji": True}, + "blocks": [ + { + "type": "input", + "element": { + "type": "conversations_select", + "placeholder": { + "type": "plain_text", + "text": "Select a conversation", + "emoji": True, + }, + "filter": { + "include": ["public", "mpim"], + "exclude_bot_users": True, + }, + }, + "label": { + "type": "plain_text", + "text": "Choose the conversation to publish your result to:", + "emoji": True, + }, + }, + ], + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_dispatch_action_configuration.py b/block-kit/tests/composition_objects/test_dispatch_action_configuration.py new file mode 100644 index 0000000..1a3a0fb --- /dev/null +++ b/block-kit/tests/composition_objects/test_dispatch_action_configuration.py @@ -0,0 +1,25 @@ +import json + +from src.composition_objects import dispatch_action_configuration + + +def test_example01(): + block = dispatch_action_configuration.example01() + actual = block.to_dict() + expected = { + "type": "input", + "dispatch_action": True, + "element": { + "type": "plain_text_input", + "multiline": True, + "dispatch_action_config": { + "trigger_actions_on": ["on_character_entered"], + }, + }, + "label": { + "type": "plain_text", + "text": "This is a multiline plain-text input", + "emoji": True, + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_option.py b/block-kit/tests/composition_objects/test_option.py new file mode 100644 index 0000000..e8593e7 --- /dev/null +++ b/block-kit/tests/composition_objects/test_option.py @@ -0,0 +1,63 @@ +import json + +from src.composition_objects import option + + +def test_example01(): + obj = option.example01() + actual = obj.to_dict() + expected = { + "text": {"type": "plain_text", "emoji": True, "text": "Save it"}, + "value": "value-2", + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) + + +def test_example02(): + blocks = option.example02() + actual = [block.to_dict() for block in blocks] + expected = [ + { + "type": "section", + "text": {"type": "mrkdwn", "text": ":mag: Search results for *Cata*"}, + }, + {"type": "divider"}, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "**\nUse Case Catalogue for the following departments/roles...", + }, + "accessory": { + "type": "static_select", + "placeholder": {"type": "plain_text", "emoji": True, "text": "Manage"}, + "options": [ + { + "text": { + "type": "plain_text", + "emoji": True, + "text": "Edit it", + }, + "value": "value-0", + }, + { + "text": { + "type": "plain_text", + "emoji": True, + "text": "Read it", + }, + "value": "value-1", + }, + { + "text": { + "type": "plain_text", + "emoji": True, + "text": "Save it", + }, + "value": "value-2", + }, + ], + }, + }, + ] + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_option_group.py b/block-kit/tests/composition_objects/test_option_group.py new file mode 100644 index 0000000..48cd500 --- /dev/null +++ b/block-kit/tests/composition_objects/test_option_group.py @@ -0,0 +1,67 @@ +import json + +from src.composition_objects import option_group + + +def test_example01(): + blocks = option_group.example01() + actual = [block.to_dict() for block in blocks] + expected = [ + { + "type": "section", + "text": {"type": "mrkdwn", "text": ":mag: Search results for *Cata*"}, + }, + {"type": "divider"}, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "**\nUse Case Catalogue for the following departments/roles...", + }, + "accessory": { + "type": "static_select", + "placeholder": {"type": "plain_text", "emoji": True, "text": "Manage"}, + "option_groups": [ + { + "label": {"type": "plain_text", "text": "Group 1"}, + "options": [ + { + "text": { + "type": "plain_text", + "text": "*this is plain_text text*", + }, + "value": "value-0", + }, + { + "text": { + "type": "plain_text", + "text": "*this is plain_text text*", + }, + "value": "value-1", + }, + { + "text": { + "type": "plain_text", + "text": "*this is plain_text text*", + }, + "value": "value-2", + }, + ], + }, + { + "label": {"type": "plain_text", "text": "Group 2"}, + "options": [ + { + "text": { + "type": "plain_text", + "text": "*this is plain_text text*", + }, + "value": "value-3", + }, + ], + }, + ], + }, + }, + ] + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_slack_file.py b/block-kit/tests/composition_objects/test_slack_file.py new file mode 100644 index 0000000..e74f11a --- /dev/null +++ b/block-kit/tests/composition_objects/test_slack_file.py @@ -0,0 +1,31 @@ +import json + +from src.composition_objects import slack_file + + +def test_example01(): + block = slack_file.example01() + actual = block.to_dict() + expected = { + "type": "image", + "title": {"type": "plain_text", "text": "Please enjoy this photo of a kitten"}, + "block_id": "image4", + "slack_file": { + "url": "https://files.slack.com/files-pri/T0123456-F0123456/xyz.png" + }, + "alt_text": "An incredibly cute kitten.", + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) + + +def test_example02(): + block = slack_file.example02() + actual = block.to_dict() + expected = { + "type": "image", + "title": {"type": "plain_text", "text": "Please enjoy this photo of a kitten"}, + "block_id": "image4", + "slack_file": {"id": "F0123456"}, + "alt_text": "An incredibly cute kitten.", + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_text.py b/block-kit/tests/composition_objects/test_text.py new file mode 100644 index 0000000..0db4964 --- /dev/null +++ b/block-kit/tests/composition_objects/test_text.py @@ -0,0 +1,16 @@ +import json + +from src.composition_objects import text + + +def test_example01(): + block = text.example01() + actual = block.to_dict() + expected = { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "A message *with some bold text* and _some italicized text_.", + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_trigger.py b/block-kit/tests/composition_objects/test_trigger.py new file mode 100644 index 0000000..353c0fe --- /dev/null +++ b/block-kit/tests/composition_objects/test_trigger.py @@ -0,0 +1,36 @@ +import json + +from src.composition_objects import trigger + + +def test_example01(): + block = trigger.example01() + actual = block.to_dict() + expected = { + "type": "section", + "text": { + "text": "A message *with some bold text* and _some italicized text_.", + "type": "mrkdwn", + }, + "accessory": { + "type": "workflow_button", + "text": {"type": "plain_text", "text": "Run Workflow"}, + "action_id": "workflowbutton123", + "workflow": { + "trigger": { + "url": "https://slack.com/shortcuts/Ft0123ABC456/xyz...zyx", + "customizable_input_parameters": [ + { + "name": "input_parameter_a", + "value": "Value for input param A", + }, + { + "name": "input_parameter_b", + "value": "Value for input param B", + }, + ], + } + }, + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_workflow.py b/block-kit/tests/composition_objects/test_workflow.py new file mode 100644 index 0000000..2b2981c --- /dev/null +++ b/block-kit/tests/composition_objects/test_workflow.py @@ -0,0 +1,36 @@ +import json + +from src.composition_objects import workflow + + +def test_example01(): + block = workflow.example01() + actual = block.to_dict() + expected = { + "type": "section", + "text": { + "text": "A message *with some bold text* and _some italicized text_.", + "type": "mrkdwn", + }, + "accessory": { + "type": "workflow_button", + "text": {"type": "plain_text", "text": "Run Workflow"}, + "action_id": "workflowbutton123", + "workflow": { + "trigger": { + "url": "https://slack.com/shortcuts/Ft0123ABC456/xyz...zyx", + "customizable_input_parameters": [ + { + "name": "input_parameter_a", + "value": "Value for input param A", + }, + { + "name": "input_parameter_b", + "value": "Value for input param B", + }, + ], + } + }, + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) From f6ab6dfda052f070a81992f02f021ff9cbc23a69 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Thu, 27 Aug 2026 23:27:19 -0700 Subject: [PATCH 02/11] test: reformat example test expected payloads with split attributes Rewrite each existing example test's `expected` reference payload so every nested dict is exploded one key:value per line with a magic trailing comma, mirroring the docs' vertical layout and keeping ruff format from re-collapsing short dicts. Values stay native `dict`/`list` literals and the `json.dumps(..., sort_keys=True)` comparison is unchanged. Co-Authored-By: Claude --- block-kit/tests/blocks/test_plan.py | 12 +-- block-kit/tests/blocks/test_rich_text.py | 80 +++++++++++++------ block-kit/tests/blocks/test_table.py | 36 ++++++--- block-kit/tests/blocks/test_task_card.py | 4 +- .../test_confirmation_dialog.py | 22 ++++- .../test_conversation_filter.py | 18 ++++- .../tests/composition_objects/test_option.py | 21 ++++- .../composition_objects/test_option_group.py | 25 ++++-- .../composition_objects/test_slack_file.py | 16 +++- .../tests/composition_objects/test_trigger.py | 7 +- .../composition_objects/test_workflow.py | 7 +- 11 files changed, 181 insertions(+), 67 deletions(-) diff --git a/block-kit/tests/blocks/test_plan.py b/block-kit/tests/blocks/test_plan.py index e806350..814e590 100644 --- a/block-kit/tests/blocks/test_plan.py +++ b/block-kit/tests/blocks/test_plan.py @@ -25,9 +25,9 @@ def test_example01(): { "type": "text", "text": "Searched database...", - } + }, ], - } + }, ], }, "output": { @@ -40,9 +40,9 @@ def test_example01(): { "type": "text", "text": "Profile data loaded", - } + }, ], - } + }, ], }, }, @@ -67,9 +67,9 @@ def test_example01(): { "type": "text", "text": "15 data points compiled", - } + }, ], - } + }, ], }, }, diff --git a/block-kit/tests/blocks/test_rich_text.py b/block-kit/tests/blocks/test_rich_text.py index fb6ef56..7c4eb20 100644 --- a/block-kit/tests/blocks/test_rich_text.py +++ b/block-kit/tests/blocks/test_rich_text.py @@ -16,9 +16,9 @@ def test_example01(): { "type": "text", "text": "Hello there, I am a basic rich text block!", - } + }, ], - } + }, ], }, { @@ -39,7 +39,7 @@ def test_example01(): }, }, ], - } + }, ], }, { @@ -60,7 +60,7 @@ def test_example01(): }, }, ], - } + }, ], }, { @@ -81,7 +81,7 @@ def test_example01(): }, }, ], - } + }, ], }, ] @@ -101,7 +101,7 @@ def test_example02(): { "type": "text", "text": "My favorite Slack features (in no particular order):", - } + }, ], }, { @@ -221,7 +221,7 @@ def test_example03(): "text": "Pancakes, extra syrup", }, ], - } + }, ], }, ], @@ -241,10 +241,10 @@ def test_example04(): { "type": "text", "text": '{\n "object": {\n "description": "this is an example of a json object"\n }\n}', - } + }, ], "border": 0, - } + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -263,7 +263,7 @@ def test_example05(): { "type": "text", "text": "What we need is good examples in our documentation.", - } + }, ], }, { @@ -288,8 +288,13 @@ def test_example06(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "broadcast", "range": "everyone"}], - } + "elements": [ + { + "type": "broadcast", + "range": "everyone", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -303,8 +308,13 @@ def test_example07(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "color", "value": "#F405B3"}], - } + "elements": [ + { + "type": "color", + "value": "#F405B3", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -318,8 +328,13 @@ def test_example08(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "channel", "channel_id": "C123ABC456"}], - } + "elements": [ + { + "type": "channel", + "channel_id": "C123ABC456", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -339,9 +354,9 @@ def test_example09(): "timestamp": 1720710212, "format": "{date_num} at {time}", "fallback": "timey", - } + }, ], - } + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -377,7 +392,7 @@ def test_example10(): "name": "checkered_flag", }, ], - } + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -391,8 +406,13 @@ def test_example11(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "link", "url": "https://api.slack.com"}], - } + "elements": [ + { + "type": "link", + "url": "https://api.slack.com", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -406,8 +426,13 @@ def test_example12(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "user", "user_id": "U123ABC456"}], - } + "elements": [ + { + "type": "user", + "user_id": "U123ABC456", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -421,8 +446,13 @@ def test_example13(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "usergroup", "usergroup_id": "G123ABC456"}], - } + "elements": [ + { + "type": "usergroup", + "usergroup_id": "G123ABC456", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/blocks/test_table.py b/block-kit/tests/blocks/test_table.py index f8eb942..d527739 100644 --- a/block-kit/tests/blocks/test_table.py +++ b/block-kit/tests/blocks/test_table.py @@ -9,16 +9,29 @@ def test_example01(): expected = { "type": "table", "column_settings": [ - {"is_wrapped": True}, - {"align": "right"}, + { + "is_wrapped": True, + }, + { + "align": "right", + }, ], "rows": [ [ - {"type": "raw_text", "text": "Header A"}, - {"type": "raw_text", "text": "Header B"}, + { + "type": "raw_text", + "text": "Header A", + }, + { + "type": "raw_text", + "text": "Header B", + }, ], [ - {"type": "raw_text", "text": "Data 1A"}, + { + "type": "raw_text", + "text": "Data 1A", + }, { "type": "rich_text", "elements": [ @@ -29,14 +42,17 @@ def test_example01(): "type": "link", "text": "Data 1B", "url": "https://slack.com", - } + }, ], - } + }, ], }, ], [ - {"type": "raw_text", "text": "Data 2A"}, + { + "type": "raw_text", + "text": "Data 2A", + }, { "type": "rich_text", "elements": [ @@ -47,9 +63,9 @@ def test_example01(): "type": "link", "text": "Data 2B", "url": "https://slack.com", - } + }, ], - } + }, ], }, ], diff --git a/block-kit/tests/blocks/test_task_card.py b/block-kit/tests/blocks/test_task_card.py index 802b924..b0a79bd 100644 --- a/block-kit/tests/blocks/test_task_card.py +++ b/block-kit/tests/blocks/test_task_card.py @@ -20,9 +20,9 @@ def test_example01(): { "type": "text", "text": "Found weather data for Chicago from 2 sources", - } + }, ], - } + }, ], }, "sources": [ diff --git a/block-kit/tests/composition_objects/test_confirmation_dialog.py b/block-kit/tests/composition_objects/test_confirmation_dialog.py index 40d3713..610f959 100644 --- a/block-kit/tests/composition_objects/test_confirmation_dialog.py +++ b/block-kit/tests/composition_objects/test_confirmation_dialog.py @@ -11,14 +11,24 @@ def test_example01(): "elements": [ { "type": "button", - "text": {"type": "plain_text", "emoji": True, "text": "Approve"}, + "text": { + "type": "plain_text", + "emoji": True, + "text": "Approve", + }, "confirm": { - "title": {"type": "plain_text", "text": "Are you sure?"}, + "title": { + "type": "plain_text", + "text": "Are you sure?", + }, "text": { "type": "mrkdwn", "text": "Would you not prefer a good game of _chess_?", }, - "confirm": {"type": "plain_text", "text": "Do it"}, + "confirm": { + "type": "plain_text", + "text": "Do it", + }, "deny": { "type": "plain_text", "text": "Stop, I changed my mind!", @@ -29,7 +39,11 @@ def test_example01(): }, { "type": "button", - "text": {"type": "plain_text", "emoji": True, "text": "Deny"}, + "text": { + "type": "plain_text", + "emoji": True, + "text": "Deny", + }, "style": "danger", "value": "click_me_123", }, diff --git a/block-kit/tests/composition_objects/test_conversation_filter.py b/block-kit/tests/composition_objects/test_conversation_filter.py index 6557146..c156ce8 100644 --- a/block-kit/tests/composition_objects/test_conversation_filter.py +++ b/block-kit/tests/composition_objects/test_conversation_filter.py @@ -7,10 +7,22 @@ def test_example01(): view = conversation_filter.example01() actual = view.to_dict() expected = { - "title": {"type": "plain_text", "text": "My App", "emoji": True}, - "submit": {"type": "plain_text", "text": "Submit", "emoji": True}, + "title": { + "type": "plain_text", + "text": "My App", + "emoji": True, + }, + "submit": { + "type": "plain_text", + "text": "Submit", + "emoji": True, + }, "type": "modal", - "close": {"type": "plain_text", "text": "Cancel", "emoji": True}, + "close": { + "type": "plain_text", + "text": "Cancel", + "emoji": True, + }, "blocks": [ { "type": "input", diff --git a/block-kit/tests/composition_objects/test_option.py b/block-kit/tests/composition_objects/test_option.py index e8593e7..b314112 100644 --- a/block-kit/tests/composition_objects/test_option.py +++ b/block-kit/tests/composition_objects/test_option.py @@ -7,7 +7,11 @@ def test_example01(): obj = option.example01() actual = obj.to_dict() expected = { - "text": {"type": "plain_text", "emoji": True, "text": "Save it"}, + "text": { + "type": "plain_text", + "emoji": True, + "text": "Save it", + }, "value": "value-2", } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -19,9 +23,14 @@ def test_example02(): expected = [ { "type": "section", - "text": {"type": "mrkdwn", "text": ":mag: Search results for *Cata*"}, + "text": { + "type": "mrkdwn", + "text": ":mag: Search results for *Cata*", + }, + }, + { + "type": "divider", }, - {"type": "divider"}, { "type": "section", "text": { @@ -30,7 +39,11 @@ def test_example02(): }, "accessory": { "type": "static_select", - "placeholder": {"type": "plain_text", "emoji": True, "text": "Manage"}, + "placeholder": { + "type": "plain_text", + "emoji": True, + "text": "Manage", + }, "options": [ { "text": { diff --git a/block-kit/tests/composition_objects/test_option_group.py b/block-kit/tests/composition_objects/test_option_group.py index 48cd500..abb141d 100644 --- a/block-kit/tests/composition_objects/test_option_group.py +++ b/block-kit/tests/composition_objects/test_option_group.py @@ -9,9 +9,14 @@ def test_example01(): expected = [ { "type": "section", - "text": {"type": "mrkdwn", "text": ":mag: Search results for *Cata*"}, + "text": { + "type": "mrkdwn", + "text": ":mag: Search results for *Cata*", + }, + }, + { + "type": "divider", }, - {"type": "divider"}, { "type": "section", "text": { @@ -20,10 +25,17 @@ def test_example01(): }, "accessory": { "type": "static_select", - "placeholder": {"type": "plain_text", "emoji": True, "text": "Manage"}, + "placeholder": { + "type": "plain_text", + "emoji": True, + "text": "Manage", + }, "option_groups": [ { - "label": {"type": "plain_text", "text": "Group 1"}, + "label": { + "type": "plain_text", + "text": "Group 1", + }, "options": [ { "text": { @@ -49,7 +61,10 @@ def test_example01(): ], }, { - "label": {"type": "plain_text", "text": "Group 2"}, + "label": { + "type": "plain_text", + "text": "Group 2", + }, "options": [ { "text": { diff --git a/block-kit/tests/composition_objects/test_slack_file.py b/block-kit/tests/composition_objects/test_slack_file.py index e74f11a..e9c22f3 100644 --- a/block-kit/tests/composition_objects/test_slack_file.py +++ b/block-kit/tests/composition_objects/test_slack_file.py @@ -8,10 +8,13 @@ def test_example01(): actual = block.to_dict() expected = { "type": "image", - "title": {"type": "plain_text", "text": "Please enjoy this photo of a kitten"}, + "title": { + "type": "plain_text", + "text": "Please enjoy this photo of a kitten", + }, "block_id": "image4", "slack_file": { - "url": "https://files.slack.com/files-pri/T0123456-F0123456/xyz.png" + "url": "https://files.slack.com/files-pri/T0123456-F0123456/xyz.png", }, "alt_text": "An incredibly cute kitten.", } @@ -23,9 +26,14 @@ def test_example02(): actual = block.to_dict() expected = { "type": "image", - "title": {"type": "plain_text", "text": "Please enjoy this photo of a kitten"}, + "title": { + "type": "plain_text", + "text": "Please enjoy this photo of a kitten", + }, "block_id": "image4", - "slack_file": {"id": "F0123456"}, + "slack_file": { + "id": "F0123456", + }, "alt_text": "An incredibly cute kitten.", } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_trigger.py b/block-kit/tests/composition_objects/test_trigger.py index 353c0fe..b297691 100644 --- a/block-kit/tests/composition_objects/test_trigger.py +++ b/block-kit/tests/composition_objects/test_trigger.py @@ -14,7 +14,10 @@ def test_example01(): }, "accessory": { "type": "workflow_button", - "text": {"type": "plain_text", "text": "Run Workflow"}, + "text": { + "type": "plain_text", + "text": "Run Workflow", + }, "action_id": "workflowbutton123", "workflow": { "trigger": { @@ -29,7 +32,7 @@ def test_example01(): "value": "Value for input param B", }, ], - } + }, }, }, } diff --git a/block-kit/tests/composition_objects/test_workflow.py b/block-kit/tests/composition_objects/test_workflow.py index 2b2981c..a1ad500 100644 --- a/block-kit/tests/composition_objects/test_workflow.py +++ b/block-kit/tests/composition_objects/test_workflow.py @@ -14,7 +14,10 @@ def test_example01(): }, "accessory": { "type": "workflow_button", - "text": {"type": "plain_text", "text": "Run Workflow"}, + "text": { + "type": "plain_text", + "text": "Run Workflow", + }, "action_id": "workflowbutton123", "workflow": { "trigger": { @@ -29,7 +32,7 @@ def test_example01(): "value": "Value for input param B", }, ], - } + }, }, }, } From 53ee07507559d9842c79644c9fd66c8707707a56 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 1 Sep 2026 00:06:06 -0700 Subject: [PATCH 03/11] refactor(block-kit): rename composition-object examples to compositions/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renames the composition-object example directory from composition_objects/ (compositionobjects/ in Java) to compositions/, matching the shorter path. Directory + all references (test imports, README impl links, Java package declarations) updated together via git mv so history is preserved. Canonical docs.slack.dev/reference/block-kit/composition-objects/ URLs are left untouched (hyphenated, never the underscore token) — only local relative implementation-link paths changed. Co-Authored-By: Claude --- block-kit/README.md | 18 +++++++++--------- .../__init__.py | 0 .../confirmation_dialog.py | 0 .../conversation_filter.py | 0 .../dispatch_action_configuration.py | 0 .../option.py | 0 .../option_group.py | 0 .../slack_file.py | 0 .../text.py | 0 .../trigger.py | 0 .../workflow.py | 0 .../__init__.py | 0 .../test_confirmation_dialog.py | 2 +- .../test_conversation_filter.py | 2 +- .../test_dispatch_action_configuration.py | 2 +- .../test_option.py | 2 +- .../test_option_group.py | 2 +- .../test_slack_file.py | 2 +- .../test_text.py | 2 +- .../test_trigger.py | 2 +- .../test_workflow.py | 2 +- 21 files changed, 18 insertions(+), 18 deletions(-) rename block-kit/src/{composition_objects => compositions}/__init__.py (100%) rename block-kit/src/{composition_objects => compositions}/confirmation_dialog.py (100%) rename block-kit/src/{composition_objects => compositions}/conversation_filter.py (100%) rename block-kit/src/{composition_objects => compositions}/dispatch_action_configuration.py (100%) rename block-kit/src/{composition_objects => compositions}/option.py (100%) rename block-kit/src/{composition_objects => compositions}/option_group.py (100%) rename block-kit/src/{composition_objects => compositions}/slack_file.py (100%) rename block-kit/src/{composition_objects => compositions}/text.py (100%) rename block-kit/src/{composition_objects => compositions}/trigger.py (100%) rename block-kit/src/{composition_objects => compositions}/workflow.py (100%) rename block-kit/tests/{composition_objects => compositions}/__init__.py (100%) rename block-kit/tests/{composition_objects => compositions}/test_confirmation_dialog.py (96%) rename block-kit/tests/{composition_objects => compositions}/test_conversation_filter.py (96%) rename block-kit/tests/{composition_objects => compositions}/test_dispatch_action_configuration.py (90%) rename block-kit/tests/{composition_objects => compositions}/test_option.py (98%) rename block-kit/tests/{composition_objects => compositions}/test_option_group.py (98%) rename block-kit/tests/{composition_objects => compositions}/test_slack_file.py (95%) rename block-kit/tests/{composition_objects => compositions}/test_text.py (90%) rename block-kit/tests/{composition_objects => compositions}/test_trigger.py (96%) rename block-kit/tests/{composition_objects => compositions}/test_workflow.py (96%) diff --git a/block-kit/README.md b/block-kit/README.md index 2247c03..afa8ce0 100644 --- a/block-kit/README.md +++ b/block-kit/README.md @@ -27,12 +27,12 @@ Read the [docs](https://docs.slack.dev/block-kit/) to learn concepts behind thes ### Composition objects -- **[Confirmation dialog](https://docs.slack.dev/reference/block-kit/composition-objects/confirmation-dialog-object)**: Defines a dialog that adds a confirmation step to interactive elements. [Implementation](./src/composition_objects/confirmation_dialog.py). -- **[Conversation filter](https://docs.slack.dev/reference/block-kit/composition-objects/conversation-filter-object)**: Defines a filter for the list of options in a conversation selector menu. [Implementation](./src/composition_objects/conversation_filter.py). -- **[Dispatch action configuration](https://docs.slack.dev/reference/block-kit/composition-objects/dispatch-action-configuration-object)**: Defines when a plain-text input element will return a block_actions interaction payload. [Implementation](./src/composition_objects/dispatch_action_configuration.py). -- **[Option](https://docs.slack.dev/reference/block-kit/composition-objects/option-object)**: Defines a single item in a number of item selection elements. [Implementation](./src/composition_objects/option.py). -- **[Option group](https://docs.slack.dev/reference/block-kit/composition-objects/option-group-object)**: Defines a way to group options in a menu. [Implementation](./src/composition_objects/option_group.py). -- **[Slack file](https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object)**: Defines an object containing Slack file information to be used in an image block or image element. [Implementation](./src/composition_objects/slack_file.py). -- **[Text](https://docs.slack.dev/reference/block-kit/composition-objects/text-object)**: Defines an object containing some text. [Implementation](./src/composition_objects/text.py). -- **[Trigger](https://docs.slack.dev/reference/block-kit/composition-objects/trigger-object)**: Defines an object containing trigger information. [Implementation](./src/composition_objects/trigger.py). -- **[Workflow](https://docs.slack.dev/reference/block-kit/composition-objects/workflow-object)**: Defines an object containing workflow information. [Implementation](./src/composition_objects/workflow.py). +- **[Confirmation dialog](https://docs.slack.dev/reference/block-kit/composition-objects/confirmation-dialog-object)**: Defines a dialog that adds a confirmation step to interactive elements. [Implementation](./src/compositions/confirmation_dialog.py). +- **[Conversation filter](https://docs.slack.dev/reference/block-kit/composition-objects/conversation-filter-object)**: Defines a filter for the list of options in a conversation selector menu. [Implementation](./src/compositions/conversation_filter.py). +- **[Dispatch action configuration](https://docs.slack.dev/reference/block-kit/composition-objects/dispatch-action-configuration-object)**: Defines when a plain-text input element will return a block_actions interaction payload. [Implementation](./src/compositions/dispatch_action_configuration.py). +- **[Option](https://docs.slack.dev/reference/block-kit/composition-objects/option-object)**: Defines a single item in a number of item selection elements. [Implementation](./src/compositions/option.py). +- **[Option group](https://docs.slack.dev/reference/block-kit/composition-objects/option-group-object)**: Defines a way to group options in a menu. [Implementation](./src/compositions/option_group.py). +- **[Slack file](https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object)**: Defines an object containing Slack file information to be used in an image block or image element. [Implementation](./src/compositions/slack_file.py). +- **[Text](https://docs.slack.dev/reference/block-kit/composition-objects/text-object)**: Defines an object containing some text. [Implementation](./src/compositions/text.py). +- **[Trigger](https://docs.slack.dev/reference/block-kit/composition-objects/trigger-object)**: Defines an object containing trigger information. [Implementation](./src/compositions/trigger.py). +- **[Workflow](https://docs.slack.dev/reference/block-kit/composition-objects/workflow-object)**: Defines an object containing workflow information. [Implementation](./src/compositions/workflow.py). diff --git a/block-kit/src/composition_objects/__init__.py b/block-kit/src/compositions/__init__.py similarity index 100% rename from block-kit/src/composition_objects/__init__.py rename to block-kit/src/compositions/__init__.py diff --git a/block-kit/src/composition_objects/confirmation_dialog.py b/block-kit/src/compositions/confirmation_dialog.py similarity index 100% rename from block-kit/src/composition_objects/confirmation_dialog.py rename to block-kit/src/compositions/confirmation_dialog.py diff --git a/block-kit/src/composition_objects/conversation_filter.py b/block-kit/src/compositions/conversation_filter.py similarity index 100% rename from block-kit/src/composition_objects/conversation_filter.py rename to block-kit/src/compositions/conversation_filter.py diff --git a/block-kit/src/composition_objects/dispatch_action_configuration.py b/block-kit/src/compositions/dispatch_action_configuration.py similarity index 100% rename from block-kit/src/composition_objects/dispatch_action_configuration.py rename to block-kit/src/compositions/dispatch_action_configuration.py diff --git a/block-kit/src/composition_objects/option.py b/block-kit/src/compositions/option.py similarity index 100% rename from block-kit/src/composition_objects/option.py rename to block-kit/src/compositions/option.py diff --git a/block-kit/src/composition_objects/option_group.py b/block-kit/src/compositions/option_group.py similarity index 100% rename from block-kit/src/composition_objects/option_group.py rename to block-kit/src/compositions/option_group.py diff --git a/block-kit/src/composition_objects/slack_file.py b/block-kit/src/compositions/slack_file.py similarity index 100% rename from block-kit/src/composition_objects/slack_file.py rename to block-kit/src/compositions/slack_file.py diff --git a/block-kit/src/composition_objects/text.py b/block-kit/src/compositions/text.py similarity index 100% rename from block-kit/src/composition_objects/text.py rename to block-kit/src/compositions/text.py diff --git a/block-kit/src/composition_objects/trigger.py b/block-kit/src/compositions/trigger.py similarity index 100% rename from block-kit/src/composition_objects/trigger.py rename to block-kit/src/compositions/trigger.py diff --git a/block-kit/src/composition_objects/workflow.py b/block-kit/src/compositions/workflow.py similarity index 100% rename from block-kit/src/composition_objects/workflow.py rename to block-kit/src/compositions/workflow.py diff --git a/block-kit/tests/composition_objects/__init__.py b/block-kit/tests/compositions/__init__.py similarity index 100% rename from block-kit/tests/composition_objects/__init__.py rename to block-kit/tests/compositions/__init__.py diff --git a/block-kit/tests/composition_objects/test_confirmation_dialog.py b/block-kit/tests/compositions/test_confirmation_dialog.py similarity index 96% rename from block-kit/tests/composition_objects/test_confirmation_dialog.py rename to block-kit/tests/compositions/test_confirmation_dialog.py index 610f959..8424a95 100644 --- a/block-kit/tests/composition_objects/test_confirmation_dialog.py +++ b/block-kit/tests/compositions/test_confirmation_dialog.py @@ -1,6 +1,6 @@ import json -from src.composition_objects import confirmation_dialog +from src.compositions import confirmation_dialog def test_example01(): diff --git a/block-kit/tests/composition_objects/test_conversation_filter.py b/block-kit/tests/compositions/test_conversation_filter.py similarity index 96% rename from block-kit/tests/composition_objects/test_conversation_filter.py rename to block-kit/tests/compositions/test_conversation_filter.py index c156ce8..25dffb2 100644 --- a/block-kit/tests/composition_objects/test_conversation_filter.py +++ b/block-kit/tests/compositions/test_conversation_filter.py @@ -1,6 +1,6 @@ import json -from src.composition_objects import conversation_filter +from src.compositions import conversation_filter def test_example01(): diff --git a/block-kit/tests/composition_objects/test_dispatch_action_configuration.py b/block-kit/tests/compositions/test_dispatch_action_configuration.py similarity index 90% rename from block-kit/tests/composition_objects/test_dispatch_action_configuration.py rename to block-kit/tests/compositions/test_dispatch_action_configuration.py index 1a3a0fb..0bb451c 100644 --- a/block-kit/tests/composition_objects/test_dispatch_action_configuration.py +++ b/block-kit/tests/compositions/test_dispatch_action_configuration.py @@ -1,6 +1,6 @@ import json -from src.composition_objects import dispatch_action_configuration +from src.compositions import dispatch_action_configuration def test_example01(): diff --git a/block-kit/tests/composition_objects/test_option.py b/block-kit/tests/compositions/test_option.py similarity index 98% rename from block-kit/tests/composition_objects/test_option.py rename to block-kit/tests/compositions/test_option.py index b314112..abdd816 100644 --- a/block-kit/tests/composition_objects/test_option.py +++ b/block-kit/tests/compositions/test_option.py @@ -1,6 +1,6 @@ import json -from src.composition_objects import option +from src.compositions import option def test_example01(): diff --git a/block-kit/tests/composition_objects/test_option_group.py b/block-kit/tests/compositions/test_option_group.py similarity index 98% rename from block-kit/tests/composition_objects/test_option_group.py rename to block-kit/tests/compositions/test_option_group.py index abb141d..e764ca1 100644 --- a/block-kit/tests/composition_objects/test_option_group.py +++ b/block-kit/tests/compositions/test_option_group.py @@ -1,6 +1,6 @@ import json -from src.composition_objects import option_group +from src.compositions import option_group def test_example01(): diff --git a/block-kit/tests/composition_objects/test_slack_file.py b/block-kit/tests/compositions/test_slack_file.py similarity index 95% rename from block-kit/tests/composition_objects/test_slack_file.py rename to block-kit/tests/compositions/test_slack_file.py index e9c22f3..56bb541 100644 --- a/block-kit/tests/composition_objects/test_slack_file.py +++ b/block-kit/tests/compositions/test_slack_file.py @@ -1,6 +1,6 @@ import json -from src.composition_objects import slack_file +from src.compositions import slack_file def test_example01(): diff --git a/block-kit/tests/composition_objects/test_text.py b/block-kit/tests/compositions/test_text.py similarity index 90% rename from block-kit/tests/composition_objects/test_text.py rename to block-kit/tests/compositions/test_text.py index 0db4964..6eb9ade 100644 --- a/block-kit/tests/composition_objects/test_text.py +++ b/block-kit/tests/compositions/test_text.py @@ -1,6 +1,6 @@ import json -from src.composition_objects import text +from src.compositions import text def test_example01(): diff --git a/block-kit/tests/composition_objects/test_trigger.py b/block-kit/tests/compositions/test_trigger.py similarity index 96% rename from block-kit/tests/composition_objects/test_trigger.py rename to block-kit/tests/compositions/test_trigger.py index b297691..cb5fccb 100644 --- a/block-kit/tests/composition_objects/test_trigger.py +++ b/block-kit/tests/compositions/test_trigger.py @@ -1,6 +1,6 @@ import json -from src.composition_objects import trigger +from src.compositions import trigger def test_example01(): diff --git a/block-kit/tests/composition_objects/test_workflow.py b/block-kit/tests/compositions/test_workflow.py similarity index 96% rename from block-kit/tests/composition_objects/test_workflow.py rename to block-kit/tests/compositions/test_workflow.py index a1ad500..a6e9f21 100644 --- a/block-kit/tests/composition_objects/test_workflow.py +++ b/block-kit/tests/compositions/test_workflow.py @@ -1,6 +1,6 @@ import json -from src.composition_objects import workflow +from src.compositions import workflow def test_example01(): From dda460898d58cf06c99edb22e0432dc2dff233dd Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 1 Sep 2026 03:14:20 -0700 Subject: [PATCH 04/11] docs(block-kit): order Option group before Option to match docs composition index Co-Authored-By: Claude --- block-kit/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-kit/README.md b/block-kit/README.md index afa8ce0..0906a2e 100644 --- a/block-kit/README.md +++ b/block-kit/README.md @@ -30,8 +30,8 @@ Read the [docs](https://docs.slack.dev/block-kit/) to learn concepts behind thes - **[Confirmation dialog](https://docs.slack.dev/reference/block-kit/composition-objects/confirmation-dialog-object)**: Defines a dialog that adds a confirmation step to interactive elements. [Implementation](./src/compositions/confirmation_dialog.py). - **[Conversation filter](https://docs.slack.dev/reference/block-kit/composition-objects/conversation-filter-object)**: Defines a filter for the list of options in a conversation selector menu. [Implementation](./src/compositions/conversation_filter.py). - **[Dispatch action configuration](https://docs.slack.dev/reference/block-kit/composition-objects/dispatch-action-configuration-object)**: Defines when a plain-text input element will return a block_actions interaction payload. [Implementation](./src/compositions/dispatch_action_configuration.py). -- **[Option](https://docs.slack.dev/reference/block-kit/composition-objects/option-object)**: Defines a single item in a number of item selection elements. [Implementation](./src/compositions/option.py). - **[Option group](https://docs.slack.dev/reference/block-kit/composition-objects/option-group-object)**: Defines a way to group options in a menu. [Implementation](./src/compositions/option_group.py). +- **[Option](https://docs.slack.dev/reference/block-kit/composition-objects/option-object)**: Defines a single item in a number of item selection elements. [Implementation](./src/compositions/option.py). - **[Slack file](https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object)**: Defines an object containing Slack file information to be used in an image block or image element. [Implementation](./src/compositions/slack_file.py). - **[Text](https://docs.slack.dev/reference/block-kit/composition-objects/text-object)**: Defines an object containing some text. [Implementation](./src/compositions/text.py). - **[Trigger](https://docs.slack.dev/reference/block-kit/composition-objects/trigger-object)**: Defines an object containing trigger information. [Implementation](./src/compositions/trigger.py). From 473ed1b14851afbc505953c6834cc760d7f95ea1 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 1 Sep 2026 03:23:25 -0700 Subject: [PATCH 05/11] docs(block-kit): align text example secondary description with docs prose Match "a section block containing a text object" from the text-object reference page. Co-Authored-By: Claude --- block-kit/src/compositions/text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-kit/src/compositions/text.py b/block-kit/src/compositions/text.py index 58977a7..39dfb34 100644 --- a/block-kit/src/compositions/text.py +++ b/block-kit/src/compositions/text.py @@ -7,7 +7,7 @@ def example01() -> SectionBlock: Defines an object containing some text. https://docs.slack.dev/reference/block-kit/composition-objects/text-object/ - A section block containing an mrkdwn text object. + A section block containing a text object. """ block = SectionBlock( text=MarkdownTextObject( From c4dfe05d5327a4bb3f8e648caaca24cf6cf4b221 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 1 Sep 2026 03:27:26 -0700 Subject: [PATCH 06/11] docs(block-kit): align slack_file example descriptions with the 'containing' phrasing Drop 'hosting'/divergent wording; unify all langs on 'An image block containing a Slack file object referenced by url/id.' Co-Authored-By: Claude --- block-kit/src/compositions/slack_file.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block-kit/src/compositions/slack_file.py b/block-kit/src/compositions/slack_file.py index a6d72a8..374c31e 100644 --- a/block-kit/src/compositions/slack_file.py +++ b/block-kit/src/compositions/slack_file.py @@ -7,7 +7,7 @@ def example01() -> ImageBlock: Defines an object containing Slack file information to be used in an image block or image element. https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object/ - An image block referencing a Slack file by URL. + An image block containing a Slack file object referenced by url. """ block = ImageBlock( title=PlainTextObject(text="Please enjoy this photo of a kitten"), @@ -22,7 +22,7 @@ def example01() -> ImageBlock: def example02() -> ImageBlock: """ - An image block referencing a Slack file by ID. + An image block containing a Slack file object referenced by id. """ block = ImageBlock( title=PlainTextObject(text="Please enjoy this photo of a kitten"), From c82231c17835620818aa11dc874f1b4ec6ac47b2 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 1 Sep 2026 03:29:22 -0700 Subject: [PATCH 07/11] docs(block-kit): match slack_file example descriptions to the blocks/image example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Duplicate the canonical 'An image block using slack_file with a url/id.' phrasing rather than diverging — the composition example demonstrates the same payload as blocks/image, so the wording matches by design. Co-Authored-By: Claude --- block-kit/src/compositions/slack_file.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block-kit/src/compositions/slack_file.py b/block-kit/src/compositions/slack_file.py index 374c31e..61f2cfa 100644 --- a/block-kit/src/compositions/slack_file.py +++ b/block-kit/src/compositions/slack_file.py @@ -7,7 +7,7 @@ def example01() -> ImageBlock: Defines an object containing Slack file information to be used in an image block or image element. https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object/ - An image block containing a Slack file object referenced by url. + An image block using slack_file with a url. """ block = ImageBlock( title=PlainTextObject(text="Please enjoy this photo of a kitten"), @@ -22,7 +22,7 @@ def example01() -> ImageBlock: def example02() -> ImageBlock: """ - An image block containing a Slack file object referenced by id. + An image block using slack_file with an id. """ block = ImageBlock( title=PlainTextObject(text="Please enjoy this photo of a kitten"), From 5cc89a5f7a348eaedf2ec5e921a916cfb847b75c Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 1 Sep 2026 03:32:26 -0700 Subject: [PATCH 08/11] docs(block-kit): align option_group example description with docs prose Match "a static select menu containing the option group object" from the option-group-object reference page; drop 'hosted'/divergent per-lang wording. Co-Authored-By: Claude --- block-kit/src/compositions/option_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-kit/src/compositions/option_group.py b/block-kit/src/compositions/option_group.py index 812387e..ad2b242 100644 --- a/block-kit/src/compositions/option_group.py +++ b/block-kit/src/compositions/option_group.py @@ -13,7 +13,7 @@ def example01() -> list[Block]: Defines a way to group options in a menu. https://docs.slack.dev/reference/block-kit/composition-objects/option-group-object/ - Option groups used within a select menu accessory on a section block. + A static select menu containing the option group object. """ blocks: list[Block] = [ SectionBlock( From df3fc8fcfd3ff3ae54476bae89baf3e79e0630a3 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 1 Sep 2026 03:37:54 -0700 Subject: [PATCH 09/11] docs(block-kit): align option example description with docs prose Use "A static select menu element with several option objects." (from the option-object reference page); drop 'hosted'/divergent per-lang wording. Co-Authored-By: Claude --- block-kit/src/compositions/option.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-kit/src/compositions/option.py b/block-kit/src/compositions/option.py index 5938550..a98cd1c 100644 --- a/block-kit/src/compositions/option.py +++ b/block-kit/src/compositions/option.py @@ -23,7 +23,7 @@ def example01() -> Option: def example02() -> list[Block]: """ - Options used within a select menu accessory on a section block. + A static select menu element with several option objects. """ blocks: list[Block] = [ SectionBlock( From c8c0f56ef61a8dd700a255bacc653c97c775cddd Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 1 Sep 2026 03:47:10 -0700 Subject: [PATCH 10/11] test: revert split-attribute reformat of blocks tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The split-attribute restyle of test_plan/test_rich_text/test_table/ test_task_card (from f6ab6df) is out of scope for the composition-objects examples PR — those blocks tests were already merged (#4, #35, #100). Move the restyle to its own PR so this one is scoped to compositions/ + README. ruff accepts both the compact (main) and split forms, so CI stays green. Co-Authored-By: Claude --- block-kit/tests/blocks/test_plan.py | 12 ++-- block-kit/tests/blocks/test_rich_text.py | 80 ++++++++---------------- block-kit/tests/blocks/test_table.py | 36 +++-------- block-kit/tests/blocks/test_task_card.py | 4 +- 4 files changed, 43 insertions(+), 89 deletions(-) diff --git a/block-kit/tests/blocks/test_plan.py b/block-kit/tests/blocks/test_plan.py index 814e590..e806350 100644 --- a/block-kit/tests/blocks/test_plan.py +++ b/block-kit/tests/blocks/test_plan.py @@ -25,9 +25,9 @@ def test_example01(): { "type": "text", "text": "Searched database...", - }, + } ], - }, + } ], }, "output": { @@ -40,9 +40,9 @@ def test_example01(): { "type": "text", "text": "Profile data loaded", - }, + } ], - }, + } ], }, }, @@ -67,9 +67,9 @@ def test_example01(): { "type": "text", "text": "15 data points compiled", - }, + } ], - }, + } ], }, }, diff --git a/block-kit/tests/blocks/test_rich_text.py b/block-kit/tests/blocks/test_rich_text.py index 7c4eb20..fb6ef56 100644 --- a/block-kit/tests/blocks/test_rich_text.py +++ b/block-kit/tests/blocks/test_rich_text.py @@ -16,9 +16,9 @@ def test_example01(): { "type": "text", "text": "Hello there, I am a basic rich text block!", - }, + } ], - }, + } ], }, { @@ -39,7 +39,7 @@ def test_example01(): }, }, ], - }, + } ], }, { @@ -60,7 +60,7 @@ def test_example01(): }, }, ], - }, + } ], }, { @@ -81,7 +81,7 @@ def test_example01(): }, }, ], - }, + } ], }, ] @@ -101,7 +101,7 @@ def test_example02(): { "type": "text", "text": "My favorite Slack features (in no particular order):", - }, + } ], }, { @@ -221,7 +221,7 @@ def test_example03(): "text": "Pancakes, extra syrup", }, ], - }, + } ], }, ], @@ -241,10 +241,10 @@ def test_example04(): { "type": "text", "text": '{\n "object": {\n "description": "this is an example of a json object"\n }\n}', - }, + } ], "border": 0, - }, + } ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -263,7 +263,7 @@ def test_example05(): { "type": "text", "text": "What we need is good examples in our documentation.", - }, + } ], }, { @@ -288,13 +288,8 @@ def test_example06(): "elements": [ { "type": "rich_text_section", - "elements": [ - { - "type": "broadcast", - "range": "everyone", - }, - ], - }, + "elements": [{"type": "broadcast", "range": "everyone"}], + } ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -308,13 +303,8 @@ def test_example07(): "elements": [ { "type": "rich_text_section", - "elements": [ - { - "type": "color", - "value": "#F405B3", - }, - ], - }, + "elements": [{"type": "color", "value": "#F405B3"}], + } ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -328,13 +318,8 @@ def test_example08(): "elements": [ { "type": "rich_text_section", - "elements": [ - { - "type": "channel", - "channel_id": "C123ABC456", - }, - ], - }, + "elements": [{"type": "channel", "channel_id": "C123ABC456"}], + } ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -354,9 +339,9 @@ def test_example09(): "timestamp": 1720710212, "format": "{date_num} at {time}", "fallback": "timey", - }, + } ], - }, + } ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -392,7 +377,7 @@ def test_example10(): "name": "checkered_flag", }, ], - }, + } ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -406,13 +391,8 @@ def test_example11(): "elements": [ { "type": "rich_text_section", - "elements": [ - { - "type": "link", - "url": "https://api.slack.com", - }, - ], - }, + "elements": [{"type": "link", "url": "https://api.slack.com"}], + } ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -426,13 +406,8 @@ def test_example12(): "elements": [ { "type": "rich_text_section", - "elements": [ - { - "type": "user", - "user_id": "U123ABC456", - }, - ], - }, + "elements": [{"type": "user", "user_id": "U123ABC456"}], + } ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -446,13 +421,8 @@ def test_example13(): "elements": [ { "type": "rich_text_section", - "elements": [ - { - "type": "usergroup", - "usergroup_id": "G123ABC456", - }, - ], - }, + "elements": [{"type": "usergroup", "usergroup_id": "G123ABC456"}], + } ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/blocks/test_table.py b/block-kit/tests/blocks/test_table.py index d527739..f8eb942 100644 --- a/block-kit/tests/blocks/test_table.py +++ b/block-kit/tests/blocks/test_table.py @@ -9,29 +9,16 @@ def test_example01(): expected = { "type": "table", "column_settings": [ - { - "is_wrapped": True, - }, - { - "align": "right", - }, + {"is_wrapped": True}, + {"align": "right"}, ], "rows": [ [ - { - "type": "raw_text", - "text": "Header A", - }, - { - "type": "raw_text", - "text": "Header B", - }, + {"type": "raw_text", "text": "Header A"}, + {"type": "raw_text", "text": "Header B"}, ], [ - { - "type": "raw_text", - "text": "Data 1A", - }, + {"type": "raw_text", "text": "Data 1A"}, { "type": "rich_text", "elements": [ @@ -42,17 +29,14 @@ def test_example01(): "type": "link", "text": "Data 1B", "url": "https://slack.com", - }, + } ], - }, + } ], }, ], [ - { - "type": "raw_text", - "text": "Data 2A", - }, + {"type": "raw_text", "text": "Data 2A"}, { "type": "rich_text", "elements": [ @@ -63,9 +47,9 @@ def test_example01(): "type": "link", "text": "Data 2B", "url": "https://slack.com", - }, + } ], - }, + } ], }, ], diff --git a/block-kit/tests/blocks/test_task_card.py b/block-kit/tests/blocks/test_task_card.py index b0a79bd..802b924 100644 --- a/block-kit/tests/blocks/test_task_card.py +++ b/block-kit/tests/blocks/test_task_card.py @@ -20,9 +20,9 @@ def test_example01(): { "type": "text", "text": "Found weather data for Chicago from 2 sources", - }, + } ], - }, + } ], }, "sources": [ From 6bafdd95e0d1cd66795a1691f4f541b6d5942772 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 1 Sep 2026 03:57:31 -0700 Subject: [PATCH 11/11] docs(block-kit): align composition example descriptions with JS/Java Match the Python secondary descriptions for confirmation_dialog, conversation_filter, dispatch_action_configuration, trigger, and workflow to the wording already used in the JS (standard) and Java example repos, so the same payload reads identically across languages. Python was the outlier using a different "...whose X does Y" phrasing; JS/Java use "...with an X carrying a Y". trigger/workflow have no JS counterpart, so they follow Java. Verified each description against the payload it builds (e.g. the dispatch input is multiline; the trigger carries customizable_input_parameters). Co-Authored-By: Claude --- block-kit/src/compositions/confirmation_dialog.py | 2 +- block-kit/src/compositions/conversation_filter.py | 2 +- block-kit/src/compositions/dispatch_action_configuration.py | 2 +- block-kit/src/compositions/trigger.py | 2 +- block-kit/src/compositions/workflow.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/block-kit/src/compositions/confirmation_dialog.py b/block-kit/src/compositions/confirmation_dialog.py index d3cfea8..54a3b91 100644 --- a/block-kit/src/compositions/confirmation_dialog.py +++ b/block-kit/src/compositions/confirmation_dialog.py @@ -12,7 +12,7 @@ def example01() -> ActionsBlock: Defines a dialog that adds a confirmation step to interactive elements. https://docs.slack.dev/reference/block-kit/composition-objects/confirmation-dialog-object/ - An actions block with a button that opens a confirmation dialog. + An actions block with a button carrying a confirmation dialog. """ block = ActionsBlock( elements=[ diff --git a/block-kit/src/compositions/conversation_filter.py b/block-kit/src/compositions/conversation_filter.py index a854f4e..11c2174 100644 --- a/block-kit/src/compositions/conversation_filter.py +++ b/block-kit/src/compositions/conversation_filter.py @@ -12,7 +12,7 @@ def example01() -> View: Defines a filter for the list of options in a conversation selector menu. https://docs.slack.dev/reference/block-kit/composition-objects/conversation-filter-object/ - A modal view whose conversations select filters the listed conversations. + A modal view with a conversations select input carrying a conversation filter. """ view = View( type="modal", diff --git a/block-kit/src/compositions/dispatch_action_configuration.py b/block-kit/src/compositions/dispatch_action_configuration.py index 563da2c..31664b3 100644 --- a/block-kit/src/compositions/dispatch_action_configuration.py +++ b/block-kit/src/compositions/dispatch_action_configuration.py @@ -11,7 +11,7 @@ def example01() -> InputBlock: Defines when a plain-text input element will return a block_actions interaction payload. https://docs.slack.dev/reference/block-kit/composition-objects/dispatch-action-configuration-object/ - An input block whose plain-text input dispatches actions on character entry. + An input block with a multiline plain-text input carrying a dispatch action configuration. """ block = InputBlock( dispatch_action=True, diff --git a/block-kit/src/compositions/trigger.py b/block-kit/src/compositions/trigger.py index f70e8af..8c49351 100644 --- a/block-kit/src/compositions/trigger.py +++ b/block-kit/src/compositions/trigger.py @@ -13,7 +13,7 @@ def example01() -> SectionBlock: Defines an object containing trigger information. https://docs.slack.dev/reference/block-kit/composition-objects/trigger-object/ - A workflow button whose trigger carries a URL and customizable inputs. + A section block with a workflow button whose trigger carries customizable input parameters. """ block = SectionBlock( text=MarkdownTextObject( diff --git a/block-kit/src/compositions/workflow.py b/block-kit/src/compositions/workflow.py index 5fc4048..b761a0f 100644 --- a/block-kit/src/compositions/workflow.py +++ b/block-kit/src/compositions/workflow.py @@ -13,7 +13,7 @@ def example01() -> SectionBlock: Defines an object containing workflow information. https://docs.slack.dev/reference/block-kit/composition-objects/workflow-object/ - A workflow button whose workflow references a configured trigger. + A section block with a workflow button whose workflow carries a trigger. """ block = SectionBlock( text=MarkdownTextObject(