Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 71 additions & 56 deletions slack_sdk/models/blocks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,67 +6,79 @@
* https://api.slack.com/reference/block-kit/blocks
* https://app.slack.com/block-kit-builder
"""
from .basic_components import ButtonStyles
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 note: Automatic import sorting and grouping captures most of these changes!

from .basic_components import ConfirmObject
from .basic_components import DynamicSelectElementTypes
from .basic_components import MarkdownTextObject
from .basic_components import Option
from .basic_components import OptionGroup
from .basic_components import PlainTextObject
from .basic_components import TextObject
from .block_elements import BlockElement
from .block_elements import ButtonElement
from .block_elements import ChannelMultiSelectElement
from .block_elements import ChannelSelectElement
from .block_elements import CheckboxesElement
from .block_elements import ConversationFilter
from .block_elements import ConversationMultiSelectElement
from .block_elements import ConversationSelectElement
from .block_elements import DatePickerElement
from .block_elements import TimePickerElement
from .block_elements import DateTimePickerElement
from .block_elements import ExternalDataMultiSelectElement
from .block_elements import ExternalDataSelectElement
from .block_elements import ImageElement
from .block_elements import InputInteractiveElement
from .block_elements import InteractiveElement
from .block_elements import LinkButtonElement
from .block_elements import OverflowMenuElement
from .block_elements import RichTextInputElement
from .block_elements import PlainTextInputElement
from .block_elements import EmailInputElement
from .block_elements import UrlInputElement
from .block_elements import NumberInputElement
from .block_elements import RadioButtonsElement
from .block_elements import SelectElement
from .block_elements import StaticMultiSelectElement
from .block_elements import StaticSelectElement
from .block_elements import UserMultiSelectElement
from .block_elements import UserSelectElement
from .block_elements import RichTextElement
from .block_elements import RichTextElementParts
from .block_elements import RichTextListElement
from .block_elements import RichTextPreformattedElement
from .block_elements import RichTextQuoteElement
from .block_elements import RichTextSectionElement
from .blocks import ActionsBlock
from .blocks import Block
from .blocks import CallBlock
from .blocks import ContextBlock
from .blocks import DividerBlock
from .blocks import FileBlock
from .blocks import HeaderBlock
from .blocks import ImageBlock
from .blocks import InputBlock
from .blocks import MarkdownBlock
from .blocks import SectionBlock
from .blocks import VideoBlock
from .blocks import RichTextBlock

from .basic_components import (
ButtonStyles,
ConfirmObject,
DynamicSelectElementTypes,
FeedbackButtonObject,
MarkdownTextObject,
Option,
OptionGroup,
PlainTextObject,
TextObject,
)
from .block_elements import (
BlockElement,
ButtonElement,
ChannelMultiSelectElement,
ChannelSelectElement,
CheckboxesElement,
ConversationFilter,
ConversationMultiSelectElement,
ConversationSelectElement,
DatePickerElement,
DateTimePickerElement,
EmailInputElement,
ExternalDataMultiSelectElement,
ExternalDataSelectElement,
FeedbackButtonsElement,
IconButtonElement,
ImageElement,
InputInteractiveElement,
InteractiveElement,
LinkButtonElement,
NumberInputElement,
OverflowMenuElement,
PlainTextInputElement,
RadioButtonsElement,
RichTextElement,
RichTextElementParts,
RichTextInputElement,
RichTextListElement,
RichTextPreformattedElement,
RichTextQuoteElement,
RichTextSectionElement,
SelectElement,
StaticMultiSelectElement,
StaticSelectElement,
TimePickerElement,
UrlInputElement,
UserMultiSelectElement,
UserSelectElement,
)
from .blocks import (
ActionsBlock,
Block,
CallBlock,
ContextActionsBlock,
ContextBlock,
DividerBlock,
FileBlock,
HeaderBlock,
ImageBlock,
InputBlock,
MarkdownBlock,
RichTextBlock,
SectionBlock,
VideoBlock,
)

__all__ = [
"ButtonStyles",
"ConfirmObject",
"DynamicSelectElementTypes",
"FeedbackButtonObject",
"MarkdownTextObject",
"Option",
"OptionGroup",
Expand All @@ -85,6 +97,8 @@
"DateTimePickerElement",
"ExternalDataMultiSelectElement",
"ExternalDataSelectElement",
"FeedbackButtonsElement",
"IconButtonElement",
"ImageElement",
"InputInteractiveElement",
"InteractiveElement",
Expand All @@ -110,6 +124,7 @@
"ActionsBlock",
"Block",
"CallBlock",
"ContextActionsBlock",
"ContextBlock",
"DividerBlock",
"FileBlock",
Expand Down
67 changes: 62 additions & 5 deletions slack_sdk/models/blocks/basic_components.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import copy
import logging
import warnings
from typing import List, Optional, Set, Union, Sequence, Dict, Any
from typing import Any, Dict, List, Optional, Sequence, Set, Union

from slack_sdk.models import show_unknown_key_warning
from slack_sdk.models.basic_objects import (
JsonObject,
JsonValidator,
)
from slack_sdk.models.basic_objects import JsonObject, JsonValidator
from slack_sdk.models.messages import Link

ButtonStyles = {"danger", "primary"}
Expand Down Expand Up @@ -526,6 +523,66 @@ def to_dict(self) -> Dict[str, Any]:
return json


class FeedbackButtonObject(JsonObject):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗣️ note: This isn't a well defined block according to the API but it's added for nested block values using these typings.

attributes: Set[str] = set()

text_max_length = 75
value_max_length = 2000

@classmethod
def parse(cls, feedback_button: Union["FeedbackButtonObject", Dict[str, Any]]):
if feedback_button:
if isinstance(feedback_button, FeedbackButtonObject):
return feedback_button
elif isinstance(feedback_button, dict):
return FeedbackButtonObject(**feedback_button)
else:
# Not yet implemented: show some warning here
return None
return None

def __init__(
self,
*,
text: Union[str, Dict[str, Any], PlainTextObject],
accessibility_label: Optional[str] = None,
value: str,
**others: Dict[str, Any],
):
"""
A feedback button element object for either positive or negative feedback.

