karafka-web 0.7.10 → 0.8.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/workflows/ci.yml +18 -5
  4. data/.ruby-version +1 -1
  5. data/CHANGELOG.md +63 -0
  6. data/Gemfile.lock +22 -22
  7. data/docker-compose.yml +3 -1
  8. data/karafka-web.gemspec +2 -2
  9. data/lib/karafka/web/config.rb +16 -3
  10. data/lib/karafka/web/contracts/config.rb +7 -2
  11. data/lib/karafka/web/errors.rb +12 -0
  12. data/lib/karafka/web/inflector.rb +33 -0
  13. data/lib/karafka/web/installer.rb +20 -11
  14. data/lib/karafka/web/management/actions/base.rb +36 -0
  15. data/lib/karafka/web/management/actions/clean_boot_file.rb +33 -0
  16. data/lib/karafka/web/management/actions/create_initial_states.rb +77 -0
  17. data/lib/karafka/web/management/actions/create_topics.rb +139 -0
  18. data/lib/karafka/web/management/actions/delete_topics.rb +30 -0
  19. data/lib/karafka/web/management/actions/enable.rb +117 -0
  20. data/lib/karafka/web/management/actions/extend_boot_file.rb +39 -0
  21. data/lib/karafka/web/management/actions/migrate_states_data.rb +18 -0
  22. data/lib/karafka/web/management/migrations/0_base.rb +58 -0
  23. data/lib/karafka/web/management/migrations/0_set_initial_consumers_metrics.rb +36 -0
  24. data/lib/karafka/web/management/migrations/0_set_initial_consumers_state.rb +43 -0
  25. data/lib/karafka/web/management/migrations/1699543515_fill_missing_received_and_sent_bytes_in_consumers_metrics.rb +26 -0
  26. data/lib/karafka/web/management/migrations/1699543515_fill_missing_received_and_sent_bytes_in_consumers_state.rb +23 -0
  27. data/lib/karafka/web/management/migrations/1700234522_introduce_waiting_in_consumers_metrics.rb +24 -0
  28. data/lib/karafka/web/management/migrations/1700234522_introduce_waiting_in_consumers_state.rb +20 -0
  29. data/lib/karafka/web/management/migrations/1700234522_remove_processing_from_consumers_metrics.rb +24 -0
  30. data/lib/karafka/web/management/migrations/1700234522_remove_processing_from_consumers_state.rb +20 -0
  31. data/lib/karafka/web/management/migrations/1704722380_split_listeners_into_active_and_paused_in_metrics.rb +36 -0
  32. data/lib/karafka/web/management/migrations/1704722380_split_listeners_into_active_and_paused_in_states.rb +32 -0
  33. data/lib/karafka/web/management/migrator.rb +117 -0
  34. data/lib/karafka/web/processing/consumer.rb +39 -38
  35. data/lib/karafka/web/processing/consumers/aggregators/metrics.rb +2 -3
  36. data/lib/karafka/web/processing/consumers/aggregators/state.rb +8 -3
  37. data/lib/karafka/web/processing/consumers/contracts/aggregated_stats.rb +5 -1
  38. data/lib/karafka/web/processing/publisher.rb +59 -0
  39. data/lib/karafka/web/tracking/consumers/contracts/job.rb +3 -2
  40. data/lib/karafka/web/tracking/consumers/contracts/partition.rb +1 -0
  41. data/lib/karafka/web/tracking/consumers/contracts/report.rb +6 -1
  42. data/lib/karafka/web/tracking/consumers/contracts/subscription_group.rb +10 -1
  43. data/lib/karafka/web/tracking/consumers/listeners/connections.rb +49 -0
  44. data/lib/karafka/web/tracking/consumers/listeners/pausing.rb +7 -4
  45. data/lib/karafka/web/tracking/consumers/listeners/processing.rb +78 -70
  46. data/lib/karafka/web/tracking/consumers/listeners/statistics.rb +40 -13
  47. data/lib/karafka/web/tracking/consumers/sampler.rb +82 -25
  48. data/lib/karafka/web/tracking/helpers/ttls/array.rb +72 -0
  49. data/lib/karafka/web/tracking/helpers/ttls/hash.rb +34 -0
  50. data/lib/karafka/web/tracking/helpers/ttls/stats.rb +49 -0
  51. data/lib/karafka/web/tracking/helpers/ttls/windows.rb +32 -0
  52. data/lib/karafka/web/tracking/reporter.rb +1 -0
  53. data/lib/karafka/web/ui/app.rb +22 -4
  54. data/lib/karafka/web/ui/base.rb +18 -2
  55. data/lib/karafka/web/ui/controllers/base.rb +34 -4
  56. data/lib/karafka/web/ui/controllers/become_pro.rb +1 -1
  57. data/lib/karafka/web/ui/controllers/cluster.rb +33 -9
  58. data/lib/karafka/web/ui/controllers/consumers.rb +8 -2
  59. data/lib/karafka/web/ui/controllers/dashboard.rb +2 -2
  60. data/lib/karafka/web/ui/controllers/errors.rb +2 -2
  61. data/lib/karafka/web/ui/controllers/jobs.rb +55 -5
  62. data/lib/karafka/web/ui/controllers/requests/params.rb +5 -0
  63. data/lib/karafka/web/ui/controllers/responses/deny.rb +15 -0
  64. data/lib/karafka/web/ui/controllers/responses/file.rb +23 -0
  65. data/lib/karafka/web/ui/controllers/responses/{data.rb → render.rb} +3 -3
  66. data/lib/karafka/web/ui/controllers/routing.rb +11 -2
  67. data/lib/karafka/web/ui/controllers/status.rb +1 -1
  68. data/lib/karafka/web/ui/helpers/application_helper.rb +70 -0
  69. data/lib/karafka/web/ui/lib/hash_proxy.rb +29 -14
  70. data/lib/karafka/web/ui/lib/sorter.rb +170 -0
  71. data/lib/karafka/web/ui/models/counters.rb +6 -0
  72. data/lib/karafka/web/ui/models/health.rb +23 -2
  73. data/lib/karafka/web/ui/models/jobs.rb +48 -0
  74. data/lib/karafka/web/ui/models/metrics/charts/aggregated.rb +33 -0
  75. data/lib/karafka/web/ui/models/metrics/charts/topics.rb +1 -1
  76. data/lib/karafka/web/ui/models/process.rb +2 -1
  77. data/lib/karafka/web/ui/models/status.rb +23 -7
  78. data/lib/karafka/web/ui/models/topic.rb +3 -1
  79. data/lib/karafka/web/ui/models/visibility_filter.rb +16 -0
  80. data/lib/karafka/web/ui/pro/app.rb +44 -6
  81. data/lib/karafka/web/ui/pro/controllers/cluster.rb +1 -0
  82. data/lib/karafka/web/ui/pro/controllers/consumers.rb +52 -6
  83. data/lib/karafka/web/ui/pro/controllers/dashboard.rb +1 -1
  84. data/lib/karafka/web/ui/pro/controllers/dlq.rb +1 -1
  85. data/lib/karafka/web/ui/pro/controllers/errors.rb +3 -3
  86. data/lib/karafka/web/ui/pro/controllers/explorer.rb +8 -8
  87. data/lib/karafka/web/ui/pro/controllers/health.rb +34 -2
  88. data/lib/karafka/web/ui/pro/controllers/jobs.rb +11 -0
  89. data/lib/karafka/web/ui/pro/controllers/messages.rb +42 -0
  90. data/lib/karafka/web/ui/pro/controllers/routing.rb +11 -2
  91. data/lib/karafka/web/ui/pro/views/consumers/_breadcrumbs.erb +8 -2
  92. data/lib/karafka/web/ui/pro/views/consumers/_consumer.erb +14 -8
  93. data/lib/karafka/web/ui/pro/views/consumers/_counters.erb +8 -6
  94. data/lib/karafka/web/ui/pro/views/consumers/consumer/_job.erb +4 -1
  95. data/lib/karafka/web/ui/pro/views/consumers/consumer/_no_jobs.erb +1 -1
  96. data/lib/karafka/web/ui/pro/views/consumers/consumer/_partition.erb +1 -3
  97. data/lib/karafka/web/ui/pro/views/consumers/consumer/_subscription_group.erb +28 -11
  98. data/lib/karafka/web/ui/pro/views/consumers/consumer/_tabs.erb +10 -3
  99. data/lib/karafka/web/ui/pro/views/consumers/index.erb +3 -3
  100. data/lib/karafka/web/ui/pro/views/consumers/pending_jobs.erb +43 -0
  101. data/lib/karafka/web/ui/pro/views/consumers/{jobs.erb → running_jobs.erb} +11 -10
  102. data/lib/karafka/web/ui/pro/views/dashboard/index.erb +7 -1
  103. data/lib/karafka/web/ui/pro/views/explorer/message/_message_actions.erb +18 -0
  104. data/lib/karafka/web/ui/pro/views/explorer/message/_metadata.erb +43 -0
  105. data/lib/karafka/web/ui/pro/views/explorer/message/_payload.erb +21 -0
  106. data/lib/karafka/web/ui/pro/views/explorer/message/_payload_actions.erb +19 -0
  107. data/lib/karafka/web/ui/pro/views/explorer/show.erb +9 -84
  108. data/lib/karafka/web/ui/pro/views/health/_breadcrumbs.erb +8 -0
  109. data/lib/karafka/web/ui/pro/views/health/_partition.erb +1 -3
  110. data/lib/karafka/web/ui/pro/views/health/_partition_offset.erb +4 -4
  111. data/lib/karafka/web/ui/pro/views/health/_partition_times.erb +32 -0
  112. data/lib/karafka/web/ui/pro/views/health/_tabs.erb +9 -0
  113. data/lib/karafka/web/ui/pro/views/health/changes.erb +66 -0
  114. data/lib/karafka/web/ui/pro/views/health/offsets.erb +14 -14
  115. data/lib/karafka/web/ui/pro/views/health/overview.erb +11 -11
  116. data/lib/karafka/web/ui/pro/views/jobs/_job.erb +1 -1
  117. data/lib/karafka/web/ui/pro/views/jobs/_no_jobs.erb +1 -1
  118. data/lib/karafka/web/ui/pro/views/jobs/pending.erb +39 -0
  119. data/lib/karafka/web/ui/pro/views/jobs/running.erb +39 -0
  120. data/lib/karafka/web/ui/pro/views/routing/_consumer_group.erb +2 -2
  121. data/lib/karafka/web/ui/pro/views/routing/_topic.erb +9 -0
  122. data/lib/karafka/web/ui/pro/views/routing/show.erb +12 -0
  123. data/lib/karafka/web/ui/pro/views/shared/_navigation.erb +1 -1
  124. data/lib/karafka/web/ui/public/javascripts/application.js +10 -0
  125. data/lib/karafka/web/ui/public/stylesheets/application.css +4 -0
  126. data/lib/karafka/web/ui/views/cluster/_breadcrumbs.erb +16 -0
  127. data/lib/karafka/web/ui/views/cluster/_tabs.erb +27 -0
  128. data/lib/karafka/web/ui/views/cluster/brokers.erb +27 -0
  129. data/lib/karafka/web/ui/views/cluster/topics.erb +35 -0
  130. data/lib/karafka/web/ui/views/consumers/_counters.erb +8 -6
  131. data/lib/karafka/web/ui/views/consumers/_summary.erb +2 -2
  132. data/lib/karafka/web/ui/views/consumers/index.erb +3 -3
  133. data/lib/karafka/web/ui/views/dashboard/_ranges_selector.erb +23 -7
  134. data/lib/karafka/web/ui/views/dashboard/index.erb +19 -8
  135. data/lib/karafka/web/ui/views/errors/show.erb +2 -23
  136. data/lib/karafka/web/ui/views/jobs/_breadcrumbs.erb +17 -1
  137. data/lib/karafka/web/ui/views/jobs/_job.erb +1 -1
  138. data/lib/karafka/web/ui/views/jobs/_no_jobs.erb +1 -1
  139. data/lib/karafka/web/ui/views/jobs/_tabs.erb +27 -0
  140. data/lib/karafka/web/ui/views/jobs/{index.erb → pending.erb} +9 -7
  141. data/lib/karafka/web/ui/{pro/views/jobs/index.erb → views/jobs/running.erb} +9 -11
  142. data/lib/karafka/web/ui/views/routing/_consumer_group.erb +14 -12
  143. data/lib/karafka/web/ui/views/shared/_navigation.erb +1 -1
  144. data/lib/karafka/web/ui/views/shared/_pagination.erb +1 -1
  145. data/lib/karafka/web/ui/views/shared/exceptions/not_allowed.erb +37 -0
  146. data/lib/karafka/web/ui/views/status/show.erb +17 -2
  147. data/lib/karafka/web/ui/views/status/warnings/_routing_topics_presence.erb +15 -0
  148. data/lib/karafka/web/version.rb +1 -1
  149. data/lib/karafka/web.rb +6 -2
  150. data.tar.gz.sig +0 -0
  151. metadata +61 -26
  152. metadata.gz.sig +0 -0
  153. data/lib/karafka/web/management/base.rb +0 -34
  154. data/lib/karafka/web/management/clean_boot_file.rb +0 -31
  155. data/lib/karafka/web/management/create_initial_states.rb +0 -101
  156. data/lib/karafka/web/management/create_topics.rb +0 -133
  157. data/lib/karafka/web/management/delete_topics.rb +0 -28
  158. data/lib/karafka/web/management/enable.rb +0 -102
  159. data/lib/karafka/web/management/extend_boot_file.rb +0 -37
  160. data/lib/karafka/web/tracking/ttl_array.rb +0 -59
  161. data/lib/karafka/web/tracking/ttl_hash.rb +0 -16
  162. data/lib/karafka/web/ui/pro/views/dashboard/_ranges_selector.erb +0 -39
  163. data/lib/karafka/web/ui/views/cluster/index.erb +0 -74
