karafka-web 0.10.0 → 0.10.2

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 (69) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +17 -0
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +12 -4
  7. data/certs/cert.pem +26 -0
  8. data/karafka-web.gemspec +2 -2
  9. data/lib/karafka/web/pro/ui/app.rb +75 -0
  10. data/lib/karafka/web/pro/ui/controllers/commanding_controller.rb +4 -4
  11. data/lib/karafka/web/pro/ui/controllers/recurring_tasks_controller.rb +131 -0
  12. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/base_controller.rb +29 -0
  13. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/explorer_controller.rb +65 -0
  14. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/schedules_controller.rb +84 -0
  15. data/lib/karafka/web/pro/ui/views/consumers/_consumer_controls.erb +13 -12
  16. data/lib/karafka/web/pro/ui/views/explorer/_partition_option.erb +10 -2
  17. data/lib/karafka/web/pro/ui/views/recurring_tasks/_actions.erb +58 -0
  18. data/lib/karafka/web/pro/ui/views/recurring_tasks/_batch_actions.erb +45 -0
  19. data/lib/karafka/web/pro/ui/views/recurring_tasks/_breadcrumbs.erb +22 -0
  20. data/lib/karafka/web/pro/ui/views/recurring_tasks/_log.erb +26 -0
  21. data/lib/karafka/web/pro/ui/views/recurring_tasks/_not_active.erb +12 -0
  22. data/lib/karafka/web/pro/ui/views/recurring_tasks/_tabs.erb +17 -0
  23. data/lib/karafka/web/pro/ui/views/recurring_tasks/_task.erb +46 -0
  24. data/lib/karafka/web/pro/ui/views/recurring_tasks/logs.erb +34 -0
  25. data/lib/karafka/web/pro/ui/views/recurring_tasks/schedule.erb +43 -0
  26. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_breadcrumbs.erb +30 -0
  27. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_message.erb +84 -0
  28. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_messages.erb +28 -0
  29. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/partition.erb +72 -0
  30. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/topic.erb +33 -0
  31. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_breadcrumbs.erb +21 -0
  32. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_no_groups.erb +11 -0
  33. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/index.erb +38 -0
  34. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/show.erb +48 -0
  35. data/lib/karafka/web/pro/ui/views/search/_breadcrumbs.erb +1 -0
  36. data/lib/karafka/web/pro/ui/views/shared/_navigation.erb +20 -0
  37. data/lib/karafka/web/pro/ui/views/topics/replication.erb +1 -1
  38. data/lib/karafka/web/tracking/consumers/listeners/errors.rb +3 -1
  39. data/lib/karafka/web/ui/base.rb +1 -1
  40. data/lib/karafka/web/ui/controllers/base_controller.rb +18 -3
  41. data/lib/karafka/web/ui/helpers/application_helper.rb +29 -8
  42. data/lib/karafka/web/ui/helpers/paths_helper.rb +18 -0
  43. data/lib/karafka/web/ui/models/recurring_tasks/log.rb +15 -0
  44. data/lib/karafka/web/ui/models/recurring_tasks/schedule.rb +75 -0
  45. data/lib/karafka/web/ui/models/recurring_tasks/task.rb +19 -0
  46. data/lib/karafka/web/ui/public/javascripts/application.js +1 -1
  47. data/lib/karafka/web/ui/public/javascripts/application.min.js +7 -7
  48. data/lib/karafka/web/ui/public/javascripts/application.min.js.br +0 -0
  49. data/lib/karafka/web/ui/public/javascripts/application.min.js.gz +0 -0
  50. data/lib/karafka/web/ui/public/javascripts/components/live_poll.js +51 -0
  51. data/lib/karafka/web/ui/public/stylesheets/application.css +5 -1
  52. data/lib/karafka/web/ui/public/stylesheets/application.min.css +2 -2
  53. data/lib/karafka/web/ui/public/stylesheets/application.min.css.br +0 -0
  54. data/lib/karafka/web/ui/public/stylesheets/application.min.css.gz +0 -0
  55. data/lib/karafka/web/ui/public/stylesheets/libs/tailwind.css +18 -6
  56. data/lib/karafka/web/ui/views/dashboard/_ranges_selector.erb +1 -1
  57. data/lib/karafka/web/ui/views/shared/_breadcrumbs.erb +1 -1
  58. data/lib/karafka/web/ui/views/shared/_navigation.erb +21 -0
  59. data/lib/karafka/web/ui/views/shared/icons/_calendar.erb +3 -0
  60. data/lib/karafka/web/ui/views/shared/icons/_check.erb +3 -0
  61. data/lib/karafka/web/ui/views/shared/icons/_play.erb +3 -0
  62. data/lib/karafka/web/ui/views/status/info/_components.erb +48 -11
  63. data/lib/karafka/web/ui/views/ux/_data_table.erb +34 -4
  64. data/lib/karafka/web/ui/views/ux/_status_rows.erb +12 -0
  65. data/lib/karafka/web/version.rb +1 -1
  66. data.tar.gz.sig +0 -0
  67. metadata +56 -27
  68. metadata.gz.sig +0 -0
  69. data/certs/cert_chain.pem +0 -26
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 973e9a2d6a32a1bd3bd1df4b812dd024631a4f444239c92bf3659cb1b31b262f
4
- data.tar.gz: 49177c26dfee8b2b88a2bf39d46c98f00d696ac6251cecf8588f9e12cf1e55f0
3
+ metadata.gz: d471de1bcc756c234f8db2345c269b878863759fb5deb195ac8579e57365efde
4
+ data.tar.gz: 12d1348a0b83353dabeeea7a5ae164be7ff834d84088cfadb7b32c7343470f66
5
5
  SHA512:
