karafka-web 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (214) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/workflows/ci.yml +13 -4
  4. data/CHANGELOG.md +119 -5
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +27 -24
  7. data/README.md +2 -0
  8. data/bin/rspecs +6 -0
  9. data/certs/cert_chain.pem +21 -21
  10. data/docker-compose.yml +22 -0
  11. data/karafka-web.gemspec +3 -3
  12. data/lib/karafka/web/app.rb +6 -2
  13. data/lib/karafka/web/cli.rb +51 -47
  14. data/lib/karafka/web/config.rb +33 -9
  15. data/lib/karafka/web/contracts/base.rb +32 -0
  16. data/lib/karafka/web/contracts/config.rb +63 -0
  17. data/lib/karafka/web/deserializer.rb +10 -1
  18. data/lib/karafka/web/errors.rb +29 -7
  19. data/lib/karafka/web/installer.rb +58 -148
  20. data/lib/karafka/web/management/base.rb +34 -0
  21. data/lib/karafka/web/management/clean_boot_file.rb +31 -0
  22. data/lib/karafka/web/management/create_initial_states.rb +101 -0
  23. data/lib/karafka/web/management/create_topics.rb +127 -0
  24. data/lib/karafka/web/management/delete_topics.rb +28 -0
  25. data/lib/karafka/web/management/enable.rb +82 -0
  26. data/lib/karafka/web/management/extend_boot_file.rb +37 -0
  27. data/lib/karafka/web/processing/consumer.rb +73 -17
  28. data/lib/karafka/web/processing/consumers/aggregators/base.rb +56 -0
  29. data/lib/karafka/web/processing/consumers/aggregators/metrics.rb +154 -0
  30. data/lib/karafka/web/processing/consumers/aggregators/state.rb +180 -0
  31. data/lib/karafka/web/processing/consumers/contracts/aggregated_stats.rb +32 -0
  32. data/lib/karafka/web/processing/consumers/contracts/metrics.rb +53 -0
  33. data/lib/karafka/web/processing/consumers/contracts/process.rb +19 -0
  34. data/lib/karafka/web/processing/consumers/contracts/state.rb +49 -0
  35. data/lib/karafka/web/processing/consumers/contracts/topic_stats.rb +21 -0
  36. data/lib/karafka/web/processing/consumers/metrics.rb +29 -0
  37. data/lib/karafka/web/processing/consumers/schema_manager.rb +56 -0
  38. data/lib/karafka/web/processing/consumers/state.rb +6 -9
  39. data/lib/karafka/web/processing/time_series_tracker.rb +130 -0
  40. data/lib/karafka/web/tracking/consumers/contracts/consumer_group.rb +2 -2
  41. data/lib/karafka/web/tracking/consumers/contracts/job.rb +2 -1
  42. data/lib/karafka/web/tracking/consumers/contracts/partition.rb +14 -1
  43. data/lib/karafka/web/tracking/consumers/contracts/report.rb +10 -8
  44. data/lib/karafka/web/tracking/consumers/contracts/subscription_group.rb +2 -2
  45. data/lib/karafka/web/tracking/consumers/contracts/topic.rb +2 -2
  46. data/lib/karafka/web/tracking/consumers/listeners/processing.rb +6 -2
  47. data/lib/karafka/web/tracking/consumers/listeners/statistics.rb +15 -1
  48. data/lib/karafka/web/tracking/consumers/reporter.rb +14 -6
  49. data/lib/karafka/web/tracking/consumers/sampler.rb +80 -39
  50. data/lib/karafka/web/tracking/contracts/error.rb +2 -1
  51. data/lib/karafka/web/ui/app.rb +20 -10
  52. data/lib/karafka/web/ui/base.rb +56 -6
  53. data/lib/karafka/web/ui/controllers/base.rb +28 -0
  54. data/lib/karafka/web/ui/controllers/become_pro.rb +1 -1
  55. data/lib/karafka/web/ui/controllers/cluster.rb +12 -6
  56. data/lib/karafka/web/ui/controllers/consumers.rb +4 -2
  57. data/lib/karafka/web/ui/controllers/dashboard.rb +32 -0
  58. data/lib/karafka/web/ui/controllers/errors.rb +19 -6
  59. data/lib/karafka/web/ui/controllers/jobs.rb +4 -2
  60. data/lib/karafka/web/ui/controllers/requests/params.rb +28 -0
  61. data/lib/karafka/web/ui/controllers/responses/redirect.rb +29 -0
  62. data/lib/karafka/web/ui/helpers/application_helper.rb +57 -14
  63. data/lib/karafka/web/ui/helpers/paths_helper.rb +48 -0
  64. data/lib/karafka/web/ui/lib/hash_proxy.rb +18 -6
  65. data/lib/karafka/web/ui/lib/paginations/base.rb +61 -0
  66. data/lib/karafka/web/ui/lib/paginations/offset_based.rb +96 -0
  67. data/lib/karafka/web/ui/lib/paginations/page_based.rb +70 -0
  68. data/lib/karafka/web/ui/lib/paginations/paginators/arrays.rb +33 -0
  69. data/lib/karafka/web/ui/lib/paginations/paginators/base.rb +23 -0
  70. data/lib/karafka/web/ui/lib/paginations/paginators/partitions.rb +52 -0
  71. data/lib/karafka/web/ui/lib/paginations/paginators/sets.rb +85 -0
  72. data/lib/karafka/web/ui/lib/paginations/watermark_offsets_based.rb +75 -0
  73. data/lib/karafka/web/ui/lib/ttl_cache.rb +82 -0
  74. data/lib/karafka/web/ui/models/cluster_info.rb +59 -0
  75. data/lib/karafka/web/ui/models/consumers_metrics.rb +46 -0
  76. data/lib/karafka/web/ui/models/{state.rb → consumers_state.rb} +6 -2
  77. data/lib/karafka/web/ui/models/health.rb +37 -7
  78. data/lib/karafka/web/ui/models/message.rb +123 -39
  79. data/lib/karafka/web/ui/models/metrics/aggregated.rb +196 -0
  80. data/lib/karafka/web/ui/models/metrics/charts/aggregated.rb +50 -0
  81. data/lib/karafka/web/ui/models/metrics/charts/topics.rb +109 -0
  82. data/lib/karafka/web/ui/models/metrics/topics.rb +101 -0
  83. data/lib/karafka/web/ui/models/partition.rb +27 -0
  84. data/lib/karafka/web/ui/models/process.rb +12 -1
  85. data/lib/karafka/web/ui/models/status.rb +110 -22
  86. data/lib/karafka/web/ui/models/visibility_filter.rb +33 -0
  87. data/lib/karafka/web/ui/pro/app.rb +87 -19
  88. data/lib/karafka/web/ui/pro/controllers/cluster.rb +11 -0
  89. data/lib/karafka/web/ui/pro/controllers/consumers.rb +13 -7
  90. data/lib/karafka/web/ui/pro/controllers/dashboard.rb +54 -0
  91. data/lib/karafka/web/ui/pro/controllers/dlq.rb +1 -2
  92. data/lib/karafka/web/ui/pro/controllers/errors.rb +46 -10
  93. data/lib/karafka/web/ui/pro/controllers/explorer.rb +145 -15
  94. data/lib/karafka/web/ui/pro/controllers/health.rb +10 -2
  95. data/lib/karafka/web/ui/pro/controllers/messages.rb +62 -0
  96. data/lib/karafka/web/ui/pro/controllers/routing.rb +44 -0
  97. data/lib/karafka/web/ui/pro/views/consumers/_breadcrumbs.erb +7 -1
  98. data/lib/karafka/web/ui/pro/views/consumers/_consumer.erb +1 -1
  99. data/lib/karafka/web/ui/pro/views/consumers/_counters.erb +7 -5
  100. data/lib/karafka/web/ui/pro/views/consumers/consumer/_job.erb +3 -3
  101. data/lib/karafka/web/ui/pro/views/consumers/consumer/_metrics.erb +5 -4
  102. data/lib/karafka/web/ui/pro/views/consumers/consumer/_partition.erb +13 -4
  103. data/lib/karafka/web/ui/pro/views/consumers/consumer/_subscription_group.erb +3 -2
  104. data/lib/karafka/web/ui/pro/views/consumers/consumer/_tabs.erb +7 -0
  105. data/lib/karafka/web/ui/pro/views/consumers/details.erb +21 -0
  106. data/lib/karafka/web/ui/pro/views/consumers/index.erb +4 -2
  107. data/lib/karafka/web/ui/pro/views/dashboard/_ranges_selector.erb +39 -0
  108. data/lib/karafka/web/ui/pro/views/dashboard/index.erb +82 -0
  109. data/lib/karafka/web/ui/pro/views/dlq/_topic.erb +1 -1
  110. data/lib/karafka/web/ui/pro/views/errors/_breadcrumbs.erb +8 -6
  111. data/lib/karafka/web/ui/pro/views/errors/_error.erb +2 -2
  112. data/lib/karafka/web/ui/pro/views/errors/_partition_option.erb +1 -1
  113. data/lib/karafka/web/ui/pro/views/errors/_table.erb +21 -0
  114. data/lib/karafka/web/ui/pro/views/errors/_title_with_select.erb +31 -0
  115. data/lib/karafka/web/ui/pro/views/errors/index.erb +9 -56
  116. data/lib/karafka/web/ui/pro/views/errors/partition.erb +17 -0
  117. data/lib/karafka/web/ui/pro/views/errors/show.erb +1 -1
  118. data/lib/karafka/web/ui/pro/views/explorer/_breadcrumbs.erb +6 -4
  119. data/lib/karafka/web/ui/pro/views/explorer/_filtered.erb +16 -0
  120. data/lib/karafka/web/ui/pro/views/explorer/_message.erb +14 -4
  121. data/lib/karafka/web/ui/pro/views/explorer/_no_topics.erb +7 -0
  122. data/lib/karafka/web/ui/pro/views/explorer/_partition_option.erb +3 -3
  123. data/lib/karafka/web/ui/pro/views/explorer/_topic.erb +1 -1
  124. data/lib/karafka/web/ui/pro/views/explorer/index.erb +12 -8
  125. data/lib/karafka/web/ui/pro/views/explorer/messages/_headers.erb +15 -0
  126. data/lib/karafka/web/ui/pro/views/explorer/messages/_key.erb +12 -0
  127. data/lib/karafka/web/ui/pro/views/explorer/partition/_details.erb +35 -0
  128. data/lib/karafka/web/ui/pro/views/explorer/partition/_messages.erb +1 -0
  129. data/lib/karafka/web/ui/pro/views/explorer/partition.erb +6 -4
  130. data/lib/karafka/web/ui/pro/views/explorer/show.erb +48 -5
  131. data/lib/karafka/web/ui/pro/views/explorer/topic/_details.erb +23 -0
  132. data/lib/karafka/web/ui/pro/views/explorer/topic/_empty.erb +3 -0
  133. data/lib/karafka/web/ui/pro/views/explorer/topic/_limited.erb +4 -0
  134. data/lib/karafka/web/ui/pro/views/explorer/topic.erb +51 -0
  135. data/lib/karafka/web/ui/pro/views/health/_breadcrumbs.erb +16 -0
  136. data/lib/karafka/web/ui/pro/views/health/_no_data.erb +9 -0
  137. data/lib/karafka/web/ui/pro/views/health/_partition.erb +17 -15
  138. data/lib/karafka/web/ui/pro/views/health/_partition_offset.erb +40 -0
  139. data/lib/karafka/web/ui/pro/views/health/_tabs.erb +27 -0
  140. data/lib/karafka/web/ui/pro/views/health/offsets.erb +71 -0
  141. data/lib/karafka/web/ui/pro/views/health/overview.erb +68 -0
  142. data/lib/karafka/web/ui/pro/views/jobs/_job.erb +6 -3
  143. data/lib/karafka/web/ui/pro/views/jobs/index.erb +4 -1
  144. data/lib/karafka/web/ui/pro/views/routing/_consumer_group.erb +37 -0
  145. data/lib/karafka/web/ui/pro/views/routing/_detail.erb +25 -0
  146. data/lib/karafka/web/ui/pro/views/routing/_topic.erb +23 -0
  147. data/lib/karafka/web/ui/pro/views/routing/index.erb +10 -0
  148. data/lib/karafka/web/ui/pro/views/routing/show.erb +26 -0
  149. data/lib/karafka/web/ui/pro/views/shared/_navigation.erb +7 -10
  150. data/lib/karafka/web/ui/public/images/logo-gray.svg +28 -0
  151. data/lib/karafka/web/ui/public/javascripts/application.js +30 -0
  152. data/lib/karafka/web/ui/public/javascripts/chart.min.js +14 -0
  153. data/lib/karafka/web/ui/public/javascripts/charts.js +330 -0
  154. data/lib/karafka/web/ui/public/javascripts/datepicker.js +6 -0
  155. data/lib/karafka/web/ui/public/javascripts/live_poll.js +39 -12
  156. data/lib/karafka/web/ui/public/javascripts/offset_datetime.js +74 -0
  157. data/lib/karafka/web/ui/public/javascripts/tabs.js +59 -0
  158. data/lib/karafka/web/ui/public/stylesheets/application.css +11 -0
  159. data/lib/karafka/web/ui/public/stylesheets/datepicker.min.css +12 -0
  160. data/lib/karafka/web/ui/views/cluster/_no_partitions.erb +3 -0
  161. data/lib/karafka/web/ui/views/cluster/_partition.erb +20 -22
  162. data/lib/karafka/web/ui/views/cluster/index.erb +6 -1
  163. data/lib/karafka/web/ui/views/consumers/_consumer.erb +1 -1
  164. data/lib/karafka/web/ui/views/consumers/_counters.erb +6 -4
  165. data/lib/karafka/web/ui/views/consumers/_summary.erb +3 -3
  166. data/lib/karafka/web/ui/views/consumers/index.erb +3 -1
  167. data/lib/karafka/web/ui/views/dashboard/_feature_pro.erb +3 -0
  168. data/lib/karafka/web/ui/views/dashboard/_not_enough_data.erb +15 -0
  169. data/lib/karafka/web/ui/views/dashboard/_ranges_selector.erb +23 -0
  170. data/lib/karafka/web/ui/views/dashboard/index.erb +95 -0
  171. data/lib/karafka/web/ui/views/errors/_detail.erb +12 -0
  172. data/lib/karafka/web/ui/views/errors/_error.erb +2 -2
  173. data/lib/karafka/web/ui/views/errors/show.erb +1 -1
  174. data/lib/karafka/web/ui/views/jobs/index.erb +3 -1
  175. data/lib/karafka/web/ui/views/layout.erb +10 -3
  176. data/lib/karafka/web/ui/views/routing/_consumer_group.erb +8 -6
  177. data/lib/karafka/web/ui/views/routing/_detail.erb +2 -2
  178. data/lib/karafka/web/ui/views/routing/_topic.erb +1 -1
  179. data/lib/karafka/web/ui/views/routing/show.erb +1 -1
  180. data/lib/karafka/web/ui/views/shared/_brand.erb +2 -2
  181. data/lib/karafka/web/ui/views/shared/_chart.erb +14 -0
  182. data/lib/karafka/web/ui/views/shared/_content.erb +2 -2
  183. data/lib/karafka/web/ui/views/shared/_feature_pro.erb +1 -1
  184. data/lib/karafka/web/ui/views/shared/_flashes.erb +9 -0
  185. data/lib/karafka/web/ui/views/shared/_footer.erb +22 -0
  186. data/lib/karafka/web/ui/views/shared/_header.erb +15 -9
  187. data/lib/karafka/web/ui/views/shared/_live_poll.erb +7 -0
  188. data/lib/karafka/web/ui/views/shared/_navigation.erb +5 -8
  189. data/lib/karafka/web/ui/views/shared/_no_paginated_data.erb +9 -0
  190. data/lib/karafka/web/ui/views/shared/_pagination.erb +17 -13
  191. data/lib/karafka/web/ui/views/shared/_tab_nav.erb +7 -0
  192. data/lib/karafka/web/ui/views/shared/exceptions/not_found.erb +34 -32
  193. data/lib/karafka/web/ui/views/shared/exceptions/pro_only.erb +45 -43
  194. data/lib/karafka/web/ui/views/status/failures/_consumers_reports_schema_state.erb +15 -0
  195. data/lib/karafka/web/ui/views/status/failures/_enabled.erb +8 -0
  196. data/lib/karafka/web/ui/views/status/failures/_initial_consumers_metrics.erb +11 -0
  197. data/lib/karafka/web/ui/views/status/failures/{_initial_state.erb → _initial_consumers_state.erb} +3 -3
  198. data/lib/karafka/web/ui/views/status/failures/_partitions.erb +14 -6
  199. data/lib/karafka/web/ui/views/status/info/_components.erb +21 -1
  200. data/lib/karafka/web/ui/views/status/show.erb +62 -5
  201. data/lib/karafka/web/ui/views/status/successes/_enabled.erb +1 -0
  202. data/lib/karafka/web/ui/views/status/warnings/_replication.erb +19 -0
  203. data/lib/karafka/web/version.rb +1 -1
  204. data/lib/karafka/web.rb +11 -0
  205. data.tar.gz.sig +0 -0
  206. metadata +124 -39
  207. metadata.gz.sig +0 -0
  208. data/lib/karafka/web/processing/consumers/aggregator.rb +0 -130
  209. data/lib/karafka/web/tracking/contracts/base.rb +0 -34
  210. data/lib/karafka/web/ui/lib/paginate_array.rb +0 -38
  211. data/lib/karafka/web/ui/pro/views/explorer/_encryption_enabled.erb +0 -18
  212. data/lib/karafka/web/ui/pro/views/explorer/partition/_watermark_offsets.erb +0 -10
  213. data/lib/karafka/web/ui/pro/views/health/index.erb +0 -60
  214. /data/lib/karafka/web/ui/pro/views/explorer/{_detail.erb → messages/_detail.erb} +0 -0
