karafka-web 0.10.0.rc2 → 0.10.1

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 (49) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -1
  3. data/CHANGELOG.md +11 -1
  4. data/Gemfile +1 -0
  5. data/Gemfile.lock +12 -4
  6. data/certs/cert.pem +26 -0
  7. data/karafka-web.gemspec +2 -2
  8. data/lib/karafka/web/pro/ui/app.rb +40 -0
  9. data/lib/karafka/web/pro/ui/controllers/commanding_controller.rb +4 -4
  10. data/lib/karafka/web/pro/ui/controllers/recurring_tasks_controller.rb +131 -0
  11. data/lib/karafka/web/pro/ui/views/consumers/_consumer_controls.erb +13 -12
  12. data/lib/karafka/web/pro/ui/views/recurring_tasks/_actions.erb +58 -0
  13. data/lib/karafka/web/pro/ui/views/recurring_tasks/_batch_actions.erb +45 -0
  14. data/lib/karafka/web/pro/ui/views/recurring_tasks/_breadcrumbs.erb +22 -0
  15. data/lib/karafka/web/pro/ui/views/recurring_tasks/_log.erb +26 -0
  16. data/lib/karafka/web/pro/ui/views/recurring_tasks/_not_active.erb +12 -0
  17. data/lib/karafka/web/pro/ui/views/recurring_tasks/_tabs.erb +17 -0
  18. data/lib/karafka/web/pro/ui/views/recurring_tasks/_task.erb +46 -0
  19. data/lib/karafka/web/pro/ui/views/recurring_tasks/logs.erb +34 -0
  20. data/lib/karafka/web/pro/ui/views/recurring_tasks/schedule.erb +43 -0
  21. data/lib/karafka/web/pro/ui/views/shared/_navigation.erb +10 -0
  22. data/lib/karafka/web/pro/ui/views/topics/replication.erb +1 -1
  23. data/lib/karafka/web/ui/helpers/application_helper.rb +8 -1
  24. data/lib/karafka/web/ui/models/recurring_tasks/log.rb +26 -0
  25. data/lib/karafka/web/ui/models/recurring_tasks/schedule.rb +86 -0
  26. data/lib/karafka/web/ui/models/recurring_tasks/task.rb +30 -0
  27. data/lib/karafka/web/ui/public/javascripts/application.js +1 -1
  28. data/lib/karafka/web/ui/public/javascripts/application.min.js +7 -7
  29. data/lib/karafka/web/ui/public/javascripts/application.min.js.br +0 -0
  30. data/lib/karafka/web/ui/public/javascripts/application.min.js.gz +0 -0
  31. data/lib/karafka/web/ui/public/javascripts/components/live_poll.js +36 -0
  32. data/lib/karafka/web/ui/public/stylesheets/application.css +5 -1
  33. data/lib/karafka/web/ui/public/stylesheets/application.min.css +2 -2
  34. data/lib/karafka/web/ui/public/stylesheets/application.min.css.br +0 -0
  35. data/lib/karafka/web/ui/public/stylesheets/application.min.css.gz +0 -0
  36. data/lib/karafka/web/ui/public/stylesheets/libs/tailwind.css +17 -5
  37. data/lib/karafka/web/ui/views/dashboard/_ranges_selector.erb +1 -1
  38. data/lib/karafka/web/ui/views/shared/_become_pro.erb +1 -1
  39. data/lib/karafka/web/ui/views/shared/_navigation.erb +11 -0
  40. data/lib/karafka/web/ui/views/shared/icons/_check.erb +3 -0
  41. data/lib/karafka/web/ui/views/shared/icons/_play.erb +3 -0
  42. data/lib/karafka/web/ui/views/status/info/_components.erb +48 -11
  43. data/lib/karafka/web/ui/views/ux/_data_table.erb +34 -4
  44. data/lib/karafka/web/ui/views/ux/_status_rows.erb +12 -0
  45. data/lib/karafka/web/version.rb +1 -1
  46. data.tar.gz.sig +0 -0
  47. metadata +41 -26
  48. metadata.gz.sig +0 -0
  49. data/certs/cert_chain.pem +0 -26
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f9e6ffa0b52fd034fba9f20be4a3862dac935610601daa3e7ac14b912ac166d
4
- data.tar.gz: d0cc099e8bcb8367c33c27326223346983fddb4bf0e8b40397c8ad2ae30a83fd
3
+ metadata.gz: 40794ee9c8b084cf75de0403b904134cbc6a762dbfa338bb9ce574b56e46ac36
4
+ data.tar.gz: dedefe087c54e118abb90e819b36b29aa253c4351aa18bd8a78d01e2c096ce79
5
5
  SHA512:
