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
@@ -0,0 +1,34 @@
1
+ <% view_title 'Logs' %>
2
+
3
+ <%== partial 'recurring_tasks/tabs' %>
4
+
5
+ <div class="col-span-12">
6
+ <% if @logs.empty? && params.current_page <= 1 %>
7
+ <%== alert_info('There are no available logs.') %>
8
+ <% elsif @logs.empty? %>
9
+ <%== partial 'shared/no_paginated_data' %>
10
+ <% else %>
11
+ <div class="data-table-wrapper">
12
+ <table class="data-table">
13
+ <thead>
14
+ <tr>
15
+ <th>Task ID</th>
16
+ <th>Result</th>
17
+ <th>Time Taken</th>
18
+ <th>Dispatched At</th>
19
+ <th>Schedule Version</th>
20
+ </tr>
21
+ </thead>
22
+ <tbody>
23
+ <%==
24
+ render_each(
25
+ @logs,
26
+ 'recurring_tasks/_log',
27
+ local: :log
28
+ )
29
+ %>
30
+ </tbody>
31
+ </table>
32
+ </div>
33
+ <% end %>
34
+ </div>
@@ -0,0 +1,43 @@
1
+ <% if @schedule %>
2
+ <% view_title "Schedule #{@schedule.schedule_version}" %>
3
+ <% else %>
4
+ <% view_title 'Schedule' %>
5
+ <% end %>
6
+
7
+ <% if @schedule %>
8
+ <%== partial 'recurring_tasks/tabs' %>
9
+
10
+ <% unless @tasks.empty? %>
11
+ <%== partial 'recurring_tasks/batch_actions' %>
12
+ <% end %>
13
+ <% end %>
14
+
15
+ <div class="col-span-12">
16
+ <% if @schedule && !@tasks.empty? %>
17
+ <div class="data-table-wrapper">
18
+ <table class="data-table">
19
+ <thead>
20
+ <tr>
21
+ <th><%== sort_link('Task ID', :id) %></th>
22
+ <th><%== sort_link('Status', :enabled) %></th>
23
+ <th><%== sort_link(:cron) %></th>
24
+ <th><%== sort_link(:previous_time) %></th>
25
+ <th><%== sort_link(:next_time) %></th>
26
+ <th></th>
27
+ </tr>
28
+ </thead>
29
+ <tbody>
30
+ <%==
31
+ render_each(
32
+ @tasks,
33
+ 'recurring_tasks/_task',
34
+ local: :task
35
+ )
36
+ %>
37
+ </tbody>
38
+ </table>
39
+ </div>
40
+ <% else %>
41
+ <%== partial 'recurring_tasks/not_active' %>
42
+ <% end %>
43
+ </div>
@@ -62,6 +62,16 @@
62
62
  </a>
63
63
  </li>
64
64
 
65
+ <li>
66
+ <a
67
+ class="sidebar-nav-item <%= nav_class(start_with: '/recurring_tasks') %>"
68
+ href="<%= root_path('recurring_tasks') %>"
69
+ >
70
+ <%== icon(:arrow_path_rounded) %>
71
+ Cron
72
+ </a>
73
+ </li>
74
+
65
75
  <li>
66
76
  <a
67
77
  class="sidebar-nav-item <%= nav_class(start_with: '/errors') %>"
@@ -9,7 +9,7 @@
9
9
  <th><%== sort_link(:partition_id) %></th>
10
10
  <th><%== sort_link(:leader) %></th>
11
11
  <th><%== sort_link(:replica_count) %></th>
12
- <th><%== sort_link('In sync brokers', :in_sync_replica_brokers) %></th>
12
+ <th><%== sort_link('In Sync Brokers', :in_sync_replica_brokers) %></th>
13
13
  </tr>
14
14
  </thead>
15
15
  <tbody>
@@ -309,7 +309,14 @@ module Karafka
309
309
  def sort_link(name, attribute = nil, rev: false)