@@ -0,0 +1,39 @@
1
+ <div class="container">
2
+ <div class="row">
3
+ <div class="col-sm-12 text-end">
4
+ <div class="btn-group btn-group-sm" role="group" aria-label="Small button group">
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 %>">
10
+ 5 minutes
11
+ </a>
12
+
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
19
+ </a>
20
+
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
27
+ </a>
28
+
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
35
+ </a>
36
+ </div>
37
+ </div>
38
+ </div>
39
+ </div>
@@ -0,0 +1,82 @@
1
+ <%== partial 'consumers/counters' %>
2
+
3
+ <% if @aggregated.sufficient? %>
4
+ <%== partial 'dashboard/ranges_selector' %>
5
+
6
+ <div class="container">
7
+ <div class="row">
8
+ <div class="col-sm-12">
9
+ <h5 class="mb-3">Processing metrics</h5>
10
+
11
+ <hr class="mb-4"/>
12
+
13
+ <ul class="nav nav-tabs" id="graphs1" role="tablist">
14
+ <%== partial 'shared/tab_nav', locals: { title: 'Messages', id: 'messages', active: true } %>
15
+ <%== partial 'shared/tab_nav', locals: { title: 'Batches', id: 'batches' } %>
16
+ <%== partial 'shared/tab_nav', locals: { title: 'Lags stored', id: 'lags-stored' } %>
17
+ <%== partial 'shared/tab_nav', locals: { title: 'Topics pace', id: 'topics-pace' } %>
18
+ <%== partial 'shared/tab_nav', locals: { title: 'Max LSO time', id: 'max-lso-time' } %>
19
+ </ul>
20
+
21
+ <div class="tab-content">
22
+ <div class="tab-pane show active" id="messages" role="tabpanel">
23
+ <% data = @aggregated_charts.with(:messages, :errors, :dead, :retries, :batch_size) %>
24
+ <%== partial 'shared/chart', locals: { data: data, id: 'messages' } %>
25
+ </div>
26
+
27
+ <div class="tab-pane" id="batches" role="tabpanel">
28
+ <% data = @aggregated_charts.with(:batches, :errors, :dead, :retries) %>
29
+ <%== partial 'shared/chart', locals: { data: data, id: 'batches' } %>
30
+ </div>
31
+
32
+ <div class="tab-pane" id="lags-stored" role="tabpanel">
33
+ <%== partial 'shared/chart', locals: { data: @topics_charts.lags_stored, id: 'lags-stored' } %>
34
+ </div>
35
+
36
+ <div class="tab-pane" id="topics-pace" role="tabpanel">
37
+ <%== partial 'shared/chart', locals: { data: @topics_charts.topics_pace, id: 'topics-pace' } %>
38
+ </div>
39
+
40
+ <div class="tab-pane" id="max-lso-time" role="tabpanel">
41
+ <%== partial 'shared/chart', locals: { data: @topics_charts.max_lso_time, id: 'max-lso-time' } %>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </div>
47
+
48
+ <div class="container">
49
+ <div class="row">
50
+ <div class="col-sm-12">
51
+ <h5 class="mb-3">Utilization metrics</h5>
52
+
53
+ <hr class="mb-4"/>
54
+
55
+ <ul class="nav nav-tabs" id="graphs2" role="tablist">
56
+ <%== partial 'shared/tab_nav', locals: { title: 'Utilization', id: 'utilization', active: true } %>
57
+ <%== partial 'shared/tab_nav', locals: { title: 'RSS', id: 'rss' } %>
58
+ <%== partial 'shared/tab_nav', locals: { title: 'Concurrency', id: 'concurrency' } %>
59
+ </ul>
60
+
61
+ <div class="tab-content">
62
+ <div class="tab-pane show active" id="utilization" role="tabpanel">
63
+ <% data = @aggregated_charts.with(:utilization) %>
64
+ <%== partial 'shared/chart', locals: { data: data, id: 'utilization', label_type_y: 'percentage' } %>
65
+ </div>
66
+
67
+ <div class="tab-pane show" id="rss" role="tabpanel">
68
+ <% data = @aggregated_charts.with(:rss, :process_rss) %>
69
+ <%== partial 'shared/chart', locals: { data: data, id: 'rss', label_type_y: 'memory' } %>
70
+ </div>
71
+
72
+ <div class="tab-pane show" id="concurrency" role="tabpanel">
73
+ <% data = @aggregated_charts.with(:processes, :workers, :listeners) %>
74
+ <%== partial 'shared/chart', locals: { data: data, id: 'concurrency' } %>
75
+ </div>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ <% else %>
81
+ <%== partial 'dashboard/not_enough_data' %>
82
+ <% end %>
@@ -2,7 +2,7 @@
2
2
  <div class="card" >