6
- metadata.gz: b88382f36d89b10ffaa249b8533210007620ae979af936b29a70a1c6b81cad8e2058a6bfc9d7c494dded5b67139da62e74629722ba1fb420d0e44664d25ea1ea
7
- data.tar.gz: 541b6de732575af548cd39a12730c1eea7c60e072f468b5b28ead575828ae2863110b2975a79dd2d3389b9d1899048d5c9f225ef6cacef3645cae87baf062a3b
6
+ metadata.gz: 88b9b6ed8082b0484dcd32a20b2cee2b77d4df762b65d0487325e03ef375e1e7ac621d612f81b3f4a6870aa4352e07286979863d656161ca7d8d880e5709d108
7
+ data.tar.gz: f9350f68d872c76d289933fbf2548b692179bae30fb2c0fccf923cdefca7131bbf3e6bf362e21a442c424fc4b43472e8334115b90c32449e80ef45a3518c3228
checksums.yaml.gz.sig CHANGED
@@ -1 +1 @@
1
- q�-oC��;��Vq�8 ��$Uz9L��yZ�^y���+$ѩ)�U=]���r�����'�WDFW*��"0�"�F�^�*k����,R��K����z���Z��5�99sjH'���{�z�/aʨZ{2����t+����a�
1
+ ��[����St���Y�Ě�D��������1�#�]; Xły}�)ҙ�*��A� ��uѭȚܟ��
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # Karafka Web Changelog
2
2
 
3
- ## 0.10.0 (Unreleased)
3
+ ## 0.10.1 (Unreleased)
4
+ - **[Feature]** Support Recurring Tasks management (Pro).
5
+ - [Enhancement] Optimize command buttons so they occupy less space.
6
+ - [Enhancement] Improve tables headers capitalization.
7
+ - [Enhancement] Prevent live-polling when user hovers over actionable links to mitigate race conditions.
8
+ - [Fix] Fix partial lack of tables hover in daily mode.
9
+ - [Fix] Fix lack of tables hover in dark mode.
10
+ - [Fix] Normalize various tables types styling.
11
+ - [Fix] Fix ranges selectors position on wide screens.
12
+
13
+ ## 0.10.0 (2024-08-19)
4
14
  - **[Breaking]** Rename and reorganize visibility filter to policies engine since it is not only about visibility.
5
15
  - **[Feature]** Replace Bootstrap with with tailwind + DaisyUI.
6
16
  - **[Feature]** Redesign the UI and move navigation to the left to make space for future features.
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.1)
5
5
  erubi (~> 1.4)
6
- karafka (>= 2.4.7, < 2.5.0)
6
+ karafka (>= 2.4.9, < 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.9)
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.9', '< 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,46 @@ 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
+
235
275
  r.on 'health' do
236
276
  controller = Controllers::HealthController.new(params)
237
277
 
@@ -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
@@ -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>
@@ -0,0 +1,58 @@
1
+ <%
2
+ trigger_path = root_path('recurring_tasks', task.id, 'trigger')
3
+ disabled_class = task.enabled? ? '' : 'btn-disabled'
4
+ %>
5
+ <form
6
+ action="<%= trigger_path %>"
7
+ method="post"
8
+ class="inline"
9
+ >
10
+ <%== csrf_tag(trigger_path) %>
11
+ <button
12
+ type="submit"
13
+ class="btn btn-primary btn-sm "
14
+ title="Trigger"
15
+ >
16
+ <%== icon(:play) %>
17
+ </button>
18
+ </form>
19
+
20
+ <%
21
+ enable_path = root_path('recurring_tasks', task.id, 'enable')
22
+ disabled_class = task.enabled? ? 'btn-disabled' : ''
23
+ %>
24
+ <form
25
+ action="<%= enable_path %>"
26
+ method="post"
27
+ class="inline"
28
+ title="Enable"
29
+ >
30
+ <%== csrf_tag(enable_path) %>
31
+ <button
32
+ type="submit"
33
+ class="btn btn-success btn-sm <%= disabled_class %>"
34
+ >
35
+ <%== icon(:check) %>
36
+ </button>
37
+ </form>
38
+
39
+ <%
40
+ disable_path = root_path('recurring_tasks', task.id, 'disable')
41
+ disabled_class = task.enabled? ? '' : 'btn-disabled'
42
+ %>
43
+ <form
44
+ action="<%= disable_path %>"
45
+ method="post"
46
+ class="inline"
47
+ title="Disable"
48
+
49
+ >
50
+ <%== csrf_tag(disable_path) %>
51
+ <button
52
+ type="submit"
53
+ class="btn btn-warning btn-sm <%= disabled_class %>"
54
+
55
+ >
56
+ <%== icon(:pause) %>
57
+ </button>
58
+ </form>
@@ -0,0 +1,45 @@
1
+ <div class="col-span-12 flex justify-end space-x-2 mb-6">
2
+ <%
3
+ trigger_all_path = root_path('recurring_tasks', 'trigger_all')
4
+ disable_class = @tasks.empty? ? 'btn-disabled' : ''
5
+ %>
6
+ <form
7
+ action="<%= trigger_all_path %>"
8
+ method="post"
9
+ class="inline-flex items-center"
10
+ >
11
+ <%== csrf_tag(trigger_all_path) %>
12
+ <button type="submit" class="btn btn-primary btn-sm <%= disable_class %>">
13
+ <%== icon(:play) %>
14
+ Trigger All
15
+ </button>
16
+ </form>
17
+
18
+ <%
19
+ enable_all_path = root_path('recurring_tasks', 'enable_all')
20
+ disable_class = @tasks.all?(&:enabled?) ? 'btn-disabled' : ''
21
+ %>
22
+ <form
23
+ action="<%= enable_all_path %>"
24
+ method="post"
25
+ class="inline-flex items-center"
26
+ >
27
+ <%== csrf_tag(enable_all_path) %>
28
+ <button type="submit" class="btn btn-success btn-sm <%= disable_class %>">
29
+ <%== icon(:check) %>
30
+ Enable All
31
+ </button>
32
+ </form>
33
+
34
+ <%
35
+ disable_all_path = root_path('recurring_tasks', 'disable_all')
36
+ disable_class = @tasks.none?(&:enabled?) ? 'btn-disabled' : ''
37
+ %>
38
+ <form action="<%= disable_all_path %>" method="post" class="inline-flex items-center">
39
+ <%== csrf_tag(disable_all_path) %>
40
+ <button type="submit" class="btn btn-warning btn-sm <%= disable_class %>">
41
+ <%== icon(:pause) %>
42
+ Disable All
43
+ </button>
44
+ </form>
45
+ </div>
@@ -0,0 +1,22 @@
1
+ <li>
2
+ <a href="<%= root_path('recurring_tasks') %>">
3
+ Recurring Tasks
4
+ </a>
5
+ </li>
6
+
7
+ <% if current_path.include?('/schedule') %>
8
+ <li>
9
+ <a href="<%= root_path('recurring_tasks/schedule') %>">
10
+ Schedule
11
+ <%= @schedule ? @schedule.schedule_version : '' %>
12
+ </a>
13
+ </li>
14
+ <% end %>
15
+
16
+ <% if current_path.include?('/logs') %>
17
+ <li>
18
+ <a href="<%= root_path('recurring_tasks/logs') %>">
19
+ Logs
20
+ </a>
21
+ </li>
22
+ <% end %>
@@ -0,0 +1,26 @@
1
+ <% result = log.task[:result] == 'success' %>
2
+ <tr class="<%= result ? '' : 'status-row-error' %>">
3
+ <td>
4
+ <%= log.id %>
5
+ </td>
6
+ <td>
7
+ <% if result %>
8
+ <%== badge_success 'Success' %>
9
+ <% else %>
10
+ <%== badge_error 'Error' %>
11
+ <% end %>
12
+ </td>
13
+ <td>
14
+ <% if result %>
15
+ <%== log.task[:time_taken].round(2) %> ms
16
+ <% else %>
17
+ N/A
18
+ <% end %>
19
+ </td>
20
+ <td>
21
+ <%== relative_time log.dispatched_at %>
22
+ </td>
23
+ <td>
24
+ <%= log.schedule_version %>
25
+ </td>
26
+ </tr>
@@ -0,0 +1,12 @@
1
+ <% alert_box_info('Recurring Tasks Data Unavailable') do %>
2
+ <p class="mb-2">
3
+ We are unable to display data related to recurring tasks. Please ensure that:
4
+ </p>
5
+
6
+ <ul class="list-disc list-inside">
7
+ <li>Recurring Tasks are enabled in your routing configuration.</li>
8
+ <li>The necessary Kafka topics have been created.</li>
9
+ <li>A schedule has been defined.</li>
10
+ <li>our Karafka server, with schedule awareness, is running and has persisted the state.</li>
11
+ </ul>
12
+ <% end %>
@@ -0,0 +1,17 @@
1
+ <div class="col-span-12 mb-9">
2
+ <div class="tab-container">
3
+ <a
4
+ href="<%= root_path('recurring_tasks', 'schedule') %>"
5
+ class="custom-tab <%= nav_class(include: 'schedule') %>"
6
+ >
7
+ Schedules
8
+ </a>
9
+
10
+ <a
11
+ href="<%= root_path('recurring_tasks', 'logs') %>"
12
+ class="custom-tab <%= nav_class(include: '/logs') %>"
13
+ >
14
+ Logs
15
+ </a>
16
+ </div>
17
+ </div>
@@ -0,0 +1,46 @@
1
+ <tr class="<%= task.enabled? ? '' : 'status-row-warning text-muted' %>">
2
+ <td>
3
+ <%= task.id %>
4
+ </td>
5
+
6
+ <td>
7
+ <% if task.enabled? %>
8
+ <%== badge_success('Enabled') %>
9
+ <% else %>
10
+ <%== badge_warning('Disabled') %>
11
+ <% end %>
12
+ </td>
13
+
14
+ <td>
15
+ <code><%= task.cron %></code>
16
+ </td>
17
+
18
+ <td>
19
+ <% if task.previous_time.positive? %>
20
+ <%== relative_time task.previous_time %>
21
+ <% else %>
22
+ Never
23
+ <% end %>
24
+ </td>
25
+
26
+ <td>
27
+ <% if task.enabled? %>
28
+ <% if task.next_time < Time.now.to_i %>
29
+ Right now
30
+ <% else %>
31
+ <%== relative_time task.next_time %>
32
+ <% end %>
33
+ <% else %>
34
+ Never
35
+ <% end %>
36
+ </td>
37
+
38
+ <td class="commands-inline-3">
39
+ <%==
40
+ partial(
41
+ 'recurring_tasks/actions',
42
+ locals: { task: task }
43
+ )
44
+ %>
45
+ </td>
46
+ </tr>