Updates every backend dependency with a newer release available, and tidies the example module alongside as any change to backend/go.mod requires.
183 lines
6.6 KiB
Go
183 lines
6.6 KiB
Go
package slack
|
|
|
|
import "fmt"
|
|
|
|
// ContainerWidth controls the rendered width of a ContainerBlock. When unset,
|
|
// Slack defaults to ContainerWidthStandard.
|
|
type ContainerWidth string
|
|
|
|
const (
|
|
ContainerWidthNarrow ContainerWidth = "narrow"
|
|
ContainerWidthStandard ContainerWidth = "standard"
|
|
ContainerWidthWide ContainerWidth = "wide"
|
|
ContainerWidthFull ContainerWidth = "full"
|
|
)
|
|
|
|
// containerMaxChildBlocks is the maximum number of child blocks Slack permits
|
|
// inside a container block.
|
|
const containerMaxChildBlocks = 10
|
|
|
|
// ContainerBlock groups a set of child blocks so they render together as a
|
|
// single, optionally collapsible, unit with a title, subtitle, and icon.
|
|
//
|
|
// More Information: https://docs.slack.dev/reference/block-kit/blocks/container-block/
|
|
type ContainerBlock struct {
|
|
Type MessageBlockType `json:"type"`
|
|
BlockID string `json:"block_id,omitempty"`
|
|
// Title is the container heading rendered as a plain_text object. One of
|
|
// Title or RichTextTitle is required; RichTextTitle takes precedence when
|
|
// both are set. Slack requires a maximum of 150 characters.
|
|
Title *TextBlockObject `json:"title,omitempty"`
|
|
// RichTextTitle is the container heading rendered as a rich_text block. It
|
|
// takes precedence over Title when both are set.
|
|
RichTextTitle *RichTextBlock `json:"rich_text_title,omitempty"`
|
|
// Subtitle is descriptive text below the title, rendered as a plain_text or
|
|
// mrkdwn object. Slack requires a maximum of 150 characters.
|
|
Subtitle *TextBlockObject `json:"subtitle,omitempty"`
|
|
// Icon is a small image displayed beside the title and subtitle.
|
|
Icon *ImageBlockElement `json:"icon,omitempty"`
|
|
// Width controls the container width. Slack defaults to standard when unset.
|
|
Width ContainerWidth `json:"width,omitempty"`
|
|
// IsCollapsible enables the container's collapse control.
|
|
IsCollapsible bool `json:"is_collapsible,omitempty"`
|
|
// DefaultCollapsed starts the container collapsed. It only applies when
|
|
// IsCollapsible is true.
|
|
DefaultCollapsed bool `json:"default_collapsed,omitempty"`
|
|
// HasHeaderDivider draws a border below the header. Slack only supports it on
|
|
// non-collapsible containers.
|
|
HasHeaderDivider bool `json:"has_header_divider,omitempty"`
|
|
// ChildBlocks are the blocks rendered inside the container. Slack requires 1
|
|
// to 10 blocks: actions, context, divider, file, header, image, input,
|
|
// rich_text, section, table, and video blocks are supported.
|
|
ChildBlocks Blocks `json:"child_blocks"`
|
|
}
|
|
|
|
// BlockType returns the type of the block.
|
|
func (s ContainerBlock) BlockType() MessageBlockType {
|
|
return s.Type
|
|
}
|
|
|
|
// ID returns the ID of the block.
|
|
func (s ContainerBlock) ID() string {
|
|
return s.BlockID
|
|
}
|
|
|
|
// Validate checks whether the block satisfies Slack's documented container
|
|
// constraints.
|
|
func (s ContainerBlock) Validate() error {
|
|
if s.Type != MBTContainer {
|
|
return fmt.Errorf("type must be %q", MBTContainer)
|
|
}
|
|
if s.Title == nil && s.RichTextTitle == nil {
|
|
return fmt.Errorf("one of title or rich_text_title is required")
|
|
}
|
|
if s.Title != nil {
|
|
if s.Title.Type != PlainTextType {
|
|
return fmt.Errorf("title must be a plain_text object")
|
|
}
|
|
if runeLen(s.Title.Text) > 150 {
|
|
return fmt.Errorf("title cannot be longer than 150 characters")
|
|
}
|
|
}
|
|
if s.Subtitle != nil {
|
|
if s.Subtitle.Type != PlainTextType && s.Subtitle.Type != MarkdownType {
|
|
return fmt.Errorf("subtitle must be a plain_text or mrkdwn object")
|
|
}
|
|
if runeLen(s.Subtitle.Text) > 150 {
|
|
return fmt.Errorf("subtitle cannot be longer than 150 characters")
|
|
}
|
|
}
|
|
switch s.Width {
|
|
case "", ContainerWidthNarrow, ContainerWidthStandard, ContainerWidthWide, ContainerWidthFull:
|
|
default:
|
|
return fmt.Errorf("width must be one of narrow, standard, wide, or full")
|
|
}
|
|
if s.Icon != nil {
|
|
if runeLen(s.Icon.AltText) > 2000 {
|
|
return fmt.Errorf("icon alt_text cannot be longer than 2000 characters")
|
|
}
|
|
if s.Icon.ImageURL != nil && runeLen(*s.Icon.ImageURL) > 3000 {
|
|
return fmt.Errorf("icon image_url cannot be longer than 3000 characters")
|
|
}
|
|
}
|
|
if s.HasHeaderDivider && s.IsCollapsible {
|
|
return fmt.Errorf("has_header_divider is only supported on non-collapsible containers")
|
|
}
|
|
if s.DefaultCollapsed && !s.IsCollapsible {
|
|
return fmt.Errorf("default_collapsed requires is_collapsible to be true")
|
|
}
|
|
if n := len(s.ChildBlocks.BlockSet); n < 1 {
|
|
return fmt.Errorf("child_blocks must have at least 1 block")
|
|
} else if n > containerMaxChildBlocks {
|
|
return fmt.Errorf("child_blocks cannot have more than %d blocks", containerMaxChildBlocks)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NewContainerBlock returns a new container block wrapping the given child
|
|
// blocks. Use the With* methods to set the title, subtitle, and other optional
|
|
// fields.
|
|
func NewContainerBlock(childBlocks ...Block) *ContainerBlock {
|
|
return &ContainerBlock{
|
|
Type: MBTContainer,
|
|
ChildBlocks: Blocks{BlockSet: childBlocks},
|
|
}
|
|
}
|
|
|
|
// WithBlockID sets the block ID for the ContainerBlock.
|
|
func (s *ContainerBlock) WithBlockID(blockID string) *ContainerBlock {
|
|
s.BlockID = blockID
|
|
return s
|
|
}
|
|
|
|
// WithTitle sets the plain_text title for the ContainerBlock.
|
|
func (s *ContainerBlock) WithTitle(title *TextBlockObject) *ContainerBlock {
|
|
s.Title = title
|
|
return s
|
|
}
|
|
|
|
// WithRichTextTitle sets the rich_text title for the ContainerBlock. It takes
|
|
// precedence over a plain_text title set with WithTitle.
|
|
func (s *ContainerBlock) WithRichTextTitle(title *RichTextBlock) *ContainerBlock {
|
|
s.RichTextTitle = title
|
|
return s
|
|
}
|
|
|
|
// WithSubtitle sets the subtitle for the ContainerBlock.
|
|
func (s *ContainerBlock) WithSubtitle(subtitle *TextBlockObject) *ContainerBlock {
|
|
s.Subtitle = subtitle
|
|
return s
|
|
}
|
|
|
|
// WithIcon sets the icon displayed beside the title for the ContainerBlock.
|
|
func (s *ContainerBlock) WithIcon(icon *ImageBlockElement) *ContainerBlock {
|
|
s.Icon = icon
|
|
return s
|
|
}
|
|
|
|
// WithWidth sets the rendered width of the ContainerBlock.
|
|
func (s *ContainerBlock) WithWidth(width ContainerWidth) *ContainerBlock {
|
|
s.Width = width
|
|
return s
|
|
}
|
|
|
|
// WithCollapsible marks the ContainerBlock collapsible and controls whether it
|
|
// starts collapsed.
|
|
func (s *ContainerBlock) WithCollapsible(collapsible, defaultCollapsed bool) *ContainerBlock {
|
|
s.IsCollapsible = collapsible
|
|
s.DefaultCollapsed = defaultCollapsed
|
|
return s
|
|
}
|
|
|
|
// WithHeaderDivider draws a border below the container header.
|
|
func (s *ContainerBlock) WithHeaderDivider(hasHeaderDivider bool) *ContainerBlock {
|
|
s.HasHeaderDivider = hasHeaderDivider
|
|
return s
|
|
}
|
|
|
|
// AddChildBlock appends a block to the container's child blocks.
|
|
func (s *ContainerBlock) AddChildBlock(block Block) *ContainerBlock {
|
|
s.ChildBlocks.BlockSet = append(s.ChildBlocks.BlockSet, block)
|
|
return s
|
|
}
|