6
- metadata.gz: 553207e2fc13646488ee0d2a219faf945829f9bc2d7d65878f65905e8cfda8b23c3c747add70b7a4cbe2e7a232bbe623089ebcadd905f989ac5e8b17685d00c4
7
- data.tar.gz: 8df62e9627819ac505eb8c64f31950e48f35cbdc9426c8ae9bf12de8250e3f44e4f358357d0f1e5847411419598b87a4d92c2e95262278f9c2d10e1364648de3
6
+ metadata.gz: 3f3eab846d445aa01714c8cea282874f9228f69af2475408d19a34b3ce43793b235f32c4484b640fad3b36ae29c90a2a8112dfd0b46685159528672355945f4c
7
+ data.tar.gz: f44a24702afe474270232a1cd5d785737fbd3e6d3b3e574b3eeb1cba5680147000092ec564ad5da7c663d6de124c7b59d9c3bd6c4e51ec80fc249eb90627fb5c
checksums.yaml.gz.sig CHANGED
Binary file
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.3.4
1
+ 3.3.5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Karafka Web Changelog
2
2
 
3
+ ## 0.10.2 (2024-09-03)
4
+ - **[Feature]** Support Future Messages management (Pro).
5
+ - [Enhancement] Do not live-reload when form active.
6
+ - [Fix] Undefined method `deep_merge` for an instance of Hash.
7
+ - [Fix] Prevent live-polling on elements wrapped in a button.
8
+ - [Fix] Fix errors extractor failure on first message-less tick / eofed
9
+
10
+ ## 0.10.1 (2024-08-23)
11
+ - **[Feature]** Support Recurring Tasks management (Pro).
12
+ - [Enhancement] Optimize command buttons so they occupy less space.
13
+ - [Enhancement] Improve tables headers capitalization.
14
+ - [Enhancement] Prevent live-polling when user hovers over actionable links to mitigate race conditions.
15
+ - [Fix] Fix partial lack of tables hover in daily mode.
16
+ - [Fix] Fix lack of tables hover in dark mode.
17
+ - [Fix] Normalize various tables types styling.
18
+ - [Fix] Fix ranges selectors position on wide screens.
19
+
3
20
  ## 0.10.0 (2024-08-19)
4
21
  - **[Breaking]** Rename and reorganize visibility filter to policies engine since it is not only about visibility.
5
22
  - **[Feature]** Replace Bootstrap with with tailwind + DaisyUI.
data/Gemfile CHANGED
@@ -9,6 +9,7 @@ gemspec
9
9
  group :test do