@@ -0,0 +1,27 @@
1
+ <%== view_title('Cluster informations') %>
2
+
3
+ <%== partial 'cluster/tabs' %>
4
+
5
+ <div class="container mb-5">
6
+ <div class="row">
7
+ <div class="col-lg-12">
8
+ <table class="processes bg-white table table-hover table-bordered table-striped">
9
+ <thead>
10
+ <tr class="align-middle">
11
+ <th><%== sort_link('Id', :broker_id) %></th>
12
+ <th><%== sort_link('Name', :broker_name) %></th>
13
+ <th><%== sort_link('Port', :broker_port) %></th>
14
+ </tr>
15
+ </thead>
16
+ <tbody>
17
+ <%==
18
+ each_partial(
19
+ @brokers,
20
+ 'cluster/broker'
21
+ )
22
+ %>
23
+ </tbody>
24
+ </table>
25
+ </div>
26
+ </div>
27
+ </div>
@@ -0,0 +1,35 @@
1
+ <%== view_title('Cluster informations') %>
2
+
3
+ <%== partial 'cluster/tabs' %>
4
+
5
+ <div class="container mb-5">
6
+ <div class="row">
7
+ <div class="col-lg-12">
8
+ <% if @partitions.empty? && params.current_page <= 1 %>
9
+ <%== partial 'cluster/no_partitions' %>
10
+ <% elsif @partitions.empty? %>
11
+ <%== partial 'shared/no_paginated_data' %>
12
+ <% else %>
13
+ <table class="processes bg-white table table-hover table-bordered table-striped">
14
+ <thead>
15
+ <tr class="align-middle">
16
+ <th><%== sort_link(:topic_name) %></th>
17
+ <th><%== sort_link(:partition_id) %></th>
18
+ <th><%== sort_link(:leader) %></th>
19
+ <th><%== sort_link(:replica_count) %></th>
20
+ <th><%== sort_link('In sync brokers', :in_sync_replica_brokers) %></th>
21
+ </tr>
22
+ </thead>
23
+ <tbody>
24
+ <%==
25
+ each_partial(
26
+ @partitions,
27
+ 'cluster/partition'
28
+ )
29
+ %>
30
+ </tbody>
31
+ </table>
32
+ <% end %>
33
+ </div>
34
+ </div>
35
+ </div>
@@ -24,18 +24,20 @@
24
24
  <div class="desc">Lag stored</div>
25
25
  </li>
26
26
  <li class="col-sm">
27
- <a href="<%= root_path('jobs') %>">
27
+ <a href="<%= root_path('jobs/running') %>">
28
28
  <div class="count mb-1">
29
29
  <%= number_with_delimiter @counters.busy, ' ' %>
30
30
  </div>
31
- <div class="desc">Busy</div>
31
+ <div class="desc">Running</div>
32
32
  </a>
33
33
  </li>
34
34
  <li class="col-sm">
35
- <div class="count mb-1">
36
- <%= number_with_delimiter @counters.enqueued, ' ' %>
37
- </div>
38
- <div class="desc">Enqueued</div>
35
+ <a href="<%= root_path('jobs/pending') %>">
36
+ <div class="count mb-1">
37
+ <%= number_with_delimiter @counters.pending, ' ' %>
38
+ </div>
39
+ <div class="desc">Pending</div>
40
+ </a>
39
41
  </li>
40
42
  <li class="col-sm">
41
43
  <a href="<%= root_path('errors') %>">
@@ -36,10 +36,10 @@
36
36
  <div class="card-body">
37
37
  <p class="card-text">
38
38
  <div class="stat mb-1">
39
- <%= @counters.listeners %>
39
+ <%= @counters.listeners.fetch(:active) %>
40
40
  </div>
