Skip to content

Commit

Permalink
Add workflow_button block element (#1399)
Browse files Browse the repository at this point in the history
  • Loading branch information
seratch authored Sep 8, 2023
1 parent d468b35 commit 60d4a95
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 1 deletion.
35 changes: 35 additions & 0 deletions slack_sdk/models/blocks/basic_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,3 +524,38 @@ def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221
if self._trigger_actions_on:
json["trigger_actions_on"] = self._trigger_actions_on
return json


class WorkflowTrigger(JsonObject):
attributes = {"trigger"}

def __init__(self, *, url: str, customizable_input_parameters: Optional[List[Dict[str, str]]] = None):
self._url = url
self._customizable_input_parameters = customizable_input_parameters

def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221
self.validate_json()
json = {"url": self._url}
if self._customizable_input_parameters is not None:
json.update({"customizable_input_parameters": self._customizable_input_parameters})
return json


class Workflow(JsonObject):
attributes = {"trigger"}

def __init__(
self,
*,
trigger: Union[WorkflowTrigger, dict],
):
self._trigger = trigger

def to_dict(self) -> Dict[str, Any]: # skipcq: PYL-W0221
self.validate_json()
json = {}
if isinstance(self._trigger, WorkflowTrigger):
json["trigger"] = self._trigger.to_dict()
else:
json["trigger"] = self._trigger
return json
59 changes: 58 additions & 1 deletion slack_sdk/models/blocks/block_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
JsonValidator,
EnumValidator,
)
from .basic_components import ButtonStyles
from .basic_components import ButtonStyles, Workflow
from .basic_components import ConfirmObject
from .basic_components import DispatchActionConfig
from .basic_components import MarkdownTextObject
Expand Down Expand Up @@ -1689,3 +1689,60 @@ def __init__(
@JsonValidator(f"options attribute must have between {options_min_length} " f"and {options_max_length} items")
def _validate_options_length(self) -> bool:
return self.options_min_length <= len(self.options) <= self.options_max_length


# -------------------------------------------------
# Workflow Button
# -------------------------------------------------


class WorkflowButtonElement(InteractiveElement):
type = "workflow_button"

@property
def attributes(self) -> Set[str]:
return super().attributes.union({"text", "workflow", "style", "accessibility_label"})

def __init__(
self,
*,
text: Union[str, dict, TextObject],
action_id: Optional[str] = None,
workflow: Optional[Union[dict, Workflow]] = None,
style: Optional[str] = None, # primary, danger
accessibility_label: Optional[str] = None,
**others: dict,
):
"""Allows users to run a link trigger with customizable inputs
Interactive component - but interactions with workflow button elements will not send block_actions events,
since these are used to start new workflow runs.
https://api.slack.com/reference/block-kit/block-elements#workflow_button
Args:
text (required): A text object that defines the button's text.
Can only be of type: plain_text. text may truncate with ~30 characters.
Maximum length for the text in this field is 75 characters.
action_id (required): An identifier for this action.
You can use this when you receive an interaction payload to identify the source of the action.
Should be unique among all other action_ids in the containing block.
Maximum length for this field is 255 characters.
workflow: A workflow object that contains details about the workflow
that will run when the button is clicked.
style: Decorates buttons with alternative visual color schemes. Use this option with restraint.
"primary" gives buttons a green outline and text, ideal for affirmation or confirmation actions.
"primary" should only be used for one button within a set.
"danger" gives buttons a red outline and text, and should be used when the action is destructive.
Use "danger" even more sparingly than "primary".
If you don't include this field, the default button style will be used.
accessibility_label: A label for longer descriptive text about a button element.
This label will be read out by screen readers instead of the button text object.
Maximum length for this field is 75 characters.
"""
super().__init__(action_id=action_id, type=self.type)
show_unknown_key_warning(self, others)

# NOTE: default_type=PlainTextObject.type here is only for backward-compatibility with version 2.5.0
self.text = TextObject.parse(text, default_type=PlainTextObject.type)
self.workflow = workflow
self.style = style
self.accessibility_label = accessibility_label
24 changes: 24 additions & 0 deletions tests/slack_sdk/models/test_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
EmailInputElement,
NumberInputElement,
UrlInputElement,
WorkflowButtonElement,
)
from . import STRING_3001_CHARS, STRING_301_CHARS

Expand Down Expand Up @@ -1213,3 +1214,26 @@ def test_focus_on_load(self):
"focus_on_load": True,
}
self.assertDictEqual(input, RadioButtonsElement(**input).to_dict())


# -------------------------------------------------
# Workflow Button
# -------------------------------------------------


class WorkflowButtonElementTests(unittest.TestCase):
def test_load(self):
input = {
"type": "workflow_button",
"text": {"type": "plain_text", "text": "Run Workflow"},
"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"},
],
}
},
}
self.assertDictEqual(input, WorkflowButtonElement(**input).to_dict())
26 changes: 26 additions & 0 deletions tests/slack_sdk/models/test_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
OptionGroup,
PlainTextObject,
)
from slack_sdk.models.blocks.basic_components import Workflow, WorkflowTrigger
from slack_sdk.models.messages import (
ChannelLink,
DateLink,
Expand Down Expand Up @@ -566,3 +567,28 @@ def test_confirm_style_validation(self):
"style": "something-wrong",
}
).validate_json()


class WorkflowTests(unittest.TestCase):
def test_creation(self):
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"},
],
)
)
self.assertDictEqual(
workflow.to_dict(),
{
"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"},
],
}
},
)

0 comments on commit 60d4a95

Please sign in to comment.