310
310
  unless attribute
311
311
  attribute = name
312
- name = SORT_NAMES[attribute] || attribute.to_s.tr('_', ' ').tr('?', '').capitalize
312
+
313
+ if SORT_NAMES[attribute]
314
+ name = SORT_NAMES[attribute]
315
+ else
316
+ name = attribute.to_s.tr('_', ' ').tr('?', '')
317
+ # Always capitalize the name
318
+ name = name.split(' ').map(&:capitalize).join(' ')
319
+ end
313
320
  end
314
321
 
315
322
  arrow_both = '&#x21D5;'
@@ -0,0 +1,26 @@
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 Ui
17
+ module Models
18
+ module RecurringTasks
19
+ # Single log entry for recurring tasks execution
20
+ class Log < Lib::HashProxy
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,86 @@
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 Ui
17
+ module Models
18
+ # Namespace for models representing recurring tasks related components taken from Kafka
19
+ module RecurringTasks
20
+ # Karafka schedule representation
21
+ class Schedule < Web::Ui::Lib::HashProxy
22
+ # Rdkafka errors we expect and handle gracefully
23
+ EXPECTED_RDKAFKA_ERRORS = %i[
24
+ unknown_topic
25
+ unknown_partition
26
+ unknown_topic_or_part
27
+ ].freeze
28
+
29
+ private_constant :EXPECTED_RDKAFKA_ERRORS
30
+
31
+ class << self
32
+ # @return [Schedule, false] current schedule or false if it was not possible to
33
+ # get it because requested topic/partition does not exist or nothing was present
34
+ def current
35
+ messages = Karafka::Admin.read_topic(
36
+ config.topics.schedules,
37
+ 0,
38
+ # We work here with the assumption that users won't click so fast to load
39
+ # more than 20 commands prior to a state flush. If that happens, this will
40
+ # return false. This is a known and expected limitation.
41
+ 20
42
+ )
43
+
44
+ # Out of those messages we pick the most recent persisted schedule
45
+ candidate = messages
46
+ .reverse
47
+ .find { |message| message.key == 'state:schedule' }
48
+
49
+ # If there is a schedule message we use its data to build schedule, if not false
50
+ return false unless candidate
51
+
52
+ # If the deserializer is not our dedicated recurring tasks deserializer, it means
53
+ # that routing for recurring tasks was not loaded, so recurring tasks are not
54
+ # active
55
+ #
56
+ # User might have used recurring tasks previously and disabled them, but still may
57
+ # navigate to them and then we should not show anything because without the
58
+ # correct deserializer it will crash anyhow
59
+ return false unless candidate.metadata.deserializers.payload == config.deserializer
60
+
61
+ new(candidate.payload)
62
+ rescue Rdkafka::RdkafkaError => e
63
+ # If any of "topic missing" is raised, we return false but other errors we re-raise
64
+ raise(e) unless EXPECTED_RDKAFKA_ERRORS.any? { |code| e.code == code }
65
+
66
+ false
67
+ end
68
+
69
+ private
70
+
71
+ # @return [Karafka::Core::Configurable::Node]
72
+ def config
73
+ Karafka::App.config.recurring_tasks
74
+ end
75
+ end
76
+
77
+ # @return [Array<Task>] tasks of the current schedule
78
+ def tasks
79
+ @tasks ||= super.values.map { |task_hash| Task.new(task_hash) }
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,30 @@
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 Ui
17
+ module Models
18
+ module RecurringTasks
19
+ # Represents a single recurring task
20
+ class Task < Lib::HashProxy
21
+ # @return [Boolean] true if this task is enabled, otherwise false
22
+ def enabled?
23
+ enabled
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -119,4 +119,4 @@ function addListeners() {
119
119
 
120
120
  document.addEventListener('turbo:load', addListeners);
121
121
 
122
- Turbo.setProgressBarDelay(250)
122
+ Turbo.setProgressBarDelay(100)