karafka-web 0.10.0 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +12 -4
- data/certs/cert.pem +26 -0
- data/karafka-web.gemspec +2 -2
- data/lib/karafka/web/pro/ui/app.rb +40 -0
- data/lib/karafka/web/pro/ui/controllers/commanding_controller.rb +4 -4
- data/lib/karafka/web/pro/ui/controllers/recurring_tasks_controller.rb +131 -0
- data/lib/karafka/web/pro/ui/views/consumers/_consumer_controls.erb +13 -12
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_actions.erb +58 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_batch_actions.erb +45 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_breadcrumbs.erb +22 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_log.erb +26 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_not_active.erb +12 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_tabs.erb +17 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_task.erb +46 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/logs.erb +34 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/schedule.erb +43 -0
- data/lib/karafka/web/pro/ui/views/shared/_navigation.erb +10 -0
- data/lib/karafka/web/pro/ui/views/topics/replication.erb +1 -1
- data/lib/karafka/web/ui/helpers/application_helper.rb +8 -1
- data/lib/karafka/web/ui/models/recurring_tasks/log.rb +26 -0
- data/lib/karafka/web/ui/models/recurring_tasks/schedule.rb +86 -0
- data/lib/karafka/web/ui/models/recurring_tasks/task.rb +30 -0
- data/lib/karafka/web/ui/public/javascripts/application.js +1 -1
- data/lib/karafka/web/ui/public/javascripts/application.min.js +7 -7
- data/lib/karafka/web/ui/public/javascripts/application.min.js.br +0 -0
- data/lib/karafka/web/ui/public/javascripts/application.min.js.gz +0 -0
- data/lib/karafka/web/ui/public/javascripts/components/live_poll.js +36 -0
- data/lib/karafka/web/ui/public/stylesheets/application.css +5 -1
- data/lib/karafka/web/ui/public/stylesheets/application.min.css +2 -2
- data/lib/karafka/web/ui/public/stylesheets/application.min.css.br +0 -0
- data/lib/karafka/web/ui/public/stylesheets/application.min.css.gz +0 -0
- data/lib/karafka/web/ui/public/stylesheets/libs/tailwind.css +17 -5
- data/lib/karafka/web/ui/views/dashboard/_ranges_selector.erb +1 -1
- data/lib/karafka/web/ui/views/shared/_navigation.erb +11 -0
- data/lib/karafka/web/ui/views/shared/icons/_check.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_play.erb +3 -0
- data/lib/karafka/web/ui/views/status/info/_components.erb +48 -11
- data/lib/karafka/web/ui/views/ux/_data_table.erb +34 -4
- data/lib/karafka/web/ui/views/ux/_status_rows.erb +12 -0
- data/lib/karafka/web/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +41 -26
- metadata.gz.sig +0 -0
- 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
|
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
|
-
|
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 = '⇕'
|
@@ -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
|