slack-ruby-block-kit 0.8.0 → 0.13.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.deepsource.toml +15 -0
  3. data/.github/workflows/ci.yml +33 -0
  4. data/.gitignore +2 -0
  5. data/.rubocop.yml +23 -1
  6. data/.rubocop_todo.yml +10 -0
  7. data/CHANGELOG.md +93 -0
  8. data/Gemfile +14 -1
  9. data/README.md +3 -1
  10. data/lib/slack/block_kit.rb +46 -2
  11. data/lib/slack/block_kit/blocks.rb +12 -0
  12. data/lib/slack/block_kit/composition/confirmation_dialog.rb +16 -0
  13. data/lib/slack/block_kit/composition/option.rb +6 -1
  14. data/lib/slack/block_kit/composition/option_group.rb +2 -2
  15. data/lib/slack/block_kit/element/button.rb +3 -11
  16. data/lib/slack/block_kit/element/channels_select.rb +3 -11
  17. data/lib/slack/block_kit/element/checkboxes.rb +53 -0
  18. data/lib/slack/block_kit/element/conversations_select.rb +3 -11
  19. data/lib/slack/block_kit/element/date_picker.rb +3 -9
  20. data/lib/slack/block_kit/element/external_select.rb +3 -12
  21. data/lib/slack/block_kit/element/multi_channels_select.rb +5 -14
  22. data/lib/slack/block_kit/element/multi_conversations_select.rb +5 -14
  23. data/lib/slack/block_kit/element/multi_external_select.rb +5 -14
  24. data/lib/slack/block_kit/element/multi_static_select.rb +18 -25
  25. data/lib/slack/block_kit/element/multi_users_select.rb +5 -14
  26. data/lib/slack/block_kit/element/overflow_menu.rb +4 -11
  27. data/lib/slack/block_kit/element/radio_buttons.rb +53 -0
  28. data/lib/slack/block_kit/element/static_select.rb +20 -25
  29. data/lib/slack/block_kit/element/timepicker.rb +49 -0
  30. data/lib/slack/block_kit/element/users_select.rb +3 -11
  31. data/lib/slack/block_kit/layout/header.rb +29 -0
  32. data/lib/slack/block_kit/layout/image.rb +1 -4
  33. data/lib/slack/block_kit/layout/input.rb +198 -3
  34. data/lib/slack/block_kit/layout/section.rb +21 -1
  35. data/lib/slack/block_kit/version.rb +7 -0
  36. data/lib/slack/surfaces/home.rb +35 -0
  37. data/lib/slack/surfaces/message.rb +34 -0
  38. data/lib/slack/surfaces/modal.rb +76 -0
  39. data/slack-ruby-block-kit.gemspec +1 -18
  40. metadata +20 -138
  41. data/.circleci/config.yml +0 -49
  42. data/Gemfile.lock +0 -74
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ module Element
6
+ # A radio button group that allows a user to choose one item from a list of possible options.
7
+ #
8
+ # https://api.slack.com/reference/messaging/block-elements#radio
9
+ class RadioButtons
10
+ include Composition::ConfirmationDialog::Confirmable
11
+
12
+ TYPE = 'radio_buttons'
13
+
14
+ attr_accessor :options
15
+
16
+ def initialize(action_id:)
17
+ @action_id = action_id
18
+ @options = []
19
+
20
+ yield(self) if block_given?
21
+ end
22
+
23
+ def option(value:, text:, initial: false)
24
+ option = Composition::Option.new(
25
+ value: value,
26
+ text: text,
27
+ initial: initial
28
+ )
29
+
30
+ @options << option
31
+
32
+ self
33
+ end
34
+
35
+ def as_json(*)
36
+ {
37
+ type: TYPE,
38
+ action_id: @action_id,
39
+ options: @options.map(&:as_json),
40
+ initial_option: initial_option&.as_json,
41
+ confirm: confirm&.as_json
42
+ }.compact
43
+ end
44
+
45
+ private
46
+
47
+ def initial_option
48
+ @options&.find(&:initial?)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -13,9 +13,11 @@ module Slack
13
13
  #