10
10
  gem 'byebug'
11
11
  gem 'factory_bot'
12
+ gem 'fugit'
12
13
  gem 'ostruct'
13
14
  gem 'rack-test'
14
15
  gem 'rspec'
data/Gemfile.lock CHANGED
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka-web (0.10.0)
4
+ karafka-web (0.10.2)
5
5
  erubi (~> 1.4)
6
- karafka (>= 2.4.7, < 2.5.0)
6
+ karafka (>= 2.4.10, < 2.5.0)
7
7
  karafka-core (>= 2.4.0, < 2.5.0)
8
8
  roda (~> 3.68, >= 3.69)
9
9
  tilt (~> 2.0)
@@ -30,19 +30,25 @@ GEM
30
30
  docile (1.4.0)
31
31
  drb (2.2.1)
32
32
  erubi (1.13.0)
33
+ et-orbi (1.2.11)
34
+ tzinfo
33
35
  factory_bot (6.4.6)
34
36
  activesupport (>= 5.0.0)
35
37
  ffi (1.17.0)
38
+ fugit (1.11.1)
39
+ et-orbi (~> 1, >= 1.2.11)
40
+ raabro (~> 1.4)
36
41
  i18n (1.14.5)
37
42
  concurrent-ruby (~> 1.0)
38
- karafka (2.4.7)
43
+ karafka (2.4.10)
39
44
  base64 (~> 0.2)
40
45
  karafka-core (>= 2.4.3, < 2.5.0)
46
+ karafka-rdkafka (>= 0.17.2)
41
47
  waterdrop (>= 2.7.3, < 3.0.0)
42
48
  zeitwerk (~> 2.3)
43
49
  karafka-core (2.4.4)
44
50
  karafka-rdkafka (>= 0.15.0, < 0.18.0)
45
- karafka-rdkafka (0.17.1)
51
+ karafka-rdkafka (0.17.3)
46
52
  ffi (~> 1.15)
47
53
  mini_portile2 (~> 2.6)
48
54
  rake (> 12)
@@ -50,6 +56,7 @@ GEM
50
56
  minitest (5.24.0)
51
57
  mutex_m (0.2.0)
52
58
  ostruct (0.6.0)
59
+ raabro (1.4.0)
53
60
  rack (3.1.4)
54
61
  rack-test (2.1.0)
55
62
  rack (>= 1.3)
@@ -95,6 +102,7 @@ PLATFORMS
95
102
  DEPENDENCIES
96
103
  byebug
97
104
  factory_bot
105
+ fugit
98
106
  karafka-web!
99
107
  ostruct
100
108
  rack-test