3
3
  <div class="card-body p-2">
4
4
  <p class="card-text mb-0 p-2">
5
- <a href="<%= root_path('explorer', topic[:topic_name], 0) %>">
5
+ <a href="<%= explorer_path(topic[:topic_name]) %>">
6
6
  <%= topic[:topic_name] %> /
7
7
  <%= topic[:partition_count] %>
8
8
  </a>
@@ -1,14 +1,16 @@
1
1
  <li class="breadcrumb-item">
2
- <a href="<%= root_path('errors', 0) %>">
2
+ <a href="<%= root_path('errors') %>">
3
3
  Errors
4
4
  </a>
5
5
  </li>
6
6
 
7
- <li class="breadcrumb-item">
8
- <a href="<%= root_path('errors', @partition_id) %>">
9
- Partition <%= @partition_id %>
10
- </a>
11
- </li>
7
+ <% if @partition_id %>
8
+ <li class="breadcrumb-item">
9
+ <a href="<%= root_path('errors', @partition_id) %>">
10
+ Partition <%= @partition_id %>
11
+ </a>
12
+ </li>
13
+ <% end %>
12
14
 
13
15
  <% if @offset %>
14
16
  <li class="breadcrumb-item">
@@ -1,4 +1,4 @@
1
- <% if error_msg.is_a?(Integer) %>
1
+ <% if error_msg.is_a?(Array) %>
2
2
  <tr>
