Skip to content
Closed
Changes from 1 commit
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
138 changes: 91 additions & 47 deletions packages/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,10 @@ export interface WorkflowStepView {

export type View = HomeView | ModalView | WorkflowStepView;

/*
* Block Elements
/**
* Composition Objects: https://api.slack.com/reference/block-kit/composition-objects
*/

export interface ImageElement {
type: 'image';
image_url: string;
alt_text: string;
}

export interface PlainTextElement {
type: 'plain_text';
text: string;
Expand All @@ -87,63 +81,81 @@ export interface MrkdwnElement {

export interface MrkdwnOption {
text: MrkdwnElement;
value?: string;
value: string;
url?: string;
description?: PlainTextElement;
}

export interface PlainTextOption {
text: PlainTextElement;
value?: string;
value: string;
url?: string;
description?: PlainTextElement;
}

export type Option = MrkdwnOption | PlainTextOption;

export interface Confirm {
title?: PlainTextElement;
title: PlainTextElement;
text: PlainTextElement | MrkdwnElement;
confirm?: PlainTextElement;
deny?: PlainTextElement;
style?: 'primary' | 'danger';
confirm: PlainTextElement;
deny: PlainTextElement;
style?: 'primary' | 'danger'; // TODO: factor out into own type
}

export type Option = MrkdwnOption | PlainTextOption;

export interface DispatchActionConfig {
trigger_actions_on?: ('on_enter_pressed' | 'on_character_entered')[];
}

/*
* Action Types
* Block Elements: https://api.slack.com/reference/block-kit/block-elements
* Also known as interactive elements
* Exported below as Action
*/

export type KnownAction =
Select | MultiSelect | Button | Overflow | Datepicker | Timepicker | RadioButtons | Checkboxes | PlainTextInput;

export interface Action {
type: string;
/**
* @description: A string acting as a unique identifier for a block.
*/
block_id?: string; // TODO: in event payloads, this property will always be present. When defining a block, however,
// it is optional. If not defined when the block is created, Slack will auto-assign a block_id for you - thus why it
// is always present in payloads. So: how can we capture that? Differentiate between the event payload vs. the block
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably have to, since I don't see a world where this particular behavior changes - and the behavior seems reasonable. Were you thinking that this Block Kit type could somehow be used to model event payload responses?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes exactly! At least, I was consider if that would be possible! If you look at the block_actions payload event's fields, you'll see that there is an array of actions provided in the payload. These actions are the exact block kit elements that were interacted with - so I was considering if it would be possible to re-use the types in this repo to try to model the items of that actions array in the block_actions payload.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for the item in actions in a block_actions payload, we already have complete types in bolt-js. If we would like to have it, we can consider moving the ones in bolt-js into this repo. Reusing Action and so on here may cause unnecessary complexity.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seratch Yes I would like to eventually move as many types for things shared across repos as possible into this repo. For the block_actions payload, for example, I know right now we only need it in bolt-js. However, in deno-slack-sdk, it is also needed. So all of this work is in prep for trying to consolidate not just around our existing node projects, but across our newer deno ones too.

// element?
}

// Selects and Multiselects are available in different surface areas so I've separated them here
export type Select = UsersSelect | StaticSelect | ConversationsSelect | ChannelsSelect | ExternalSelect;

export type MultiSelect =
MultiUsersSelect | MultiStaticSelect | MultiConversationsSelect | MultiChannelsSelect | MultiExternalSelect;

export interface Action {
type: string;
action_id?: string;
}

export interface UsersSelect extends Action {
type: 'users_select';
action_id: string;
initial_user?: string;
placeholder?: PlainTextElement;
placeholder: PlainTextElement;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am sure that this is optional, so this change should be reverted. The document is wrong! See a Block Kit Builder example

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct! I was very surprised but confirmed that for all these Block Elements, both placeholder and action_id are optional. I am working on a PR to update the docs. Thanks for pointing this out, I have updated these to set placeholder and action_id to optional.

confirm?: Confirm;
focus_on_load?: boolean;
}

export interface MultiUsersSelect extends Action {
type: 'multi_users_select';
action_id: string;
initial_users?: string[];
placeholder?: PlainTextElement;
placeholder: PlainTextElement;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

max_selected_items?: number;
confirm?: Confirm;
focus_on_load?: boolean;
}

export interface StaticSelect extends Action {
type: 'static_select';
placeholder?: PlainTextElement;
placeholder: PlainTextElement;
action_id: string;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: when you build a block element, setting action_id is optional (auto-generated one will be used in the case). thus, strictly speaking, this can be optional

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure action_id is optional? The docs say it is required. I know block_id is optional and one will be auto-generated for you in that case.
I will test this today in real apps and report back!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow I can't believe it, action_id is optional 😆

initial_option?: PlainTextOption;
options?: PlainTextOption[];
option_groups?: {
Expand All @@ -156,9 +168,10 @@ export interface StaticSelect extends Action {

export interface MultiStaticSelect extends Action {
type: 'multi_static_select';
placeholder?: PlainTextElement;
placeholder: PlainTextElement;
action_id: string;
initial_options?: PlainTextOption[];
options?: PlainTextOption[];
options?: PlainTextOption[]; // TODO: options and option_groups are mutually exclusive
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point but i am unsure how we can represent this type of constraints in a simple way

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will ask Neil who is the deno-slack-sdk type master 😄

option_groups?: {
label: PlainTextElement;
options: PlainTextOption[];
Expand All @@ -171,7 +184,8 @@ export interface MultiStaticSelect extends Action {
export interface ConversationsSelect extends Action {
type: 'conversations_select';
initial_conversation?: string;
placeholder?: PlainTextElement;
action_id: string;
placeholder: PlainTextElement;
confirm?: Confirm;
response_url_enabled?: boolean;
default_to_current_conversation?: boolean;
Expand All @@ -186,7 +200,7 @@ export interface ConversationsSelect extends Action {
export interface MultiConversationsSelect extends Action {
type: 'multi_conversations_select';
initial_conversations?: string[];
placeholder?: PlainTextElement;
placeholder: PlainTextElement;
max_selected_items?: number;
confirm?: Confirm;
default_to_current_conversation?: boolean;
Expand All @@ -200,58 +214,75 @@ export interface MultiConversationsSelect extends Action {

export interface ChannelsSelect extends Action {
type: 'channels_select';
action_id: string;
initial_channel?: string;
placeholder?: PlainTextElement;
placeholder: PlainTextElement;
response_url_enabled?: boolean;
confirm?: Confirm;
focus_on_load?: boolean;
}

export interface MultiChannelsSelect extends Action {
type: 'multi_channels_select';
action_id: string;
initial_channels?: string[];
placeholder?: PlainTextElement;
placeholder: PlainTextElement;
max_selected_items?: number;
confirm?: Confirm;
focus_on_load?: boolean;
}

export interface ExternalSelect extends Action {
type: 'external_select';
action_id: string;
initial_option?: PlainTextOption;
placeholder?: PlainTextElement;
placeholder: PlainTextElement;
min_query_length?: number;
confirm?: Confirm;
focus_on_load?: boolean;
}

export interface MultiExternalSelect extends Action {
type: 'multi_external_select';
action_id: string;
initial_options?: PlainTextOption[];
placeholder?: PlainTextElement;
placeholder: PlainTextElement;
min_query_length?: number;
max_selected_items?: number;
confirm?: Confirm;
focus_on_load?: boolean;
}

export interface Button extends Action {
type: 'button';
accessibility_label?: string;
/**
* @description: An identifier for this button action. You can use this when you receive an interaction payload to
* identify the source of the action. Should be unique among all other `action_id`s in the containing block. Maximum
* length for this field is 255 characters.
*/
action_id: string;
confirm?: Confirm;
style?: 'danger' | 'primary';
text: PlainTextElement;
value?: string;
type: 'button';
/**
* @description: A URL to load in the user's browser when the button is clicked. Maximum length for this field is
* 3000 characters.
*/
url?: string;
style?: 'danger' | 'primary';
confirm?: Confirm;
accessibility_label?: string;
value?: string;
}

export interface Overflow extends Action {
type: 'overflow';
action_id: string;
options: PlainTextOption[];
confirm?: Confirm;
}

export interface Datepicker extends Action {
type: 'datepicker';
action_id: string;
initial_date?: string;
placeholder?: PlainTextElement;
confirm?: Confirm;
Expand All @@ -260,15 +291,17 @@ export interface Datepicker extends Action {

export interface Timepicker extends Action {
type: 'timepicker';
action_id: string;
initial_time?: string;
placeholder?: PlainTextElement;
confirm?: Confirm;
focus_on_load?: boolean;
timezone?: string;
timezone?: string; // TODO: this is not listed? https://api.slack.com/reference/block-kit/block-elements#timepicker__fields
}

export interface RadioButtons extends Action {
type: 'radio_buttons';
action_id: string;
initial_option?: Option;
options: Option[];
confirm?: Confirm;
Expand All @@ -277,6 +310,7 @@ export interface RadioButtons extends Action {

export interface Checkboxes extends Action {
type: 'checkboxes';
action_id: string;
initial_options?: Option[];
options: Option[];
confirm?: Confirm;
Expand All @@ -285,6 +319,7 @@ export interface Checkboxes extends Action {

export interface PlainTextInput extends Action {
type: 'plain_text_input';
action_id: string;
placeholder?: PlainTextElement;
initial_value?: string;
multiline?: boolean;
Expand All @@ -294,22 +329,30 @@ export interface PlainTextInput extends Action {
focus_on_load?: boolean;
}

export interface DispatchActionConfig {
trigger_actions_on?: ('on_enter_pressed' | 'on_character_entered')[];
export interface ImageElement {
type: 'image';
image_url: string;
alt_text: string;
}

/*
* Block Types
/**
* Layout Blocks: https://api.slack.com/reference/block-kit/blocks
*/

export type KnownBlock = ImageBlock | ContextBlock | ActionsBlock | DividerBlock |
SectionBlock | InputBlock | FileBlock | HeaderBlock | VideoBlock;

export interface Block {
type: string;
/**
* @description: A string acting as a unique identifier for a block. If not specified, a `block_id` will be generated.
* You can use this `block_id` when you receive an interaction payload to identify the source of the action. Maximum
* length for this field is 255 characters. block_id should be unique for each message and each iteration of a
* message. If a message is updated, use a new block_id.
*/
block_id?: string;
}

export type KnownBlock = ImageBlock | ContextBlock | ActionsBlock | DividerBlock |
SectionBlock | InputBlock | FileBlock | HeaderBlock | VideoBlock;

export interface ImageBlock extends Block {
type: 'image';
image_url: string;
Expand All @@ -324,7 +367,7 @@ export interface ContextBlock extends Block {

export interface ActionsBlock extends Block {
type: 'actions';
elements: (Button | Overflow | Datepicker | Timepicker | Select | RadioButtons | Checkboxes | Action)[];
elements: (Button | Overflow | Datepicker | Timepicker | Select | MultiSelect | RadioButtons | Checkboxes | Action)[];
}

export interface DividerBlock extends Block {
Expand All @@ -339,6 +382,7 @@ export interface SectionBlock extends Block {
| Overflow
| Datepicker
| Timepicker
| PlainTextInput
| Select
| MultiSelect
| Action
Expand Down