41
41
  <div class="desc">
42
- Listeners
42
+ Active Listeners
43
43
  </div>
44
44
  </p>
45
45
  </div>
@@ -12,11 +12,11 @@
12
12
  <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
13
13
  <thead>
14
14
  <tr class="align-middle">
15
- <th>Name</th>
16
- <th class="col-sm-2">Started</th>
15
+ <th><%== sort_link(:name) %></th>
16
+ <th class="col-sm-2"><%== sort_link('Started', :started_at, rev: true) %></th>
17
17
  <th class="col-sm-1">Memory</th>
18
18
  <th class="col-sm-1">Utilization</th>
19
- <th class="col-sm-1">Total lag</th>
19
+ <th class="col-sm-1"><%== sort_link(:lag_stored) %></th>
20
20
  </tr>
21
21
  </thead>
22
22
  <tbody>
@@ -2,20 +2,36 @@
2
2
  <div class="row">
3
3
  <div class="col-sm-12 text-end">
4
4
  <div class="btn-group btn-group-sm" role="group" aria-label="Small button group">
5
- <a type="button" href="<%= root_path('dashboard') %>" class="btn btn-outline-primary active">
5
+ <%
6
+ path = root_path('dashboard?range=seconds')
7
+ active = params.current_range == :seconds ? 'active' : false
8
+ %>
9
+ <a type="button" href="<%= path %>" class="btn btn-outline-primary <%= active %>">
6
10
  5 minutes
7
11
  </a>
8
12
 
9
- <a type="button" href="#" class="btn btn-outline-primary disabled" title="Pro feature">
10
- <s>1 hour</s>
13
+ <%
14
+ path = root_path('dashboard?range=minutes')
15
+ active = params.current_range == :minutes ? 'active' : false
16
+ %>
17
+ <a type="button" href="<%= path %>" class="btn btn-outline-primary <%= active %>">
18
+ 1 hour
11
19
  </a>