Args:
text (required): An object containing some text. Maximum length for this field is 75 characters.
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.
value (required): The button value. Maximum length for this field is 2000 characters.
"""
self._text: Optional[TextObject] = PlainTextObject.parse(text, default_type=PlainTextObject.type)
self._accessibility_label: Optional[str] = accessibility_label
self._value: Optional[str] = value
show_unknown_key_warning(self, others)

@JsonValidator(f"text attribute cannot exceed {text_max_length} characters")
def text_length(self) -> bool:
return self._text is None or len(self._text.text) <= self.text_max_length

@JsonValidator(f"value attribute cannot exceed {value_max_length} characters")
def value_length(self) -> bool:
return self._value is None or len(self._value) <= self.value_max_length

def to_dict(self) -> Dict[str, Any]:
self.validate_json()
json: Dict[str, Union[str, dict]] = {}
if self._text:
json["text"] = self._text.to_dict()
if self._accessibility_label:
json["accessibility_label"] = self._accessibility_label
if self._value:
json["value"] = self._value
return json


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

Expand Down
119 changes: 105 additions & 14 deletions slack_sdk/models/blocks/block_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,24 @@
import re
import warnings
from abc import ABCMeta
from typing import Iterator, List, Optional, Set, Type, Union, Sequence, Dict, Any
from typing import Any, Dict, Iterator, List, Optional, Sequence, Set, Type, Union

from slack_sdk.models import show_unknown_key_warning
from slack_sdk.models.basic_objects import (
JsonObject,
JsonValidator,
EnumValidator,
from slack_sdk.models.basic_objects import EnumValidator, JsonObject, JsonValidator

from .basic_components import (
ButtonStyles,
ConfirmObject,
DispatchActionConfig,
FeedbackButtonObject,
MarkdownTextObject,
Option,
OptionGroup,
PlainTextObject,
SlackFile,
TextObject,
Workflow,
)
from .basic_components import ButtonStyles, Workflow, SlackFile
from .basic_components import ConfirmObject
from .basic_components import DispatchActionConfig
from .basic_components import MarkdownTextObject
from .basic_components import Option
from .basic_components import OptionGroup
from .basic_components import PlainTextObject
from .basic_components import TextObject


# -------------------------------------------------
# Block Elements
Expand Down Expand Up @@ -539,6 +540,43 @@ def _validate_initial_date_time_valid(self) -> bool:
return self.initial_date_time is None or (0 <= self.initial_date_time <= 9999999999)


# -------------------------------------------------
# Feedback Buttons Element
# -------------------------------------------------


class FeedbackButtonsElement(InteractiveElement):
type = "feedback_buttons"

@property
def attributes(self) -> Set[str]: # type: ignore[override]
return super().attributes.union({"positive_button", "negative_button"})

def __init__(
self,
*,
action_id: Optional[str] = None,
positive_button: Union[dict, FeedbackButtonObject],
negative_button: Union[dict, FeedbackButtonObject],
**others: dict,
):
"""Buttons to indicate positive or negative feedback.

Args:
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.
positive_button (required): A button to indicate positive feedback.
negative_button (required): A button to indicate negative feedback.
"""
super().__init__(action_id=action_id, type=self.type)
show_unknown_key_warning(self, others)

self.positive_button = FeedbackButtonObject.parse(positive_button)
self.negative_button = FeedbackButtonObject.parse(negative_button)


# -------------------------------------------------
# Image
# -------------------------------------------------
Expand Down Expand Up @@ -587,6 +625,59 @@ def _validate_alt_text_length(self) -> bool:
return len(self.alt_text) <= self.alt_text_max_length # type: ignore[arg-type]


# -------------------------------------------------
# Icon Button Element
# -------------------------------------------------


class IconButtonElement(InteractiveElement):
type = "icon_button"

@property
def attributes(self) -> Set[str]: # type: ignore[override]
return super().attributes.union({"icon", "text", "accessibility_label", "value", "visible_to_user_ids", "confirm"})

def __init__(
self,
*,
action_id: Optional[str] = None,
icon: str,
text: Union[str, dict, TextObject],
accessibility_label: Optional[str] = None,
value: Optional[str] = None,
visible_to_user_ids: Optional[List[str]] = None,
confirm: Optional[Union[dict, ConfirmObject]] = None,
**others: dict,
):
"""An icon button to perform actions.

Args:
action_id: 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.
icon (required): The icon to show (e.g., 'trash').
text (required): Defines an object containing some text.
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.
value: The button value.
Maximum length for this field is 2000 characters.
visible_to_user_ids: User IDs for which the icon appears.
Maximum length for this field is 10 user IDs.
confirm: A confirm object that defines an optional confirmation dialog after the button is clicked.
"""
super().__init__(action_id=action_id, type=self.type)
show_unknown_key_warning(self, others)

self.icon = icon
self.text = TextObject.parse(text, PlainTextObject.type)
self.accessibility_label = accessibility_label
self.value = value
self.visible_to_user_ids = visible_to_user_ids
self.confirm = ConfirmObject.parse(confirm) if confirm else None


# -------------------------------------------------
# Static Select
# -------------------------------------------------
Expand Down
Loading