Skip to content

Commit 993d0bf

Browse files
zimegClaude
andauthored
feat: add plan and task_card block examples (#35)
Co-authored-by: Claude <svc-devxp-claude@slack-corp.com>
1 parent 1925dfc commit 993d0bf

File tree

5 files changed

+231
-1
lines changed

5 files changed

+231
-1
lines changed

block-kit/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@ Read the [docs](https://docs.slack.dev/block-kit/) to learn concepts behind thes
99
### Blocks
1010

1111
- **[Actions](https://docs.slack.dev/reference/block-kit/blocks/actions-block)**: Holds multiple interactive elements. [Implementation](./src/blocks/actions.py).
12-
- **[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).
1312
- **[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).
13+
- **[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).
1414
- **[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).
1515
- **[File](https://docs.slack.dev/reference/block-kit/blocks/file-block)**: Displays info about remote files. [Implementation](./src/blocks/file.py).
1616
- **[Header](https://docs.slack.dev/reference/block-kit/blocks/header-block)**: Displays a larger-sized text. [Implementation](./src/blocks/header.py).
1717
- **[Image](https://docs.slack.dev/reference/block-kit/blocks/image-block)**: Displays an image. [Implementation](./src/blocks/image.py).
1818
- **[Input](https://docs.slack.dev/reference/block-kit/blocks/input-block)**: Collects information from users via elements. [Implementation](./src/blocks/input.py).
1919
- **[Markdown](https://docs.slack.dev/reference/block-kit/blocks/markdown-block)**: Displays formatted markdown. [Implementation](./src/blocks/markdown.py).
20+
- **[Plan](https://docs.slack.dev/reference/block-kit/blocks/plan-block)**: Displays a collection of related tasks. [Implementation](./src/blocks/plan.py).
2021
- **[Rich text](https://docs.slack.dev/reference/block-kit/blocks/rich-text-block)**: Displays formatted, structured representation of text. [Implementation](./src/blocks/rich_text.py).
2122
- **[Section](https://docs.slack.dev/reference/block-kit/blocks/section-block)**: Displays text, possibly alongside elements. [Implementation](./src/blocks/section.py).
23+
- **[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).
2224
- **[Video](https://docs.slack.dev/reference/block-kit/blocks/video-block)**: Displays an embedded video player. [Implementation](./src/blocks/video.py).

block-kit/src/blocks/plan.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from slack_sdk.models.blocks import PlanBlock, RichTextBlock, TaskCardBlock
2+
from slack_sdk.models.blocks.block_elements import (
3+
RichTextElementParts,
4+
RichTextSectionElement,
5+
)
6+
7+
8+
def example01() -> PlanBlock:
9+
"""
10+
Displays a collection of related tasks.
11+
https://docs.slack.dev/reference/block-kit/blocks/plan-block/
12+
13+
A plan block with multiple task cards in various states.
14+
"""
15+
block = PlanBlock(
16+
title="Thinking completed",
17+
tasks=[
18+
TaskCardBlock(
19+
task_id="call_001",
20+
title="Fetched user profile information",
21+
status="in_progress",
22+
details=RichTextBlock(
23+
block_id="viMWO",
24+
elements=[
25+
RichTextSectionElement(
26+
elements=[
27+
RichTextElementParts.Text(text="Searched database...")
28+
]
29+
)
30+
],
31+
),
32+
output=RichTextBlock(
33+
block_id="viMWO",
34+
elements=[
35+
RichTextSectionElement(
36+
elements=[
37+
RichTextElementParts.Text(text="Profile data loaded")
38+
]
39+
)
40+
],
41+
),
42+
),
43+
TaskCardBlock(
44+
task_id="call_002",
45+
title="Checked user permissions",
46+
status="pending",
47+
),
48+
TaskCardBlock(
49+
task_id="call_003",
50+
title="Generated comprehensive user report",
51+
status="complete",
52+
output=RichTextBlock(
53+
block_id="crsk",
54+
elements=[
55+
RichTextSectionElement(
56+
elements=[
57+
RichTextElementParts.Text(
58+
text="15 data points compiled"
59+
)
60+
]
61+
)
62+
],
63+
),
64+
),
65+
],
66+
)
67+
return block

block-kit/src/blocks/task_card.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from slack_sdk.models.blocks import RichTextBlock, TaskCardBlock
2+
from slack_sdk.models.blocks.block_elements import (
3+
RichTextElementParts,
4+
RichTextSectionElement,
5+
UrlSourceElement,
6+
)
7+
8+
9+
def example01() -> TaskCardBlock:
10+
"""
11+
Displays a single task, representing a single action.
12+
https://docs.slack.dev/reference/block-kit/blocks/task-card-block/
13+
14+
A task card with output and sources.
15+
"""
16+
block = TaskCardBlock(
17+
task_id="task_1",
18+
title="Fetching weather data",
19+
status="pending",
20+
output=RichTextBlock(
21+
elements=[
22+
RichTextSectionElement(
23+
elements=[
24+
RichTextElementParts.Text(
25+
text="Found weather data for Chicago from 2 sources"
26+
)
27+
]
28+
)
29+
]
30+
),
31+
sources=[
32+
UrlSourceElement(
33+
url="https://weather.com/",
34+
text="weather.com",
35+
),
36+
UrlSourceElement(
37+
url="https://www.accuweather.com/",
38+
text="accuweather.com",
39+
),
40+
],
41+
)
42+
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 plan
4+
5+
6+
def test_example01():
7+
block = plan.example01()
8+
actual = block.to_dict()
9+
expected = {
10+
"type": "plan",
11+
"title": "Thinking completed",
12+
"tasks": [
13+
{
14+
"type": "task_card",
15+
"task_id": "call_001",
16+
"title": "Fetched user profile information",
17+
"status": "in_progress",
18+
"details": {
19+
"type": "rich_text",
20+
"block_id": "viMWO",
21+
"elements": [
22+
{
23+
"type": "rich_text_section",
24+
"elements": [
25+
{
26+
"type": "text",
27+
"text": "Searched database...",
28+
}
29+
],
30+
}
31+
],
32+
},
33+
"output": {
34+
"type": "rich_text",
35+
"block_id": "viMWO",
36+
"elements": [
37+
{
38+
"type": "rich_text_section",
39+
"elements": [
40+
{
41+
"type": "text",
42+
"text": "Profile data loaded",
43+
}
44+
],
45+
}
46+
],
47+
},
48+
},
49+
{
50+
"type": "task_card",
51+
"task_id": "call_002",
52+
"title": "Checked user permissions",
53+
"status": "pending",
54+
},
55+
{
56+
"type": "task_card",
57+
"task_id": "call_003",
58+
"title": "Generated comprehensive user report",
59+
"status": "complete",
60+
"output": {
61+
"type": "rich_text",
62+
"block_id": "crsk",
63+
"elements": [
64+
{
65+
"type": "rich_text_section",
66+
"elements": [
67+
{
68+
"type": "text",
69+
"text": "15 data points compiled",
70+
}
71+
],
72+
}
73+
],
74+
},
75+
},
76+
],
77+
}
78+
assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import json
2+
3+
from src.blocks import task_card
4+
5+
6+
def test_example01():
7+
block = task_card.example01()
8+
actual = block.to_dict()
9+
expected = {
10+
"type": "task_card",
11+
"task_id": "task_1",
12+
"title": "Fetching weather data",
13+
"status": "pending",
14+
"output": {
15+
"type": "rich_text",
16+
"elements": [
17+
{
18+
"type": "rich_text_section",
19+
"elements": [
20+
{
21+
"type": "text",
22+
"text": "Found weather data for Chicago from 2 sources",
23+
}
24+
],
25+
}
26+
],
27+
},
28+
"sources": [
29+
{
30+
"type": "url",
31+
"url": "https://weather.com/",
32+
"text": "weather.com",
33+
},
34+
{
35+
"type": "url",
36+
"url": "https://www.accuweather.com/",
37+
"text": "accuweather.com",
38+
},
39+
],
40+
}
41+
assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True)

0 commit comments

Comments
 (0)