slackapi / java-slack-sdk

Slack Developer Kit (including Bolt for Java) for any JVM language
https://slack.dev/java-slack-sdk/
MIT License
568 stars 210 forks source link

MarkdownTextObject as text in OptionObject entries for StaticSelectElements #1291

Closed RovoMe closed 4 months ago

RovoMe commented 4 months ago

We're using Java Bolt 1.37.0 and currently trying to setup a modal that allows users to select options suggested by our internal API.

We noticed that when setting up a StaticSelectElement for providing some static options user can choose from before making further dynamic options based on the static selection, and providing a MarkdownTextObject as OptionObject Slack/Bolt doesn't seem to like that:

  @Nonnull
  public View generateView() {
    return View.builder()
            .type("modal")
            .callbackId("filterTickets")
            .title(ViewTitle.builder()
                    .type("plain_text")
                    .text("Show tickets")
                    .build())
            .submit(ViewSubmit.builder()
                    .type("plain_text")
                    .text("Submit")
                    .emoji(true)
                    .build())
            .close(ViewClose.builder()
                    .type("plain_text")
                    .text("Cancel")
                    .emoji(true)
                    .build())
            .blocks(List.of(
                    SectionBlock.builder()
                            .blockId("ticketTypeFilterBlock")
                            .text(MarkdownTextObject.builder()
                                    .text("Select which tickets to show")
                                    .build())
                            .accessory(ticketTypeFilterOptions(ticketTypeFilter))
                            .build(),
                    ...
            ))
            .build();
  }

  @Nonnull
  private StaticSelectElement ticketTypeFilterOptions(@Nullable final String ticketFilter) {
    OptionObject ticketTypeFilterOptionAll = OptionObject.builder()
            .text(MarkdownTextObject.builder()
                    .text("all")
                    .build())
            .value("all")
            .build();
    OptionObject ticketTypeFilterOptionSupport = OptionObject.builder()
            .text(MarkdownTextObject.builder()
                    .text("support")
                    .build())
            .value("support")
            .build();
    OptionObject ticketTypeFilterOptionOnboarding = OptionObject.builder()
            .text(MarkdownTextObject.builder()
                    .text("onboarding")
                    .build())
            .value("onboarding")
            .build();
    OptionObject ticketTypeFilterOptionConnection = OptionObject.builder()
            .text(MarkdownTextObject.builder()
                    .text("connection")
                    .build())
            .value("connection")
            .build();
    OptionObject ticketTypeFilterOptionGeneric = OptionObject.builder()
            .text(MarkdownTextObject.builder()
                    .text("generic")
                    .build())
            .value("generic")
            .build();
    StaticSelectElement.StaticSelectElementBuilder ticketTypeFilterOption =
            StaticSelectElement.builder()
                    .placeholder(PlainTextObject.builder()
                            .text("Select an item")
                            .build())
                    .options(List.of(
                            ticketTypeFilterOptionAll,
                            ticketTypeFilterOptionSupport,
                            ticketTypeFilterOptionOnboarding,
                            ticketTypeFilterOptionConnection,
                            ticketTypeFilterOptionGeneric)
                    )
                    .actionId("ticketTypeFilter");

    if (StringUtils.isNotBlank(ticketFilter)) {
      switch (ticketFilter) {
        case "support" -> ticketTypeFilterOption.initialOption(ticketTypeFilterOptionSupport);
        case "onboarding" ->
                ticketTypeFilterOption.initialOption(ticketTypeFilterOptionOnboarding);
        case "connection" ->
                ticketTypeFilterOption.initialOption(ticketTypeFilterOptionConnection);
        case "generic" -> ticketTypeFilterOption.initialOption(ticketTypeFilterOptionGeneric);
        default -> ticketTypeFilterOption.initialOption(ticketTypeFilterOptionAll); // *all*
      }
    }
    return ticketTypeFilterOption.build();
  }

As far as I can see, OptionObject can take in any TextObjects so a MarkdownTextObject should be feasible, I guess. However, when executing this modal and logging the error hints I see the following log (reshaped for easier readability):

HINT: [
  [ERROR] failed to match all allowed schemas [json-pointer:/view], 
  [ERROR] failed to match all allowed schemas [json-pointer:/view/blocks/0/accessory/options/0/text], 
  [ERROR] must be a valid enum value [json-pointer:/view/blocks/0/accessory/options/0/text/type], 
  [ERROR] failed to match all allowed schemas [json-pointer:/view/blocks/0/accessory/options/1/text], 
  [ERROR] must be a valid enum value [json-pointer:/view/blocks/0/accessory/options/1/text/type], 
  [ERROR] failed to match all allowed schemas [json-pointer:/view/blocks/0/accessory/options/2/text], 
  [ERROR] must be a valid enum value [json-pointer:/view/blocks/0/accessory/options/2/text/type], 
  [ERROR] failed to match all allowed schemas [json-pointer:/view/blocks/0/accessory/options/3/text], 
  [ERROR] must be a valid enum value [json-pointer:/view/blocks/0/accessory/options/3/text/type], 
  [ERROR] failed to match all allowed schemas [json-pointer:/view/blocks/0/accessory/options/4/text], 
  [ERROR] must be a valid enum value [json-pointer:/view/blocks/0/accessory/options/4/text/type]
 ]

when swapping PlainTextObject for MarkdownTextObject, the form renders as expected.

Do I miss something in regards to configuring select options when providing "formatted" Markdown text? In such a case, how should the initialization of the OptionObject then look like, or are only PlainTextObjects supported by this GUI element?

WilliamBergamin commented 4 months ago

Hi @RovoMe thanks for writing in 💯

are only PlainTextObjects supported by this GUI element?

You are correct, according to our documentation for the option object used in the static select element only the plain_text object is supported

However if the option object is used in a radio button or checkbox then the mrkdwn text objects are supported

RovoMe commented 4 months ago

Ah, thank you for this information. Didn't see the hint on that in the reference documentation