Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
61f0681
feat(block-kit): add data_table layout block
zimeg Jun 26, 2026
a6cc250
Merge remote-tracking branch 'origin/main' into chore/block-kit-data-…
zimeg Sep 9, 2026
715e9a2
docs(block-kit): re-sync data_table javadoc to docs + node review
zimeg Sep 9, 2026
6d8ffce
refactor(block-kit): group dataTable DSL entry with the net-new blocks
zimeg Sep 9, 2026
43e03d1
refactor(block-kit): share the TableCell cell model across table + da…
zimeg Sep 9, 2026
698d88a
refactor(block-kit): name raw cell classes RawTextObject / RawNumberO…
zimeg Sep 9, 2026
393dd22
refactor(block-kit): tidy data_table factory order and RichTextBlock …
zimeg Sep 9, 2026
f6e66bf
docs(block-kit): correct RawNumberObject text as required, not optional
zimeg Sep 9, 2026
e417c31
docs(block-kit): drop the parenthetical example from RawNumberObject
zimeg Sep 9, 2026
36396ef
docs(block-kit): document raw cell fields per-field, matching node
zimeg Sep 9, 2026
ec6733e
feat(block-kit): add rawText / rawNumber BlockCompositions helpers
zimeg Sep 9, 2026
60a4781
refactor(block-kit): take Double in rawNumber helper to match the model
zimeg Sep 9, 2026
088b3db
Merge branch 'main' into chore/block-kit-data-table
zimeg Nov 5, 2026
e9dd2b0
Merge branch 'main' into chore/block-kit-data-table
zimeg Nov 5, 2026
3bea79a
Merge branch 'main' into chore/block-kit-data-table
zimeg Nov 5, 2026
dcac25b
feat(block-kit): support action_cell in data_table rows
zimeg Nov 5, 2026
25cb507
chore: address review notes on data_table
zimeg Nov 6, 2026
3390832
test: inline the action cell json in each data_table test
zimeg Nov 6, 2026
75a408b
test: drop the extra action cell without fallback test
zimeg Nov 6, 2026
47fb8d0
test: trim extra action cell tests and inline the unknown cell json
zimeg Nov 6, 2026
75b0c01
test: fold the action cell into the data_table parse and build tests
zimeg Nov 6, 2026
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 @@ -11,6 +11,7 @@
import com.slack.api.model.block.ContextBlockElement;
import com.slack.api.model.block.ContextActionsBlockElement;
import com.slack.api.model.block.LayoutBlock;
import com.slack.api.model.block.composition.TableCell;
import com.slack.api.model.block.composition.TextObject;
import com.slack.api.model.block.element.BlockElement;
import com.slack.api.model.block.element.RichTextElement;
Expand Down Expand Up @@ -80,6 +81,7 @@ public static void registerTypeAdapters(GsonBuilder builder, boolean failOnUnkno
.registerTypeAdapter(ContextActionsBlockElement.class, new GsonContextActionsBlockElementFactory(failOnUnknownProps))
.registerTypeAdapter(BlockElement.class, new GsonBlockElementFactory(failOnUnknownProps))
.registerTypeAdapter(RichTextElement.class, new GsonRichTextElementFactory(failOnUnknownProps))
.registerTypeAdapter(TableCell.class, new GsonTableCellFactory(failOnUnknownProps))
Comment thread
zimeg marked this conversation as resolved.
Resolved
.registerTypeAdapter(FunctionExecutedEvent.InputValue.class, new GsonFunctionExecutedEventInputValueFactory())
.registerTypeAdapter(Attachment.VideoHtml.class, new GsonMessageAttachmentVideoHtmlFactory(failOnUnknownProps))
.registerTypeAdapter(MessageChangedEvent.PreviousMessage.class, new GsonMessageChangedEventPreviousMessageFactory(failOnUnknownProps))
Expand Down
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();
}

// DataTableBlock

