karafka-web 0.10.0 → 0.10.2

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