Skip to content
Draft
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
1 change: 1 addition & 0 deletions block-kit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Read the [docs](https://docs.slack.dev/block-kit/) to learn concepts behind thes
- **[Actions](https://docs.slack.dev/reference/block-kit/blocks/actions-block)**: Holds multiple interactive elements. [Implementation](./src/blocks/actions.py).
- **[Context](https://docs.slack.dev/reference/block-kit/blocks/context-block)**: Provides contextual info, which can include both images and text. [Implementation](./src/blocks/context.py).
- **[Context actions](https://docs.slack.dev/reference/block-kit/blocks/context-actions-block)**: Displays actions as contextual info, which can include both feedback buttons and icon buttons. [Implementation](./src/blocks/context_actions.py).
- **[Data table](https://docs.slack.dev/reference/block-kit/blocks/data-table-block)**: Displays a rich table that supports pagination, sorting, and filtering. [Implementation](./src/blocks/data_table.py).
- **[Divider](https://docs.slack.dev/reference/block-kit/blocks/divider-block)**: Visually separates pieces of info inside of a message. [Implementation](./src/blocks/divider.py).
- **[File](https://docs.slack.dev/reference/block-kit/blocks/file-block)**: Displays info about remote files. [Implementation](./src/blocks/file.py).
- **[Header](https://docs.slack.dev/reference/block-kit/blocks/header-block)**: Displays a larger-sized text. [Implementation](./src/blocks/header.py).
Expand Down
130 changes: 130 additions & 0 deletions block-kit/src/blocks/data_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
from typing import Any, Dict, Optional, Sequence, Set

from slack_sdk.models.basic_objects import JsonValidator
from slack_sdk.models.blocks import Block


class DataTableBlock(Block):
type = "data_table"

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

def __init__(
self,
*,
rows: Sequence[Sequence[Dict[str, Any]]],
caption: str,
page_size: Optional[int] = None,
row_header_column_index: Optional[int] = None,
block_id: Optional[str] = None,
):
"""Displays a rich table that supports pagination, sorting, and filtering.
https://docs.slack.dev/reference/block-kit/blocks/data-table-block

Args:
rows (required): An array consisting of table rows. The first row is always a
header row. Tables have between 2 and 101 rows and between 1 and 20 columns.
Cells can have a type of raw_text, raw_number, or rich_text, but the header
row does not allow rich_text cells.
caption (required): A caption describing the contents of the table.
page_size: The number of rows to display per page, between 1 and 100. Defaults to 5.
row_header_column_index: The zero-based index of the column that identifies row
headers. Defaults to 0.
block_id: A unique identifier for a block. If not specified, a block_id will be
generated. Maximum length for this field is 255 characters.
"""
super().__init__(type=self.type, block_id=block_id)
self.rows = rows
self.caption = caption
self.page_size = page_size
self.row_header_column_index = row_header_column_index

@JsonValidator("rows attribute must be specified")
def _validate_rows(self) -> bool:
return self.rows is not None and len(self.rows) > 0

@JsonValidator("caption attribute must be specified")
def _validate_caption(self) -> bool:
return self.caption is not None and len(self.caption) > 0


def example01() -> DataTableBlock:
"""
Displays a rich table that supports pagination, sorting, and filtering.
https://docs.slack.dev/reference/block-kit/blocks/data-table-block/

A data table with raw text and rich text cells alongside a caption.
"""
block = DataTableBlock(
caption="A Fabulous Table",
rows=[
[
{"type": "raw_text", "text": "Name"},
{"type": "raw_text", "text": "Department"},
{"type": "raw_text", "text": "Badge"},
],
[
{"type": "raw_text", "text": "Data Refinement Department"},
{"type": "raw_text", "text": "MDR"},
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "Blue",
"style": {"bold": True},
}
],
}
],
},
],
[
{"type": "raw_text", "text": "Art Sourcing Department"},
{"type": "raw_text", "text": "O&D"},
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_section",
"elements": [
{"type": "text", "text": "Green"},
{
"type": "text",
"text": "review",
"style": {"italic": True},
},
],
}
],
},
],
[
{"type": "raw_text", "text": "Wellness Department"},
{"type": "raw_text", "text": "Wellness Center"},
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "Limited",
"style": {"bold": True},
}
],
}
],
},
],
],
)
return block
78 changes: 78 additions & 0 deletions block-kit/tests/blocks/test_data_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import json

from src.blocks import data_table


def test_example01():
block = data_table.example01()
actual = block.to_dict()
expected = {
"type": "data_table",
"caption": "A Fabulous Table",
"rows": [
[
{"type": "raw_text", "text": "Name"},
{"type": "raw_text", "text": "Department"},
{"type": "raw_text", "text": "Badge"},
],
[
{"type": "raw_text", "text": "Data Refinement Department"},
{"type": "raw_text", "text": "MDR"},
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "Blue",
"style": {"bold": True},
}
],
}
],
},
],
[
{"type": "raw_text", "text": "Art Sourcing Department"},
{"type": "raw_text", "text": "O&D"},
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_section",
"elements": [
{"type": "text", "text": "Green"},
{
"type": "text",
"text": "review",
"style": {"italic": True},
},
],
}
],
},
],
[
{"type": "raw_text", "text": "Wellness Department"},
{"type": "raw_text", "text": "Wellness Center"},
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "Limited",
"style": {"bold": True},
}
],
}
],
},
],
],
}
assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True)