slack-ruby-block-kit 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.circleci/config.yml +49 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.rubocop.yml +15 -0
- data/.rubocop_todo.yml +38 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +59 -0
- data/LICENSE.txt +21 -0
- data/README.md +95 -0
- data/Rakefile +8 -0
- data/lib/slack-ruby-block-kit.rb +3 -0
- data/lib/slack/block_kit.rb +26 -0
- data/lib/slack/block_kit/blocks.rb +71 -0
- data/lib/slack/block_kit/composition/confirmation_dialog.rb +53 -0
- data/lib/slack/block_kit/composition/mrkdwn.rb +28 -0
- data/lib/slack/block_kit/composition/option.rb +25 -0
- data/lib/slack/block_kit/composition/option_group.rb +35 -0
- data/lib/slack/block_kit/composition/plain_text.rb +27 -0
- data/lib/slack/block_kit/element/button.rb +48 -0
- data/lib/slack/block_kit/element/channels_select.rb +48 -0
- data/lib/slack/block_kit/element/conversations_select.rb +49 -0
- data/lib/slack/block_kit/element/date_picker.rb +48 -0
- data/lib/slack/block_kit/element/external_select.rb +56 -0
- data/lib/slack/block_kit/element/image.rb +29 -0
- data/lib/slack/block_kit/element/overflow_menu.rb +58 -0
- data/lib/slack/block_kit/element/static_select.rb +81 -0
- data/lib/slack/block_kit/element/users_select.rb +48 -0
- data/lib/slack/block_kit/layout/actions.rb +138 -0
- data/lib/slack/block_kit/layout/context.rb +48 -0
- data/lib/slack/block_kit/layout/divider.rb +26 -0
- data/lib/slack/block_kit/layout/image.rb +37 -0
- data/lib/slack/block_kit/layout/section.rb +173 -0
- data/slack-ruby-block-kit.gemspec +37 -0
- metadata +161 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module Element
|
6
|
+
# A select menu, just as with a standard HTML <select> tag, creates a drop
|
7
|
+
# down menu with a list of options for a user to choose. The select menu
|
8
|
+
# also includes type-ahead functionality, where a user can type a part or
|
9
|
+
# all of an option string to filter the list.
|
10
|
+
#
|
11
|
+
# This is the simplest form of select menu, with a static list of options
|
12
|
+
# passed in when defining the element.
|
13
|
+
#
|
14
|
+
# https://api.slack.com/reference/messaging/block-elements#static-select
|
15
|
+
class StaticSelect
|
16
|
+
TYPE = 'static_select'
|
17
|
+
|
18
|
+
attr_accessor :confirm, :options, :option_groups, :initial_option
|
19
|
+
|
20
|
+
def initialize(placeholder:, action_id:, emoji: nil)
|
21
|
+
@placeholder = Composition::PlainText.new(text: placeholder, emoji: emoji)
|
22
|
+
@action_id = action_id
|
23
|
+
|
24
|
+
yield(self) if block_given?
|
25
|
+
end
|
26
|
+
|
27
|
+
def confirmation_dialog
|
28
|
+
@confirm = Composition::ConfirmationDialog.new
|
29
|
+
|
30
|
+
yield(@confirm) if block_given?
|
31
|
+
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def option(value:, text:, emoji: nil)
|
36
|
+
@options ||= []
|
37
|
+
@options << Composition::Option.new(
|
38
|
+
value: value,
|
39
|
+
text: text,
|
40
|
+
emoji: emoji
|
41
|
+
)
|
42
|
+
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def option_group(label:, emoji: nil)
|
47
|
+
option_group = Composition::OptionGroup.new(label: label, emoji: emoji)
|
48
|
+
|
49
|
+
yield(option_group) if block_given?
|
50
|
+
|
51
|
+
@option_groups ||= []
|
52
|
+
@option_groups << option_group
|
53
|
+
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
def initial(value:, text:, emoji: nil)
|
58
|
+
@initial_option = Composition::Option.new(
|
59
|
+
value: value,
|
60
|
+
text: text,
|
61
|
+
emoji: emoji
|
62
|
+
)
|
63
|
+
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def as_json(*)
|
68
|
+
{
|
69
|
+
type: TYPE,
|
70
|
+
placeholder: @placeholder.as_json,
|
71
|
+
action_id: @action_id,
|
72
|
+
options: @options&.map(&:as_json),
|
73
|
+
option_groups: @option_groups&.map(&:as_json),
|
74
|
+
initial_option: @initial_option&.as_json,
|
75
|
+
confirm: @confirm&.as_json
|
76
|
+
}.compact
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module Element
|
6
|
+
# A select menu, just as with a standard HTML <select> tag, creates a drop
|
7
|
+
# down menu with a list of options for a user to choose. The select menu
|
8
|
+
# also includes type-ahead functionality, where a user can type a part or
|
9
|
+
# all of an option string to filter the list.
|
10
|
+
#
|
11
|
+
# This select menu will populate its options with a list of Slack users
|
12
|
+
# visible to the current user in the active workspace.
|
13
|
+
#
|
14
|
+
# https://api.slack.com/reference/messaging/block-elements#users-select
|
15
|
+
class UsersSelect
|
16
|
+
TYPE = 'users_select'
|
17
|
+
|
18
|
+
attr_accessor :confirm
|
19
|
+
|
20
|
+
def initialize(placeholder:, action_id:, initial: nil, emoji: nil)
|
21
|
+
@placeholder = Composition::PlainText.new(text: placeholder, emoji: emoji)
|
22
|
+
@action_id = action_id
|
23
|
+
@initial_user = initial
|
24
|
+
|
25
|
+
yield(self) if block_given?
|
26
|
+
end
|
27
|
+
|
28
|
+
def confirmation_dialog
|
29
|
+
@confirm = Composition::ConfirmationDialog.new
|
30
|
+
|
31
|
+
yield(@confirm) if block_given?
|
32
|
+
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def as_json(*)
|
37
|
+
{
|
38
|
+
type: TYPE,
|
39
|
+
placeholder: @placeholder.as_json,
|
40
|
+
action_id: @action_id,
|
41
|
+
initial_user: @initial_user,
|
42
|
+
confirm: @confirm&.as_json
|
43
|
+
}.compact
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module Layout
|
6
|
+
# A block that is used to hold interactive elements.
|
7
|
+
#
|
8
|
+
# https://api.slack.com/reference/messaging/blocks#actions
|
9
|
+
class Actions
|
10
|
+
TYPE = 'actions'
|
11
|
+
|
12
|
+
attr_accessor :elements
|
13
|
+
|
14
|
+
def initialize(block_id: nil)
|
15
|
+
@block_id = block_id
|
16
|
+
@elements = []
|
17
|
+
|
18
|
+
yield(self) if block_given?
|
19
|
+
end
|
20
|
+
|
21
|
+
def button(text:, action_id:, style: nil, emoji: nil, url: nil, value: nil)
|
22
|
+
element = Element::Button.new(
|
23
|
+
text: text,
|
24
|
+
action_id: action_id,
|
25
|
+
style: style,
|
26
|
+
emoji: emoji,
|
27
|
+
url: url,
|
28
|
+
value: value
|
29
|
+
)
|
30
|
+
|
31
|
+
yield(element) if block_given?
|
32
|
+
|
33
|
+
append(element)
|
34
|
+
end
|
35
|
+
|
36
|
+
def channel_select(placeholder:, action_id:, initial: nil, emoji: nil)
|
37
|
+
element = Element::ChannelsSelect.new(
|
38
|
+
placeholder: placeholder,
|
39
|
+
action_id: action_id,
|
40
|
+
initial: initial,
|
41
|
+
emoji: emoji
|
42
|
+
)
|
43
|
+
|
44
|
+
yield(element) if block_given?
|
45
|
+
|
46
|
+
append(element)
|
47
|
+
end
|
48
|
+
|
49
|
+
def converstation_select(placeholder:, action_id:, initial: nil, emoji: nil)
|
50
|
+
element = Element::ConversationsSelect.new(
|
51
|
+
placeholder: placeholder,
|
52
|
+
action_id: action_id,
|
53
|
+
initial: initial,
|
54
|
+
emoji: emoji
|
55
|
+
)
|
56
|
+
|
57
|
+
yield(element) if block_given?
|
58
|
+
|
59
|
+
append(element)
|
60
|
+
end
|
61
|
+
|
62
|
+
def date_picker(action_id:, placeholder: nil, initial: nil, emoji: nil)
|
63
|
+
element = Element::DatePicker.new(
|
64
|
+
placeholder: placeholder,
|
65
|
+
action_id: action_id,
|
66
|
+
initial: initial,
|
67
|
+
emoji: emoji
|
68
|
+
)
|
69
|
+
|
70
|
+
yield(element) if block_given?
|
71
|
+
|
72
|
+
append(element)
|
73
|
+
end
|
74
|
+
|
75
|
+
def external_select(placeholder:, action_id:, initial: nil, min_query_length: nil, emoji: nil)
|
76
|
+
element = Element::ExternalSelect.new(
|
77
|
+
placeholder: placeholder,
|
78
|
+
action_id: action_id,
|
79
|
+
initial: initial,
|
80
|
+
min_query_length: min_query_length,
|
81
|
+
emoji: emoji
|
82
|
+
)
|
83
|
+
|
84
|
+
yield(element) if block_given?
|
85
|
+
|
86
|
+
append(element)
|
87
|
+
end
|
88
|
+
|
89
|
+
def overflow_menu(action_id:)
|
90
|
+
element = Element::OverflowMenu.new(action_id: action_id)
|
91
|
+
|
92
|
+
yield(element) if block_given?
|
93
|
+
|
94
|
+
append(element)
|
95
|
+
end
|
96
|
+
|
97
|
+
def static_select(placeholder:, action_id:, emoji: nil)
|
98
|
+
element = Element::StaticSelect.new(
|
99
|
+
placeholder: placeholder,
|
100
|
+
action_id: action_id,
|
101
|
+
emoji: emoji
|
102
|
+
)
|
103
|
+
|
104
|
+
yield(element) if block_given?
|
105
|
+
|
106
|
+
append(element)
|
107
|
+
end
|
108
|
+
|
109
|
+
def users_select(placeholder:, action_id:, initial: nil, emoji: nil)
|
110
|
+
element = Element::UsersSelect.new(
|
111
|
+
placeholder: placeholder,
|
112
|
+
action_id: action_id,
|
113
|
+
emoji: emoji,
|
114
|
+
initial: initial
|
115
|
+
)
|
116
|
+
|
117
|
+
yield(element) if block_given?
|
118
|
+
|
119
|
+
append(element)
|
120
|
+
end
|
121
|
+
|
122
|
+
def append(element)
|
123
|
+
@elements << element
|
124
|
+
|
125
|
+
self
|
126
|
+
end
|
127
|
+
|
128
|
+
def as_json(*)
|
129
|
+
{
|
130
|
+
type: TYPE,
|
131
|
+
elements: @elements.map(&:as_json),
|
132
|
+
block_id: @block_id
|
133
|
+
}.compact
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module Layout
|
6
|
+
# Displays message context, which can include both images and text.
|
7
|
+
#
|
8
|
+
# https://api.slack.com/reference/messaging/blocks#context
|
9
|
+
class Context
|
10
|
+
TYPE = 'context'
|
11
|
+
|
12
|
+
attr_accessor :elements
|
13
|
+
def initialize(block_id: nil)
|
14
|
+
@block_id = block_id
|
15
|
+
@elements = []
|
16
|
+
|
17
|
+
yield(self) if block_given?
|
18
|
+
end
|
19
|
+
|
20
|
+
def image(url:, alt_text:)
|
21
|
+
append(Element::Image.new(image_url: url, alt_text: alt_text))
|
22
|
+
end
|
23
|
+
|
24
|
+
def plain_text(text:, emoji: nil)
|
25
|
+
append(Composition::PlainText.new(text: text, emoji: emoji))
|
26
|
+
end
|
27
|
+
|
28
|
+
def mrkdwn(text:, verbatim: nil)
|
29
|
+
append(Composition::Mrkdwn.new(text: text, verbatim: verbatim))
|
30
|
+
end
|
31
|
+
|
32
|
+
def append(element)
|
33
|
+
@elements << element
|
34
|
+
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def as_json(*)
|
39
|
+
{
|
40
|
+
type: TYPE,
|
41
|
+
elements: @elements.map(&:as_json),
|
42
|
+
block_id: @block_id
|
43
|
+
}.compact
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module Layout
|
6
|
+
# A content divider, like an <hr>, to split up different blocks inside of
|
7
|
+
# a message.
|
8
|
+
#
|
9
|
+
# https://api.slack.com/reference/messaging/blocks#divider
|
10
|
+
class Divider
|
11
|
+
TYPE = 'divider'
|
12
|
+
|
13
|
+
def initialize(block_id: nil)
|
14
|
+
@block_id = block_id
|
15
|
+
end
|
16
|
+
|
17
|
+
def as_json(*)
|
18
|
+
{
|
19
|
+
type: TYPE,
|
20
|
+
block_id: @block_id
|
21
|
+
}.compact
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module Layout
|
6
|
+
# A simple image block, designed to make those cat photos really pop.
|
7
|
+
#
|
8
|
+
# https://api.slack.com/reference/messaging/blocks#context
|
9
|
+
class Image
|
10
|
+
TYPE = 'image'
|
11
|
+
|
12
|
+
def initialize(url:, alt_text:, title: nil, block_id: nil, emoji: nil)
|
13
|
+
@image_url = url
|
14
|
+
@alt_text = alt_text
|
15
|
+
@block_id = block_id
|
16
|
+
|
17
|
+
return unless title
|
18
|
+
|
19
|
+
@title = Composition::PlainText.new(
|
20
|
+
text: title,
|
21
|
+
emoji: emoji
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def as_json(*)
|
26
|
+
{
|
27
|
+
type: TYPE,
|
28
|
+
image_url: @image_url,
|
29
|
+
alt_text: @alt_text,
|
30
|
+
title: @title&.as_json,
|
31
|
+
block_id: @block_id
|
32
|
+
}.compact
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module Layout
|
6
|
+
# A section is one of the most flexible blocks available - it can be used
|
7
|
+
# as a simple text block, in combination with text fields, or side-by-side
|
8
|
+
# with any of the available block elements.
|
9
|
+
#
|
10
|
+
# https://api.slack.com/reference/messaging/blocks#section
|
11
|
+
class Section
|
12
|
+
TYPE = 'section'
|
13
|
+
|
14
|
+
attr_accessor :fields, :text, :accessory
|
15
|
+
|
16
|
+
def initialize(block_id: nil)
|
17
|
+
@block_id = block_id
|
18
|
+
|
19
|
+
yield(self) if block_given?
|
20
|
+
end
|
21
|
+
|
22
|
+
def plaintext_field(text:, emoji: nil)
|
23
|
+
@fields ||= []
|
24
|
+
|
25
|
+
@fields << Composition::PlainText.new(text: text, emoji: emoji)
|
26
|
+
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def mrkdwn_field(text:, verbatim: nil)
|
31
|
+
@fields ||= []
|
32
|
+
|
33
|
+
@fields << Composition::Mrkdwn.new(text: text, verbatim: verbatim)
|
34
|
+
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def plain_text(text:, emoji: nil)
|
39
|
+
@text = Composition::PlainText.new(text: text, emoji: emoji)
|
40
|
+
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def mrkdwn(text:, verbatim: nil)
|
45
|
+
@text = Composition::Mrkdwn.new(text: text, verbatim: verbatim)
|
46
|
+
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def button(text:, action_id:, style: nil, emoji: nil, url: nil, value: nil)
|
51
|
+
element = Element::Button.new(
|
52
|
+
text: text,
|
53
|
+
action_id: action_id,
|
54
|
+
style: style,
|
55
|
+
emoji: emoji,
|
56
|
+
url: url,
|
57
|
+
value: value
|
58
|
+
)
|
59
|
+
|
60
|
+
yield(element) if block_given?
|
61
|
+
|
62
|
+
accessorise(element)
|
63
|
+
end
|
64
|
+
|
65
|
+
def channel_select(placeholder:, action_id:, initial: nil, emoji: nil)
|
66
|
+
element = Element::ChannelsSelect.new(
|
67
|
+
placeholder: placeholder,
|
68
|
+
action_id: action_id,
|
69
|
+
initial: initial,
|
70
|
+
emoji: emoji
|
71
|
+
)
|
72
|
+
|
73
|
+
yield(element) if block_given?
|
74
|
+
|
75
|
+
accessorise(element)
|
76
|
+
end
|
77
|
+
|
78
|
+
def conversation_select(placeholder:, action_id:, initial: nil, emoji: nil)
|
79
|
+
element = Element::ConversationsSelect.new(
|
80
|
+
placeholder: placeholder,
|
81
|
+
action_id: action_id,
|
82
|
+
initial: initial,
|
83
|
+
emoji: emoji
|
84
|
+
)
|
85
|
+
|
86
|
+
yield(element) if block_given?
|
87
|
+
|
88
|
+
accessorise(element)
|
89
|
+
end
|
90
|
+
|
91
|
+
def date_picker(action_id:, placeholder: nil, initial: nil, emoji: nil)
|
92
|
+
element = Element::DatePicker.new(
|
93
|
+
placeholder: placeholder,
|
94
|
+
action_id: action_id,
|
95
|
+
initial: initial,
|
96
|
+
emoji: emoji
|
97
|
+
)
|
98
|
+
|
99
|
+
yield(element) if block_given?
|
100
|
+
|
101
|
+
accessorise(element)
|
102
|
+
end
|
103
|
+
|
104
|
+
def external_select(placeholder:, action_id:, initial: nil, min_query_length: nil, emoji: nil)
|
105
|
+
element = Element::ExternalSelect.new(
|
106
|
+
placeholder: placeholder,
|
107
|
+
action_id: action_id,
|
108
|
+
initial: initial,
|
109
|
+
min_query_length: min_query_length,
|
110
|
+
emoji: emoji
|
111
|
+
)
|
112
|
+
|
113
|
+
yield(element) if block_given?
|
114
|
+
|
115
|
+
accessorise(element)
|
116
|
+
end
|
117
|
+
|
118
|
+
def overflow_menu(action_id:)
|
119
|
+
element = Element::OverflowMenu.new(action_id: action_id)
|
120
|
+
|
121
|
+
yield(element) if block_given?
|
122
|
+
|
123
|
+
accessorise(element)
|
124
|
+
end
|
125
|
+
|
126
|
+
def static_select(placeholder:, action_id:, emoji: nil)
|
127
|
+
element = Element::StaticSelect.new(
|
128
|
+
placeholder: placeholder,
|
129
|
+
action_id: action_id,
|
130
|
+
emoji: emoji
|
131
|
+
)
|
132
|
+
|
133
|
+
yield(element) if block_given?
|
134
|
+
|
135
|
+
accessorise(element)
|
136
|
+
end
|
137
|
+
|
138
|
+
def users_select(placeholder:, action_id:, initial: nil, emoji: nil)
|
139
|
+
element = Element::UsersSelect.new(
|
140
|
+
placeholder: placeholder,
|
141
|
+
action_id: action_id,
|
142
|
+
emoji: emoji,
|
143
|
+
initial: initial
|
144
|
+
)
|
145
|
+
|
146
|
+
yield(element) if block_given?
|
147
|
+
|
148
|
+
accessorise(element)
|
149
|
+
end
|
150
|
+
|
151
|
+
def image(url:, alt_text:)
|
152
|
+
accessorize(Element::Image.new(image_url: url, alt_text: alt_text))
|
153
|
+
end
|
154
|
+
|
155
|
+
def accessorise(element)
|
156
|
+
@accessory = element
|
157
|
+
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
161
|
+
def as_json(*)
|
162
|
+
{
|
163
|
+
type: TYPE,
|
164
|
+
text: @text.as_json,
|
165
|
+
block_id: @block_id,
|
166
|
+
fields: @fields&.map(&:as_json),
|
167
|
+
accessory: @accessory&.as_json
|
168
|
+
}.compact
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|