data/certs/cert.pem ADDED
@@ -0,0 +1,26 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEcDCCAtigAwIBAgIBATANBgkqhkiG9w0BAQsFADA/MRAwDgYDVQQDDAdjb250
3
+ YWN0MRcwFQYKCZImiZPyLGQBGRYHa2FyYWZrYTESMBAGCgmSJomT8ixkARkWAmlv
4
+ MB4XDTI0MDgyMzEwMTkyMFoXDTQ5MDgxNzEwMTkyMFowPzEQMA4GA1UEAwwHY29u
5
+ dGFjdDEXMBUGCgmSJomT8ixkARkWB2thcmFma2ExEjAQBgoJkiaJk/IsZAEZFgJp
6
+ bzCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAKjLhLjQqUlNayxkXnO+
7
+ PsmCDs/KFIzhrsYMfLZRZNaWmzV3ujljMOdDjd4snM2X06C41iVdQPWjpe3j8vVe
8
+ ZXEWR/twSbOP6Eeg8WVH2wCOo0x5i7yhVn4UBLH4JpfEMCbemVcWQ9ry9OMg4WpH
9
+ Uu4dRwxFV7hzCz3p0QfNLRI4miAxnGWcnlD98IJRjBAksTuR1Llj0vbOrDGsL9ZT
10
+ JeXP2gdRLd8SqzAFJEWrbeTBCBU7gfSh3oMg5SVDLjaqf7Kz5wC/8bDZydzanOxB
11
+ T6CDXPsCnllmvTNx2ei2T5rGYJOzJeNTmJLLK6hJWUlAvaQSvCwZRvFJ0tVGLEoS
12
+ flqSr6uGyyl1eMUsNmsH4BqPEYcAV6P2PKTv2vUR8AP0raDvZ3xL1TKvfRb8xRpo
13
+ vPopCGlY5XBWEc6QERHfVLTIVsjnls2/Ujj4h8/TSfqqYnaHKefIMLbuD/tquMjD
14
+ iWQsW2qStBV0T+U7FijKxVfrfqZP7GxQmDAc9o1iiyAa3QIDAQABo3cwdTAJBgNV
15
+ HRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU3O4dTXmvE7YpAkszGzR9DdL9
16
+ sbEwHQYDVR0RBBYwFIESY29udGFjdEBrYXJhZmthLmlvMB0GA1UdEgQWMBSBEmNv
17
+ bnRhY3RAa2FyYWZrYS5pbzANBgkqhkiG9w0BAQsFAAOCAYEAVKTfoLXn7mqdSxIR
18
+ eqxcR6Huudg1jes81s1+X0uiRTR3hxxKZ3Y82cPsee9zYWyBrN8TA4KA0WILTru7
19
+ Ygxvzha0SRPsSiaKLmgOJ+61ebI4+bOORzIJLpD6GxCxu1r7MI4+0r1u1xe0EWi8
20
+ agkVo1k4Vi8cKMLm6Gl9b3wG9zQBw6fcgKwmpjKiNnOLP+OytzUANrIUJjoq6oal
21
+ TC+f/Uc0TLaRqUaW/bejxzDWWHoM3SU6aoLPuerglzp9zZVzihXwx3jPLUVKDFpF
22
+ Rl2lcBDxlpYGueGo0/oNzGJAAy6js8jhtHC9+19PD53vk7wHtFTZ/0ugDQYnwQ+x
23
+ oml2fAAuVWpTBCgOVFe6XCQpMKopzoxQ1PjKztW2KYxgJdIBX87SnL3aWuBQmhRd
24
+ i9zWxov0mr44TWegTVeypcWGd/0nxu1+QHVNHJrpqlPBRvwQsUm7fwmRInGpcaB8
25
+ ap8wNYvryYzrzvzUxIVFBVM5PacgkFqRmolCa8I7tdKQN+R1
26
+ -----END CERTIFICATE-----
data/karafka-web.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.licenses = %w[LGPL-3.0-only Commercial]
18
18
 
19
19
  spec.add_dependency 'erubi', '~> 1.4'
20
- spec.add_dependency 'karafka', '>= 2.4.7', '< 2.5.0'
20
+ spec.add_dependency 'karafka', '>= 2.4.10', '< 2.5.0'
21
21
  spec.add_dependency 'karafka-core', '>= 2.4.0', '< 2.5.0'
22
22
  spec.add_dependency 'roda', '~> 3.68', '>= 3.69'
23
23
  spec.add_dependency 'tilt', '~> 2.0'
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.signing_key = File.expand_path('~/.ssh/gem-private_key.pem')
31
31
  end
32
32
 
33
- spec.cert_chain = %w[certs/cert_chain.pem]
33
+ spec.cert_chain = %w[certs/cert.pem]
34
34
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
35
35
  spec.executables = %w[karafka-web]
36
36
  spec.require_paths = %w[lib]
@@ -232,6 +232,81 @@ module Karafka
232
232
  end
233
233
  end
234
234
 