3
3
  <td colspan="5" class="text-center text-muted">
4
4
  This error has either been removed or compacted and is no longer available.
@@ -22,7 +22,7 @@
22
22
  </td>
23
23
  <td>
24
24
  <%= error[:error_class] %>:
25
- <%= error[:error_message].first(200) %>
25
+ <%= error[:error_message][0..199] %>
26
26
  </td>
27
27
  <td>
28
28
  <%== relative_time error[:occurred_at] %>
@@ -3,5 +3,5 @@
3
3
  <% else %>
4
4
  <option value="<%= root_path('errors', partition) %>">
5
5
  <% end %>
6
- <%= partition %>
6
+ <%= partition || 'All' %>
7
7
  </option>
@@ -0,0 +1,21 @@
1
+ <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
2
+ <thead>
3
+ <tr class="align-middle">
4
+ <th>Origin</th>
5
+ <th>Process name</th>
6
+ <th>Error</th>
7
+ <th>Occurred at</th>
8
+ <th></th>
9
+ </tr>
10
+ </thead>
11
+
12
+ <tbody>
13
+ <%==
14
+ each_partial(
15
+ @error_messages,
16
+ 'errors/error',
17
+ local: :error_msg
18
+ )
19
+ %>
20
+ </tbody>
21
+ </table>
@@ -0,0 +1,31 @@
1
+ <div class="container mb-4">
2
+ <div class="row">
3
+ <div class="col">
4
+ <h3>
5
+ Errors
6
+ </h3>
7
+ </div>
8
+
9
+ <div class="col">
10
+ <div class="col-auto text-end">
11
+ <label class="col-form-label">Partition</label>
12
+ </div>
13
+ </div>
14
+
15
+ <div class="col pt-1 mb-0 pb-0">
16
+ <div class="col-auto">
17
+ <select class="form-select form-select-sm mb-0 form-control" id="current-partition">
18
+ <%==
19
+ each_partial(
20
+ [nil] + @partitions_count.times.to_a,
21
+ 'errors/partition_option',
22
+ local: :partition
23
+ )
24
+ %>
25
+ </select>
26
+ </div>
27
+ </div>
28
+ </div>
29
+
30
+ <hr>
31
+ </div>
@@ -1,65 +1,18 @@
1
- <div class="container mb-4">
2
- <div class="row">
3
- <div class="col">
4
- <h3>
5
- Errors
6
- </h3>
7
- </div>
8
-
9
- <div class="col">
10
- <div class="col-auto text-end">
11
- <label class="col-form-label">Partition</label>
12
- </div>
13
- </div>
14
-
15
- <div class="col pt-1 mb-0 pb-0">
16
- <div class="col-auto">
17
- <select class="form-select form-select-sm mb-0 form-control" id="current-partition">
18
- <%==
19
- each_partial(
20
- @partitions_count.times.to_a,
21
- 'errors/partition_option',
22
- local: :partition
23
- )
24
- %>
25
- </select>
26
- </div>
27
- </div>
28
- </div>
29
-
30
- <hr>
31
- </div>
1
+ <%== partial('errors/title_with_select') %>
32
2
 