12
20
 
13
- <a type="button" href="#" class="btn btn-outline-primary disabled" title="Pro feature">
14
- <s>24 hours</s>
21
+ <%
22
+ path = root_path('dashboard?range=hours')
23
+ active = params.current_range == :hours ? 'active' : false
24
+ %>
25
+ <a type="button" href="<%= path %>" class="btn btn-outline-primary <%= active %>">
26
+ 24 hours
15
27
  </a>
16
28
 
17
- <a type="button" href="#" class="btn btn-outline-primary disabled" title="Pro feature">
18
- <s>7 days</s>
29
+ <%
30
+ path = root_path('dashboard?range=days')
31
+ active = params.current_range == :days ? 'active' : false
32
+ %>
33
+ <a type="button" href="<%= path %>" class="btn btn-outline-primary <%= active %>">
34
+ 7 days
19
35
  </a>
20
36
  </div>
21
37
  </div>
@@ -25,6 +25,7 @@
25
25
  <%== partial 'shared/tab_nav', locals: { title: 'Batches', id: 'batches' } %>
26
26
  <%== partial 'shared/tab_nav', locals: { title: 'Lags stored', id: 'lags-stored' } %>
27
27
  <%== partial 'shared/tab_nav', locals: { title: 'Topics pace', id: 'topics-pace' } %>
28
+ <%== partial 'shared/tab_nav', locals: { title: 'Max LSO time', id: 'max-lso-time' } %>
28
29
  </ul>
29
30
 
30
31
  <div class="tab-content">
@@ -34,9 +35,8 @@
34
35
  </div>
35
36
 
36
37
  <div class="tab-pane" id="batches" role="tabpanel">
37
- <%== partial 'dashboard/feature_pro' %>
38
- <% data = { batches: set.call(20), errors: set.call, dead: set.call, retries: set.call }.to_json %>
39
- <%== partial 'shared/chart', locals: { data: data, id: 'batches', blurred: true } %>
38
+ <% data = @aggregated_charts.with(:batches, :errors, :dead, :retries) %>
39
+ <%== partial 'shared/chart', locals: { data: data, id: 'batches' } %>
40
40
  </div>
41
41
 
42
42
  <div class="tab-pane" id="lags-stored" role="tabpanel">
@@ -50,6 +50,12 @@
50
50
  <% data = { topic1: set.call(20), topic2: set.call(10), topic3: set.call(100) }.to_json %>
51
51
  <%== partial 'shared/chart', locals: { data: data, id: 'topics-pace', blurred: true } %>
52
52
  </div>
53
+
54
+ <div class="tab-pane" id="max-lso-time" role="tabpanel">
55
+ <%== partial 'dashboard/feature_pro' %>
56
+ <% data = { max_lso: set.call(2, 0..5) }.to_json %>
57
+ <%== partial 'shared/chart', locals: { data: data, id: 'max-lso-time', blurred: true } %>
58
+ </div>
53
59
  </div>
54
60
  </div>
55
61
  </div>
@@ -66,13 +72,13 @@
66
72
  <%== partial 'shared/tab_nav', locals: { title: 'Utilization', id: 'utilization', active: true } %>
67
73
  <%== partial 'shared/tab_nav', locals: { title: 'RSS', id: 'rss' } %>
68
74
  <%== partial 'shared/tab_nav', locals: { title: 'Concurrency', id: 'concurrency' } %>
75
+ <%== partial 'shared/tab_nav', locals: { title: 'Data transfers', id: 'data-transfers' } %>
69
76
  </ul>
70
77
 
71
78
  <div class="tab-content">
72
79
  <div class="tab-pane show active" id="utilization" role="tabpanel">
73
- <%== partial 'dashboard/feature_pro' %>
74
- <% data = { utilization: set.call(50) }.to_json %>
75
- <%== partial 'shared/chart', locals: { data: data, id: 'utilization', blurred: true } %>
80
+ <% data = @aggregated_charts.with(:utilization) %>
81
+ <%== partial 'shared/chart', locals: { data: data, id: 'utilization', label_type_y: 'percentage' } %>
76
82
  </div>
77
83
 
78
84
  <div class="tab-pane show" id="rss" role="tabpanel">
@@ -82,9 +88,14 @@
82
88
  </div>
83
89
 
84
90
  <div class="tab-pane show" id="concurrency" role="tabpanel">
91
+ <% data = @aggregated_charts.with(:processes, :workers, :active_listeners, :standby_listeners) %>
92
+ <%== partial 'shared/chart', locals: { data: data, id: 'concurrency' } %>
93
+ </div>
94
+
95
+ <div class="tab-pane show" id="data-transfers" role="tabpanel">
85
96
  <%== partial 'dashboard/feature_pro' %>