235
+ r.on 'recurring_tasks' do
236
+ controller = Controllers::RecurringTasksController.new(params)
237
+
238
+ r.get 'schedule' do
239
+ controller.schedule
240
+ end
241
+
242
+ r.get 'logs' do
243
+ controller.logs
244
+ end
245
+
246
+ r.post 'trigger_all' do
247
+ controller.trigger_all
248
+ end
249
+
250
+ r.post 'enable_all' do
251
+ controller.enable_all
252
+ end
253
+
254
+ r.post 'disable_all' do
255
+ controller.disable_all
256
+ end
257
+
258
+ r.post String, 'trigger' do |task_id|
259
+ controller.trigger(task_id)
260
+ end
261
+
262
+ r.post String, 'enable' do |task_id|
263
+ controller.enable(task_id)
264
+ end
265
+
266
+ r.post String, 'disable' do |task_id|
267
+ controller.disable(task_id)
268
+ end
269
+
270
+ r.get do
271
+ r.redirect root_path('recurring_tasks/schedule')
272
+ end
273
+ end
274
+
275
+ r.on 'scheduled_messages' do
276
+ r.on 'schedules' do
277
+ controller = Controllers::ScheduledMessages::SchedulesController.new(params)
278
+
279
+ r.get String do |topic_id|
280
+ controller.show(topic_id)
281
+ end
282
+
283
+ r.get do
284
+ controller.index
285
+ end
286
+ end
287
+
288
+ r.on 'explorer' do
289
+ controller = Controllers::ScheduledMessages::ExplorerController.new(params)
290
+
291
+ r.get String do |topic_id|
292
+ controller.topic(topic_id)
293
+ end
294
+
295
+ r.get String, Integer do |topic_id, partition_id|
296
+ controller.partition(topic_id, partition_id)
297
+ end
298
+
299
+ # Jumps to offset matching the expected time
300
+ r.get String, Integer, Time do |topic_id, partition_id, time|
301
+ controller.closest(topic_id, partition_id, time)
302
+ end
303
+ end
304
+
305
+ r.get do
306
+ r.redirect root_path('scheduled_messages/schedules')
307
+ end
308
+ end
309
+
235
310
  r.on 'health' do
236
311
  controller = Controllers::HealthController.new(params)
237
312
 
@@ -27,7 +27,7 @@ module Karafka
27
27
 
28
28
  redirect(
29
29
  :back,
30
- success: dispatched_to_one_msg(:probe, process_id)
30
+ success: dispatched_to_one(:probe, process_id)
31
31
  )
32
32
  end
33
33
 
@@ -39,7 +39,7 @@ module Karafka
39
39
 
40
40
  redirect(
41
41
  :back,
42
- success: dispatched_to_one_msg(:quiet, process_id)
42
+ success: dispatched_to_one(:quiet, process_id)
43
43
  )
44
44
  end
45
45
 
@@ -51,7 +51,7 @@ module Karafka
51
51
 
52
52
  redirect(
53
53
  :back,
54
- success: dispatched_to_one_msg(:stop, process_id)
54
+ success: dispatched_to_one(:stop, process_id)
55
55
  )
56
56
  end
57
57
 
@@ -96,7 +96,7 @@ module Karafka
96
96
  # @param command [Symbol]
97
97
  # @param process_id [String]
98
98
  # @return [String] flash message that command has been dispatched to a given process
99
- def dispatched_to_one_msg(command, process_id)
99
+ def dispatched_to_one(command, process_id)
100
100
  command_name = command.to_s.capitalize
101
101
 
