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,59 @@
1
+ // Bootstrap tabs management with local storage for selected tab + restore
2
+ //
3
+ // Because we have pages where tabs are under the same view and some of them include charts, we
4
+ // keep track of them and in case user is back, we restore the last tab that was active
5
+
6
+ function readAllActiveTabs() {
7
+ let raw_active_tabs = localStorage.karafkaActiveTabs
8
+
9
+ if (raw_active_tabs == undefined) {
10
+ return {}
11
+ } else {
12
+ return JSON.parse(raw_active_tabs)
13
+ }
14
+ }
15
+
16
+ function saveAllActiveTabs(data) {
17
+ localStorage.karafkaActiveTabs = JSON.stringify(data)
18
+ }
19
+
20
+ function saveCurrentActiveTabs() {
21
+ let active_tabs = document.querySelectorAll('.tab-content > .active')
22
+ let url = window.location.href.split('?')[0]
23
+ let current = []
24
+ let tabs = readAllActiveTabs()
25
+
26
+ for (var i = 0; i < active_tabs.length; i++) {
27
+ var active_tab = active_tabs[i]
28
+ current.push(active_tab.id)
29
+ }
30
+
31
+ tabs[url] = current
32
+ saveAllActiveTabs(tabs)
33
+ }
34
+
35
+ function setActiveTabs() {
36
+ let url = window.location.href.split('?')[0]
37
+ let tabs = readAllActiveTabs()
38
+ let active_tabs = tabs[url]
39
+
40
+ if (tabs[url] == undefined) { return }
41
+
42
+ for (var i = 0; i < active_tabs.length; i++) {
43
+ var active_tab = active_tabs[i]
44
+ var tab = document.getElementById(active_tab + '-tab')
45
+
46
+ if (tab != undefined) {
47
+ var bsTab = new bootstrap.Tab(tab)
48
+ bsTab.show()
49
+ }
50
+ }
51
+ }
52
+
53
+ function manageTabs() {
54
+ setActiveTabs()
55
+
56
+ document.addEventListener('shown.bs.tab', function (event) {
57
+ saveCurrentActiveTabs()
58
+ })
59
+ }
@@ -2,6 +2,9 @@ body {
2
2
  background-color: #f5f6fe;
3
3
  font-size: 95%;
4
4
  color: #393939;
5
+ display: flex;
6
+ min-height: 100vh;
7
+ flex-direction: column;
5
8
  }
6
9
 
7
10
  #content {
