Skip to content
Draft
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 @@ -129,4 +129,10 @@ public static ShareShortcutBlock shareShortcut() {
return ShareShortcutBlock.builder().build();
}

// DataVisualizationBlock

public static DataVisualizationBlock dataVisualization(ModelConfigurator<DataVisualizationBlock.DataVisualizationBlockBuilder> configurator) {
return configurator.configure(DataVisualizationBlock.builder()).build();
}

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

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

import java.util.List;

/**
* The axis configuration of a bar, area, or line {@link DataVisualizationChart}.
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block">Data visualization block</a>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DataVisualizationAxisConfig {
/**
* The x-axis labels that define the display order of categories. Each maximum 20 characters.
*/
private List<String> categories;

/**
* The x-axis title. Maximum 50 characters.
*/
private String xLabel;

/**
* The y-axis title. Maximum 50 characters.
*/
private String yLabel;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.slack.api.model.block;

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

/**
* A data visualization is a layout block used to render a chart from supplied data. The chart may be
* a pie, bar, area, or line chart, configured via the {@link DataVisualizationChart chart} object.
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block">Data visualization block</a>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DataVisualizationBlock implements LayoutBlock {
public static final String TYPE = "data_visualization";
private final String type = TYPE;

/**
* The label displayed above the chart. Maximum 50 characters.
*/
private String title;

/**
* The chart to render. One of pie, bar, area, or line.
*/
private DataVisualizationChart chart;

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

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

import java.util.List;

/**
* The chart rendered by a {@link DataVisualizationBlock}.
*
* <p>For a pie chart ({@code type} = {@code pie}), supply {@code segments}. For a bar, area, or line
* chart ({@code type} = {@code bar}, {@code area}, or {@code line}), supply {@code series} together
* with an {@link DataVisualizationAxisConfig axis config}.</p>
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block">Data visualization block</a>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DataVisualizationChart {
/**
* The type of chart. One of {@code pie}, {@code bar}, {@code area}, or {@code line}.
*/
private String type;

/**
* The segments of a pie chart. Required for pie charts; between 1 and 6 items.
*/
private List<DataVisualizationSegment> segments;

/**
* The data series of a bar, area, or line chart. Required for those chart types; between 1 and 6 items.
*/
private List<DataVisualizationSeries> series;

/**
* The axis configuration for a bar, area, or line chart. Required for those chart types.
*/
private DataVisualizationAxisConfig axisConfig;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.slack.api.model.block;

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

/**
* A single data point of a {@link DataVisualizationSeries}.
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block">Data visualization block</a>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DataVisualizationDataPoint {
/**
* The x-axis category. Must match a category defined in the chart's
* {@link DataVisualizationAxisConfig axis config}. Maximum 20 characters.
*/
private String label;

/**
* The y-axis value. Negative values are permitted.
*/
private Double value;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.slack.api.model.block;

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

/**
* A single segment of a pie chart within a {@link DataVisualizationChart}.
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block">Data visualization block</a>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DataVisualizationSegment {
/**
* The legend/hover text for the segment. Maximum 20 characters.
*/
private String label;

/**
* The weight of the segment. Must be greater than 0.
*/
private Double value;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.slack.api.model.block;

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

import java.util.List;

/**
* A single data series of a bar, area, or line chart within a {@link DataVisualizationChart}.
*
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block">Data visualization block</a>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DataVisualizationSeries {
/**
* The legend identifier for the series. Must be unique per chart. Maximum 20 characters.
*/
private String name;

