abdolence / slack-morphism

Type-safe and reactive Slack client with blocks templating DSL and rate control for Scala

Home Page:https://slack.abdolence.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Can you dynamically specify a list of choice items?

smithandrewl opened this issue · comments

In the following example from the documentation, choiceItem objects are specified as static constructor parameters to the choiceItems class.

My question is, is it possible to pass a dynamically created list of choiceItem objects (literally a sequence or list of choiceItem) to a choiceItems constructor? How can I build a dynamic list of choiceItems?

I used map to create a sequence of choiceItem instances, but I can't pass it to the choiceItems constructor as it gets a compiler error.

Example Of Static Item Choices:

// Conditional item of overflow menu:
sectionBlock(
  text = md"Test 2",
  accessory = overflow(
    action_id = SlackActionId("-"),
    options = choiceItems(
      choiceItem( text = pt"test-menu-item 1", value = "1" ),
      choiceItem( text = pt"test-menu-item 2", value = "2" ),
      optionally( someUserParam > 0 ) ( choiceItem( text = pt"conditional-menu-item 3", value = "3" ) )
    )
  )
)

Hey,

The reason you (probably) receive a compiler error, that you trying to use choiceItems with Seq[] of choiceItem directly. However choiceItems expects a lazy-computed list of items (to be able to use optional/conditional code as in your example).

So it is something like this:

choiceItems(
  Seq(
       (
                        () => choiceItem( text = pt"test-menu-item 1", value = "1" )
       ),
       (
                        () => choiceItem( text = pt"test-menu-item 2", value = "2" )
       )
    ):_*
)

Yet, it is cumbersome and I don't recommend it in case you just need a list of choice items, and you can use NonEmptyList directly instead of choiceItems:

              sectionBlock(
                text = md"Test 2",
                accessory = overflow(
                  action_id = SlackActionId("-"),
                  options = NonEmptyList.fromListUnsafe(
                    List(
                        choiceItem( text = pt"test-menu-item 1", value = "1" )
                    )
                  )
                )
              )

fromListUnsafe - now this is important to understand, you can't have an empty list of choices, and this will throw an exception in that case. Look at https://typelevel.org/cats/datatypes/nel.html for details.

To clarify, if you have at least one static choice, it is better to use NonEmptyList with it and avoid fromListUnsafe construction if possible.

And the most safer option would be this:

sectionBlock(
                text = md"Test 2",
                accessory =
                  // Our dynamic list data
                  List(
                    choiceItem( text = pt"test-menu-item 1", value = "1" ),
                    choiceItem( text = pt"test-menu-item 1", value = "1" )
                  ) match {
                    case head :: tail =>
                      // Yay, we have at least on choice
                      Some(
                        overflow(
                          action_id = SlackActionId("-"),
                          options = NonEmptyList(head, tail)
                        )
                      )
                    case _ => {
                      // Fallback, we have no data to show as options, so we don't use overflow at all
                      None
                    }
                  }
              )

Hope this helps. Let me know if something isn't clear.

To avoid confusion with this behaviour, I made some changes in 3.0.2 that provide an ability to use choiceItems (and similar construction) with just any Iterable. I'll release it soon.

Thanks so much!