Skip to content

feat(block-kit): add data_table layout block - #1613

Open
zimeg wants to merge 12 commits into
mainfrom
chore/block-kit-data-table
Open

feat(block-kit): add data_table layout block#1613
zimeg wants to merge 12 commits into
mainfrom
chore/block-kit-data-table

Conversation

@zimeg

@zimeg zimeg commented Jun 26, 2026

Copy link
Copy Markdown
Member

Summary

Adds the new data_table Block Kit layout block to the Java SDK model. The block displays rich tables that support pagination, sorting, filtering, and interactivity, where each row is a list of cells (raw_text, raw_number, or rich_text).

What's included:

  • DataTableBlock (type data_table) with rows, caption, pageSize, rowHeaderColumnIndex, and blockId.
  • The shared TableCell cell model in com.slack.api.model.block.composition: RawTextTableCell (raw_text), RawNumberTableCell (raw_number), and RichTextBlock (rich_text, which now implements TableCell). DataTableBlock.rows is List<List<TableCell>>.
  • GsonTableCellFactory to deserialize cells by type, registered for TableCell in both the client GsonFactory and the model test factory.
  • DataTableBlock registered in GsonLayoutBlockFactory.
  • Blocks.dataTable(...) builder DSL entry.

Field javadoc mirrors the data-table-block reference Fields table verbatim, kept in sync with the corresponding node SDK PR (slackapi/node-slack-sdk#2638) after its review.

Shared cell model with the table block

The data_table cells are the same raw_text / raw_number / rich_text cell model the table block uses, so this PR uses the shared TableCell family (interface + RawTextTableCell / RawNumberTableCell in ...block.composition, deserialized by a single GsonTableCellFactory) rather than a parallel data_table-only set. This is the same cell model the sibling table-block PR #1611 introduces — identical definitions, same package — so the two are aligned by construction: whichever lands second drops the now-duplicate cell files in a trivial merge. No behavioral reconciliation needed. (Mirrors node and python, which likewise share one cell model across both blocks — node's @slack/types composition objects, python's slack_sdk.models.blocks.basic_components.)

Reference

Schema: https://docs.slack.dev/reference/block-kit/blocks/data-table-block

Validation

Run in the touched modules (against latest main merged in):

  • ./mvnw -pl slack-api-model -am test -Dtest=BlockKitTest -Djacoco.skip=true — Tests run: 57, Failures: 0, Errors: 0. Includes parseDataTableBlock (deserialization of all three cell types + page_size/row_header_column_index) and buildDataTableBlock (builder DSL + round-trip serialization).
  • ./mvnw -pl slack-api-client -am test-compile -Djacoco.skip=true — BUILD SUCCESS (verifies the GsonFactory change in the client module compiles).

Note: jacoco.skip=true was required because the locally available JDK is 25 and the pinned JaCoCo agent (0.8.7) cannot instrument class file major version 69. This is an environment limitation unrelated to the change; the surefire test execution itself passes. CI runs the JDK 8/14/17 matrix, where JaCoCo is unaffected.

This repo does not use changesets (Maven multi-module project), so no changeset was added.

Co-Authored-By: Claude svc-devxp-claude@slack-corp.com

Add the new `data_table` Block Kit layout block to the model:
DataTableBlock plus its cell model (DataTableCell interface with
RawTextDataTableCell, RawNumberDataTableCell, and RichTextBlock for
rich_text cells), the GsonDataTableCellFactory deserializer, factory
registration, and a `dataTable` builder DSL entry.

Ref: https://docs.slack.dev/reference/block-kit/blocks/data-table-block

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 65.21739% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.75%. Comparing base (b3e25bf) to head (60a4781).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...api/model/block/composition/BlockCompositions.java 0.00% 4 Missing ⚠️
.../com/slack/api/util/json/GsonTableCellFactory.java 75.00% 3 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #1613      +/-   ##
============================================
- Coverage     72.80%   72.75%   -0.05%     
- Complexity     4551     4556       +5     
============================================
  Files           483      484       +1     
  Lines         14456    14479      +23     
  Branches       1513     1513              
============================================
+ Hits          10524    10534      +10     
- Misses         3037     3047      +10     
- Partials        895      898       +3     
Flag Coverage Δ
jdk-14 72.75% <65.21%> (-0.05%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

zimeg and others added 2 commits September 8, 2026 17:15
…table

# Conflicts:
#	slack-api-model/src/main/java/com/slack/api/util/json/GsonLayoutBlockFactory.java
#	slack-api-model/src/test/java/test_locally/api/model/block/BlockKitTest.java
Mirror the reviewed node SDK PR (slackapi/node-slack-sdk#2638):

- Correct the max row count: the model previously stated up to 100 data
  rows (101 including header); the reference documents 201 rows (200 data
  rows plus header). The 100 cap was page_size, not the row maximum. Drop
  the stale count from the javadoc rather than restate it.
- Align each field's javadoc with the data-table-block reference Fields
  table verbatim (rows, caption, page_size, row_header_column_index).
- Trim RawTextDataTableCell / RawNumberDataTableCell to the terse,
  docs-minimal descriptions (drop the invented sorting/formatting tails);
  document value and text per the docs.

Ref: https://docs.slack.dev/reference/block-kit/blocks/data-table-block

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
@zimeg zimeg self-assigned this Sep 9, 2026
@zimeg zimeg added enhancement M-T: A feature request for new functionality semver:minor project:slack-api-model project:slack-api-model project:slack-api-client project:slack-api-client labels Sep 9, 2026
@zimeg
zimeg marked this pull request as ready for review September 9, 2026 00:16
@zimeg
zimeg requested a review from a team as a code owner September 9, 2026 00:16
@zimeg
zimeg marked this pull request as draft September 9, 2026 00:19
zimeg and others added 7 commits September 8, 2026 17:22
Blocks.java keeps the recently-added blocks (Alert, Card, Carousel,
Container, TaskCard) in a cluster at the end rather than slotting them
alphabetically into the original core entries. Move the dataTable(...)
builder into that cluster (after container, before taskCard) so a
net-new block sits with its peers instead of splitting the old core
from the new group.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
…ta_table

The data_table cells (raw_text / raw_number / rich_text) are the same
cell model the table block uses. Rather than ship a parallel
DataTableCell family, adopt the shared TableCell interface and its
RawTextTableCell / RawNumberTableCell implementations in
com.slack.api.model.block.composition, deserialized by a single
GsonTableCellFactory:

- Remove DataTableCell, RawTextDataTableCell, RawNumberDataTableCell,
  and GsonDataTableCellFactory.
- Add TableCell, RawTextTableCell, RawNumberTableCell (in ...block.composition)
  and GsonTableCellFactory (in ...util.json).
- DataTableBlock.rows is now List<List<TableCell>>; RichTextBlock
  implements TableCell; the client and model-test GsonFactory register
  TableCell -> GsonTableCellFactory.

This is the same cell model the sibling table-block PR (#1611)
introduces, placed in the same package with identical definitions, so
whichever of the two lands second drops the now-duplicate files in a
trivial merge. Mirrors how node (@slack/types composition objects) and
python (slack_sdk basic_components) also share one cell model across
both blocks.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
…bject

Rename the concrete TableCell implementations from RawTextTableCell /
RawNumberTableCell to RawTextObject / RawNumberObject, matching the
composition-object naming used by the other SDKs (python RawTextObject /
RawNumberObject) and this repo's own ...Object grammar (PlainTextObject,
MarkdownTextObject, OptionObject). The shared TableCell interface is the
supertype the list is parameterized on (Java has no union types, so
List<List<TableCell>> is how the raw_text | raw_number | rich_text union
is expressed); only the implementation names change.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
…import

- GsonLayoutBlockFactory: move the DataTableBlock case into alphabetical
  order (between ContextBlock and DividerBlock) instead of after
  SectionBlock.
- RichTextBlock: import com.slack.api.model.block.composition.TableCell
  and use the simple name in the implements clause rather than the fully
  qualified type inline.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
The raw_number schema marks text as required (required: [type, value,
text], text minLength 1) — the javadoc wrongly called it optional. Match
the schema: text carries the display representation of the value and must
be at least one character long.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Keep the text-is-display + min-length note, drop the "(for example a
formatted string)" aside.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Restructure RawNumberObject and RawTextObject to per-field javadoc,
mirroring the node @slack/types descriptions and matching this repo's
own per-field convention (OptionObject, ConfirmationDialogObject):

- class: "Defines an object containing a numeric value." / "...some text."
- value: "The numeric value."
- text (number): "The text used to display the value. The minimum length is 1 character."
- text (text): "The text for the block. The minimum length is 1 character."

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Add BlockCompositions.rawText(...) and rawNumber(...) factory helpers for
the raw table cell objects, mirroring the plainText / markdownText DSL
(configurator overload plus a convenience overload). Gives callers an
ergonomic way to build data_table / table cells without the raw builder.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
zimeg added a commit to slack-samples/bolt-java-examples that referenced this pull request Sep 9, 2026
…Text

Use the BlockCompositions.rawText(...) helper for the raw_text cells
instead of RawTextObject.builder(), per the block-kit AGENTS.md guidance
to build composition objects through BlockCompositions.* rather than raw
builders. Depends on the rawText/rawNumber helpers added in
slackapi/java-slack-sdk#1613.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
RawNumberObject.value is a (nullable) Double; the two-arg rawNumber
convenience overload took a primitive double, narrowing the model's
type. Use Double so the helper mirrors the field exactly.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>

@zimeg zimeg left a comment

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.

☕ Ideas to share where included I callout a pattern I'm uncertain of around rawText and rawNumber!

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!

.registerTypeAdapter(ContextActionsBlockElement.class, new GsonContextActionsBlockElementFactory(failOnUnknownProps))
.registerTypeAdapter(BlockElement.class, new GsonBlockElementFactory(failOnUnknownProps))
.registerTypeAdapter(RichTextElement.class, new GsonRichTextElementFactory(failOnUnknownProps))
.registerTypeAdapter(TableCell.class, new GsonTableCellFactory(failOnUnknownProps))

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: Here we add custom deserialization to handle the various type possibilities of the table cell.

Comment on lines +57 to +65
// 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();
}

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"),

@zimeg
zimeg marked this pull request as ready for review September 9, 2026 04:22
@zimeg zimeg added this to the 1.51.1 milestone Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement M-T: A feature request for new functionality project:slack-api-client project:slack-api-client project:slack-api-model project:slack-api-model semver:minor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant