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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +1 -1
- data/CHANGELOG.md +11 -1
- 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/_become_pro.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
|