Skip to content

Commit 683656a

Browse files
zimegClaude
andcommitted
Allow mrkdwn descriptions on OptionObject (fixes #1471)
`OptionObject.description` was hard-typed to `PlainTextObject`, so a `mrkdwn` description on a radio-button or checkbox option was coerced to plain_text on deserialize, losing the markdown. The option-object docs state that radio buttons and checkboxes can use mrkdwn text objects for the description. Widen the field to `TextObject` (the same type already used for `OptionObject.text`), which routes deserialization through the existing polymorphic text-object factory so `mrkdwn` round-trips as a `MarkdownTextObject` and `plain_text` still returns a `PlainTextObject`. The Kotlin DSL gains a `markdownDescription(...)` overload alongside the existing plain_text `description(...)`. Source-compatible: all call sites pass plain_text and the getter's declared type only broadens. Ref: https://docs.slack.dev/reference/block-kit/composition-objects/option-object Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
1 parent dbe498c commit 683656a

3 files changed

Lines changed: 81 additions & 6 deletions

File tree

‎slack-api-model-kotlin-extension/src/main/kotlin/com/slack/api/model/kotlin_extension/block/composition/OptionObjectBuilder.kt‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.slack.api.model.kotlin_extension.block.composition
22

3+
import com.slack.api.model.block.composition.MarkdownTextObject
34
import com.slack.api.model.block.composition.OptionObject
45
import com.slack.api.model.block.composition.PlainTextObject
6+
import com.slack.api.model.block.composition.TextObject
57
import com.slack.api.model.kotlin_extension.block.BlockLayoutBuilder
68
import com.slack.api.model.kotlin_extension.block.Builder
79
import com.slack.api.model.kotlin_extension.block.composition.container.SingleTextObjectContainer
@@ -14,7 +16,7 @@ class OptionObjectBuilder private constructor(
1416
) : Builder<OptionObject>, TextObjectDsl by textContainer {
1517
private var value: String? = null
1618
private var url: String? = null
17-
private var description: PlainTextObject? = null
19+
private var description: TextObject? = null
1820

1921
constructor() : this(SingleTextObjectContainer())
2022

@@ -40,15 +42,25 @@ class OptionObjectBuilder private constructor(
4042
}
4143

4244
/**
43-
* a line of descriptive text shown below the text field beside the radio button. Maximum length for the text
44-
* object within this field is 75 characters.
45+
* A plain_text line of descriptive text shown below the text field beside the radio button. Maximum length for the
46+
* text object within this field is 75 characters.
4547
*
4648
* @see <a href="https://docs.slack.dev/reference/block-kit/composition-objects/option-object">Option object documentation</a>
4749
*/
4850
fun description(text: String, emoji: Boolean? = null) {
4951
description = PlainTextObject(text, emoji)
5052
}
5153

54+
/**
55+
* A mrkdwn line of descriptive text shown below the text field beside the radio button. Only radio buttons and
56+
* checkboxes can use mrkdwn descriptions. Maximum length for the text object within this field is 75 characters.
57+
*
58+
* @see <a href="https://docs.slack.dev/reference/block-kit/composition-objects/option-object">Option object documentation</a>
59+
*/
60+
fun markdownDescription(text: String, verbatim: Boolean? = null) {
61+
description = MarkdownTextObject(text, verbatim)
62+
}
63+
5264
override fun build(): OptionObject {
5365
return OptionObject.builder()
5466
.description(description)

‎slack-api-model/src/main/java/com/slack/api/model/block/composition/OptionObject.java‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@ public class OptionObject {
2929
private String value;
3030

3131
/**
32-
* A plain_text only text object that defines a line of descriptive text shown
33-
* below the text field beside the radio button.
32+
* A text object that defines a line of descriptive text shown below the text
33+
* field beside the radio button. Overflow, select, and multi-select menus can
34+
* only use plain_text objects, while radio buttons and checkboxes can use
35+
* mrkdwn text objects.
3436
* Maximum length for the text object within this field is 75 characters.
3537
*/
36-
private PlainTextObject description;
38+
private TextObject description;
3739

3840
/**
3941
* A URL to load in the user's browser when the option is clicked.

‎slack-api-model/src/test/java/test_locally/api/model/block/BlockKitTest.java‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import com.slack.api.model.Message;
66
import com.slack.api.model.block.*;
77
import com.slack.api.model.block.composition.ConfirmationDialogObject;
8+
import com.slack.api.model.block.composition.MarkdownTextObject;
9+
import com.slack.api.model.block.composition.OptionObject;
10+
import com.slack.api.model.block.composition.PlainTextObject;
811
import com.slack.api.model.block.element.*;
912
import com.slack.api.model.view.View;
1013
import org.junit.Test;
@@ -2426,4 +2429,62 @@ public void buildTaskCardBlock() {
24262429
assertThat(taskCard.getStatus(), is("in_progress"));
24272430
assertThat(taskCard.getSources().size(), is(1));
24282431
}
2432+
2433+
@Test
2434+
public void parseCheckboxesWithMrkdwnOptionDescription() {
2435+
String json = "{" +
2436+
" \"blocks\": [\n" +
2437+
" {\n" +
2438+
" \"type\": \"actions\",\n" +
2439+
" \"elements\": [\n" +
2440+
" {\n" +
2441+
" \"type\": \"checkboxes\",\n" +
2442+
" \"action_id\": \"this_is_an_action_id\",\n" +
2443+
" \"options\": [\n" +
2444+
" {\n" +
2445+
" \"value\": \"A1\",\n" +
2446+
" \"text\": {\n" +
2447+
" \"type\": \"plain_text\",\n" +
2448+
" \"text\": \"Checkbox 1\"\n" +
2449+
" },\n" +
2450+
" \"description\": {\n" +
2451+
" \"type\": \"mrkdwn\",\n" +
2452+
" \"text\": \"*bold* description\"\n" +
2453+
" }\n" +
2454+
" },\n" +
2455+
" {\n" +
2456+
" \"value\": \"A2\",\n" +
2457+
" \"text\": {\n" +
2458+
" \"type\": \"plain_text\",\n" +
2459+
" \"text\": \"Checkbox 2\"\n" +
2460+
" },\n" +
2461+
" \"description\": {\n" +
2462+
" \"type\": \"plain_text\",\n" +
2463+
" \"text\": \"plain description\"\n" +
2464+
" }\n" +
2465+
" }\n" +
2466+
" ]\n" +
2467+
" }\n" +
2468+
" ]\n" +
2469+
" }\n" +
2470+
" ]\n" +
2471+
"}";
2472+
Message message = GsonFactory.createSnakeCase().fromJson(json, Message.class);
2473+
assertThat(message, is(notNullValue()));
2474+
ActionsBlock block = (ActionsBlock) message.getBlocks().get(0);
2475+
CheckboxesElement checkboxes = (CheckboxesElement) block.getElements().get(0);
2476+
2477+
// A mrkdwn description must round-trip as a MarkdownTextObject, not be
2478+
// coerced to plain_text (regression test for slackapi/java-slack-sdk#1471).
2479+
OptionObject mrkdwnOption = checkboxes.getOptions().get(0);
2480+
assertThat(mrkdwnOption.getDescription(), instanceOf(MarkdownTextObject.class));
2481+
assertThat(mrkdwnOption.getDescription().getType(), is("mrkdwn"));
2482+
assertThat(((MarkdownTextObject) mrkdwnOption.getDescription()).getText(), is("*bold* description"));
2483+
2484+
// A plain_text description still deserializes as PlainTextObject.
2485+
OptionObject plainOption = checkboxes.getOptions().get(1);
2486+
assertThat(plainOption.getDescription(), instanceOf(PlainTextObject.class));
2487+
assertThat(plainOption.getDescription().getType(), is("plain_text"));
2488+
assertThat(((PlainTextObject) plainOption.getDescription()).getText(), is("plain description"));
2489+
}
24292490
}

0 commit comments

Comments
 (0)