102
102
  "The #{command_name} command has been dispatched to the #{process_id} process."
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This Karafka component is a Pro component under a commercial license.
4
+ # This Karafka component is NOT licensed under LGPL.
5
+ #
6
+ # All of the commercial components are present in the lib/karafka/pro directory of this
7
+ # repository and their usage requires commercial license agreement.
8
+ #
9
+ # Karafka has also commercial-friendly license, commercial support and commercial components.
10
+ #
11
+ # By sending a pull request to the pro components, you are agreeing to transfer the copyright of
12
+ # your code to Maciej Mensfeld.
13
+
14
+ module Karafka
15
+ module Web
16
+ module Pro
17
+ module Ui
18
+ module Controllers
19
+ # Controller for viewing and managing recurring tasks
20
+ class RecurringTasksController < Web::Ui::Controllers::ClusterController
21
+ self.sortable_attributes = %w[
22
+ id
23
+ enabled
24
+ cron
25
+ previous_time
26
+ next_time
27
+ ].freeze
28
+
29
+ # Displays the current schedule
30
+ def schedule
31
+ @schedule = Models::RecurringTasks::Schedule.current
32
+
33
+ @tasks = refine(@schedule.tasks) if @schedule
34
+
35
+ render
36
+ end
37
+
38
+ # Displays the execution logs
39
+ def logs
40
+ @watermark_offsets = Models::WatermarkOffsets.find(logs_topic, 0)
41
+ previous_offset, @logs, next_offset, = current_page_data
42
+
43
+ paginate(
44
+ previous_offset,
45
+ @params.current_offset,
46
+ next_offset,
47
+ @logs.map(&:offset)
48
+ )
49
+
50
+ # We remap this so we can represent the payloads as logs that we expect
51
+ @logs.map! { |log| Models::RecurringTasks::Log.new(log.payload) }
52
+
53
+ render
54
+ end
55
+
56
+ # Actions definitions that trigger appropriate recurring tasks action + display a nice
57
+ # flash message.
58
+ %i[
59
+ trigger
60
+ enable
61
+ disable
62
+ ].each do |action|
63
+ define_method :"#{action}_all" do
64
+ command(action, '*')
65
+
66
+ redirect(
67
+ :back,
68
+ success: dispatched_to_all(action)
69
+ )
70
+ end
71
+
72
+ define_method action do |task_id|
73
+ command(action, task_id)
74
+
75
+ redirect(
76
+ :back,
77
+ success: dispatched_to_one(action, task_id)
78
+ )
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ # @return [Array] Array with requested messages as well as pagination details and other
85
+ # obtained metadata
86
+ def current_page_data
87
+ Models::Message.offset_page(
88
+ logs_topic,
89
+ 0,
90
+ @params.current_offset,
91
+ @watermark_offsets
92
+ )
93
+ end
94
+
95
+ # @return [String] recurring tasks logs topic
96
+ def logs_topic
97
+ ::Karafka::App.config.recurring_tasks.topics.logs
98
+ end
99
+
100
+ # Runs the recurring tasks command
101
+ #
102
+ # @param command [String] command we want to invoke
103
+ # @param task_id [String] task id or '*' to target expected task
104
+ def command(command, task_id)
105
+ Karafka::Pro::RecurringTasks.public_send(command, task_id)
106
+ end
107
+
108
+ # Generates a nice flash message about the dispatch
109
+ # @param command [Symbol]
110
+ # @param task_id [String]
111
+ # @return [String] flash message that command has been dispatched to a given task
112
+ def dispatched_to_one(command, task_id)
113
+ command_name = command.to_s.capitalize
114
+
115
+ "The #{command_name} command has been dispatched to the #{task_id} task."
116
+ end
117
+
118
+ # Generates a nice flash message about dispatch of multi-task command
119
+ # @param command [Symbol]
120
+ # @return [String] flash message that command has been dispatched
121
+ def dispatched_to_all(command)
122
+ command_name = command.to_s.capitalize
123
+
124
+ "The #{command_name} command has been dispatched to all tasks."
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This Karafka component is a Pro component under a commercial license.
4
+ # This Karafka component is NOT licensed under LGPL.
5
+ #
6
+ # All of the commercial components are present in the lib/karafka/pro directory of this
7
+ # repository and their usage requires commercial license agreement.
8
+ #
9
+ # Karafka has also commercial-friendly license, commercial support and commercial components.
10
+ #
11
+ # By sending a pull request to the pro components, you are agreeing to transfer the copyright of
12
+ # your code to Maciej Mensfeld.
13
+
14
+ module Karafka
15
+ module Web
16
+ module Pro
17
+ module Ui
18
+ module Controllers
19
+ # Namespace for all controllers related to scheduled messages
20
+ module ScheduledMessages
21
+ # Base Pro controller for scheduled messages
22
+ class BaseController < Controllers::BaseController
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This Karafka component is a Pro component under a commercial license.
4
+ # This Karafka component is NOT licensed under LGPL.
5
+ #
6
+ # All of the commercial components are present in the lib/karafka/pro directory of this
7
+ # repository and their usage requires commercial license agreement.
8
+ #
9
+ # Karafka has also commercial-friendly license, commercial support and commercial components.
10
+ #
11
+ # By sending a pull request to the pro components, you are agreeing to transfer the copyright of
12
+ # your code to Maciej Mensfeld.
13
+
14
+ module Karafka
15
+ module Web
16
+ module Pro
17
+ module Ui
18
+ module Controllers
19
+ module ScheduledMessages
20
+ # Allows for exploration of dispatch messages in a less generic form that via the
21
+ # explorer as different details are present
22
+ class ExplorerController < BaseController
23
+ # Displays aggregated messages from (potentially) all partitions of a topic
24
+ #
25
+ # @param topic_id [String]
26
+ def topic(topic_id)
27
+ response = Controllers::ExplorerController
28
+ .new(@params)
29
+ .topic(topic_id)
30
+
31
+ render(attributes: response.attributes)
32
+ end
33
+
34
+ # Shows messages available in a given partition
35
+ #
36
+ # @param topic_id [String]
37
+ # @param partition_id [Integer]
38
+ def partition(topic_id, partition_id)
39
+ response = Controllers::ExplorerController
40
+ .new(@params)
41
+ .partition(topic_id, partition_id)
42
+
43
+ render(attributes: response.attributes)
44
+ end
45
+
46
+ # Finds the closest offset matching the requested time and redirects to this location
47
+ # Note, that it redirects to closest but always younger.
48
+ #
49
+ # @param topic_id [String]
50
+ # @param partition_id [Integer]
51
+ # @param time [Time] time of the message
52
+ def closest(topic_id, partition_id, time)
53
+ response = Controllers::ExplorerController
54
+ .new(@params)
55
+ .closest(topic_id, partition_id, time)
56
+
57
+ redirect("scheduled_messages/#{response.path}")
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This Karafka component is a Pro component under a commercial license.
4
+ # This Karafka component is NOT licensed under LGPL.
5
+ #
6
+ # All of the commercial components are present in the lib/karafka/pro directory of this
7
+ # repository and their usage requires commercial license agreement.
8
+ #
9
+ # Karafka has also commercial-friendly license, commercial support and commercial components.
10
+ #
11
+ # By sending a pull request to the pro components, you are agreeing to transfer the copyright of
12
+ # your code to Maciej Mensfeld.
13
+
14
+ module Karafka
15
+ module Web
16
+ module Pro
17
+ module Ui
18
+ module Controllers
19
+ # Namespace for all controllers related to scheduled messages
20
+ module ScheduledMessages
21
+ # Controller to display list of schedules (groups) and details about each
22
+ class SchedulesController < BaseController
23
+ # Displays list of groups
24
+ def index
25
+ topics = Models::Topic.all
26
+
27
+ # Names of scheduled messages topics defined in the routing
28
+ # They may not exist (yet) so we filter them based on the existing topics in the
29
+ # cluster
30
+ candidates = Karafka::App
31
+ .routes
32
+ .map(&:topics)
33
+ .map(&:to_a)
34
+ .flatten
35
+ .select(&:scheduled_messages?)
36
+ .reject { |topic| topic.name.end_with?(states_postfix) }
37
+ .map(&:name)
38
+ .sort
39
+
40
+ @topics = topics.select { |topic| candidates.include?(topic.topic_name) }
41
+
42
+ render
43
+ end
44
+
45
+ # Displays all partitions statistics (if any) with number of messages to dispatch
46
+ # @param schedule_name [String] name of the schedules messages topic
47
+ def show(schedule_name)
48
+ @schedule_name = schedule_name
49
+ @stats_topic_name = "#{schedule_name}#{states_postfix}"
50
+ @stats_info = Karafka::Admin.topic_info(@stats_topic_name)
51
+
52
+ @states = {}
53
+ @stats_info[:partition_count].times { |i| @states[i] = false }
54
+
55
+ Karafka::Pro::Iterator.new({ @stats_topic_name => -1 }).each do |message|
56
+ @states[message.partition] = message.payload
57
+ end
58
+
59
+ # Sort by partition id
60
+ @states = @states.sort_by { |key, _| key.to_s }.to_h
61
+ # Sort daily from closest date
62
+ @states.each_value do |details|
63
+ # Skip false predefined values from sorting
64
+ next unless details
65
+
66
+ details[:daily] = details[:daily].sort_by { |key, _| key.to_s }.to_h
67
+ end
68
+
69
+ render
70
+ end
71
+
72
+ private
73
+
74
+ # @return [String] states topic postfix
75
+ def states_postfix
76
+ @states_postfix ||= Karafka::App.config.scheduled_messages.states_postfix
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -43,17 +43,16 @@
43
43
  <%= process.lag_hybrid %>
