Skip to content

Commit bc44e40

Browse files
zimegClaude
andcommitted
feat(block-kit): add data table block example
Add a data_table Block Kit example mirroring the official docs example, including a typed DataTableBlock (net-new; not yet in slack_sdk), a unit test asserting the produced block, and a README entry. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
1 parent c5662c6 commit bc44e40

3 files changed

Lines changed: 209 additions & 0 deletions

File tree

‎block-kit/README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Read the [docs](https://docs.slack.dev/block-kit/) to learn concepts behind thes
1111
- **[Actions](https://docs.slack.dev/reference/block-kit/blocks/actions-block)**: Holds multiple interactive elements. [Implementation](./src/blocks/actions.py).
1212
- **[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).
1313
- **[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).
14+
- **[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).
1415
- **[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).
1516
- **[File](https://docs.slack.dev/reference/block-kit/blocks/file-block)**: Displays info about remote files. [Implementation](./src/blocks/file.py).
1617
- **[Header](https://docs.slack.dev/reference/block-kit/blocks/header-block)**: Displays a larger-sized text. [Implementation](./src/blocks/header.py).

‎block-kit/src/blocks/data_table.py‎

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
from typing import Any, Dict, Optional, Sequence, Set
2+
3+
from slack_sdk.models.basic_objects import JsonValidator
4+
from slack_sdk.models.blocks import Block
5+
6+
7+
class DataTableBlock(Block):
8+
type = "data_table"
9+
10+
@property
11+
def attributes(self) -> Set[str]: # type: ignore[override]
12+
return super().attributes.union(
13+
{"rows", "caption", "page_size", "row_header_column_index"}
14+
)
15+
16+
def __init__(
17+
self,
18+
*,
19+
rows: Sequence[Sequence[Dict[str, Any]]],
20+
caption: str,
21+
page_size: Optional[int] = None,
22+
row_header_column_index: Optional[int] = None,
23+
block_id: Optional[str] = None,
24+
):
25+
"""Displays a rich table that supports pagination, sorting, and filtering.
26+
https://docs.slack.dev/reference/block-kit/blocks/data-table-block
27+
28+
Args:
29+
rows (required): An array consisting of table rows. The first row is always a
30+
header row. Tables have between 2 and 101 rows and between 1 and 20 columns.
31+
Cells can have a type of raw_text, raw_number, or rich_text, but the header
32+
row does not allow rich_text cells.
33+
caption (required): A caption describing the contents of the table.
34+
page_size: The number of rows to display per page, between 1 and 100. Defaults to 5.
35+
row_header_column_index: The zero-based index of the column that identifies row
36+
headers. Defaults to 0.
37+
block_id: A unique identifier for a block. If not specified, a block_id will be
38+
generated. Maximum length for this field is 255 characters.
39+
"""
40+
super().__init__(type=self.type, block_id=block_id)
41+
self.rows = rows
42+
self.caption = caption
43+
self.page_size = page_size
44+
self.row_header_column_index = row_header_column_index
45+
46+
@JsonValidator("rows attribute must be specified")
47+
def _validate_rows(self) -> bool:
48+
return self.rows is not None and len(self.rows) > 0
49+
50+
@JsonValidator("caption attribute must be specified")
51+
def _validate_caption(self) -> bool:
52+
return self.caption is not None and len(self.caption) > 0
53+
54+
55+
def example01() -> DataTableBlock:
56+
"""
57+
Displays a rich table that supports pagination, sorting, and filtering.
58+
https://docs.slack.dev/reference/block-kit/blocks/data-table-block/
59+
60+
A data table with raw text and rich text cells alongside a caption.
61+
"""
62+
block = DataTableBlock(
63+
caption="A Fabulous Table",
64+
rows=[
65+
[
66+
{"type": "raw_text", "text": "Name"},
67+
{"type": "raw_text", "text": "Department"},
68+
{"type": "raw_text", "text": "Badge"},
69+
],
70+
[
71+
{"type": "raw_text", "text": "Data Refinement Department"},
72+
{"type": "raw_text", "text": "MDR"},
73+
{
74+
"type": "rich_text",
75+
"elements": [
76+
{
77+
"type": "rich_text_section",
78+
"elements": [
79+
{
80+
"type": "text",
81+
"text": "Blue",
82+
"style": {"bold": True},
83+
}
84+
],
85+
}
86+
],
87+
},
88+
],
89+
[
90+
{"type": "raw_text", "text": "Art Sourcing Department"},
91+
{"type": "raw_text", "text": "O&D"},
92+
{
93+
"type": "rich_text",
94+
"elements": [
95+
{
96+
"type": "rich_text_section",
97+
"elements": [
98+
{"type": "text", "text": "Green"},
99+
{
100+
"type": "text",
101+
"text": "review",
102+
"style": {"italic": True},
103+
},
104+
],
105+
}
106+
],
107+
},
108+
],
109+
[
110+
{"type": "raw_text", "text": "Wellness Department"},
111+
{"type": "raw_text", "text": "Wellness Center"},
112+
{
113+
"type": "rich_text",
114+
"elements": [
115+
{
116+
"type": "rich_text_section",
117+
"elements": [
118+
{
119+
"type": "text",
120+
"text": "Limited",
121+
"style": {"bold": True},
122+
}
123+
],
124+
}
125+
],
126+
},
127+
],
128+
],
129+
)
130+
return block
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import json
2+
3+
from src.blocks import data_table
4+
5+
6+
def test_example01():
7+
block = data_table.example01()
8+
actual = block.to_dict()
9+
expected = {
10+
"type": "data_table",
11+
"caption": "A Fabulous Table",
12+
"rows": [
13+
[
14+
{"type": "raw_text", "text": "Name"},
15+
{"type": "raw_text", "text": "Department"},
16+
{"type": "raw_text", "text": "Badge"},
17+
],
18+
[
19+
{"type": "raw_text", "text": "Data Refinement Department"},
20+
{"type": "raw_text", "text": "MDR"},
21+
{
22+
"type": "rich_text",
23+
"elements": [
24+
{
25+
"type": "rich_text_section",
26+
"elements": [
27+
{
28+
"type": "text",
29+
"text": "Blue",
30+
"style": {"bold": True},
31+
}
32+
],
33+
}
34+
],
35+
},
36+
],
37+
[
38+
{"type": "raw_text", "text": "Art Sourcing Department"},
39+
{"type": "raw_text", "text": "O&D"},
40+
{
41+
"type": "rich_text",
42+
"elements": [
43+
{
44+
"type": "rich_text_section",
45+
"elements": [
46+
{"type": "text", "text": "Green"},
47+
{
48+
"type": "text",
49+
"text": "review",
50+
"style": {"italic": True},
51+
},
52+
],
53+
}
54+
],
55+
},
56+
],
57+
[
58+
{"type": "raw_text", "text": "Wellness Department"},
59+
{"type": "raw_text", "text": "Wellness Center"},
60+
{
61+
"type": "rich_text",
62+
"elements": [
63+
{
64+
"type": "rich_text_section",
65+
"elements": [
66+
{
67+
"type": "text",
68+
"text": "Limited",
69+
"style": {"bold": True},
70+
}
71+
],
72+
}
73+
],
74+
},
75+
],
76+
],
77+
}
78+
assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True)

0 commit comments

Comments
 (0)