14
14
  # https://api.slack.com/reference/messaging/block-elements#static-select
15
15
  class StaticSelect
16
+ include Composition::ConfirmationDialog::Confirmable
17
+
16
18
  TYPE = 'static_select'
17
19
 
18
- attr_accessor :confirm, :options, :option_groups, :initial_option
20
+ attr_accessor :options, :option_groups
19
21
 
20
22
  def initialize(placeholder:, action_id:, emoji: nil)
21
23
  @placeholder = Composition::PlainText.new(text: placeholder, emoji: emoji)
@@ -24,20 +26,13 @@ module Slack
24
26
  yield(self) if block_given?
25
27
  end
26
28
 
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)
29
+ def option(value:, text:, initial: false, emoji: nil)
36
30
  @options ||= []
37
31
  @options << Composition::Option.new(
38
32
  value: value,
39
33
  text: text,
40
- emoji: emoji
34
+ emoji: emoji,
35
+ initial: initial
41
36
  )
42
37
 
43
38
  self
@@ -54,27 +49,27 @@ module Slack
54
49
  self
55
50
  end
56
51
 
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
52
  def as_json(*)
68
53
  {
69
54
  type: TYPE,
70
55
  placeholder: @placeholder.as_json,
71
56
  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
57
+ options: options&.map(&:as_json),
58
+ option_groups: option_groups&.map(&:as_json),
59
+ initial_option: initial_option&.as_json,
60
+ confirm: confirm&.as_json
76
61
  }.compact
77
62
  end
63
+
64
+ private
65
+
66
+ def initial_option
67
+ opts = options || option_groups&.flat_map(&:options)
68
+
69
+ return unless opts
70
+
71
+ opts.find(&:initial?)
72
+ end
78
73
  end
79
74
  end
80
75
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ module Element
6
+ # An element which allows selection of a time of day.
7
+ #
8
+ # On desktop clients, this time picker will take the form of a dropdown
9
+ # list with free-text entry for precise choices. On mobile clients, the
10
+ # time picker will use native time picker UIs.
11
+ #
12
+ # https://api.slack.com/reference/block-kit/block-elements#timepicker
13
+ class Timepicker
14
+ include Composition::ConfirmationDialog::Confirmable
15
+
16
+ TYPE = 'timepicker'
17
+
18
+ def initialize(action_id:)
19
+ @placeholder, @initial_time = nil
20
+ @action_id = action_id
21
+
22
+ yield(self) if block_given?
23
+ end
24
+
25
+ def placeholder(text:, emoji: nil)
26
+ @placeholder = Composition::PlainText.new(text: text, emoji: emoji)
27
+
28
+ self
29
+ end
30
+
31
+ def initial_time(time_str)
32
+ @initial_time = time_str
33
+
34
+ self
35
+ end
36
+
37
+ def as_json(*)
38
+ {
39
+ type: TYPE,
40
+ action_id: @action_id,
41
+ placeholder: @placeholder&.as_json,
42
+ initial_time: @initial_time,
43
+ confirm: confirm&.as_json
44
+ }.compact
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -13,9 +13,9 @@ module Slack
13
13
  #
14
14
  # https://api.slack.com/reference/messaging/block-elements#users-select
15
15
  class UsersSelect
16
- TYPE = 'users_select'
16
+ include Composition::ConfirmationDialog::Confirmable
17
17
 
18
- attr_accessor :confirm
18
+ TYPE = 'users_select'
19
19
 
20
20
  def initialize(placeholder:, action_id:, initial: nil, emoji: nil)
21
21
  @placeholder = Composition::PlainText.new(text: placeholder, emoji: emoji)
@@ -25,21 +25,13 @@ module Slack
25
25
  yield(self) if block_given?
26
26
  end
27
27
 
28
- def confirmation_dialog
29
- @confirm = Composition::ConfirmationDialog.new
30
-
31
- yield(@confirm) if block_given?
32
-
33
- self
34
- end
35
-
36
28
  def as_json(*)
37
29
  {
38
30
  type: TYPE,
39
31
  placeholder: @placeholder.as_json,
40
32
  action_id: @action_id,
41
33
  initial_user: @initial_user,
42
- confirm: @confirm&.as_json
34
+ confirm: confirm&.as_json
43
35
  }.compact