33
3
  <div class="container">
34
4
  <div class="row mb-5">
35
5
  <div class="col-sm-12">
36
- <%== partial('explorer/partition/watermark_offsets') %>
6
+ <%== partial('explorer/topic/details') %>
7
+
8
+ <% if @limited %>
9
+ <%== partial('explorer/topic/limited') %>
10
+ <% end %>
37
11
 
38
- <% if @watermark_offsets.empty? %>
39
- <%== partial 'errors/no_errors' %>
40
- <% elsif @watermark_offsets.cleaned? %>
41
- <%== partial 'errors/cleaned' %>
12
+ <% if @error_messages.empty? && params.current_page == 1 %>
13
+ <%== partial 'explorer/topic/empty' %>
42
14
  <% else %>
43
- <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
44
- <thead>
45
- <tr class="align-middle">
46
- <th>Origin</th>
47
- <th>Process name</th>
48
- <th>Error</th>
49
- <th>Occurred at</th>
50
- <th></th>
51
- </tr>
52
- </thead>
53
- <tbody>
54
- <%==
55
- each_partial(
56
- @error_messages,
57
- 'errors/error',
58
- local: :error_msg
59
- )
60
- %>
61
- </tbody>
62
- </table>
15
+ <%== partial 'errors/table' %>
63
16
  <% end %>