44
44
  </td>
45
45
 
46
- <td class="commands">
46
+ <td class="commands-inline-3">
47
47
  <%
48
48
  probe_path = root_path('commanding', process.id, 'probe')
49
49
  disabled_class = process.status != 'stopped' ? '' : 'btn-disabled'
50
50
  %>
51
- <form action="<%= probe_path %>" method="post" class="">
51
+ <form action="<%= probe_path %>" method="post" class="inline" title="Probe">
52
52
  <%== csrf_tag(probe_path) %>
53
53
 
54
- <button type="submit" class="btn btn-info btn-sm w-full max-w-xs mb-1 <%= disabled_class %>">
54
+ <button type="submit" class="btn btn-info btn-sm <%= disabled_class %>">
55
55
  <%== icon(:gear) %>
56
- Probe
57
56
  </button>
58
57
  </form>
59
58
 
@@ -61,16 +60,17 @@
61
60
  quiet_path = root_path('commanding', process.id, 'quiet')
62
61
  disabled_class = process.status == 'running' ? '' : 'btn-disabled'
63
62
 
64
- unless process.execution_mode == 'standalone'
63
+ if process.execution_mode == 'standalone'
64
+ title = 'Quiet'
65
+ else
65
66
  disabled_class = 'btn-disabled'
