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
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ public static ContainerBlock container(ModelConfigurator<ContainerBlock.Containe
return configurator.configure(ContainerBlock.builder()).build();
}

// PlanBlock

public static PlanBlock plan(ModelConfigurator<PlanBlock.PlanBlockBuilder> configurator) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

suggestion: Could we add a plan(...) case to BlocksTest like the taskCard one? The checklist in slack-api-model/AGENTS.md asks for a test per helper.

return configurator.configure(PlanBlock.builder()).build();
}

// TaskCardBlock

public static TaskCardBlock taskCard(ModelConfigurator<TaskCardBlock.TaskCardBlockBuilder> configurator) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.slack.api.model.block;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
* Displays a collection of related tasks.
*
* https://docs.slack.dev/reference/block-kit/blocks/plan-block
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PlanBlock implements LayoutBlock {
public static final String TYPE = "plan";

/**
* The type of block. For this block, type will always be {@code plan}.
*/
private final String type = TYPE;

/**
* Title of the plan in plain text.
*/
private String title;

/**
* A sequence of task card blocks, maximum of 50 tasks. Each one contains task-like objects without a type,
* and each {@code task_id} in a plan must be unique.
*/
private List<TaskCardBlock> tasks;

private String blockId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ private Class<? extends LayoutBlock> getLayoutClassInstance(String typeName) {
return InputBlock.class;
case MarkdownBlock.TYPE:
return MarkdownBlock.class;
case PlanBlock.TYPE:
return PlanBlock.class;
case RichTextBlock.TYPE:
return RichTextBlock.class;
case SectionBlock.TYPE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2456,6 +2456,151 @@ public void buildTaskCardBlock() {
assertThat(taskCard.getSources().size(), is(1));
}

@Test
public void parsePlanBlock() {
String json = "{\n" +
" \"blocks\": [\n" +
" {\n" +
" \"type\": \"plan\",\n" +
" \"title\": \"Thinking completed\",\n" +
" \"tasks\": [\n" +
" {\n" +
" \"task_id\": \"call_001\",\n" +
" \"title\": \"Fetched user profile information\",\n" +
" \"status\": \"in_progress\",\n" +
" \"details\": {\n" +
" \"type\": \"rich_text\",\n" +
" \"block_id\": \"viMWO\",\n" +
" \"elements\": [\n" +
" {\n" +
" \"type\": \"rich_text_section\",\n" +
" \"elements\": [\n" +
" {\n" +
" \"type\": \"text\",\n" +
" \"text\": \"Searched database...\"\n" +
" }\n" +
" ]\n" +
" }\n" +
" ]\n" +
" },\n" +
" \"output\": {\n" +
" \"type\": \"rich_text\",\n" +
" \"block_id\": \"viMWO\",\n" +
" \"elements\": [\n" +
" {\n" +
" \"type\": \"rich_text_section\",\n" +
" \"elements\": [\n" +
" {\n" +
" \"type\": \"text\",\n" +
" \"text\": \"Profile data loaded\"\n" +
" }\n" +
" ]\n" +
" }\n" +
" ]\n" +
" }\n" +
" },\n" +
" {\n" +
" \"task_id\": \"call_002\",\n" +
" \"title\": \"Checked user permissions\",\n" +
" \"status\": \"in_progress\"\n" +
" },\n" +
" {\n" +
" \"task_id\": \"call_003\",\n" +
" \"title\": \"Generated comprehensive user report\",\n" +
" \"status\": \"complete\",\n" +
" \"output\": {\n" +
" \"type\": \"rich_text\",\n" +
" \"block_id\": \"crsk\",\n" +
" \"elements\": [\n" +
" {\n" +
" \"type\": \"rich_text_section\",\n" +
" \"elements\": [\n" +
" {\n" +
" \"type\": \"text\",\n" +
" \"text\": \"15 data points compiled\"\n" +
" }\n" +
" ]\n" +
" }\n" +
" ]\n" +
" }\n" +
" }\n" +
" ]\n" +
" }\n" +
" ]\n" +
"}";
Gson gson = GsonFactory.createSnakeCase();
Message message = gson.fromJson(json, Message.class);
assertThat(message, is(notNullValue()));
assertThat(message.getBlocks().size(), is(1));

PlanBlock plan = (PlanBlock) message.getBlocks().get(0);
assertThat(plan.getType(), is("plan"));
assertThat(plan.getTitle(), is("Thinking completed"));
assertThat(plan.getTasks().size(), is(3));

assertThat(plan.getTasks().get(0).getTaskId(), is("call_001"));
assertThat(plan.getTasks().get(0).getTitle(), is("Fetched user profile information"));
assertThat(plan.getTasks().get(0).getStatus(), is("in_progress"));
assertThat(plan.getTasks().get(0).getDetails().getBlockId(), is("viMWO"));
assertThat(plan.getTasks().get(0).getOutput().getBlockId(), is("viMWO"));

assertThat(plan.getTasks().get(1).getTaskId(), is("call_002"));
assertThat(plan.getTasks().get(1).getTitle(), is("Checked user permissions"));
assertThat(plan.getTasks().get(1).getStatus(), is("in_progress"));

assertThat(plan.getTasks().get(2).getTaskId(), is("call_003"));
assertThat(plan.getTasks().get(2).getTitle(), is("Generated comprehensive user report"));
assertThat(plan.getTasks().get(2).getStatus(), is("complete"));
assertThat(plan.getTasks().get(2).getOutput().getBlockId(), is("crsk"));
}

@Test
public void buildPlanBlock() {
PlanBlock plan = Blocks.plan(p -> p
.title("Thinking completed")
.tasks(Arrays.asList(
Blocks.taskCard(t -> t
.taskId("call_001")
.title("Fetched user profile information")
.status("in_progress")
.details(Blocks.richText(r -> r
.blockId("viMWO")
.elements(Arrays.asList(RichTextSectionElement.builder()
.elements(Arrays.asList(RichTextSectionElement.Text.builder()
.text("Searched database...")
.build()))
.build()))))
.output(Blocks.richText(r -> r
.blockId("viMWO")
.elements(Arrays.asList(RichTextSectionElement.builder()
.elements(Arrays.asList(RichTextSectionElement.Text.builder()
.text("Profile data loaded")
.build()))
.build()))))),
Blocks.taskCard(t -> t
.taskId("call_002")
.title("Checked user permissions")
.status("in_progress")),
Blocks.taskCard(t -> t
.taskId("call_003")
.title("Generated comprehensive user report")
.status("complete")
.output(Blocks.richText(r -> r
.blockId("crsk")
.elements(Arrays.asList(RichTextSectionElement.builder()
.elements(Arrays.asList(RichTextSectionElement.Text.builder()
.text("15 data points compiled")
.build()))
.build()))))))));
assertThat(plan, is(notNullValue()));
assertThat(plan.getType(), is("plan"));
assertThat(plan.getTitle(), is("Thinking completed"));
assertThat(plan.getTasks().size(), is(3));
assertThat(plan.getTasks().get(0).getTaskId(), is("call_001"));
assertThat(plan.getTasks().get(1).getTaskId(), is("call_002"));
assertThat(plan.getTasks().get(2).getTaskId(), is("call_003"));
}

@Test
public void parseAuthProviderBlock() {
String json = "{\"type\":\"home\",\"blocks\":[\n" +
Expand Down
Loading