64
17
  </div>
65
18
  </div>
@@ -0,0 +1,17 @@
1
+ <%== partial('errors/title_with_select') %>
2
+
3
+ <div class="container">
4
+ <div class="row mb-5">
5
+ <div class="col-sm-12">
6
+ <%== partial('explorer/partition/details') %>
7
+
8
+ <% if @watermark_offsets.empty? %>
9
+ <%== partial 'errors/no_errors' %>
10
+ <% elsif @watermark_offsets.cleaned? %>
11
+ <%== partial 'errors/cleaned' %>
12
+ <% else %>
13
+ <%== partial 'errors/table' %>
14
+ <% end %>
15
+ </div>
16
+ </div>
17
+ </div>
@@ -45,7 +45,7 @@
45
45
  </div>
46
46
  </div>
47
47
 
48
- <div class="row mb-4">
48
+ <div class="row mb-5">
49
49
  <div class="col-sm-12">
50
50
  <div class="card">
51
51
  <div class="card-body">
@@ -6,7 +6,7 @@
6
6
 
7
7
  <% if @topic_id %>
8
8
  <li class="breadcrumb-item">
9
- <a href="<%= root_path('explorer', @topic_id, 0) %>">
9
+ <a href="<%= explorer_path(@topic_id) %>">
10
10
  <%= @topic_id %>