86
- <% data = { processes: set.call(2, 0..0), workers: set.call(4, 0..0), listeners: set.call(3, 0..0) }.to_json %>
87
- <%== partial 'shared/chart', locals: { data: data, id: 'concurrency', blurred: true } %>
97
+ <% data = { bytes_received: set.call(4, 10..15), bytes_sent: set.call(2, 0..5) }.to_json %>
98
+ <%== partial 'shared/chart', locals: { data: data, id: 'data-transfers', blurred: true } %>
88
99
  </div>
89
100
  </div>
90
101
  </div>
@@ -36,7 +36,7 @@
36
36
  </div>
37
37
  </div>
38
38
 
39
- <div class="row mb-2">
39
+ <div class="row mb-4">
40
40
  <div class="col-sm-12">
41
41
  <h5 class="mb-2">
42
42
  Backtrace
@@ -45,32 +45,11 @@
45
45
  </div>
46
46
  </div>
47
47
 
48
- <div class="mb-4">
49
- <%== partial 'shared/feature_pro' %>
50
- </div>
51
-
52
48
  <div class="row mb-5">
53
49
  <div class="col-sm-12">
54
50
  <div class="card">
55
51
  <div class="card-body">
56
- <pre class="m-0 p-0 blurred"><code class="wrapped json p-0 m-0">this is just an example backtrace
57
- please subscribe to our Pro offering to be able to view the real one
58
- gems/karafka-rdkafka/lib/rdkafka/consumer.rb:255:in `query_watermark_offsets'
59
- gems/karafka/lib/karafka/admin.rb:56:in `block in read_topic'
60
- gems/karafka/lib/karafka/admin.rb:184:in `with_consumer'
61
- gems/karafka/lib/karafka/admin.rb:55:in `read_topic'
62
- /mnt/software/Karafka/karafka-web/lib/karafka/web/processing/consumers/state.rb:19:in `current'
63
- /mnt/software/Karafka/karafka-web/lib/karafka/web/processing/consumers/aggregator.rb:45:in `state'
64
- /mnt/software/Karafka/karafka-web/lib/karafka/web/processing/consumers/aggregator.rb:38:in `to_json'
65
- gems/karafka/lib/karafka/processing/strategies/default.rb:136:in `block in handle_shutdown'
66
- gems/karafka-core/lib/karafka/core/monitoring/notifications.rb:118:in `measure_time_taken'
67
- gems/karafka-core/lib/karafka/core/monitoring/notifications.rb:94:in `instrument'
68
- gems/karafka-core/lib/karafka/core/monitoring/monitor.rb:34:in `instrument'
69
- gems/karafka/lib/karafka/processing/strategies/default.rb:135:in `handle_shutdown'
70
- gems/karafka/lib/karafka/base_consumer.rb:134:in `on_shutdown'
71
- gems/karafka/lib/karafka/processing/executor.rb:123:in `shutdown'
72
- gems/karafka/lib/karafka/processing/jobs/shutdown.rb:18:in `call'
73
- gems/karafka/lib/karafka/helpers/async.rb:28:in `block in async_call'</code></pre>
52
+ <pre class="m-0 p-0"><code class="wrapped json p-0 m-0"><%= @error_message.payload[:backtrace] %></code></pre>
74
53
  </div>
75
54
  </div>
76
55
  </div>
@@ -1,5 +1,21 @@
1
1
  <li class="breadcrumb-item">
2
2
  <a href="<%= root_path('jobs') %>">
3
- Running jobs
3
+ Jobs
4
4
  </a>
5
5
  </li>
6
+
7
+ <% if current_path.include?('/running') %>
8
+ <li class="breadcrumb-item">
9
+ <a href="<%= root_path('jobs/running') %>">
10
+ Running
11
+ </a>
12
+ </li>
13
+ <% end %>
14
+
15
+ <% if current_path.include?('/pending') %>
16
+ <li class="breadcrumb-item">
17
+ <a href="<%= root_path('jobs/pending') %>">
18
+ Pending
19
+ </a>
20
+ </li>
21
+ <% end %>
@@ -22,6 +22,6 @@
22
22
  <code>#<%= job.type %></code>
23
23
  </td>
24
24
  <td>
25
- <%== relative_time job.started_at %>
25
+ <%== relative_time job.updated_at %>
26
26
  </td>
27
27
  </tr>
@@ -2,7 +2,7 @@
2
2
  <div class="row">
3
3
  <div class="col-lg-12">
4
4
  <div class="alert alert-info" role="alert">
5
- There are no running jobs at the moment.
5
+ There are no <%= type %> jobs at the moment.
6
6
  </div>
7
7
  </div>
8
8
  </div>