public static DataTableBlock dataTable(ModelConfigurator<DataTableBlock.DataTableBlockBuilder> configurator) {
return configurator.configure(DataTableBlock.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,48 @@
package com.slack.api.model.block;

import com.slack.api.model.block.composition.TableCell;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;

/**
* Displays rich tables that support pagination, sorting, filtering, and interactivity.
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-table-block">Data table block</a>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DataTableBlock implements LayoutBlock {
public static final String TYPE = "data_table";
private final String type = TYPE;

/**
* An array consisting of table rows.
*/
@Builder.Default
private List<List<TableCell>> rows = new ArrayList<>();

/**
* A caption for the table; used as the value for the HTML caption element.
*/
private String caption;

/**
* Number of rows per page. Min {@code 1}, Max {@code 100}. Defaults to {@code 5} if omitted.
*/
private Integer pageSize;

/**
* The 0-based index of the column that uniquely identifies each row (the row header). This column
* is treated as the row's primary identifier for screen readers. Defaults to {@code 0} if omitted.
*/
private Integer rowHeaderColumnIndex;

private String blockId;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.slack.api.model.block;

import com.slack.api.model.block.composition.TableCell;
import com.slack.api.model.block.element.BlockElement;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand All @@ -16,7 +17,7 @@
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RichTextBlock implements LayoutBlock {
public class RichTextBlock implements LayoutBlock, TableCell {
public static final String TYPE = "rich_text";
private final String type = TYPE;
@Builder.Default
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.slack.api.model.block.composition;

import com.slack.api.model.block.element.ButtonElement;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* Defines a cell containing a button. Action cells can only be used in the data table block, not the table block.
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-table-block">Data table block</a>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ActionCellObject implements TableCell {
public static final String TYPE = "action_cell";
private final String type = TYPE;

/**
* A button element.
*/
private ButtonElement element;

/**
* A raw_text or raw_number cell.
*/
private TableCell fallback;
Comment on lines +27 to +30

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

🔭 note: This might be generic to other table cells but we leave validation to the API here.

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.slack.api.model.block.composition;

import com.slack.api.model.ModelConfigurator;
import com.slack.api.model.block.element.ButtonElement;

import java.util.Arrays;
import java.util.List;
Expand All @@ -22,6 +23,16 @@ public static List<OptionObject> asOptions(OptionObject... options) {
return Arrays.asList(options);
}

// ActionCellObject

public static ActionCellObject actionCell(ModelConfigurator<ActionCellObject.ActionCellObjectBuilder> configurator) {
return configurator.configure(ActionCellObject.builder()).build();
}

public static ActionCellObject actionCell(ButtonElement element) {
return ActionCellObject.builder().element(element).build();
}

// ConfirmationDialogObject

public static ConfirmationDialogObject confirmationDialog(
Expand Down Expand Up @@ -54,6 +65,26 @@ public static MarkdownTextObject markdownText(String text) {
return MarkdownTextObject.builder().text(text).build();
}

// RawNumberObject

public static RawNumberObject rawNumber(ModelConfigurator<RawNumberObject.RawNumberObjectBuilder> configurator) {
return configurator.configure(RawNumberObject.builder()).build();
}

public static RawNumberObject rawNumber(Double value, String text) {
return RawNumberObject.builder().value(value).text(text).build();
}
Comment on lines +68 to +76

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

👁️‍🗨️ note: These introduce helper functions to BlockComposition that aren't documented but IMHO are helpful for:

- RawTextObject.builder().text("Name").build()
+ BlockCompositions.rawText("Name"),


// RawTextObject

public static RawTextObject rawText(ModelConfigurator<RawTextObject.RawTextObjectBuilder> configurator) {
return configurator.configure(RawTextObject.builder()).build();
}

public static RawTextObject rawText(String text) {
return RawTextObject.builder().text(text).build();
}

// OptionGroupObject

public static OptionGroupObject optionGroup(ModelConfigurator<OptionGroupObject.OptionGroupObjectBuilder> configurator) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.slack.api.model.block.composition;

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

/**
* Defines an object containing a numeric value.
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-table-block">Data table block</a>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RawNumberObject implements TableCell {
public static final String TYPE = "raw_number";
private final String type = TYPE;

/**
* The numeric value.
*/
private Double value;

/**
* The text used to display the value. The minimum length is 1 character.
*/
private String text;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.slack.api.model.block.composition;

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

/**
* Defines an object containing some text.
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-table-block">Data table block</a>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RawTextObject implements TableCell {
public static final String TYPE = "raw_text";
private final String type = TYPE;

/**
* The text for the block. The minimum length is 1 character.
*/
private String text;
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

🦠 note: I have some confidence this is a consistent shared type but it's not clear if it's meant to be stable because it's not in reference. Hoping to add this here and #1611 for shared implementation!

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.slack.api.model.block.composition;

/**
* A single cell within a table or data table row. A cell can be one of:
*
* <ul>
* <li>{@link ActionCellObject} ({@code action_cell}), in data table blocks only</li>
* <li>{@link RawTextObject} ({@code raw_text})</li>
* <li>{@link RawNumberObject} ({@code raw_number})</li>
* <li>{@link com.slack.api.model.block.RichTextBlock RichTextBlock} ({@code rich_text})</li>
* </ul>
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-table-block">Data table block</a>
*/
public interface TableCell {

String getType();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.slack.api.model.block.composition;

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

/**
* https://docs.slack.dev/reference/block-kit/blocks/data-table-block
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UnknownTableCell implements TableCell {
private String type;
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ private Class<? extends LayoutBlock> getLayoutClassInstance(String typeName) {
return ContextActionsBlock.class;
case ContextBlock.TYPE:
return ContextBlock.class;
case DataTableBlock.TYPE:
return DataTableBlock.class;
case DividerBlock.TYPE:
return DividerBlock.class;
case FileBlock.TYPE:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.slack.api.util.json;

import com.google.gson.*;
import com.slack.api.model.block.RichTextBlock;
import com.slack.api.model.block.composition.ActionCellObject;
import com.slack.api.model.block.composition.RawNumberObject;
import com.slack.api.model.block.composition.RawTextObject;
import com.slack.api.model.block.composition.TableCell;
import com.slack.api.model.block.composition.UnknownTableCell;

import java.lang.reflect.Type;

/**
* Factory for deserializing the cells of a
* {@link com.slack.api.model.block.DataTableBlock data table block}.
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-table-block">Data table block</a>
*/
public class GsonTableCellFactory implements JsonDeserializer<TableCell>, JsonSerializer<TableCell> {

private final boolean failOnUnknownProperties;

public GsonTableCellFactory() {
this(false);
}

public GsonTableCellFactory(boolean failOnUnknownProperties) {
this.failOnUnknownProperties = failOnUnknownProperties;
}

@Override
public TableCell deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final JsonPrimitive prim = (JsonPrimitive) jsonObject.get("type");
final String typeName = prim.getAsString();
final Class<? extends TableCell> clazz = getTableCellClassInstance(typeName);
return context.deserialize(jsonObject, clazz);
}

@Override
public JsonElement serialize(TableCell src, Type typeOfSrc, JsonSerializationContext context) {
return context.serialize(src);
}

private Class<? extends TableCell> getTableCellClassInstance(String typeName) {
switch (typeName) {
case ActionCellObject.TYPE:
return ActionCellObject.class;
case RawTextObject.TYPE:
return RawTextObject.class;
case RawNumberObject.TYPE:
return RawNumberObject.class;
case RichTextBlock.TYPE:
return RichTextBlock.class;
default:
if (failOnUnknownProperties) {
throw new JsonParseException("Unknown table cell type: " + typeName);
} else {
return UnknownTableCell.class;
}
}
}
}
Loading
Loading