11
11
  </a>
12
12
  </li>
@@ -14,16 +14,18 @@
14
14
 
15
15
  <% if @partition_id %>
16
16
  <li class="breadcrumb-item">
17
- <a href="<%= root_path('explorer', @topic_id, @partition_id) %>">
17
+ <a href="<%= explorer_path(@topic_id, @partition_id) %>">
18
18
  Partition <%= @partition_id %>
19
19
  </a>
20
20
  </li>
21
21
  <% end %>
22
22
 
23
23
  <% if @offset %>
24
+ <% mapped_offset = @offset == -1 ? 'Recent' : @offset %>
25
+
24
26
  <li class="breadcrumb-item active">
25
- <a href="<%= root_path('explorer', @topic_id, @partition_id, @offset) %>">
26
- <%= @offset %>
27
+ <a href="<%= explorer_path(@topic_id, @partition_id, mapped_offset) %>">
28
+ <%= mapped_offset %>
27
29
  </a>
28
30
  </li>
29
31
  <% end %>
@@ -0,0 +1,16 @@
1
+ <div class="row">
2
+ <div class="col-sm-12">
3
+ <div class="alert alert-warning" role="alert">
4
+ <h4 class="alert-heading">
5
+ This payload cannot be displayed.
6
+ </h4>
7
+ <p class="mt-3">
8
+ Payload visibility for this message was disabled.
9
+ </p>
10
+ <hr>
11
+ <p class="mb-0">
12
+ This message payload may contain sensitive data, and its visibility was limited by using the Karafka Web-UI visibility filtering capabilities.
13
+ </p>
14
+ </div>
15
+ </div>
16
+ </div>
@@ -1,7 +1,10 @@
1
- <% if message.is_a?(Integer) %>
1
+ <% if message.is_a?(Array) %>
2
2
  <tr>
3
3
  <td class="text-muted">
4
- <%= message %>
4
+ <%= message[0] %>
5
+ </td>
6
+ <td class="text-muted">
7
+ <%= message[1] %>
5
8
  </td>
6
9
  <td colspan="3" class="text-center text-muted">
7
10
  This message has either been removed or compacted and is no longer available.
@@ -9,6 +12,9 @@
9
12
  </tr>
10
13
  <% else %>
11
14
  <tr>
15
+ <td>
16
+ <%= message.partition %>
17
+ </td>
12
18
  <td>
13
19
  <%= message.offset %>
14
20
  </td>
@@ -16,10 +22,14 @@
16
22
  <%== time_with_label(message.timestamp) %>
17
23
  </td>
18
24
  <td>
19
- <%= message.key %>
25
+ <% if @visibility_filter.key?(message) %>
26
+ <%= message.key %>
27
+ <% else %>
28
+ <span class="text-muted">[Filtered]</span>
29
+ <% end %>
20
30
  </td>
21
31
  <td class="text-center">
22
- <a href="<%= root_path('explorer', message.topic, message.partition, message.offset) %>" class="btn btn-sm btn-secondary">
32
+ <a href="<%= explorer_path(message.topic, message.partition, message.offset) %>" class="btn btn-sm btn-secondary">
23
33
  Details
24
34
  </a>
25
35
  </td>
@@ -0,0 +1,7 @@
1
+ <div class="row">
2
+ <div class="col-lg-12">
3
+ <div class="alert alert-info" role="alert">
4
+ There are no available topics in the current cluster.
5
+ </div>
6
+ </div>
7
+ </div>
@@ -1,7 +1,7 @@
1
1
  <% if @partition_id == partition %>
2
- <option value="<%= root_path('explorer', @topic_id, partition) %>" selected=selected>
2
+ <option value="<%= explorer_path(@topic_id, partition) %>" selected=selected>
3
3
  <% else %>
4
- <option value="<%= root_path('explorer', @topic_id, partition) %>">
4
+ <option value="<%= explorer_path(@topic_id, partition) %>">
5
5
  <% end %>
6
- <%= partition %>
6
+ <%= partition || 'All' %>
7
7
  </option>
@@ -2,7 +2,7 @@
2
2
  <div class="card" >
3
3
  <div class="card-body p-2">
4
4
  <p class="card-text mb-0 p-2">