@@ -0,0 +1,27 @@
1
+ <div class="container">
2
+ <div class="row mb-5">
3
+ <div class="col-sm-12">
4
+
5
+ <ul class="nav nav-tabs">
6
+ <li class="nav-item">
7
+ <a
8
+ class="nav-link <%= nav_class(include: 'running') %>"
9
+ href="<%= root_path('jobs', 'running') %>"
10
+ >
11
+ Running (<%= @jobs_counters.running %>)
12
+ </a>
13
+ </li>
14
+
15
+ <li class="nav-item">
16
+ <a
17
+ class="nav-link <%= nav_class(include: 'pending') %>"
18
+ href="<%= root_path('jobs', 'pending') %>"
19
+ >
20
+ Pending (<%= @jobs_counters.pending %>)
21
+ </a>
22
+ </li>
23
+ </ul>
24
+
25
+ </div>
26
+ </div>
27
+ </div>
@@ -1,7 +1,9 @@
1
- <%== view_title('Running jobs', hr: true) %>
1
+ <%== view_title('Pending jobs', hr: false) %>
2
+
3
+ <%== partial 'jobs/tabs' %>
2
4
 
3
5
  <% if @jobs.empty? && params.current_page <= 1 %>
4
- <%== partial 'jobs/no_jobs' %>
6
+ <%== partial 'jobs/no_jobs', locals: { type: 'pending' } %>
5
7
  <% elsif @jobs.empty? %>
6
8
  <%== partial 'shared/no_paginated_data' %>
7
9
  <% else %>
@@ -11,11 +13,11 @@
11
13
  <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
12
14
  <thead>
13
15
  <tr class="align-middle">
14
- <th>Process</th>
15
- <th>Topic</th>
16
- <th>Consumer</th>
17
- <th>Type</th>
18
- <th>Started at</th>
16
+ <th><%== sort_link('Process', :name) %></th>
17
+ <th><%== sort_link(:topic) %></th>
18
+ <th><%== sort_link(:consumer) %></th>
19
+ <th><%== sort_link(:type) %></th>
20
+ <th><%== sort_link('Created at', :updated_at, rev: true) %></th>
19
21
  </tr>
20
22
  </thead>
21
23
  <tbody>
@@ -1,7 +1,9 @@
1
- <%== view_title('Running jobs', hr: true) %>
1
+ <%== view_title('Running jobs', hr: false) %>
2
+
3
+ <%== partial 'jobs/tabs' %>
2
4
 
3
5
  <% if @jobs.empty? && params.current_page <= 1 %>
4
- <%== partial 'jobs/no_jobs' %>
6
+ <%== partial 'jobs/no_jobs', locals: { type: 'running' } %>
5
7
  <% elsif @jobs.empty? %>
6
8
  <%== partial 'shared/no_paginated_data' %>
7
9
  <% else %>
@@ -11,15 +13,11 @@
11
13
  <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
12
14
  <thead>
13
15
  <tr class="align-middle">
14
- <th>Process</th>
15
- <th>Topic</th>
16
- <th>Consumer</th>
17
- <th>Type</th>
18
- <th>Messages</th>
19
- <th>First offset</th>
20
- <th>Last offset</th>
21
- <th>Committed offset</th>
22
- <th>Started at</th>
16
+ <th><%== sort_link('Process', :name) %></th>
17
+ <th><%== sort_link(:topic) %></th>
18
+ <th><%== sort_link(:consumer) %></th>
19
+ <th><%== sort_link(:type) %></th>
20
+ <th><%== sort_link('Started at', :updated_at, rev: true) %></th>
23
21
  </tr>
24
22
  </thead>
25
23
  <tbody>
@@ -13,22 +13,24 @@
13
13
  <thead>
14
14
  <tr class="align-middle">
15
15
  <th>Subscription group</th>
16
- <th>Topic</th>
17
- <th>Active</th>
16
+ <th><%== sort_link('Topic', :name) %></th>
17
+ <th><%== sort_link('Active', :active?) %></th>
18
18
  <th></th>
19
19
  </tr>
20
20
  </thead>
21
21
  <tbody>
22
- <% consumer_group.topics.each do |topic| %>
23
- <%==
24
- partial(
25
- 'routing/topic',
26
- locals: {
27
- subscription_group: topic.subscription_group,
28
- topic: topic
29
- }
30
- )
31
- %>
22
+ <% consumer_group.subscription_groups.each do |subscription_group| %>
23
+ <% subscription_group.topics.each do |topic| %>
24
+ <%==
25
+ partial(
26
+ 'routing/topic',
27
+ locals: {
28
+ subscription_group: subscription_group,
29
+ topic: topic
30
+ }
31
+ )
32
+ %>
33
+ <% end %>
32
34
  <% end %>
33
35
  </tbody>
34
36
  </table>
@@ -15,7 +15,7 @@
15
15
  </a>
16
16
  </li>
17
17
  <li class="nav-item ms-3">
18
- <a class="nav-link <%= nav_class(start_with: '/jobs') %>" href="<%= root_path('jobs') %>">
18
+ <a class="nav-link <%= nav_class(start_with: '/jobs') %>" href="<%= root_path('jobs/running') %>">
19
19
  Jobs
20
20
  </a>
21
21
  </li>
@@ -4,7 +4,7 @@
4
4
  <nav>
5
5
  <ul class="pagination justify-content-center">