66
67
  title = 'Supported only in standalone consumer processes'
67
68
  end
68
69
  %>
69
- <form action="<%= quiet_path %>" method="post" class="" title="<%= title %>">
70
+ <form action="<%= quiet_path %>" method="post" class="inline" title="<%= title %>">
70
71
  <%== csrf_tag(quiet_path) %>
71
- <button type="submit" class="btn btn-warning btn-sm w-full max-w-xs mb-1 <%= disabled_class %>">
72
+ <button type="submit" class="btn btn-warning btn-sm <%= disabled_class %>">
72
73
  <%== icon(:pause) %>
73
- Quiet
74
74
  </button>
75
75
  </form>
76
76
 
@@ -78,16 +78,17 @@
78
78
  stop_path = root_path('commanding', process.id, 'stop')
79
79
  disabled_class = process.status != 'stopping' && process.status != 'stopped' ? '' : 'btn-disabled'
80
80
 
81
- unless process.execution_mode == 'standalone'
81
+ if process.execution_mode == 'standalone'
82
+ title = 'Stop'
83
+ else
82
84
  disabled_class = 'btn-disabled'
83
85
  title = 'Supported only in standalone consumer processes'
84
86
  end
85
87
  %>
86
- <form action="<%= stop_path %>" method="post" class="" title="<%= title %>">
88
+ <form action="<%= stop_path %>" method="post" class="inline" title="<%= title %>">
87
89
  <%== csrf_tag(stop_path) %>
88
- <button type="submit" class="btn btn-error btn-sm w-full max-w-xs <%= disabled_class %>">
90
+ <button type="submit" class="btn btn-error btn-sm <%= disabled_class %>">
89
91
  <%== icon(:stop) %>
90
- Stop
91
92
  </button>
92
93
  </form>
93
94
  </td>
@@ -1,7 +1,15 @@
1
+ <%
2
+ path = if @selector_path_method
3
+ public_send(@selector_path_method, @topic_id, partition)
4
+ else
5
+ explorer_path(@topic_id, partition)
6
+ end
7
+ %>
8
+
1
9
  <% if @partition_id == partition %>
2
- <option value="<%= explorer_path(@topic_id, partition) %>" selected=selected>
10
+ <option value="<%= path %>" selected=selected>
3
11
  <% else %>
4
- <option value="<%= explorer_path(@topic_id, partition) %>">
12
+ <option value="<%= path %>">
5
13
  <% end %>
6
14
  <%= partition || 'All' %>
7
15
  </option>