@@ -112,3 +115,11 @@ code.wrapped {
112
115
  .blurred {
113
116
  filter: blur(4px)
114
117
  }
118
+
119
+ main {
120
+ flex: 1;
121
+ }
122
+
123
+ .chartjs-wrapper {
124
+ height: 250px;
125
+ }
@@ -0,0 +1,12 @@
1
+ /*
2
+ * Air Datepicker v3.4.0 (https://air-datepicker.com)
3
+ * Copyright (c) Timofey Marochkin
4
+ * Licensed under MIT (https://github.com/t1m0n/air-datepicker/blob/v3/LICENSE.md)
5
+ */
6
+ .air-datepicker-cell.-year-.-other-decade-,.air-datepicker-cell.-day-.-other-month-{color:var(--adp-color-other-month)}.air-datepicker-cell.-year-.-other-decade-:hover,.air-datepicker-cell.-day-.-other-month-:hover{color:var(--adp-color-other-month-hover)}.-disabled-.-focus-.air-datepicker-cell.-year-.-other-decade-,.-disabled-.-focus-.air-datepicker-cell.-day-.-other-month-{color:var(--adp-color-other-month)}.-selected-.air-datepicker-cell.-year-.-other-decade-,.-selected-.air-datepicker-cell.-day-.-other-month-{color:#fff;background:var(--adp-background-color-selected-other-month)}.-selected-.-focus-.air-datepicker-cell.-year-.-other-decade-,.-selected-.-focus-.air-datepicker-cell.-day-.-other-month-{background:var(--adp-background-color-selected-other-month-focused)}.-in-range-.air-datepicker-cell.-year-.-other-decade-,.-in-range-.air-datepicker-cell.-day-.-other-month-{background-color:var(--adp-background-color-in-range);color:var(--adp-color)}.-in-range-.-focus-.air-datepicker-cell.-year-.-other-decade-,.-in-range-.-focus-.air-datepicker-cell.-day-.-other-month-{background-color:var(--adp-background-color-in-range-focused)}.air-datepicker-cell.-year-.-other-decade-:empty,.air-datepicker-cell.-day-.-other-month-:empty{background:none;border:none}.air-datepicker-cell{border-radius:var(--adp-cell-border-radius);box-sizing:border-box;cursor:pointer;display:flex;position:relative;align-items:center;justify-content:center;z-index:1}.air-datepicker-cell.-focus-{background:var(--adp-cell-background-color-hover)}.air-datepicker-cell.-current-{color:var(--adp-color-current-date)}.air-datepicker-cell.-current-.-focus-{color:var(--adp-color)}.air-datepicker-cell.-current-.-in-range-{color:var(--adp-color-current-date)}.air-datepicker-cell.-disabled-{cursor:default;color:var(--adp-color-disabled)}.air-datepicker-cell.-disabled-.-focus-{color:var(--adp-color-disabled)}.air-datepicker-cell.-disabled-.-in-range-{color:var(--adp-color-disabled-in-range)}.air-datepicker-cell.-disabled-.-current-.-focus-{color:var(--adp-color-disabled)}.air-datepicker-cell.-in-range-{background:var(--adp-cell-background-color-in-range);border-radius:0}.air-datepicker-cell.-in-range-:hover{background:var(--adp-cell-background-color-in-range-hover)}.air-datepicker-cell.-range-from-{border:1px solid var(--adp-cell-border-color-in-range);background-color:var(--adp-cell-background-color-in-range);border-radius:var(--adp-cell-border-radius) 0 0 var(--adp-cell-border-radius)}.air-datepicker-cell.-range-to-{border:1px solid var(--adp-cell-border-color-in-range);background-color:var(--adp-cell-background-color-in-range);border-radius:0 var(--adp-cell-border-radius) var(--adp-cell-border-radius) 0}.air-datepicker-cell.-range-to-.-range-from-{border-radius:var(--adp-cell-border-radius)}.air-datepicker-cell.-selected-{color:#fff;border:none;background:var(--adp-cell-background-color-selected)}.air-datepicker-cell.-selected-.-current-{color:#fff;background:var(--adp-cell-background-color-selected)}.air-datepicker-cell.-selected-.-focus-{background:var(--adp-cell-background-color-selected-hover)}
7
+ .air-datepicker-body{transition:all var(--adp-transition-duration) var(--adp-transition-ease)}.air-datepicker-body.-hidden-{display:none}.air-datepicker-body--day-names{display:grid;grid-template-columns:repeat(7, var(--adp-day-cell-width));margin:8px 0 3px}.air-datepicker-body--day-name{color:var(--adp-day-name-color);display:flex;align-items:center;justify-content:center;flex:1;text-align:center;text-transform:uppercase;font-size:.8em}.air-datepicker-body--day-name.-clickable-{cursor:pointer}.air-datepicker-body--day-name.-clickable-:hover{color:var(--adp-day-name-color-hover)}.air-datepicker-body--cells{display:grid}.air-datepicker-body--cells.-days-{grid-template-columns:repeat(7, var(--adp-day-cell-width));grid-auto-rows:var(--adp-day-cell-height)}.air-datepicker-body--cells.-months-{grid-template-columns:repeat(3, 1fr);grid-auto-rows:var(--adp-month-cell-height)}.air-datepicker-body--cells.-years-{grid-template-columns:repeat(4, 1fr);grid-auto-rows:var(--adp-year-cell-height)}
8
+ .air-datepicker-nav{display:flex;justify-content:space-between;border-bottom:1px solid var(--adp-border-color-inner);min-height:var(--adp-nav-height);padding:var(--adp-padding);box-sizing:content-box}.-only-timepicker- .air-datepicker-nav{display:none}.air-datepicker-nav--title,.air-datepicker-nav--action{display:flex;cursor:pointer;align-items:center;justify-content:center}.air-datepicker-nav--action{width:var(--adp-nav-action-size);border-radius:var(--adp-border-radius);-webkit-user-select:none;-moz-user-select:none;user-select:none}.air-datepicker-nav--action:hover{background:var(--adp-background-color-hover)}.air-datepicker-nav--action:active{background:var(--adp-background-color-active)}.air-datepicker-nav--action.-disabled-{visibility:hidden}.air-datepicker-nav--action svg{width:32px;height:32px}.air-datepicker-nav--action path{fill:none;stroke:var(--adp-nav-arrow-color);stroke-width:2px}.air-datepicker-nav--title{border-radius:var(--adp-border-radius);padding:0 8px}.air-datepicker-nav--title i{font-style:normal;color:var(--adp-nav-color-secondary);margin-left:.3em}.air-datepicker-nav--title:hover{background:var(--adp-background-color-hover)}.air-datepicker-nav--title:active{background:var(--adp-background-color-active)}.air-datepicker-nav--title.-disabled-{cursor:default;background:none}
9
+ .air-datepicker-buttons{display:grid;grid-auto-columns:1fr;grid-auto-flow:column}.air-datepicker-button{display:inline-flex;color:var(--adp-btn-color);border-radius:var(--adp-btn-border-radius);cursor:pointer;height:var(--adp-btn-height);border:none;background:rgba(255,255,255,0)}.air-datepicker-button:hover{color:var(--adp-btn-color-hover);background:var(--adp-btn-background-color-hover)}.air-datepicker-button:focus{color:var(--adp-btn-color-hover);background:var(--adp-btn-background-color-hover);outline:none}.air-datepicker-button:active{background:var(--adp-btn-background-color-active)}.air-datepicker-button span{outline:none;display:flex;align-items:center;justify-content:center;width:100%;height:100%}
10
+ .air-datepicker-time{display:grid;grid-template-columns:max-content 1fr;grid-column-gap:12px;align-items:center;position:relative;padding:0 var(--adp-time-padding-inner)}.-only-timepicker- .air-datepicker-time{border-top:none}.air-datepicker-time--current{display:flex;align-items:center;flex:1;font-size:14px;text-align:center}.air-datepicker-time--current-colon{margin:0 2px 3px;line-height:1}.air-datepicker-time--current-hours,.air-datepicker-time--current-minutes{line-height:1;font-size:19px;font-family:"Century Gothic",CenturyGothic,AppleGothic,sans-serif;position:relative;z-index:1}.air-datepicker-time--current-hours:after,.air-datepicker-time--current-minutes:after{content:"";background:var(--adp-background-color-hover);border-radius:var(--adp-border-radius);position:absolute;left:-2px;top:-3px;right:-2px;bottom:-2px;z-index:-1;opacity:0}.air-datepicker-time--current-hours.-focus-:after,.air-datepicker-time--current-minutes.-focus-:after{opacity:1}.air-datepicker-time--current-ampm{text-transform:uppercase;align-self:flex-end;color:var(--adp-time-day-period-color);margin-left:6px;font-size:11px;margin-bottom:1px}.air-datepicker-time--row{display:flex;align-items:center;font-size:11px;height:17px;background:linear-gradient(to right, var(--adp-time-track-color), var(--adp-time-track-color)) left 50%/100% var(--adp-time-track-height) no-repeat}.air-datepicker-time--row:first-child{margin-bottom:4px}.air-datepicker-time--row input[type=range]{background:none;cursor:pointer;flex:1;height:100%;width:100%;padding:0;margin:0;-webkit-appearance:none}.air-datepicker-time--row input[type=range]::-webkit-slider-thumb{-webkit-appearance:none}.air-datepicker-time--row input[type=range]::-ms-tooltip{display:none}.air-datepicker-time--row input[type=range]:hover::-webkit-slider-thumb{border-color:var(--adp-time-track-color-hover)}.air-datepicker-time--row input[type=range]:hover::-moz-range-thumb{border-color:var(--adp-time-track-color-hover)}.air-datepicker-time--row input[type=range]:hover::-ms-thumb{border-color:var(--adp-time-track-color-hover)}.air-datepicker-time--row input[type=range]:focus{outline:none}.air-datepicker-time--row input[type=range]:focus::-webkit-slider-thumb{background:var(--adp-cell-background-color-selected);border-color:var(--adp-cell-background-color-selected)}.air-datepicker-time--row input[type=range]:focus::-moz-range-thumb{background:var(--adp-cell-background-color-selected);border-color:var(--adp-cell-background-color-selected)}.air-datepicker-time--row input[type=range]:focus::-ms-thumb{background:var(--adp-cell-background-color-selected);border-color:var(--adp-cell-background-color-selected)}.air-datepicker-time--row input[type=range]::-webkit-slider-thumb{box-sizing:border-box;height:12px;width:12px;border-radius:3px;border:1px solid var(--adp-time-track-color);background:#fff;cursor:pointer;-webkit-transition:background var(--adp-transition-duration);transition:background var(--adp-transition-duration)}.air-datepicker-time--row input[type=range]::-moz-range-thumb{box-sizing:border-box;height:12px;width:12px;border-radius:3px;border:1px solid var(--adp-time-track-color);background:#fff;cursor:pointer;-moz-transition:background var(--adp-transition-duration);transition:background var(--adp-transition-duration)}.air-datepicker-time--row input[type=range]::-ms-thumb{box-sizing:border-box;height:12px;width:12px;border-radius:3px;border:1px solid var(--adp-time-track-color);background:#fff;cursor:pointer;-ms-transition:background var(--adp-transition-duration);transition:background var(--adp-transition-duration)}.air-datepicker-time--row input[type=range]::-webkit-slider-thumb{margin-top:calc(var(--adp-time-thumb-size)/2*-1)}.air-datepicker-time--row input[type=range]::-webkit-slider-runnable-track{border:none;height:var(--adp-time-track-height);cursor:pointer;color:rgba(0,0,0,0);background:rgba(0,0,0,0)}.air-datepicker-time--row input[type=range]::-moz-range-track{border:none;height:var(--adp-time-track-height);cursor:pointer;color:rgba(0,0,0,0);background:rgba(0,0,0,0)}.air-datepicker-time--row input[type=range]::-ms-track{border:none;height:var(--adp-time-track-height);cursor:pointer;color:rgba(0,0,0,0);background:rgba(0,0,0,0)}.air-datepicker-time--row input[type=range]::-ms-fill-lower{background:rgba(0,0,0,0)}.air-datepicker-time--row input[type=range]::-ms-fill-upper{background:rgba(0,0,0,0)}
11
+ .air-datepicker{--adp-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--adp-font-size: 14px;--adp-width: 246px;--adp-z-index: 100;--adp-padding: 4px;--adp-grid-areas: "nav" "body" "timepicker" "buttons";--adp-transition-duration: .3s;--adp-transition-ease: ease-out;--adp-transition-offset: 8px;--adp-background-color: #fff;--adp-background-color-hover: #f0f0f0;--adp-background-color-active: #eaeaea;--adp-background-color-in-range: rgba(92, 196, 239, .1);--adp-background-color-in-range-focused: rgba(92, 196, 239, .2);--adp-background-color-selected-other-month-focused: #8ad5f4;--adp-background-color-selected-other-month: #a2ddf6;--adp-color: #4a4a4a;--adp-color-secondary: #9c9c9c;--adp-accent-color: #4eb5e6;--adp-color-current-date: var(--adp-accent-color);--adp-color-other-month: #dedede;--adp-color-disabled: #aeaeae;--adp-color-disabled-in-range: #939393;--adp-color-other-month-hover: #c5c5c5;--adp-border-color: #dbdbdb;--adp-border-color-inner: #efefef;--adp-border-radius: 4px;--adp-border-color-inline: #d7d7d7;--adp-nav-height: 32px;--adp-nav-arrow-color: var(--adp-color-secondary);--adp-nav-action-size: 32px;--adp-nav-color-secondary: var(--adp-color-secondary);--adp-day-name-color: #ff9a19;--adp-day-name-color-hover: #8ad5f4;--adp-day-cell-width: 1fr;--adp-day-cell-height: 32px;--adp-month-cell-height: 42px;--adp-year-cell-height: 56px;--adp-pointer-size: 10px;--adp-poiner-border-radius: 2px;--adp-pointer-offset: 14px;--adp-cell-border-radius: 4px;--adp-cell-background-color-hover: var(--adp-background-color-hover);--adp-cell-background-color-selected: #5cc4ef;--adp-cell-background-color-selected-hover: #45bced;--adp-cell-background-color-in-range: rgba(92, 196, 239, 0.1);--adp-cell-background-color-in-range-hover: rgba(92, 196, 239, 0.2);--adp-cell-border-color-in-range: var(--adp-cell-background-color-selected);--adp-btn-height: 32px;--adp-btn-color: var(--adp-accent-color);--adp-btn-color-hover: var(--adp-color);--adp-btn-border-radius: var(--adp-border-radius);--adp-btn-background-color-hover: var(--adp-background-color-hover);--adp-btn-background-color-active: var(--adp-background-color-active);--adp-time-track-height: 1px;--adp-time-track-color: #dedede;--adp-time-track-color-hover: #b1b1b1;--adp-time-thumb-size: 12px;--adp-time-padding-inner: 10px;--adp-time-day-period-color: var(--adp-color-secondary);--adp-mobile-font-size: 16px;--adp-mobile-nav-height: 40px;--adp-mobile-width: 320px;--adp-mobile-day-cell-height: 38px;--adp-mobile-month-cell-height: 48px;--adp-mobile-year-cell-height: 64px}.air-datepicker-overlay{--adp-overlay-background-color: rgba(0, 0, 0, .3);--adp-overlay-transition-duration: .3s;--adp-overlay-transition-ease: ease-out;--adp-overlay-z-index: 99}
12
+ .air-datepicker{background:var(--adp-background-color);border:1px solid var(--adp-border-color);box-shadow:0 4px 12px rgba(0,0,0,.15);border-radius:var(--adp-border-radius);box-sizing:content-box;display:grid;grid-template-columns:1fr;grid-template-rows:repeat(4, max-content);grid-template-areas:var(--adp-grid-areas);font-family:var(--adp-font-family),sans-serif;font-size:var(--adp-font-size);color:var(--adp-color);width:var(--adp-width);position:absolute;transition:opacity var(--adp-transition-duration) var(--adp-transition-ease),transform var(--adp-transition-duration) var(--adp-transition-ease);z-index:var(--adp-z-index)}.air-datepicker:not(.-custom-position-){opacity:0}.air-datepicker.-from-top-{transform:translateY(calc(var(--adp-transition-offset) * -1))}.air-datepicker.-from-right-{transform:translateX(var(--adp-transition-offset))}.air-datepicker.-from-bottom-{transform:translateY(var(--adp-transition-offset))}.air-datepicker.-from-left-{transform:translateX(calc(var(--adp-transition-offset) * -1))}.air-datepicker.-active-:not(.-custom-position-){transform:translate(0, 0);opacity:1}.air-datepicker.-active-.-custom-position-{transition:none}.air-datepicker.-inline-{border-color:var(--adp-border-color-inline);box-shadow:none;position:static;left:auto;right:auto;opacity:1;transform:none}.air-datepicker.-inline- .air-datepicker--pointer{display:none}.air-datepicker.-is-mobile-{--adp-font-size: var(--adp-mobile-font-size);--adp-day-cell-height: var(--adp-mobile-day-cell-height);--adp-month-cell-height: var(--adp-mobile-month-cell-height);--adp-year-cell-height: var(--adp-mobile-year-cell-height);--adp-nav-height: var(--adp-mobile-nav-height);--adp-nav-action-size: var(--adp-mobile-nav-height);position:fixed;width:var(--adp-mobile-width);border:none}.air-datepicker.-is-mobile- *{-webkit-tap-highlight-color:rgba(0,0,0,0)}.air-datepicker.-is-mobile- .air-datepicker--pointer{display:none}.air-datepicker.-is-mobile-:not(.-custom-position-){transform:translate(-50%, calc(-50% + var(--adp-transition-offset)))}.air-datepicker.-is-mobile-.-active-:not(.-custom-position-){transform:translate(-50%, -50%)}.air-datepicker.-custom-position-{transition:none}.air-datepicker-global-container{position:absolute;left:0;top:0}.air-datepicker--pointer{--pointer-half-size: calc(var(--adp-pointer-size) / 2);position:absolute;width:var(--adp-pointer-size);height:var(--adp-pointer-size);z-index:-1}.air-datepicker--pointer:after{content:"";position:absolute;background:#fff;border-top:1px solid var(--adp-border-color-inline);border-right:1px solid var(--adp-border-color-inline);border-top-right-radius:var(--adp-poiner-border-radius);width:var(--adp-pointer-size);height:var(--adp-pointer-size);box-sizing:border-box}.-top-left- .air-datepicker--pointer,.-top-center- .air-datepicker--pointer,.-top-right- .air-datepicker--pointer,[data-popper-placement^=top] .air-datepicker--pointer{top:calc(100% - var(--pointer-half-size) + 1px)}.-top-left- .air-datepicker--pointer:after,.-top-center- .air-datepicker--pointer:after,.-top-right- .air-datepicker--pointer:after,[data-popper-placement^=top] .air-datepicker--pointer:after{transform:rotate(135deg)}.-right-top- .air-datepicker--pointer,.-right-center- .air-datepicker--pointer,.-right-bottom- .air-datepicker--pointer,[data-popper-placement^=right] .air-datepicker--pointer{right:calc(100% - var(--pointer-half-size) + 1px)}.-right-top- .air-datepicker--pointer:after,.-right-center- .air-datepicker--pointer:after,.-right-bottom- .air-datepicker--pointer:after,[data-popper-placement^=right] .air-datepicker--pointer:after{transform:rotate(225deg)}.-bottom-left- .air-datepicker--pointer,.-bottom-center- .air-datepicker--pointer,.-bottom-right- .air-datepicker--pointer,[data-popper-placement^=bottom] .air-datepicker--pointer{bottom:calc(100% - var(--pointer-half-size) + 1px)}.-bottom-left- .air-datepicker--pointer:after,.-bottom-center- .air-datepicker--pointer:after,.-bottom-right- .air-datepicker--pointer:after,[data-popper-placement^=bottom] .air-datepicker--pointer:after{transform:rotate(315deg)}.-left-top- .air-datepicker--pointer,.-left-center- .air-datepicker--pointer,.-left-bottom- .air-datepicker--pointer,[data-popper-placement^=left] .air-datepicker--pointer{left:calc(100% - var(--pointer-half-size) + 1px)}.-left-top- .air-datepicker--pointer:after,.-left-center- .air-datepicker--pointer:after,.-left-bottom- .air-datepicker--pointer:after,[data-popper-placement^=left] .air-datepicker--pointer:after{transform:rotate(45deg)}.-top-left- .air-datepicker--pointer,.-bottom-left- .air-datepicker--pointer{left:var(--adp-pointer-offset)}.-top-right- .air-datepicker--pointer,.-bottom-right- .air-datepicker--pointer{right:var(--adp-pointer-offset)}.-top-center- .air-datepicker--pointer,.-bottom-center- .air-datepicker--pointer{left:calc(50% - var(--adp-pointer-size)/2)}.-left-top- .air-datepicker--pointer,.-right-top- .air-datepicker--pointer{top:var(--adp-pointer-offset)}.-left-bottom- .air-datepicker--pointer,.-right-bottom- .air-datepicker--pointer{bottom:var(--adp-pointer-offset)}.-left-center- .air-datepicker--pointer,.-right-center- .air-datepicker--pointer{top:calc(50% - var(--adp-pointer-size)/2)}.air-datepicker--navigation{grid-area:nav}.air-datepicker--content{box-sizing:content-box;padding:var(--adp-padding);grid-area:body}.-only-timepicker- .air-datepicker--content{display:none}.air-datepicker--time{grid-area:timepicker}.air-datepicker--buttons{grid-area:buttons}.air-datepicker--buttons,.air-datepicker--time{padding:var(--adp-padding);border-top:1px solid var(--adp-border-color-inner)}.air-datepicker-overlay{position:fixed;background:var(--adp-overlay-background-color);left:0;top:0;width:0;height:0;opacity:0;transition:opacity var(--adp-overlay-transition-duration) var(--adp-overlay-transition-ease),left 0s,height 0s,width 0s;transition-delay:0s,var(--adp-overlay-transition-duration),var(--adp-overlay-transition-duration),var(--adp-overlay-transition-duration);z-index:var(--adp-overlay-z-index)}.air-datepicker-overlay.-active-{opacity:1;width:100%;height:100%;transition:opacity var(--adp-overlay-transition-duration) var(--adp-overlay-transition-ease),height 0s,width 0s}
@@ -0,0 +1,3 @@
1
+ <div class="alert alert-info" role="alert">
2
+ There are no topics partitions to display.
3
+ </div>
@@ -1,24 +1,22 @@
1
1
  <% topic = partition[:topic] %>
2
2
 
3
- <% if topic[:topic_name] != '__consumer_offsets' %>
4
- <tr>
5
- <td>
6
- <a href="<%= root_path('explorer', topic[:topic_name], 0) %>">
7
- <%= topic[:topic_name] %>
8
- </a>
9
- <td>
10
- <a href="<%= root_path('explorer', topic[:topic_name], partition[:partition_id]) %>">
11
- <%= partition[:partition_id] %>
12
- </a>
13
- </td>
14
- <td>
15
- <%= partition[:leader] %>
16
- </td>
17
- <td>
18
- <%= partition[:replica_count] %>
19
- </td>
20
- <td>
21
- <%= partition[:in_sync_replica_brokers] %>
22
- </td>
23
- </tr>
24
- <% end %>
3
+ <tr>
4
+ <td>
5
+ <a href="<%= explorer_path(topic[:topic_name]) %>">
6
+ <%= topic[:topic_name] %>
7
+ </a>
8
+ <td>
9
+ <a href="<%= explorer_path(topic[:topic_name], partition[:partition_id]) %>">
10
+ <%= partition[:partition_id] %>
11
+ </a>
12
+ </td>
13
+ <td>
14
+ <%= partition[:leader] %>
15
+ </td>
16
+ <td>
17
+ <%= partition[:replica_count] %>
18
+ </td>
19
+ <td>
20
+ <%= partition[:in_sync_replica_brokers] %>
21
+ </td>
22
+ </tr>
@@ -42,9 +42,13 @@
42
42
  <hr/>
43
43
  </div>
44
44
  </div>
45
-
46
45
  <div class="row">
47
46
  <div class="col-lg-12">
47
+ <% if @partitions.empty? && params.current_page <= 1 %>
48
+ <%== partial 'cluster/no_partitions' %>
49
+ <% elsif @partitions.empty? %>
50
+ <%== partial 'shared/no_paginated_data' %>
51
+ <% else %>
48
52
  <table class="processes bg-white table table-hover table-bordered table-striped">
49
53
  <thead>
50
54
  <tr class="align-middle">
@@ -64,6 +68,7 @@
64
68
  %>
65
69
  </tbody>
66
70
  </table>
71
+ <% end %>
67
72
  </div>
68
73
  </div>
69
74
  </div>
@@ -38,7 +38,7 @@
38
38
 
39
39
  <td>
40
40
  <span class="badge bg-primary badge-topic">
41
- <%= process.concurrency %> /
41
+ <%= process.workers %> /
42
42
  <%= process.busy %>
43
43
  </span>
44
44
  </td>
@@ -14,12 +14,14 @@
14
14
  <div class="desc">Batches</div>
15
15
  </li>
16
16
  <li class="col-sm">
17
- <div class="count mb-1"><%= @processes.sum(&:lag_stored) %></div>
18
- <div class="desc">Lag</div>
17
+ <div class="count mb-1"><%= @counters.lag_stored %></div>
18
+ <div class="desc">Lag stored</div>
19
19
  </li>
20
20
  <li class="col-sm">
21
- <div class="count mb-1"><%= @counters.busy %></div>
22
- <div class="desc">Busy</div>
21
+ <a href="<%= root_path('jobs') %>">
22
+ <div class="count mb-1"><%= @counters.busy %></div>
23
+ <div class="desc">Busy</div>
24
+ </a>
23
25
  </li>
24
26
  <li class="col-sm">
25
27
  <div class="count mb-1"><%= @counters.enqueued %></div>
@@ -21,10 +21,10 @@
21
21
  <div class="card-body">
22
22
  <p class="card-text">
23
23
  <div class="stat mb-1">
24
- <%= @counters.threads_count %>
24
+ <%= @counters.workers %>
25
25
  </div>
26
26
  <div class="desc">
27
- Worker threads
27
+ Workers
28
28
  </div>
29
29
  </p>
30
30
  </div>
@@ -36,7 +36,7 @@
36
36
  <div class="card-body">
37
37
  <p class="card-text">
38
38
  <div class="stat mb-1">
39
- <%= @counters.listeners_count %>
39
+ <%= @counters.listeners %>
40
40
  </div>
41
41
  <div class="desc">
42
42
  Listeners
@@ -4,8 +4,10 @@
4
4
  <div class="container">
5
5
  <div class="row">
6
6
  <div class="col-sm-12">
7
- <% if @processes.empty? %>
7
+ <% if @processes.empty? && params.current_page <= 1 %>
8
8
  <%== partial 'consumers/no_consumers' %>
9
+ <% elsif @processes.empty? %>
10
+ <%== partial 'shared/no_paginated_data' %>
9
11
  <% else %>
10
12
  <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
11
13
  <thead>
@@ -0,0 +1,3 @@
1
+ <div class="mt-3">
2
+ <%== partial 'shared/feature_pro' %>
3
+ </div>
@@ -0,0 +1,15 @@
1
+ <div class="container">
2
+ <div class="row">
3
+ <div class="col-sm-12">
4
+ <div class="alert alert-info" role="alert">
5
+ <p>
6
+ There needs to be more data to draw meaningful graphs.
7
+ </p>
8
+
9
+ <p class="mb-0">
10
+ If you are sure you are running at least one <code>karafka server</code> instance and you do not see charts in a few minutes, please ensure that it can report to the <code><%= Karafka::Web.config.topics.consumers.reports %></code> topic and that Web-UI is correctly installed.
11
+ </p>
12
+ </div>
13
+ </div>
14
+ </div>
15
+ </div>
@@ -0,0 +1,23 @@
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
+ <a type="button" href="<%= root_path('dashboard') %>" class="btn btn-outline-primary active">
6
+ 5 minutes
7
+ </a>
8
+
9
+ <a type="button" href="#" class="btn btn-outline-primary disabled" title="Pro feature">
10
+ <s>1 hour</s>
11
+ </a>
12
+
13
+ <a type="button" href="#" class="btn btn-outline-primary disabled" title="Pro feature">
14
+ <s>24 hours</s>
15
+ </a>
16
+
17
+ <a type="button" href="#" class="btn btn-outline-primary disabled" title="Pro feature">
18
+ <s>7 days</s>
19
+ </a>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ </div>
@@ -0,0 +1,95 @@
1
+ <%
2
+ # Generates a nice set of semi-random data that does not change more often than once every
3
+ # 24 hours not to make OSS users angry
4
+ rand = Random.new(Date.today.to_time.to_i)
5
+ baseline = Date.today.strftime('%m').to_i + 2
6
+ set = ->(modifier = 0, range = (-2..2)) do
7
+ Array.new(60) { |i| [i, baseline + rand.rand(range) + modifier] }
8
+ end
9
+ %>
10
+
11
+ <%== partial 'consumers/counters' %>
12
+
13
+ <% if @aggregated.sufficient? %>
14
+ <%== partial 'dashboard/ranges_selector' %>
15
+
16
+ <div class="container">
17
+ <div class="row">
18
+ <div class="col-sm-12">
19
+ <h5 class="mb-3">Processing metrics</h5>
20
+
21
+ <hr class="mb-4"/>
22
+
23
+ <ul class="nav nav-tabs" id="graphs1" role="tablist">
24
+ <%== partial 'shared/tab_nav', locals: { title: 'Messages', id: 'messages', active: true } %>
25
+ <%== partial 'shared/tab_nav', locals: { title: 'Batches', id: 'batches' } %>
26
+ <%== partial 'shared/tab_nav', locals: { title: 'Lags stored', id: 'lags-stored' } %>
27
+ <%== partial 'shared/tab_nav', locals: { title: 'Topics pace', id: 'topics-pace' } %>
28
+ </ul>
29
+
30
+ <div class="tab-content">
31
+ <div class="tab-pane show active" id="messages" role="tabpanel">
32
+ <% data = @aggregated_charts.with(:messages) %>
33
+ <%== partial 'shared/chart', locals: { data: data, id: 'messages' } %>
34
+ </div>
35
+
36
+ <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 } %>
40
+ </div>
41
+
42
+ <div class="tab-pane" id="lags-stored" role="tabpanel">
43
+ <%== partial 'dashboard/feature_pro' %>
44
+ <% data = { enqueued: set.call, busy: set.call }.to_json %>
45
+ <%== partial 'shared/chart', locals: { data: data, id: 'lags-stored', blurred: true } %>
46
+ </div>
47
+
48
+ <div class="tab-pane" id="topics-pace" role="tabpanel">
49
+ <%== partial 'dashboard/feature_pro' %>
50
+ <% data = { topic1: set.call(20), topic2: set.call(10), topic3: set.call(100) }.to_json %>
51
+ <%== partial 'shared/chart', locals: { data: data, id: 'topics-pace', blurred: true } %>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+
58
+ <div class="container">
59
+ <div class="row">
60
+ <div class="col-sm-12">
61
+ <h5 class="mb-3">Utilization metrics</h5>
62
+
63
+ <hr class="mb-4"/>
64
+
65
+ <ul class="nav nav-tabs" id="graphs2" role="tablist">
66
+ <%== partial 'shared/tab_nav', locals: { title: 'Utilization', id: 'utilization', active: true } %>
67
+ <%== partial 'shared/tab_nav', locals: { title: 'RSS', id: 'rss' } %>
68
+ <%== partial 'shared/tab_nav', locals: { title: 'Concurrency', id: 'concurrency' } %>
69
+ </ul>
70
+
71
+ <div class="tab-content">
72
+ <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 } %>
76
+ </div>
77
+
78
+ <div class="tab-pane show" id="rss" role="tabpanel">
79
+ <%== partial 'dashboard/feature_pro' %>
80
+ <% data = { rss: set.call(1_050), process_rss: set.call(1_000) }.to_json %>
81
+ <%== partial 'shared/chart', locals: { data: data, id: 'rss', blurred: true } %>
82
+ </div>
83
+
84
+ <div class="tab-pane show" id="concurrency" role="tabpanel">
85
+ <%== 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 } %>
88
+ </div>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ <% else %>
94
+ <%== partial 'dashboard/not_enough_data' %>
95
+ <% end %>
@@ -9,6 +9,18 @@
9
9
  ***
10
10
  <% elsif k2.to_s == 'tags' %>
11
11
  <%== tags(v2) %>
12
+ <% elsif k2.to_s == 'first_offset' %>
13
+ <a href="<%= explorer_path(v[:topic], v[:partition], v[:first_offset]) %>">
14
+ <%= v2 %>
15
+ </a>
16
+ <% elsif k2.to_s == 'last_offset' %>
17
+ <a href="<%= explorer_path(v[:topic], v[:partition], v[:last_offset]) %>">
18
+ <%= v2 %>
19
+ </a>
20
+ <% elsif k2.to_s == 'committed_offset' && v2 >=0 %>
21
+ <a href="<%= explorer_path(v[:topic], v[:partition], v[:committed_offset]) %>">
22
+ <%= v2 %>
23
+ </a>
12
24
  <% else %>
13
25
  <%= v2 %>
14
26
  <% end %>
@@ -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] %>
@@ -49,7 +49,7 @@
49
49
  <%== partial 'shared/feature_pro' %>
50
50
  </div>
51
51
 
52
- <div class="row mb-4">
52
+ <div class="row mb-5">
53
53
  <div class="col-sm-12">
54
54
  <div class="card">
55
55
  <div class="card-body">
@@ -1,7 +1,9 @@
1
1
  <%== view_title('Running jobs', hr: true) %>
2
2
 
3
- <% if @jobs.empty? %>
3
+ <% if @jobs.empty? && params.current_page <= 1 %>
4
4
  <%== partial 'jobs/no_jobs' %>
5
+ <% elsif @jobs.empty? %>
6
+ <%== partial 'shared/no_paginated_data' %>
5
7
  <% else %>
6
8
  <div class="container">
7
9
  <div class="row mb-5">
@@ -9,15 +9,22 @@
9
9
  <%== yield %>
10
10
  <% else %>
11
11
  <nav class="navbar navbar-expand-lg navbar-dark shadow-sm mb-4">
12
- <div class="container">
12
+ <div class="container-fluid">
13
13
  <%== partial 'shared/brand' %>
14
14
  <%== partial 'shared/navigation' %>
15
+ <%== partial 'shared/live_poll' %>
15
16
  </div>
16
17
  </nav>
17
18
 
18
- <%== partial 'shared/become_pro' %>
19
+ <main>
20
+ <%== partial 'shared/become_pro' %>
19
21
 
20
- <%== partial 'shared/content', locals: { content: yield } %>
22
+ <%== partial 'shared/flashes' %>
23
+
24
+ <%== partial 'shared/content', locals: { content: yield } %>
25
+ </main>
26
+
27
+ <%== partial 'shared/footer' %>
21
28
  <% end %>
22
29
  </body>
23
30
  </html>
@@ -1,8 +1,8 @@
1
1
  <div class="row mb-4">
2
2
  <div class="col-sm-12">
3
- <h5 class="mb-2">
3
+ <h4 class="mb-2">
4
4
  <%= consumer_group.id %>
5
- </h5>
5
+ </h4>
6
6
  <hr/>
7
7
  </div>
8
8
  </div>
@@ -19,12 +19,14 @@
19
19
  </tr>
20
20
  </thead>
21
21
  <tbody>
22
- <% consumer_group.subscription_groups.each do |subscription_group| %>
22
+ <% consumer_group.topics.each do |topic| %>
23
23
  <%==
24
- each_partial(
25
- subscription_group.topics,
24
+ partial(
26
25
  'routing/topic',
27
- locals: { subscription_group: subscription_group }
26
+ locals: {
27
+ subscription_group: topic.subscription_group,
28
+ topic: topic
29
+ }
28
30
  )
29
31
  %>
30
32
  <% end %>
@@ -1,5 +1,5 @@
1
- <% if v.is_a?(Hash) %>
2
- <% v.each do |k2, v2| %>
1
+ <% if v.is_a?(Hash) || v.respond_to?(:to_h) %>
2
+ <% v.to_h.each do |k2, v2| %>
3
3
  <tr>
4
4
  <td>
5
5
  <%= "#{k}.#{k2}" %>
@@ -1,6 +1,6 @@
1
1
  <tr>
2
2
  <td>
3
- <%= subscription_group.id %>
3
+ <%= subscription_group %>
4
4
  </td>
5
5
  <td>
6
6
  <%= topic.name %>
@@ -8,7 +8,7 @@
8
8
  <div class="col-sm-12">
9
9
  <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
10
10
  <tbody>
11
- <% @topic.to_h.each do |k, v| %>
11
+ <% flat_hash(@topic.to_h).each do |k, v| %>
12
12
  <%==
13
13
  partial(
14
14
  'routing/detail',
@@ -1,3 +1,3 @@
1
- <a class="navbar-brand" href="<%= root_path %>">
2
- <img src="<%= root_path('images/logo.svg') %>" alt="Karafka" height="20" width="95" class="d-inline-block align-text-top"/>
1
+ <a class="navbar-brand ms-4" href="<%= root_path %>">
2
+ <img src="<%= asset_path('images/logo.svg') %>" alt="Karafka" height="20" width="95" class="d-inline-block align-text-top"/>
3
3
  </a>
@@ -0,0 +1,14 @@
1
+ <%
2
+ blurred ||= false
3
+ label_type_y ||= 'numerical'
4
+ label_type_x ||= 'date'
5
+ %>
6
+ <div class="mt-4 chartjs-wrapper">
7
+ <canvas
8
+ id="<%= id %>-chart"
9
+ class="chartjs <%= 'blurred' if blurred %>"
10
+ data-datasets="<%= data %>"
11
+ data-label_type_y="<%= label_type_y %>"
12
+ data-label_type_x="<%= label_type_x %>"
13
+ ></canvas>
14
+ </div>
@@ -1,5 +1,5 @@
1
1
  <div id="content">
2
- <main class="mb-5">
2
+ <div class="mb-4">
3
3
  <% if @breadcrumbs != false %>
4
4
  <div class="container mb-5">
5
5
  <nav aria-label="breadcrumb">
@@ -25,7 +25,7 @@
25
25
  <% end %>
26
26
 
27
27
  <%== content %>
28
- </main>
28
+ </div>
29
29
 
30
30
  <%== partial 'shared/pagination' %>
31
31
  </div>
@@ -1,4 +1,4 @@
1
1
  <div class="alert alert-light">
2
- This Web UI feature is available only to <a target="_blank" href="https://karafka.io/#become-pro">Pro</a>
2
+ This feature is available only to <a target="_blank" href="https://karafka.io/#become-pro">Pro</a>
3
3
  users.
4
4
  </div>
@@ -0,0 +1,9 @@
1
+ <% flash.each do |name, message| %>
2
+ <div class="mb-4">
3
+ <div class="container">
4
+ <p class="alert alert-<%= name %>">
5
+ <%= message %>
6
+ </p>
7
+ </div>
8
+ </div>
9
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <div class="container">
2
+ <footer class="footer mt-auto d-flex flex-wrap justify-content-between align-items-center pt-4 py-3 my-3 ps-3 pe-3 border-top">
3
+ <div class="col-md-4 d-flex align-items-center">
4
+ <a href="https://karafka.io" class="mb-3 me-2 mb-md-0 text-muted text-decoration-none lh-1">
5
+ <img src="<%= asset_path('images/logo-gray.svg') %>" style="max-width: 80px; margin-top: -5px">
6
+ </a>
7
+
8
+ <span class="text-muted">
9
+ &#169;
10
+ 2015 -
11
+ <%= Date.today.year %>
12
+ <a href="https://mensfeld.pl" class="text-muted">Maciej Mensfeld</a>
13
+ </span>
14
+ </div>
15
+
16
+ <ul class="nav col-md-4 justify-content-end list-unstyled d-flex">
17
+ <li class="ms-3"><a class="text-muted" href="https://karafka.io/docs">Docs</a></li>
18
+ <li class="ms-3"><a class="text-muted" href="https://karafka.io/#support">Support</a></li>
19
+ <li class="ms-3"><a class="text-muted" href="https://github.com/karafka/karafka">Github</a></li>
20
+ </ul>
21
+ </footer>
22
+ </div>