6
6
  <li class="page-item <%= 'disabled' unless @pagination.first_offset? %>">
7
- <a class="page-link" href="<%= current_path(@pagination.offset_key => @pagination.first_offset) %>">
7
+ <a class="page-link" href="<%= current_path(@pagination.offset_key => @pagination.first_offset || 1) %>">
8
8
  <span>&laquo;</span>
9
9
  </a>
10
10
  </li>
@@ -0,0 +1,37 @@
1
+ <main>
2
+ <div id="content">
3
+ <div class="d-flex align-items-center justify-content-center vh-100">
4
+ <div class="error-message text-center">
5
+ <h1 class="display-1 fw-bold">403</h1>
6
+
7
+ <p class="fs-3 md-5">
8
+ <span class="text-danger">
9
+ Oops!
10
+ </span>
11
+ Not permitted.
12
+ </p>
13
+
14
+ <div class="lead">
15
+ <p class="mb-5">
16
+ You don't have permission to view this page.
17
+ </p>
18
+
19
+ <p>
20
+ Please make sure, that:
21
+ </p>
22
+
23
+ <ul class="mb-5 text-start">
24
+ <li>You have visited the <a href="<%= root_path('status') %>">Status</a> page to troubleshoot any potential issues</li>
25
+ <li>You are authorized to access the resource you requested</li>
26
+ <li>Web UI configuration permits the action you requested</li>
27
+ </ul>
28
+
29
+ <p>
30
+ <a href="<%= root_path %>" class="btn btn-primary">Go Home</a>
31
+ <a href="<%= root_path('status') %>" class="btn btn-success">Status page</a>
32
+ </p>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </main>
@@ -7,7 +7,7 @@
7
7
  partial(
8
8
  "status/#{@status.enabled.to_s}",
9
9
  locals: {
10
- title: 'Web-UI setup in karafka.rb',
10
+ title: 'Web UI setup in karafka.rb',
11
11
  description: partial(
12
12
  "status/#{@status.enabled.partial_namespace}/enabled",
13
13
  locals: {
@@ -37,7 +37,7 @@
37
37
  partial(
38
38
  "status/#{@status.topics.to_s}",
39
39
  locals: {
40
- title: 'Topics presence',
40
+ title: 'Web UI topics presence',
41
41
  description: partial(
42
42
  'status/failures/topics',
43
43
  locals: {
@@ -165,6 +165,21 @@
165
165
  )
166
166
  %>
167
167
 
168
+ <%==
169
+ partial(
170
+ "status/#{@status.routing_topics_presence.to_s}",
171
+ locals: {
172
+ title: 'Routing topics presence',
173
+ description: partial(
174
+ 'status/warnings/routing_topics_presence',
175
+ locals: {
176
+ details: @status.routing_topics_presence.details
177
+ }
178
+ )
179
+ }
180
+ )
181
+ %>
182
+
168
183
  <%==
169
184
  partial(
170
185
  "status/#{@status.pro_subscription.to_s}",
@@ -0,0 +1,15 @@
1
+ <p>
2
+ The following active topics present in your <code>karafka.rb</code> file were not located in the Kafka cluster:
3
+ </p>
4
+
5
+ <ul>
6
+ <% details.each do |topic_name| %>
7
+ <li>
8
+ <code><%= topic_name %></code>
9
+ </li>
10
+ <% end %>
11
+ </ul>
12
+
13
+ <p>
14
+ Although not an error, having topics in <code>karafka.rb</code> that still needs to be added to Kafka could lead to issues. It's better to create these topics beforehand to avoid potential errors.
15
+ </p>
@@ -3,6 +3,6 @@
3
3
  module Karafka
4
4
  module Web
5
5
  # Current gem version
6
- VERSION = '0.7.10'
6
+ VERSION = '0.8.0.rc1'
7
7
  end
8
8
  end
data/lib/karafka/web.rb CHANGED
@@ -53,7 +53,10 @@ module Karafka
53
53
  end
54
54
  end
55
55
 
56
+ require_relative 'web/inflector'
57
+
56
58
  loader = Zeitwerk::Loader.new
59
+
57
60
  # Make sure pro is not loaded unless Pro
58
61
  loader.ignore(Karafka::Web.gem_root.join('lib/karafka/web/ui/pro'))
59
62
 
@@ -62,9 +65,10 @@ Karafka::Licenser.detect do
62
65
  loader = Zeitwerk::Loader.new
63
66
  end
64
67
 
65
- root = File.expand_path('..', __dir__)
66
68
  loader.tag = 'karafka-web'
67
- loader.inflector = Zeitwerk::GemInflector.new("#{root}/karafka/web.rb")
69
+ # Use our custom inflector to support migrations
70
+ root = File.expand_path('..', __dir__)
71
+ loader.inflector = Karafka::Web::Inflector.new("#{root}/karafka/web.rb")
68
72
  loader.push_dir(root)
69
73
 
70
74
  loader.setup
data.tar.gz.sig CHANGED
Binary file