5
- <a href="<%= root_path('explorer', topic[:topic_name], 0) %>">
5
+ <a href="<%= explorer_path(topic[:topic_name]) %>">
6
6
  <%= topic[:topic_name] %> /
7
7
  <%= topic[:partition_count] %>
8
8
  </a>
@@ -6,12 +6,16 @@
6
6
  </div>
7
7
 
8
8
  <div class="container">
9
- <div class="row mb-5 row-cols-1 row-cols-md-4 g-4">
10
- <%==
11
- each_partial(
12
- @topics,
13
- 'explorer/topic'
14
- )
15
- %>
16
- </div>
9
+ <% if @topics.empty? %>
10
+ <%== partial 'explorer/no_topics' %>
11
+ <% else %>
12
+ <div class="row mb-5 row-cols-1 row-cols-md-4 g-4">
13
+ <%==
14
+ each_partial(
15
+ @topics,
16
+ 'explorer/topic'
17
+ )
18
+ %>
19
+ </div>
20
+ <% end %>
17
21
  </div>
@@ -0,0 +1,15 @@
1
+ <% visible = @visibility_filter.headers?(message) %>
2
+ <% message.metadata.to_h.fetch(:headers).each do |k, v| %>
3
+ <tr>
4
+ <td>
5
+ <%= "headers.#{k}" %>
6
+ </td>
7
+ <td>
8
+ <% if visible %>
9
+ <%= object_value_to_s(v) %>
10
+ <% else %>
11
+ <span class="text-muted">[Filtered]</span>
12
+ <% end %>
13
+ </td>
14
+ </tr>
15
+ <% end %>
@@ -0,0 +1,12 @@
1
+ <tr>
2
+ <td>
3
+ key
4
+ </td>
5
+ <td>
6
+ <% if @visibility_filter.key?(message) %>
7
+ <%= message.key %>
8
+ <% else %>
9
+ <span class="text-muted">[Filtered]</span>
10
+ <% end %>
11
+ </td>
12
+ </tr>
@@ -0,0 +1,35 @@
1
+ <div class="container mb-4">
2
+ <div class="row">
3
+ <div class="col-sm-6 ms-0 ps-0">
4
+ <% if @messages && !@messages.empty? %>
5
+ <a
6
+ href="<%= explorer_path(@topic_id, @partition_id, 'recent') %>"
7
+ class="btn btn-secondary btn-sm"
8
+ title="Display the most recent message for this partition"
9
+ >
10
+ &#x2192; Recent
11
+ </a>
12
+ <% end %>
13
+
14
+ <% closest_path = explorer_path(@topic_id, @partition_id) %>
15
+ <input
16
+ type="button"
17
+ class="btn-secondary btn btn-sm"
18
+ id="offset-lookup-datepicker"
19
+ value="&#128198;"
20
+ data-target="<%= closest_path %>"
21
+ />
22
+ </div>
23
+
24
+ <div class="col-sm-6 text-end me-0 pe-0">
25
+ Watermark offsets:
26
+ <span class="badge bg-secondary mt-1 mb-1">
27
+ high: <%= @watermark_offsets.high %>
28
+ </span>
29
+
30
+ <span class="badge bg-secondary mt-1 mb-1">
31
+ low: <%= @watermark_offsets.low %>
32
+ </span>
33
+ </div>
34
+ </div>
35
+ </div>
@@ -1,6 +1,7 @@
1
1
  <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
2
2
  <thead>
3
3
  <tr class="align-middle">
4
+ <th>Partition</th>
4
5
  <th>Offset</th>
5
6
  <th>Timestamp</th>
6
7
  <th>Key</th>
@@ -17,7 +17,7 @@
17
17
  <select class="form-select form-select-sm mb-0 form-control" id="current-partition">
18
18
  <%==
19
19
  each_partial(
20
- @partitions_count.times.to_a,
20
+ [nil] + @partitions_count.times.to_a,
21
21
  'explorer/partition_option',
22
22
  local: :partition
23
23
  )
@@ -33,12 +33,14 @@
33
33
  <div class="container">
34
34
  <div class="row mb-5">
35
35
  <div class="col-sm-12">
36
- <%== partial('explorer/partition/watermark_offsets') %>
36
+ <%== partial('explorer/partition/details') %>
37
37
 
38
- <% if @watermark_offsets.empty? %>
38
+ <% if @watermark_offsets.empty? && params.current_page == 1 %>
39
39
  <%== partial 'explorer/partition/empty' %>
40
- <% elsif @watermark_offsets.cleaned? %>
40
+ <% elsif @watermark_offsets.cleaned? && params.current_page == 1 %>
41
41
  <%== partial 'explorer/partition/cleaned' %>
42
+ <% elsif @messages.empty? %>
43
+ <%== partial 'shared/no_paginated_data' %>
42
44
  <% else %>
43
45
  <%== partial('explorer/partition/messages') %>
44
46
  <% end %>