/**
* The data points of the series, one per category. Between 1 and 20 items.
*/
private List<DataVisualizationDataPoint> data;
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ private Class<? extends LayoutBlock> getLayoutClassInstance(String typeName) {
return RichTextBlock.class;
case ShareShortcutBlock.TYPE:
return ShareShortcutBlock.class;
case DataVisualizationBlock.TYPE:
return DataVisualizationBlock.class;
default:
if (failOnUnknownProperties) {
throw new JsonParseException("Unsupported layout block type: " + typeName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1802,6 +1802,110 @@ public void parseLinkTriggerMessages() {
}


@Test
public void parseDataVisualizationPie() {
// https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block
String json = "{\n" +
" \"blocks\": [\n" +
" {\n" +
" \"type\": \"data_visualization\",\n" +
" \"block_id\": \"dv1\",\n" +
" \"title\": \"Sales by region\",\n" +
" \"chart\": {\n" +
" \"type\": \"pie\",\n" +
" \"segments\": [\n" +
" { \"label\": \"North\", \"value\": 40 },\n" +
" { \"label\": \"South\", \"value\": 60 }\n" +
" ]\n" +
" }\n" +
" }\n" +
" ]\n" +
"}";
Message message = GsonFactory.createSnakeCase().fromJson(json, Message.class);
assertThat(message, is(notNullValue()));
assertThat(message.getBlocks().size(), is(1));
DataVisualizationBlock block = (DataVisualizationBlock) message.getBlocks().get(0);
assertThat(block.getType(), is("data_visualization"));
assertThat(block.getBlockId(), is("dv1"));
assertThat(block.getTitle(), is("Sales by region"));
assertThat(block.getChart().getType(), is("pie"));
assertThat(block.getChart().getSegments().size(), is(2));
assertThat(block.getChart().getSegments().get(0).getLabel(), is("North"));
assertThat(block.getChart().getSegments().get(0).getValue(), is(40.0));
assertThat(block.getChart().getSeries(), is(nullValue()));
assertThat(block.getChart().getAxisConfig(), is(nullValue()));
}

@Test
public void parseDataVisualizationBar() {
// https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block
String json = "{\n" +
" \"blocks\": [\n" +
" {\n" +
" \"type\": \"data_visualization\",\n" +
" \"title\": \"Revenue\",\n" +
" \"chart\": {\n" +
" \"type\": \"bar\",\n" +
" \"series\": [\n" +
" {\n" +
" \"name\": \"2025\",\n" +
" \"data\": [\n" +
" { \"label\": \"Q1\", \"value\": 100 },\n" +
" { \"label\": \"Q2\", \"value\": -20 }\n" +
" ]\n" +
" }\n" +
" ],\n" +
" \"axis_config\": {\n" +
" \"categories\": [\"Q1\", \"Q2\"],\n" +
" \"x_label\": \"Quarter\",\n" +
" \"y_label\": \"USD\"\n" +
" }\n" +
" }\n" +
" }\n" +
" ]\n" +
"}";
Message message = GsonFactory.createSnakeCase().fromJson(json, Message.class);
assertThat(message, is(notNullValue()));
assertThat(message.getBlocks().size(), is(1));
DataVisualizationBlock block = (DataVisualizationBlock) message.getBlocks().get(0);
assertThat(block.getTitle(), is("Revenue"));
assertThat(block.getChart().getType(), is("bar"));
assertThat(block.getChart().getSeries().size(), is(1));
assertThat(block.getChart().getSeries().get(0).getName(), is("2025"));
assertThat(block.getChart().getSeries().get(0).getData().size(), is(2));
assertThat(block.getChart().getSeries().get(0).getData().get(1).getValue(), is(-20.0));
assertThat(block.getChart().getAxisConfig().getCategories(), is(Arrays.asList("Q1", "Q2")));
assertThat(block.getChart().getAxisConfig().getXLabel(), is("Quarter"));
assertThat(block.getChart().getAxisConfig().getYLabel(), is("USD"));
assertThat(block.getChart().getSegments(), is(nullValue()));
}

@Test
public void dataVisualizationBuilderRoundTrip() {
DataVisualizationBlock block = dataVisualization(dv -> dv
.blockId("dv-builder")
.title("Sales by region")
.chart(DataVisualizationChart.builder()
.type("pie")
.segments(Arrays.asList(
DataVisualizationSegment.builder().label("North").value(40.0).build(),
DataVisualizationSegment.builder().label("South").value(60.0).build()
))
.build()));
assertThat(block, is(notNullValue()));
assertThat(block.getType(), is("data_visualization"));

Gson gson = GsonFactory.createSnakeCase();
String output = gson.toJson(block);
DataVisualizationBlock parsed = gson.fromJson(output, DataVisualizationBlock.class);
assertThat(parsed.getTitle(), is("Sales by region"));
assertThat(parsed.getBlockId(), is("dv-builder"));
assertThat(parsed.getChart().getType(), is("pie"));
assertThat(parsed.getChart().getSegments().size(), is(2));
assertThat(parsed.getChart().getSegments().get(1).getLabel(), is("South"));
assertThat(parsed.getChart().getSegments().get(1).getValue(), is(60.0));
}

@Test
public void parseRichTextElements() {
String json = "{\n" +
Expand Down