44
36
  end
45
37
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ module Layout
6
+ # A header is a plain-text block that displays in a larger, bold font.
7
+ # Use it to delineate between different groups of content in your app's
8
+ # surfaces.
9
+ #
10
+ # https://api.slack.com/reference/block-kit/blocks#header
11
+ class Header
12
+ TYPE = 'header'
13
+
14
+ def initialize(text:, block_id: nil, emoji: nil)
15
+ @text = Composition::PlainText.new(text: text, emoji: emoji)
16
+ @block_id = block_id
17
+ end
18
+
19
+ def as_json(*)
20
+ {
21
+ type: TYPE,
22
+ text: @text.as_json,
23
+ block_id: @block_id
24
+ }.compact
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -13,10 +13,7 @@ module Slack
13
13
  @image_url = url
14
14
  @alt_text = alt_text
15
15
  @block_id = block_id
16
-
17
- return unless title
18
-
19
- @title = Composition::PlainText.new(
16
+ @title = title && Composition::PlainText.new(
20
17
  text: title,
21
18
  emoji: emoji
22
19
  )
@@ -4,18 +4,20 @@ module Slack
4
4
  module BlockKit
5
5
  module Layout
6
6
  # A block that collects information from users - it can hold a plain-text
7
- # input element, a select menu element, a multi-select menu element, or a
8
- # datepicker.
7
+ # input element, a checkbox element, a radio button element,
8
+ # a select menu element, a multi-select menu element, or a datepicker.
9
9
  #
10
10
  # https://api.slack.com/reference/block-kit/blocks#input
11
+ # rubocop:disable Metrics/ClassLength
11
12
  class Input
13
+ # rubocop:enable Metrics/ClassLength
12
14
  TYPE = 'input'
13
15
 
14
16
  attr_accessor :label, :element, :block_id, :hint, :optional, :emoji
15
17
 
16
18
  def initialize(
17
19
  label:,
18
- element:,
20
+ element: nil,
19
21
  block_id: nil,
20
22
  hint: nil,
21
23
  optional: nil,
@@ -28,6 +30,199 @@ module Slack
28
30
  @element = element
29
31
  end
30
32
 
33
+ def conversation_select(placeholder:, action_id:, initial: nil, emoji: nil)
34
+ @element = Element::ConversationsSelect.new(
35
+ placeholder: placeholder,
36
+ action_id: action_id,
37
+ initial: initial,
38
+ emoji: emoji
39
+ )
40
+
41
+ yield(@element) if block_given?
42
+
43
+ self
44
+ end
45
+
46
+ def multi_conversations_select(placeholder:, action_id:, initial: nil, emoji: nil, max_selected_items: nil)
47
+ @element = Element::MultiConversationsSelect.new(
48
+ placeholder: placeholder,
49
+ action_id: action_id,
50
+ initial: initial,
51
+ emoji: emoji,
52
+ max_selected_items: max_selected_items
53
+ )
54
+
55
+ yield(@element) if block_given?
56
+
57
+ self
58
+ end
59
+
60
+ def channels_select(placeholder:, action_id:, initial: nil, emoji: nil)
61
+ @element = Element::ChannelsSelect.new(
62
+ placeholder: placeholder,
63
+ action_id: action_id,
64
+ initial: initial,
65
+ emoji: emoji
66
+ )
67
+
68
+ yield(@element) if block_given?
69
+
70
+ self
71
+ end
72
+
73
+ def checkboxes(action_id:)
74
+ @element = Element::Checkboxes.new(action_id: action_id)
75
+
76
+ yield(@element) if block_given?
77
+
78
+ self
79
+ end
80
+
81
+ def datepicker(action_id:, placeholder: nil, initial: nil, emoji: nil)
82
+ @element = Element::DatePicker.new(
83
+ action_id: action_id,
84
+ placeholder: placeholder,
85
+ initial: initial,
86
+ emoji: emoji
87
+ )
88
+
89
+ yield(@element) if block_given?
90
+
91
+ self
92
+ end
93
+
94
+ def multi_channels_select(placeholder:, action_id:, initial: nil, emoji: nil, max_selected_items: nil)
95
+ @element = Element::MultiChannelsSelect.new(
96
+ placeholder: placeholder,
97
+ action_id: action_id,
98
+ initial: initial,
99
+ emoji: emoji,
100
+ max_selected_items: max_selected_items
101
+ )
102
+
103
+ yield(@element) if block_given?
104
+
105
+ self
106
+ end
107
+
108
+ def static_select(placeholder:, action_id:, emoji: nil)
109
+ @element = Element::StaticSelect.new(
110
+ placeholder: placeholder,
111
+ action_id: action_id,
112
+ emoji: emoji
113
+ )
114
+
115
+ yield(@element) if block_given?
116
+
117
+ self
118
+ end
119
+
120
+ def multi_static_select(placeholder:, action_id:, emoji: nil, max_selected_items: nil)
121
+ @element = Element::MultiStaticSelect.new(
122
+ placeholder: placeholder,
123
+ action_id: action_id,
124
+ emoji: emoji,
125
+ max_selected_items: max_selected_items
126
+ )
127
+
128
+ yield(@element) if block_given?
129
+
130
+ self
131
+ end
132
+
133
+ def external_select(placeholder:, action_id:, initial: nil, min_query_length: nil, emoji: nil)
134
+ @element = Element::ExternalSelect.new(
135
+ placeholder: placeholder,
136
+ action_id: action_id,
137
+ initial: initial,
138
+ min_query_length: min_query_length,
139
+ emoji: emoji
140
+ )
141
+
142
+ yield(@element) if block_given?
143
+
144
+ self
145
+ end
146
+
147
+ def multi_external_select(
148
+ placeholder:,
149
+ action_id:,
150
+ initial: nil,
151
+ min_query_length: nil,
152
+ emoji: nil,
153
+ max_selected_items: nil
154
+ )
155
+ @element = Element::MultiExternalSelect.new(
156
+ placeholder: placeholder,
157
+ action_id: action_id,
158
+ initial: initial,
159
+ min_query_length: min_query_length,
160
+ emoji: emoji,
161
+ max_selected_items: max_selected_items
162
+ )
163
+
164
+ yield(@element) if block_given?
165
+
166
+ self
167
+ end
168
+
169
+ def plain_text_input(
170
+ action_id:,
171
+ placeholder: nil,
172
+ emoji: nil,
173
+ initial_value: nil,
174
+ multiline: nil,
175
+ min_length: nil,
176
+ max_length: nil
177
+ )
178
+ @element = Element::PlainTextInput.new(
179
+ action_id: action_id,
180
+ placeholder: placeholder,
181
+ emoji: emoji,
182
+ initial_value: initial_value,
183
+ multiline: multiline,
184
+ min_length: min_length,
185
+ max_length: max_length
186
+ )
187
+
188
+ self
189
+ end
190
+
191
+ def radio_buttons(action_id:)
192
+ @element = Element::RadioButtons.new(action_id: action_id)
193
+
194
+ yield(@element) if block_given?
195
+
196
+ self
197
+ end
198
+
199
+ def users_select(placeholder:, action_id:, initial: nil, emoji: nil)
200
+ @element = Element::UsersSelect.new(
201
+ placeholder: placeholder,
202
+ action_id: action_id,
203
+ initial: initial,
204
+ emoji: emoji
205
+ )
206
+
207
+ yield(@element) if block_given?
208
+
209
+ self
210
+ end
211
+
212
+ def multi_users_select(placeholder:, action_id:, initial: nil, emoji: nil, max_selected_items: nil)
213
+ @element = Element::MultiUsersSelect.new(
214
+ placeholder: placeholder,
215
+ action_id: action_id,
216
+ initial: initial,
217
+ emoji: emoji,
218
+ max_selected_items: max_selected_items
219
+ )
220
+
221
+ yield(@element) if block_given?
222
+
223
+ self
224
+ end
225
+
31
226
  def as_json(*)
32
227
  {
33
228
  type: TYPE,