slack-ruby-block-kit 0.8.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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,