karafka-web 0.9.2 → 0.10.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/workflows/ci.yml +30 -0
  4. data/.gitignore +2 -0
  5. data/.ruby-version +1 -1
  6. data/CHANGELOG.md +84 -3
  7. data/Gemfile +1 -0
  8. data/Gemfile.lock +30 -25
  9. data/LICENSE +1 -1
  10. data/bin/build_assets +51 -0
  11. data/bin/release +6 -0
  12. data/config/locales/pro_errors.yml +18 -0
  13. data/docker-compose.yml +1 -1
  14. data/gulpfile.js +73 -0
  15. data/karafka-web.gemspec +7 -2
  16. data/lib/karafka/web/config.rb +9 -10
  17. data/lib/karafka/web/contracts/base.rb +2 -0
  18. data/lib/karafka/web/contracts/config.rb +2 -1
  19. data/lib/karafka/web/errors.rb +12 -0
  20. data/lib/karafka/web/inflector.rb +1 -1
  21. data/lib/karafka/web/management/actions/enable.rb +11 -0
  22. data/lib/karafka/web/management/migrations/consumers_metrics/0_set_initial.rb +39 -0
  23. data/lib/karafka/web/management/migrations/consumers_metrics/1699543515_fill_missing_received_and_sent_bytes.rb +28 -0
  24. data/lib/karafka/web/management/migrations/consumers_metrics/1700234522_introduce_waiting.rb +26 -0
  25. data/lib/karafka/web/management/migrations/consumers_metrics/1700234522_remove_processing.rb +26 -0
  26. data/lib/karafka/web/management/migrations/consumers_metrics/1704722380_split_listeners_into_active_and_paused.rb +38 -0
  27. data/lib/karafka/web/management/migrations/consumers_metrics/1706607960_introduce_lag_total.rb +40 -0
  28. data/lib/karafka/web/management/migrations/consumers_metrics/1706611396_rename_lag_total_to_lag_hybrid.rb +38 -0
  29. data/lib/karafka/web/management/migrations/consumers_metrics/1716218393_populate_jobs_metrics.rb +26 -0
  30. data/lib/karafka/web/management/migrations/consumers_states/0_set_initial.rb +46 -0
  31. data/lib/karafka/web/management/migrations/consumers_states/1699543515_fill_missing_received_and_sent_bytes.rb +25 -0
  32. data/lib/karafka/web/management/migrations/consumers_states/1700234522_introduce_waiting.rb +22 -0
  33. data/lib/karafka/web/management/migrations/consumers_states/1700234522_remove_processing.rb +22 -0
  34. data/lib/karafka/web/management/migrations/consumers_states/1704722380_split_listeners_into_active_and_paused.rb +34 -0
  35. data/lib/karafka/web/management/migrations/consumers_states/1706607960_introduce_lag_total.rb +24 -0
  36. data/lib/karafka/web/management/migrations/consumers_states/1706611396_rename_lag_total_to_lag_hybrid.rb +23 -0
  37. data/lib/karafka/web/management/migrations/consumers_states/1716218393_add_jobs_counter.rb +24 -0
  38. data/lib/karafka/web/management/migrator.rb +5 -5
  39. data/lib/karafka/web/pro/commanding/commands/base.rb +8 -0
  40. data/lib/karafka/web/pro/commanding/commands/quiet.rb +4 -1
  41. data/lib/karafka/web/pro/commanding/commands/stop.rb +4 -1
  42. data/lib/karafka/web/pro/loader.rb +8 -0
  43. data/lib/karafka/web/pro/ui/app.rb +44 -7
  44. data/lib/karafka/web/pro/ui/controllers/dlq_controller.rb +1 -1
  45. data/lib/karafka/web/pro/ui/controllers/errors_controller.rb +1 -0
  46. data/lib/karafka/web/pro/ui/controllers/explorer_controller.rb +6 -14
  47. data/lib/karafka/web/pro/ui/controllers/messages_controller.rb +5 -4
  48. data/lib/karafka/web/pro/ui/controllers/search_controller.rb +73 -0
  49. data/lib/karafka/web/pro/ui/controllers/support_controller.rb +26 -0
  50. data/lib/karafka/web/pro/ui/controllers/topics_controller.rb +31 -0
  51. data/lib/karafka/web/pro/ui/controllers/ux_controller.rb +26 -0
  52. data/lib/karafka/web/pro/ui/lib/policies/config.rb +39 -0
  53. data/lib/karafka/web/pro/ui/lib/policies/contracts/config.rb +46 -0
  54. data/lib/karafka/web/pro/ui/lib/policies/messages.rb +76 -0
  55. data/lib/karafka/web/pro/ui/lib/policies/requests.rb +36 -0
  56. data/lib/karafka/web/pro/ui/lib/policies.rb +34 -0
  57. data/lib/karafka/web/pro/ui/lib/safe_runner.rb +98 -0
  58. data/lib/karafka/web/pro/ui/lib/search/config.rb +53 -0
  59. data/lib/karafka/web/pro/ui/lib/search/contracts/config.rb +101 -0
  60. data/lib/karafka/web/pro/ui/lib/search/contracts/form.rb +111 -0
  61. data/lib/karafka/web/pro/ui/lib/search/matchers/base.rb +59 -0
  62. data/lib/karafka/web/pro/ui/lib/search/matchers/raw_header_includes.rb +57 -0
  63. data/lib/karafka/web/pro/ui/lib/search/matchers/raw_key_includes.rb +41 -0
  64. data/lib/karafka/web/pro/ui/lib/search/matchers/raw_payload_includes.rb +45 -0
  65. data/lib/karafka/web/pro/ui/lib/search/normalizer.rb +47 -0
  66. data/lib/karafka/web/pro/ui/lib/search/runner.rb +230 -0
  67. data/lib/karafka/web/pro/ui/lib/search.rb +36 -0
  68. data/lib/karafka/web/pro/ui/views/cluster/_breadcrumbs.erb +4 -4
  69. data/lib/karafka/web/pro/ui/views/cluster/_tabs.erb +14 -24
  70. data/lib/karafka/web/pro/ui/views/cluster/index.erb +20 -22
  71. data/lib/karafka/web/pro/ui/views/cluster/show.erb +21 -25
  72. data/lib/karafka/web/pro/ui/views/commands/_backtrace.erb +4 -19
  73. data/lib/karafka/web/pro/ui/views/commands/_breadcrumbs.erb +3 -3
  74. data/lib/karafka/web/pro/ui/views/commands/_command.erb +6 -6
  75. data/lib/karafka/web/pro/ui/views/commands/_command_details.erb +1 -11
  76. data/lib/karafka/web/pro/ui/views/commands/_incompatible_schema.erb +3 -14
  77. data/lib/karafka/web/pro/ui/views/commands/_metadata.erb +33 -42
  78. data/lib/karafka/web/pro/ui/views/commands/_table.erb +9 -3
  79. data/lib/karafka/web/pro/ui/views/commands/index.erb +18 -12
  80. data/lib/karafka/web/pro/ui/views/commands/show.erb +24 -29
  81. data/lib/karafka/web/pro/ui/views/consumers/_breadcrumbs.erb +8 -8
  82. data/lib/karafka/web/pro/ui/views/consumers/_consumer.erb +13 -23
  83. data/lib/karafka/web/pro/ui/views/consumers/_consumer_controls.erb +51 -35
  84. data/lib/karafka/web/pro/ui/views/consumers/_consumer_performance.erb +1 -1
  85. data/lib/karafka/web/pro/ui/views/consumers/_tabs.erb +28 -30
  86. data/lib/karafka/web/pro/ui/views/consumers/consumer/_commands.erb +68 -28
  87. data/lib/karafka/web/pro/ui/views/consumers/consumer/_job.erb +1 -1
  88. data/lib/karafka/web/pro/ui/views/consumers/consumer/_metrics.erb +114 -133
  89. data/lib/karafka/web/pro/ui/views/consumers/consumer/_partition.erb +4 -4
  90. data/lib/karafka/web/pro/ui/views/consumers/consumer/_stopped.erb +6 -9
  91. data/lib/karafka/web/pro/ui/views/consumers/consumer/_subscription_group.erb +116 -126
  92. data/lib/karafka/web/pro/ui/views/consumers/consumer/_tabs.erb +26 -31
  93. data/lib/karafka/web/pro/ui/views/consumers/controls.erb +53 -57
  94. data/lib/karafka/web/pro/ui/views/consumers/details.erb +4 -17
  95. data/lib/karafka/web/pro/ui/views/consumers/index.erb +31 -34
  96. data/lib/karafka/web/pro/ui/views/consumers/pending_jobs.erb +41 -46
  97. data/lib/karafka/web/pro/ui/views/consumers/performance.erb +43 -47
  98. data/lib/karafka/web/pro/ui/views/consumers/running_jobs.erb +41 -46
  99. data/lib/karafka/web/pro/ui/views/consumers/subscriptions.erb +14 -17
  100. data/lib/karafka/web/pro/ui/views/dashboard/index.erb +67 -76
  101. data/lib/karafka/web/pro/ui/views/dlq/_breadcrumbs.erb +1 -1
  102. data/lib/karafka/web/pro/ui/views/dlq/_no_topics.erb +1 -7
  103. data/lib/karafka/web/pro/ui/views/dlq/_topic.erb +7 -10
  104. data/lib/karafka/web/pro/ui/views/dlq/index.erb +8 -10
  105. data/lib/karafka/web/pro/ui/views/errors/_breadcrumbs.erb +3 -3
  106. data/lib/karafka/web/pro/ui/views/errors/_error.erb +8 -5
  107. data/lib/karafka/web/pro/ui/views/errors/_selector.erb +12 -0
  108. data/lib/karafka/web/pro/ui/views/errors/_table.erb +5 -4
  109. data/lib/karafka/web/pro/ui/views/errors/index.erb +50 -15
  110. data/lib/karafka/web/pro/ui/views/errors/partition.erb +61 -14
  111. data/lib/karafka/web/pro/ui/views/errors/show.erb +28 -46
  112. data/lib/karafka/web/pro/ui/views/explorer/_breadcrumbs.erb +11 -3
  113. data/lib/karafka/web/pro/ui/views/explorer/_failed_deserialization.erb +8 -3
  114. data/lib/karafka/web/pro/ui/views/explorer/_message.erb +12 -6
  115. data/lib/karafka/web/pro/ui/views/explorer/_no_topics.erb +1 -5
  116. data/lib/karafka/web/pro/ui/views/explorer/_selector.erb +12 -0
  117. data/lib/karafka/web/pro/ui/views/explorer/_topic.erb +6 -8
  118. data/lib/karafka/web/pro/ui/views/explorer/index.erb +13 -15
  119. data/lib/karafka/web/pro/ui/views/explorer/message/_metadata.erb +68 -32
  120. data/lib/karafka/web/pro/ui/views/explorer/message/_payload.erb +17 -16
  121. data/lib/karafka/web/pro/ui/views/explorer/message/_resources_utilization.erb +127 -0
  122. data/lib/karafka/web/pro/ui/views/explorer/message/_too_big_to_be_displayed.erb +20 -0
  123. data/lib/karafka/web/pro/ui/views/explorer/messages/_detail.erb +1 -1
  124. data/lib/karafka/web/pro/ui/views/explorer/partition/_cleaned.erb +3 -5
  125. data/lib/karafka/web/pro/ui/views/explorer/partition/_empty.erb +3 -5
  126. data/lib/karafka/web/pro/ui/views/explorer/partition/_messages.erb +6 -3
  127. data/lib/karafka/web/pro/ui/views/explorer/partition.erb +67 -46
  128. data/lib/karafka/web/pro/ui/views/explorer/show.erb +85 -21
  129. data/lib/karafka/web/pro/ui/views/explorer/topic/_actions.erb +27 -0
  130. data/lib/karafka/web/pro/ui/views/explorer/topic/_empty.erb +3 -5
  131. data/lib/karafka/web/pro/ui/views/explorer/topic/_limited.erb +8 -10
  132. data/lib/karafka/web/pro/ui/views/explorer/topic.erb +24 -44
  133. data/lib/karafka/web/pro/ui/views/health/_breadcrumbs.erb +7 -7
  134. data/lib/karafka/web/pro/ui/views/health/_no_data.erb +1 -7
  135. data/lib/karafka/web/pro/ui/views/health/_partition.erb +3 -3
  136. data/lib/karafka/web/pro/ui/views/health/_partition_lags.erb +3 -3
  137. data/lib/karafka/web/pro/ui/views/health/_partition_offset.erb +2 -2
  138. data/lib/karafka/web/pro/ui/views/health/_partition_times.erb +3 -7
  139. data/lib/karafka/web/pro/ui/views/health/_table_metadata.erb +8 -0
  140. data/lib/karafka/web/pro/ui/views/health/_tabs.erb +32 -49
  141. data/lib/karafka/web/pro/ui/views/health/changes.erb +51 -51
  142. data/lib/karafka/web/pro/ui/views/health/cluster_lags.erb +28 -41
  143. data/lib/karafka/web/pro/ui/views/health/lags.erb +52 -52
  144. data/lib/karafka/web/pro/ui/views/health/offsets.erb +55 -55
  145. data/lib/karafka/web/pro/ui/views/health/overview.erb +60 -60
  146. data/lib/karafka/web/pro/ui/views/jobs/_job.erb +1 -1
  147. data/lib/karafka/web/pro/ui/views/jobs/_no_jobs.erb +1 -7
  148. data/lib/karafka/web/pro/ui/views/jobs/pending.erb +36 -38
  149. data/lib/karafka/web/pro/ui/views/jobs/running.erb +36 -38
  150. data/lib/karafka/web/pro/ui/views/routing/_consumer_group.erb +7 -12
  151. data/lib/karafka/web/pro/ui/views/routing/_topic.erb +13 -11
  152. data/lib/karafka/web/pro/ui/views/routing/index.erb +7 -9
  153. data/lib/karafka/web/pro/ui/views/routing/show.erb +41 -33
  154. data/lib/karafka/web/pro/ui/views/search/_fix_errors.erb +3 -0
  155. data/lib/karafka/web/pro/ui/views/search/_metadata.erb +71 -0
  156. data/lib/karafka/web/pro/ui/views/search/_no_results.erb +3 -0
  157. data/lib/karafka/web/pro/ui/views/search/_no_search_criteria.erb +5 -0
  158. data/lib/karafka/web/pro/ui/views/search/_search_criteria.erb +37 -0
  159. data/lib/karafka/web/pro/ui/views/search/_search_modal.erb +139 -0
  160. data/lib/karafka/web/pro/ui/views/search/_timeout.erb +3 -0
  161. data/lib/karafka/web/pro/ui/views/search/index.erb +29 -0
  162. data/lib/karafka/web/pro/ui/views/shared/_navigation.erb +80 -28
  163. data/lib/karafka/web/pro/ui/views/topics/_breadcrumbs.erb +14 -6
  164. data/lib/karafka/web/pro/ui/views/topics/_partition_offsets.erb +10 -0
  165. data/lib/karafka/web/pro/ui/views/topics/_tabs.erb +26 -32
  166. data/lib/karafka/web/pro/ui/views/topics/_topic.erb +7 -10
  167. data/lib/karafka/web/pro/ui/views/topics/config.erb +21 -25
  168. data/lib/karafka/web/pro/ui/views/topics/distribution/_badges.erb +10 -5
  169. data/lib/karafka/web/pro/ui/views/topics/distribution/_chart.erb +3 -1
  170. data/lib/karafka/web/pro/ui/views/topics/distribution/_limited.erb +1 -1
  171. data/lib/karafka/web/pro/ui/views/topics/distribution.erb +34 -39
  172. data/lib/karafka/web/pro/ui/views/topics/index.erb +13 -15
  173. data/lib/karafka/web/pro/ui/views/topics/offsets.erb +24 -0
  174. data/lib/karafka/web/pro/ui/views/topics/replication.erb +20 -24
  175. data/lib/karafka/web/processing/consumers/aggregators/metrics.rb +1 -1
  176. data/lib/karafka/web/processing/consumers/aggregators/state.rb +1 -1
  177. data/lib/karafka/web/processing/consumers/contracts/aggregated_stats.rb +1 -0
  178. data/lib/karafka/web/tracking/consumers/contracts/report.rb +6 -0
  179. data/lib/karafka/web/tracking/consumers/listeners/connections.rb +8 -6
  180. data/lib/karafka/web/tracking/consumers/listeners/processing.rb +2 -0
  181. data/lib/karafka/web/tracking/consumers/listeners/tags.rb +1 -1
  182. data/lib/karafka/web/tracking/consumers/reporter.rb +6 -8
  183. data/lib/karafka/web/tracking/consumers/sampler.rb +16 -5
  184. data/lib/karafka/web/ui/app.rb +20 -1
  185. data/lib/karafka/web/ui/base.rb +26 -20
  186. data/lib/karafka/web/ui/controllers/base_controller.rb +6 -4
  187. data/lib/karafka/web/ui/controllers/dashboard_controller.rb +8 -0
  188. data/lib/karafka/web/ui/controllers/requests/params.rb +16 -2
  189. data/lib/karafka/web/ui/controllers/support_controller.rb +17 -0
  190. data/lib/karafka/web/ui/controllers/ux_controller.rb +17 -0
  191. data/lib/karafka/web/ui/helpers/application_helper.rb +75 -42
  192. data/lib/karafka/web/ui/helpers/paths_helper.rb +24 -0
  193. data/lib/karafka/web/ui/helpers/tailwind_helper.rb +90 -0
  194. data/lib/karafka/web/ui/lib/sorter.rb +1 -1
  195. data/lib/karafka/web/ui/models/metrics/aggregated.rb +1 -0
  196. data/lib/karafka/web/ui/models/metrics/charts/topics.rb +36 -20
  197. data/lib/karafka/web/ui/models/status.rb +28 -1
  198. data/lib/karafka/web/ui/public/images/calendar.svg +3 -0
  199. data/lib/karafka/web/ui/public/javascripts/application.js +39 -15
  200. data/lib/karafka/web/ui/public/javascripts/application.min.js +64 -0
  201. data/lib/karafka/web/ui/public/javascripts/application.min.js.br +0 -0
  202. data/lib/karafka/web/ui/public/javascripts/application.min.js.gz +0 -0
  203. data/lib/karafka/web/ui/public/javascripts/charts/types/line.js +41 -9
  204. data/lib/karafka/web/ui/public/javascripts/components/btn_toggle_manager.js +37 -0
  205. data/lib/karafka/web/ui/public/javascripts/{live_poll.js → components/live_poll.js} +44 -8
  206. data/lib/karafka/web/ui/public/javascripts/{offset_datetime.js → components/offset_datetime.js} +1 -1
  207. data/lib/karafka/web/ui/public/javascripts/components/search.js +102 -0
  208. data/lib/karafka/web/ui/public/javascripts/components/tabs_manager.js +84 -0
  209. data/lib/karafka/web/ui/public/javascripts/components/theme_manager.js +59 -0
  210. data/lib/karafka/web/ui/public/javascripts/components/turbo_tracker.js +30 -0
  211. data/lib/karafka/web/ui/public/javascripts/libs/datepicker.js +2 -2
  212. data/lib/karafka/web/ui/public/javascripts/libs/turbo.js +6618 -0
  213. data/lib/karafka/web/ui/public/stylesheets/application.css +16 -113
  214. data/lib/karafka/web/ui/public/stylesheets/application.min.css +13 -0
  215. data/lib/karafka/web/ui/public/stylesheets/application.min.css.br +0 -0
  216. data/lib/karafka/web/ui/public/stylesheets/application.min.css.gz +0 -0
  217. data/lib/karafka/web/ui/public/stylesheets/libs/highlight_dark.min.css +8 -0
  218. data/lib/karafka/web/ui/public/stylesheets/libs/highlight_dark.min.css.br +0 -0
  219. data/lib/karafka/web/ui/public/stylesheets/libs/highlight_dark.min.css.gz +0 -0
  220. data/lib/karafka/web/ui/public/stylesheets/libs/highlight_light.min.css.br +0 -0
  221. data/lib/karafka/web/ui/public/stylesheets/libs/highlight_light.min.css.gz +0 -0
  222. data/lib/karafka/web/ui/public/stylesheets/libs/tailwind.css +391 -0
  223. data/lib/karafka/web/ui/views/cluster/_breadcrumbs.erb +3 -3
  224. data/lib/karafka/web/ui/views/cluster/_tabs.erb +14 -24
  225. data/lib/karafka/web/ui/views/cluster/brokers.erb +20 -22
  226. data/lib/karafka/web/ui/views/cluster/replication.erb +28 -32
  227. data/lib/karafka/web/ui/views/consumers/_assignments_badges.erb +1 -1
  228. data/lib/karafka/web/ui/views/consumers/_breadcrumbs.erb +5 -0
  229. data/lib/karafka/web/ui/views/consumers/_consumer.erb +9 -13
  230. data/lib/karafka/web/ui/views/consumers/_no_consumers.erb +2 -8
  231. data/lib/karafka/web/ui/views/consumers/_summary.erb +34 -45
  232. data/lib/karafka/web/ui/views/consumers/_tabs.erb +35 -0
  233. data/lib/karafka/web/ui/views/consumers/index.erb +31 -33
  234. data/lib/karafka/web/ui/views/dashboard/_counters.erb +76 -0
  235. data/lib/karafka/web/ui/views/dashboard/_feature_pro.erb +6 -2
  236. data/lib/karafka/web/ui/views/dashboard/_not_enough_data.erb +3 -15
  237. data/lib/karafka/web/ui/views/dashboard/_ranges_selector.erb +12 -12
  238. data/lib/karafka/web/ui/views/dashboard/index.erb +78 -52
  239. data/lib/karafka/web/ui/views/errors/_breadcrumbs.erb +2 -2
  240. data/lib/karafka/web/ui/views/errors/_detail.erb +1 -3
  241. data/lib/karafka/web/ui/views/errors/_error.erb +3 -5
  242. data/lib/karafka/web/ui/views/errors/index.erb +34 -44
  243. data/lib/karafka/web/ui/views/errors/show.erb +29 -47
  244. data/lib/karafka/web/ui/views/jobs/_breadcrumbs.erb +3 -3
  245. data/lib/karafka/web/ui/views/jobs/_job.erb +1 -1
  246. data/lib/karafka/web/ui/views/jobs/_no_jobs.erb +1 -7
  247. data/lib/karafka/web/ui/views/jobs/_tabs.erb +14 -24
  248. data/lib/karafka/web/ui/views/jobs/pending.erb +30 -32
  249. data/lib/karafka/web/ui/views/jobs/running.erb +30 -32
  250. data/lib/karafka/web/ui/views/layout.erb +37 -21
  251. data/lib/karafka/web/ui/views/routing/_breadcrumbs.erb +2 -2
  252. data/lib/karafka/web/ui/views/routing/_consumer_group.erb +7 -12
  253. data/lib/karafka/web/ui/views/routing/_topic.erb +3 -5
  254. data/lib/karafka/web/ui/views/routing/index.erb +7 -9
  255. data/lib/karafka/web/ui/views/routing/show.erb +30 -22
  256. data/lib/karafka/web/ui/views/shared/_become_pro.erb +8 -8
  257. data/lib/karafka/web/ui/views/shared/_brand.erb +2 -2
  258. data/lib/karafka/web/ui/views/shared/_breadcrumbs.erb +23 -0
  259. data/lib/karafka/web/ui/views/shared/_content.erb +2 -28
  260. data/lib/karafka/web/ui/views/shared/_controls.erb +15 -0
  261. data/lib/karafka/web/ui/views/shared/_flashes.erb +5 -7
  262. data/lib/karafka/web/ui/views/shared/_header.erb +14 -19
  263. data/lib/karafka/web/ui/views/shared/_navigation.erb +84 -28
  264. data/lib/karafka/web/ui/views/shared/_no_paginated_data.erb +5 -9
  265. data/lib/karafka/web/ui/views/shared/_pagination.erb +11 -11
  266. data/lib/karafka/web/ui/views/shared/_tab_nav.erb +4 -5
  267. data/lib/karafka/web/ui/views/shared/_title.erb +5 -0
  268. data/lib/karafka/web/ui/views/shared/alerts/_box_error.erb +15 -0
  269. data/lib/karafka/web/ui/views/shared/alerts/_box_info.erb +15 -0
  270. data/lib/karafka/web/ui/views/shared/alerts/_box_primary.erb +15 -0
  271. data/lib/karafka/web/ui/views/shared/alerts/_box_secondary.erb +15 -0
  272. data/lib/karafka/web/ui/views/shared/alerts/_box_success.erb +15 -0
  273. data/lib/karafka/web/ui/views/shared/alerts/_box_warning.erb +15 -0
  274. data/lib/karafka/web/ui/views/shared/alerts/_error.erb +4 -0
  275. data/lib/karafka/web/ui/views/shared/alerts/_info.erb +5 -2
  276. data/lib/karafka/web/ui/views/shared/alerts/_primary.erb +4 -0
  277. data/lib/karafka/web/ui/views/shared/alerts/_secondary.erb +4 -0
  278. data/lib/karafka/web/ui/views/shared/alerts/_success.erb +4 -0
  279. data/lib/karafka/web/ui/views/shared/alerts/_warning.erb +4 -0
  280. data/lib/karafka/web/ui/views/shared/charts/_line.erb +1 -1
  281. data/lib/karafka/web/ui/views/shared/exceptions/not_allowed.erb +14 -19
  282. data/lib/karafka/web/ui/views/shared/exceptions/not_found.erb +16 -21
  283. data/lib/karafka/web/ui/views/shared/exceptions/pro_only.erb +16 -28
  284. data/lib/karafka/web/ui/views/shared/icons/_arrow_down_on_square.erb +3 -0
  285. data/lib/karafka/web/ui/views/shared/icons/_arrow_down_tray.erb +3 -0
  286. data/lib/karafka/web/ui/views/shared/icons/_arrow_on_squares.erb +3 -0
  287. data/lib/karafka/web/ui/views/shared/icons/_arrow_path_rounded.erb +3 -0
  288. data/lib/karafka/web/ui/views/shared/icons/_arrow_uturn_right.erb +3 -0
  289. data/lib/karafka/web/ui/views/shared/icons/_arrows_right_left.erb +3 -0
  290. data/lib/karafka/web/ui/views/shared/icons/_blocks.erb +3 -0
  291. data/lib/karafka/web/ui/views/shared/icons/_book_open.erb +3 -0
  292. data/lib/karafka/web/ui/views/shared/icons/_bug.erb +3 -0
  293. data/lib/karafka/web/ui/views/shared/icons/_burger.erb +14 -0
  294. data/lib/karafka/web/ui/views/shared/icons/_calendar_days.erb +3 -0
  295. data/lib/karafka/web/ui/views/shared/icons/_chart_bar.erb +3 -0
  296. data/lib/karafka/web/ui/views/shared/icons/_check_badge.erb +3 -0
  297. data/lib/karafka/web/ui/views/shared/icons/_check_circle.erb +3 -0
  298. data/lib/karafka/web/ui/views/shared/icons/_circle_stack.erb +3 -0
  299. data/lib/karafka/web/ui/views/shared/icons/_cpu.erb +3 -0
  300. data/lib/karafka/web/ui/views/shared/icons/_document_glass.erb +3 -0
  301. data/lib/karafka/web/ui/views/shared/icons/_exclamation_triangle.erb +3 -0
  302. data/lib/karafka/web/ui/views/shared/icons/_eye.erb +4 -0
  303. data/lib/karafka/web/ui/views/shared/icons/_gear.erb +4 -0
  304. data/lib/karafka/web/ui/views/shared/icons/_github.erb +13 -0
  305. data/lib/karafka/web/ui/views/shared/icons/_globe.erb +3 -0
  306. data/lib/karafka/web/ui/views/shared/icons/_heart.erb +3 -0
  307. data/lib/karafka/web/ui/views/shared/icons/_home.erb +3 -0
  308. data/lib/karafka/web/ui/views/shared/icons/_info_circle.erb +3 -0
  309. data/lib/karafka/web/ui/views/shared/icons/_lifebuoy.erb +3 -0
  310. data/lib/karafka/web/ui/views/shared/icons/_light_bulb.erb +3 -0
  311. data/lib/karafka/web/ui/views/shared/icons/_list_bullets.erb +3 -0
  312. data/lib/karafka/web/ui/views/shared/icons/_magnifying_glass.erb +3 -0
  313. data/lib/karafka/web/ui/views/shared/icons/_moon.erb +3 -0
  314. data/lib/karafka/web/ui/views/shared/icons/_offices.erb +3 -0
  315. data/lib/karafka/web/ui/views/shared/icons/_pause.erb +3 -0
  316. data/lib/karafka/web/ui/views/shared/icons/_pause_circle.erb +3 -0
  317. data/lib/karafka/web/ui/views/shared/icons/_play_circle.erb +4 -0
  318. data/lib/karafka/web/ui/views/shared/icons/_question_circle.erb +3 -0
  319. data/lib/karafka/web/ui/views/shared/icons/_queue_list.erb +3 -0
  320. data/lib/karafka/web/ui/views/shared/icons/_refresh.erb +3 -0
  321. data/lib/karafka/web/ui/views/shared/icons/_slack.erb +16 -0
  322. data/lib/karafka/web/ui/views/shared/icons/_stop.erb +3 -0
  323. data/lib/karafka/web/ui/views/shared/icons/_sun.erb +3 -0
  324. data/lib/karafka/web/ui/views/shared/icons/_x_circle.erb +3 -0
  325. data/lib/karafka/web/ui/views/shared/icons/_x_mark.erb +3 -0
  326. data/lib/karafka/web/ui/views/status/_breadcrumbs.erb +1 -1
  327. data/lib/karafka/web/ui/views/status/_failure.erb +2 -13
  328. data/lib/karafka/web/ui/views/status/_halted.erb +2 -10
  329. data/lib/karafka/web/ui/views/status/_info.erb +2 -13
  330. data/lib/karafka/web/ui/views/status/_success.erb +2 -10
  331. data/lib/karafka/web/ui/views/status/_warning.erb +2 -13
  332. data/lib/karafka/web/ui/views/status/failures/_connection.erb +2 -2
  333. data/lib/karafka/web/ui/views/status/failures/_consumers_reports.erb +3 -3
  334. data/lib/karafka/web/ui/views/status/failures/_consumers_reports_schema_state.erb +4 -4
  335. data/lib/karafka/web/ui/views/status/failures/_enabled.erb +2 -2
  336. data/lib/karafka/web/ui/views/status/failures/_initial_consumers_metrics.erb +6 -6
  337. data/lib/karafka/web/ui/views/status/failures/_initial_consumers_state.erb +6 -6
  338. data/lib/karafka/web/ui/views/status/failures/_live_reporting.erb +2 -2
  339. data/lib/karafka/web/ui/views/status/failures/_materializing_lag.erb +11 -0
  340. data/lib/karafka/web/ui/views/status/failures/_partitions.erb +3 -3
  341. data/lib/karafka/web/ui/views/status/failures/_state_calculation.erb +2 -2
  342. data/lib/karafka/web/ui/views/status/failures/_topics.erb +3 -3
  343. data/lib/karafka/web/ui/views/status/info/_components.erb +14 -41
  344. data/lib/karafka/web/ui/views/status/show.erb +165 -154
  345. data/lib/karafka/web/ui/views/status/warnings/_connection.erb +3 -3
  346. data/lib/karafka/web/ui/views/status/warnings/_pro_subscription.erb +2 -2
  347. data/lib/karafka/web/ui/views/status/warnings/_replication.erb +2 -2
  348. data/lib/karafka/web/ui/views/status/warnings/_routing_topics_presence.erb +1 -1
  349. data/lib/karafka/web/ui/views/support/_breadcrumbs.erb +5 -0
  350. data/lib/karafka/web/ui/views/support/show.erb +71 -0
  351. data/lib/karafka/web/ui/views/ux/_alerts.erb +25 -0
  352. data/lib/karafka/web/ui/views/ux/_badges.erb +21 -0
  353. data/lib/karafka/web/ui/views/ux/_breadcrumbs.erb +5 -0
  354. data/lib/karafka/web/ui/views/ux/_buttons.erb +47 -0
  355. data/lib/karafka/web/ui/views/ux/_card_detail.erb +15 -0
  356. data/lib/karafka/web/ui/views/ux/_card_metric.erb +123 -0
  357. data/lib/karafka/web/ui/views/ux/_card_summary.erb +72 -0
  358. data/lib/karafka/web/ui/views/ux/_card_support.erb +39 -0
  359. data/lib/karafka/web/ui/views/ux/_code.erb +9 -0
  360. data/lib/karafka/web/ui/views/ux/_data_table.erb +52 -0
  361. data/lib/karafka/web/ui/views/ux/_headers.erb +2 -0
  362. data/lib/karafka/web/ui/views/ux/_icons.erb +9 -0
  363. data/lib/karafka/web/ui/views/ux/_pagination.erb +32 -0
  364. data/lib/karafka/web/ui/views/ux/_row_table.erb +52 -0
  365. data/lib/karafka/web/ui/views/ux/_status_rows.erb +53 -0
  366. data/lib/karafka/web/ui/views/ux/_tabs.erb +14 -0
  367. data/lib/karafka/web/ui/views/ux/_text.erb +2 -0
  368. data/lib/karafka/web/ui/views/ux/_topic_tiles.erb +42 -0
  369. data/lib/karafka/web/ui/views/ux/show.erb +19 -0
  370. data/lib/karafka/web/version.rb +1 -1
  371. data/lib/karafka/web.rb +2 -0
  372. data/package-lock.json +4158 -0
  373. data/package.json +15 -0
  374. data/postcss.config.js +6 -0
  375. data/tailwind.config.js +16 -0
  376. data.tar.gz.sig +4 -0
  377. metadata +203 -51
  378. metadata.gz.sig +0 -0
  379. data/lib/karafka/web/management/migrations/0_set_initial_consumers_metrics.rb +0 -36
  380. data/lib/karafka/web/management/migrations/0_set_initial_consumers_state.rb +0 -43
  381. data/lib/karafka/web/management/migrations/1699543515_fill_missing_received_and_sent_bytes_in_consumers_metrics.rb +0 -26
  382. data/lib/karafka/web/management/migrations/1699543515_fill_missing_received_and_sent_bytes_in_consumers_state.rb +0 -23
  383. data/lib/karafka/web/management/migrations/1700234522_introduce_waiting_in_consumers_metrics.rb +0 -24
  384. data/lib/karafka/web/management/migrations/1700234522_introduce_waiting_in_consumers_state.rb +0 -20
  385. data/lib/karafka/web/management/migrations/1700234522_remove_processing_from_consumers_metrics.rb +0 -24
  386. data/lib/karafka/web/management/migrations/1700234522_remove_processing_from_consumers_state.rb +0 -20
  387. data/lib/karafka/web/management/migrations/1704722380_split_listeners_into_active_and_paused_in_metrics.rb +0 -36
  388. data/lib/karafka/web/management/migrations/1704722380_split_listeners_into_active_and_paused_in_states.rb +0 -32
  389. data/lib/karafka/web/management/migrations/1706607960_introduce_lag_total_in_metrics.rb +0 -38
  390. data/lib/karafka/web/management/migrations/1706607960_introduce_lag_total_in_states.rb +0 -22
  391. data/lib/karafka/web/management/migrations/1706611396_rename_lag_total_to_lag_hybrid_in_metrics.rb +0 -36
  392. data/lib/karafka/web/management/migrations/1706611396_rename_lag_total_to_lag_hybrid_in_states.rb +0 -21
  393. data/lib/karafka/web/pro/ui/views/cluster/brokers.erb +0 -27
  394. data/lib/karafka/web/pro/ui/views/commands/_details.erb +0 -26
  395. data/lib/karafka/web/pro/ui/views/consumers/_counters.erb +0 -72
  396. data/lib/karafka/web/pro/ui/views/consumers/consumer/_title.erb +0 -5
  397. data/lib/karafka/web/pro/ui/views/errors/_title_with_select.erb +0 -31
  398. data/lib/karafka/web/pro/ui/views/explorer/message/_message_actions.erb +0 -18
  399. data/lib/karafka/web/pro/ui/views/explorer/message/_payload_actions.erb +0 -19
  400. data/lib/karafka/web/pro/ui/views/explorer/partition/_details.erb +0 -35
  401. data/lib/karafka/web/pro/ui/views/explorer/topic/_details.erb +0 -23
  402. data/lib/karafka/web/pro/ui/views/health/_consumer_group_header.erb +0 -14
  403. data/lib/karafka/web/ui/controllers/responses/deny.rb +0 -15
  404. data/lib/karafka/web/ui/helpers/alerts_helper.rb +0 -23
  405. data/lib/karafka/web/ui/lib/safe_runner.rb +0 -59
  406. data/lib/karafka/web/ui/models/visibility_filter.rb +0 -49
  407. data/lib/karafka/web/ui/public/javascripts/libs/bootstrap.min.js +0 -6
  408. data/lib/karafka/web/ui/public/javascripts/tabs_manager.js +0 -57
  409. data/lib/karafka/web/ui/public/stylesheets/libs/bootstrap.min.css +0 -6
  410. data/lib/karafka/web/ui/views/consumers/_counters.erb +0 -62
  411. data/lib/karafka/web/ui/views/errors/_watermark_offsets.erb +0 -10
  412. data/lib/karafka/web/ui/views/shared/_feature_pro.erb +0 -4
  413. data/lib/karafka/web/ui/views/shared/_footer.erb +0 -22
  414. data/lib/karafka/web/ui/views/shared/_live_poll.erb +0 -7
  415. /data/lib/karafka/web/management/migrations/{0_base.rb → base.rb} +0 -0
  416. /data/lib/karafka/web/ui/public/javascripts/{charts.js → components/charts.js} +0 -0
  417. /data/lib/karafka/web/ui/public/stylesheets/libs/{highlight.min.css → highlight_light.min.css} +0 -0
@@ -1,12 +1,9 @@
1
- <div class="col">
2
- <div class="card" >
3
- <div class="card-body p-2">
4
- <p class="card-text mb-0 p-2">
5
- <a href="<%= root_path('topics', topic.topic_name, 'config') %>">
6
- <%= topic.topic_name %> /
7
- <%= topic.partition_count %>
8
- </a>
9
- </p>
10
- </div>
1
+ <div class="topic-tile">
2
+ <div class="topic-tile-body">
3
+ <p class="topic-tile-text">
4
+ <a href="<%= root_path('topics', topic.topic_name, 'config') %>" class="topic-tile-link">
5
+ <%= topic.topic_name %> / <%= topic.partition_count %>
6
+ </a>
7
+ </p>
11
8
  </div>
12
9
  </div>
@@ -1,29 +1,25 @@
1
- <%== view_title(@topic.topic_name, hr: false) %>
1
+ <% view_title @topic.topic_name %>
2
2
 
3
3
  <%== partial 'topics/tabs' %>
4
4
 
5
- <div class="container mb-5">
6
- <div class="row">
7
- <div class="col-lg-12 table-responsive">
8
- <table class="processes bg-white table table-hover table-bordered table-striped">
9
- <thead>
10
- <tr class="align-middle">
11
- <th><%== sort_link(:name) %></th>
12
- <th><%== sort_link(:value) %></th>
13
- <th><%== sort_link(:default?) %></th>
14
- <th><%== sort_link(:sensitive?) %></th>
15
- <th><%== sort_link(:read_only?) %></th>
16
- </tr>
17
- </thead>
18
- <tbody>
19
- <%==
20
- each_partial(
21
- @configs,
22
- 'cluster/config'
23
- )
24
- %>
25
- </tbody>
26
- </table>
27
- </div>
28
- </div>
5
+ <div class="data-table-wrapper">
6
+ <table class="data-table">
7
+ <thead>
8
+ <tr>
9
+ <th><%== sort_link(:name) %></th>
10
+ <th><%== sort_link(:value) %></th>
11
+ <th><%== sort_link(:default?) %></th>
12
+ <th><%== sort_link(:sensitive?) %></th>
13
+ <th><%== sort_link(:read_only?) %></th>
14
+ </tr>
15
+ </thead>
16
+ <tbody>
17
+ <%==
18
+ each_partial(
19
+ @configs,
20
+ 'cluster/config'
21
+ )
22
+ %>
23
+ </tbody>
24
+ </table>
29
25
  </div>
@@ -1,7 +1,12 @@
1
- <p class="text-end">
2
- <span class="badge bg-primary">Total messages: <%= number_with_delimiter @aggregated.sum.round, ' ' %></span>
3
- <span class="badge bg-primary">Std dev: <%= @aggregated.std_dev %></span>
4
- <span class="badge bg-primary">Std dev relative: <%= @aggregated.std_dev_rel %>%</span>
1
+ <p class="text-end mb-5">
2
+ <%==
3
+ value = number_with_delimiter @aggregated.sum.round, ' '
4
+ badge_primary("Total messages: #{value}")
5
+ %>
6
+
7
+ <%== badge_primary("Std dev: #{@aggregated.std_dev}") %>
8
+ <%== badge_primary("Std dev relative: #{@aggregated.std_dev_rel}%") %>
9
+
5
10
  <% partitions_range = [@active_partitions.first, @active_partitions.last].uniq.join(' to ') %>
6
- <span class="badge bg-secondary">Partitions: <%= partitions_range %></span>
11
+ <%== badge_secondary("Partitions: #{partitions_range}") %>
7
12
  </p>
@@ -1,2 +1,4 @@
1
1
  <% data = { 'Estimated count': @distribution.map { [_1.partition_id, _1.count] } }.to_json %>
2
- <%== partial 'shared/charts/bar', locals: { data: data, id: 'distribution' } %>
2
+ <div class="mb-5">
3
+ <%== partial 'shared/charts/bar', locals: { data: data, id: 'distribution' } %>
4
+ </div>
@@ -1,4 +1,4 @@
1
- <div class="mb-4">
1
+ <div class="mb-10">
2
2
  <%==
3
3
  alert_info(
4
4
  '
@@ -1,47 +1,42 @@
1
- <%== view_title(@topic.topic_name, hr: false) %>
1
+ <% view_title @topic.topic_name %>
2
2
 
3
3
  <%== partial 'topics/tabs' %>
4
4
 
5
- <div class="container">
6
- <div class="row">
7
- <div class="col-lg-12">
8
- <% if @limited %>
9
- <%== partial 'topics/distribution/limited' %>
10
- <% end %>
5
+ <% if @limited %>
6
+ <%== partial 'topics/distribution/limited' %>
7
+ <% end %>
11
8
 
12
- <% if @aggregated.sum.zero? %>
13
- <%== partial 'topics/distribution/empty_partitions' %>
14
- <% else %>
15
- <% if @active_partitions.size >= 2 %>
16
- <%== partial 'topics/distribution/chart' %>
17
- <% end %>
9
+ <% if @aggregated.sum.zero? %>
10
+ <%== partial 'topics/distribution/empty_partitions' %>
11
+ <% else %>
12
+ <div class="col-span-12 mb-3">
13
+ <% if @active_partitions.size >= 2 %>
14
+ <%== partial 'topics/distribution/chart' %>
15
+ <% end %>
18
16
 
19
- <div id="refreshable" class="mt-4">
20
- <%== partial 'topics/distribution/badges' %>
21
-
22
- <div class="table-responsive">
23
- <table class="bg-white table table-hover table-bordered table-striped mt-4 mb-4">
24
- <thead>
25
- <tr class="align-middle">
26
- <th><%== sort_link(:partition_id) %></th>
27
- <th><%== sort_link('Estimated count', :count) %></th>
28
- <th><%== sort_link('Total share', :share) %></th>
29
- <th><%== sort_link(:diff) %></th>
30
- </tr>
31
- </thead>
32
- <tbody>
33
- <%==
34
- each_partial(
35
- @distribution,
36
- 'topics/distribution/partition'
37
- )
38
- %>
39
- </tbody>
40
- </table>
41
- </div>
42
- </div>
43
- <% end %>
17
+ <div id="refreshable" class="mt-4">
18
+ <%== partial 'topics/distribution/badges' %>
44
19
 
20
+ <div class="data-table-wrapper">
21
+ <table class="data-table">
22
+ <thead>
23
+ <tr>
24
+ <th><%== sort_link(:partition_id) %></th>
25
+ <th><%== sort_link('Estimated count', :count) %></th>
26
+ <th><%== sort_link('Total share', :share) %></th>
27
+ <th><%== sort_link(:diff) %></th>
28
+ </tr>
29
+ </thead>
30
+ <tbody>
31
+ <%==
32
+ each_partial(
33
+ @distribution,
34
+ 'topics/distribution/partition'
35
+ )
36
+ %>
37
+ </tbody>
38
+ </table>
39
+ </div>
45
40
  </div>
46
41
  </div>
47
- </div>
42
+ <% end %>
@@ -1,16 +1,14 @@
1
- <%== view_title('Topics', hr: true) %>
1
+ <% view_title 'Topics' %>
2
2
 
3
- <div class="container">
4
- <% if @topics.empty? %>
5
- <%== partial 'explorer/no_topics' %>
6
- <% else %>
7
- <div class="row mb-5 row-cols-1 row-cols-md-4 g-4">
8
- <%==
9
- each_partial(
10
- @topics,
11
- 'topics/topic'
12
- )
13
- %>
14
- </div>
15
- <% end %>
16
- </div>
3
+ <% if @topics.empty? %>
4
+ <%== partial 'explorer/no_topics' %>
5
+ <% else %>
6
+ <div class="topic-tiles">
7
+ <%==
8
+ each_partial(
9
+ @topics,
10
+ 'topics/topic'
11
+ )
12
+ %>
13
+ </div>
14
+ <% end %>
@@ -0,0 +1,24 @@
1
+ <% view_title @topic.topic_name %>
2
+
3
+ <%== partial 'topics/tabs' %>
4
+
5
+ <div class="data-table-wrapper">
6
+ <table class="data-table">
7
+ <thead>
8
+ <tr>
9
+ <th><%== sort_link(:partition_id) %></th>
10
+ <th><%== sort_link(:low) %></th>
11
+ <th><%== sort_link(:high) %></th>
12
+ <th><%== sort_link('Count', :diff) %></th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <%==
17
+ each_partial(
18
+ @offsets,
19
+ 'topics/partition_offsets'
20
+ )
21
+ %>
22
+ </tbody>
23
+ </table>
24
+ </div>
@@ -1,28 +1,24 @@
1
- <%== view_title(@topic.topic_name, hr: false) %>
1
+ <% view_title @topic.topic_name %>
2
2
 
3
3
  <%== partial 'topics/tabs' %>
4
4
 
5
- <div class="container mb-5">
6
- <div class="row">
7
- <div class="col-lg-12 table-responsive">
8
- <table class="processes bg-white table table-hover table-bordered table-striped">
9
- <thead>
10
- <tr class="align-middle">
11
- <th><%== sort_link(:partition_id) %></th>
12
- <th><%== sort_link(:leader) %></th>
13
- <th><%== sort_link(:replica_count) %></th>
14
- <th><%== sort_link('In sync brokers', :in_sync_replica_brokers) %></th>
15
- </tr>
16
- </thead>
17
- <tbody>
18
- <%==
19
- each_partial(
20
- @partitions,
21
- 'topics/partition'
22
- )
23
- %>
24
- </tbody>
25
- </table>
26
- </div>
27
- </div>
5
+ <div class="data-table-wrapper">
6
+ <table class="data-table">
7
+ <thead>
8
+ <tr>
9
+ <th><%== sort_link(:partition_id) %></th>
10
+ <th><%== sort_link(:leader) %></th>
11
+ <th><%== sort_link(:replica_count) %></th>
12
+ <th><%== sort_link('In sync brokers', :in_sync_replica_brokers) %></th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <%==
17
+ each_partial(
18
+ @partitions,
19
+ 'topics/partition'
20
+ )
21
+ %>
22
+ </tbody>
23
+ </table>
28
24
  </div>
@@ -11,7 +11,7 @@ module Karafka
11
11
  class Metrics < Base
12
12
  # Current schema version
13
13
  # This is used for detecting incompatible changes and writing migrations
14
- SCHEMA_VERSION = '1.2.1'
14
+ SCHEMA_VERSION = '1.3.0'
15
15
 
16
16
  def initialize
17
17
  super
@@ -20,7 +20,7 @@ module Karafka
20
20
  # Current schema version
21
21
  # This can be used in the future for detecting incompatible changes and writing
22
22
  # migrations
23
- SCHEMA_VERSION = '1.3.1'
23
+ SCHEMA_VERSION = '1.4.0'
24
24
 
25
25
  # @param schema_manager [Karafka::Web::Processing::Consumers::SchemaManager] schema
26
26
  # manager that tracks the compatibility of schemas.
@@ -11,6 +11,7 @@ module Karafka
11
11
  configure
12
12
 
13
13
  required(:batches) { |val| val.is_a?(Integer) && val >= 0 }
14
+ required(:jobs) { |val| val.is_a?(Integer) && val >= 0 }
14
15
  required(:messages) { |val| val.is_a?(Integer) && val >= 0 }
15
16
  required(:retries) { |val| val.is_a?(Integer) && val >= 0 }
16
17
  required(:dead) { |val| val.is_a?(Integer) && val >= 0 }
@@ -29,6 +29,7 @@ module Karafka
29
29
  required(:threads) { |val| val.is_a?(Integer) && val >= 0 }
30
30
  required(:workers) { |val| val.is_a?(Integer) && val.positive? }
31
31
  required(:tags) { |val| val.is_a?(Karafka::Core::Taggable::Tags) }
32
+ required(:execution_mode) { |val| val.is_a?(String) && !val.empty? }
32
33
 
33
34
  nested(:listeners) do
34
35
  required(:active) { |val| val.is_a?(Integer) && val >= 0 }
@@ -60,6 +61,11 @@ module Karafka
60
61
  required(:utilization) { |val| val.is_a?(Numeric) && val >= 0 }
61
62
 
62
63
  nested(:total) do
64
+ # There can be jobs that run without new data batches like revocation, periodic,
65
+ # shutdown, etc. We want to track them. This is needed because in case of a
66
+ # setup where those are significant, user may have a false sense that nothing
67
+ # is happening in the system when no new messages are coming
68
+ required(:jobs) { |val| val.is_a?(Integer) && val >= 0 }
63
69
  required(:batches) { |val| val.is_a?(Integer) && val >= 0 }
64
70
  required(:messages) { |val| val.is_a?(Integer) && val >= 0 }
65
71
  required(:errors) { |val| val.is_a?(Integer) && val >= 0 }
@@ -7,11 +7,15 @@ module Karafka
7
7
  module Listeners
8
8
  # Listener for listening on connections related events like polling, etc
9
9
  class Connections < Base
10
- # Set first poll time before we start fetching so we always have a poll time
11
- # and we don't have to worry about it being always available
10
+ # Initializes the subscription group with defaults so it is always available
12
11
  # @param event [Karafka::Core::Monitoring::Event]
13
12
  def on_connection_listener_before_fetch_loop(event)
14
- on_connection_listener_fetch_loop_received(event)
13
+ sg_id = event[:subscription_group].id
14
+
15
+ track do |sampler|
16
+ # This will initialize the hash upon first request
17
+ sampler.subscription_groups[sg_id]
18
+ end
15
19
  end
16
20
 
17
21
  # When fetch loop is done it means this subscription group is no longer active and we
@@ -36,9 +40,7 @@ module Karafka
36
40
  sg_id = event[:subscription_group].id
37
41
 
38
42
  track do |sampler|
39
- sampler.subscription_groups[sg_id] = {
40
- polled_at: monotonic_now
41
- }
43
+ sampler.subscription_groups[sg_id][:polled_at] = monotonic_now
42
44
  end
43
45
  end
44
46
  end
@@ -51,6 +51,7 @@ module Karafka
51
51
  track do |sampler|
52
52
  # We count batches and messages prior to the execution, so they are tracked even
53
53
  # if error occurs, etc.
54
+ sampler.counters[:jobs] += 1
54
55
  sampler.counters[:batches] += 1
55
56
  sampler.counters[:messages] += messages_count
56
57
  sampler.jobs[jid] = job_details
@@ -120,6 +121,7 @@ module Karafka
120
121
  job_details = job_details(consumer, '#{action}')
121
122
 
122
123
  track do |sampler|
124
+ sampler.counters[:jobs] += 1
123
125
  sampler.jobs[jid] = job_details
124
126
  end
125
127
  end
@@ -47,7 +47,7 @@ module Karafka
47
47
  attempt = consumer.coordinator.pause_tracker.attempt
48
48
 
49
49
  if attempt > 1
50
- consumer.tags.add(:attempt, "attempt:#{attempt}")
50
+ consumer.tags.add(:attempt, "attempt: #{attempt}")
51
51
  else
52
52
  consumer.tags.delete(:attempt)
53
53
  end
@@ -6,13 +6,6 @@ module Karafka
6
6
  module Consumers
7
7
  # Reports the collected data about the process and sends it, so we can use it in the UI
8
8
  class Reporter < Tracking::Reporter
9
- # Minimum number of messages to produce to produce them in sync mode
10
- # This acts as a small back-off not to overload the system in case we would have
11
- # extremely big number of errors happening
12
- PRODUCE_SYNC_THRESHOLD = 25
13
-
14
- private_constant :PRODUCE_SYNC_THRESHOLD
15
-
16
9
  # This mutex is shared between tracker and samplers so there is no case where metrics
17
10
  # would be collected same time tracker reports
18
11
  MUTEX = Mutex.new
@@ -134,7 +127,7 @@ module Karafka
134
127
  # normal operations we should not have that many messages to dispatch and it should not
135
128
  # slowdown any processing.
136
129
  def produce(messages)
137
- if messages.count >= PRODUCE_SYNC_THRESHOLD
130
+ if messages.count >= sync_threshold
138
131
  ::Karafka::Web.producer.produce_many_sync(messages)
139
132
  else
140
133
  ::Karafka::Web.producer.produce_many_async(messages)
@@ -145,6 +138,11 @@ module Karafka
145
138
  rescue WaterDrop::Errors::ProducerClosedError
146
139
  nil
147
140
  end
141
+
142
+ # @return [Integer] min number of messages when we switch to sync flushing to slow things
143
+ def sync_threshold
144
+ @sync_threshold ||= ::Karafka::Web.config.tracking.consumers.sync_threshold
145
+ end
148
146
  end
149
147
  end
150
148
  end
@@ -15,10 +15,12 @@ module Karafka
15
15
  # Current schema version
16
16
  # This is used for detecting incompatible changes and not using outdated data during
17
17
  # upgrades
18
- SCHEMA_VERSION = '1.3.0'
18
+ SCHEMA_VERSION = '1.4.0'
19
19
 
20
20
  # Counters that count events occurrences during the given window
21
21
  COUNTERS_BASE = {
22
+ # Number of processed jobs of any type
23
+ jobs: 0,
22
24
  # Number of processed batches
23
25
  batches: 0,
24
26
  # Number of processed messages
@@ -38,13 +40,21 @@ module Karafka
38
40
 
39
41
  @windows = Helpers::Ttls::Windows.new
40
42
  @counters = COUNTERS_BASE.dup
43
+
41
44
  @consumer_groups = Hash.new do |h, cg_id|
42
45
  h[cg_id] = {
43
46
  id: cg_id,
44
47
  subscription_groups: {}
45
48
  }
46
49
  end
47
- @subscription_groups = {}
50
+
51
+ @subscription_groups = Hash.new do |h, sg_id|
52
+ h[sg_id] = {
53
+ id: sg_id,
54
+ polled_at: monotonic_now
55
+ }
56
+ end
57
+
48
58
  @errors = []
49
59
  @pauses = {}
50
60
  @jobs = {}
@@ -73,6 +83,7 @@ module Karafka
73
83
  id: process_id,
74
84
  started_at: started_at,
75
85
  status: ::Karafka::App.config.internal.status.to_s,
86
+ execution_mode: ::Karafka::Server.execution_mode.to_s,
76
87
  listeners: listeners,
77
88
  workers: workers,
78
89
  memory_usage: @memory_usage,
@@ -148,7 +159,7 @@ module Karafka
148
159
 
149
160
  # We divide by 1_000 to convert from milliseconds
150
161
  # We multiply by 100 to have it in % scale
151
- totals.sum / 1_000 / workers / timefactor * 100
162
+ (totals.sum / 1_000 / workers / timefactor * 100).round(2)
152
163
  end
153
164
 
154
165
  # @return [Hash] number of active and standby listeners
@@ -294,12 +305,12 @@ module Karafka
294
305
  @consumer_groups.each_value do |cg_details|
295
306
  cg_details.each do
296
307
  cg_details.fetch(:subscription_groups, {}).each do |sg_id, sg_details|
297
- # This should be always available, since we subscription group polled at time
308
+ # This should be always available, since the subscription group polled at time
298
309
  # is first initialized before we start polling, there should be no case where
299
310
  # we have statistics about a given subscription group but we do not have the
300
311
  # last polling time
301
312
  polled_at = subscription_groups.fetch(sg_id).fetch(:polled_at)
302
- sg_details[:state][:poll_age] = monotonic_now - polled_at
313
+ sg_details[:state][:poll_age] = (monotonic_now - polled_at).round(2)
303
314
  end
304
315
  end
305
316
  end
@@ -27,12 +27,21 @@ module Karafka
27
27
  end
28
28
 
29
29
  r.on 'consumers' do
30
+ %w[
31
+ performance
32
+ controls
33
+ commands
34
+ ].each do |path|
35
+ r.get path do |_process_id|
36
+ raise Errors::Ui::ProOnlyError
37
+ end
38
+ end
39
+
30
40
  r.get String, 'subscriptions' do |_process_id|
31
41
  raise Errors::Ui::ProOnlyError
32
42
  end
33
43
 
34
44
  r.get do
35
- @breadcrumbs = false
36
45
  controller = Controllers::ConsumersController.new(params)
37
46
  controller.index
38
47
  end
@@ -108,6 +117,16 @@ module Karafka
108
117
  controller = Controllers::StatusController.new(params)
109
118
  controller.show
110
119
  end
120
+
121
+ r.get 'ux' do
122
+ controller = Controllers::UxController.new(params)
123
+ controller.show
124
+ end
125
+
126
+ r.get 'support' do
127
+ controller = Controllers::SupportController.new(params)
128
+ controller.show
129
+ end
111
130
  end
112
131
  end
113
132
  end
@@ -7,7 +7,7 @@ module Karafka
7
7
  class Base < Roda
8
8
  include Helpers::PathsHelper
9
9
  include Helpers::ApplicationHelper
10
- include Helpers::AlertsHelper
10
+ include Helpers::TailwindHelper
11
11
 
12
12
  # Details that need to be evaluated in the context of OSS or Pro web UI.
13
13
  # If those would be evaluated in the base, they would not be initialized as expected
@@ -17,7 +17,9 @@ module Karafka
17
17
  root: Karafka::Web.gem_root.join('lib/karafka/web/ui/public'),
18
18
  # Cache all static files for the end user for as long as possible
19
19
  # We can do it because we ship per version assets so they invalidate with gem bumps
20
- headers: { 'Cache-Control' => 'max-age=31536000, immutable' }
20
+ headers: { 'Cache-Control' => 'max-age=31536000, immutable' },
21
+ gzip: true,
22
+ brotli: true
21
23
  )
22
24
  plugin :render_each
23
25
  plugin :partials
@@ -35,6 +37,9 @@ module Karafka
35
37
  plugin :hooks
36
38
  plugin :flash
37
39
  plugin :path
40
+ plugin :capture_erb
41
+ plugin :content_for
42
+ plugin :inject_erb
38
43
 
39
44
  # Based on
40
45
  # https://github.com/sidekiq/sidekiq/blob/ae6ca119/lib/sidekiq/web/application.rb#L8
@@ -48,7 +53,7 @@ module Karafka
48
53
  csp.manifest_src "'self'"
49
54
  csp.media_src "'self'"
50
55
  csp.object_src "'none'"
51
- csp.script_src "'self' https: http: 'unsafe-inline'"
56
+ csp.script_src "'self' https: http:"
52
57
  csp.style_src "'self' https: http: 'unsafe-inline'"
53
58
  csp.worker_src "'self'"
54
59
  csp.base_uri "'self'"
@@ -60,12 +65,6 @@ module Karafka
60
65
  render_response(result)
61
66
  end
62
67
 
63
- handle_block_result Controllers::Responses::Deny do
64
- @error = true
65
- response.status = 403
66
- view 'shared/exceptions/not_allowed'
67
- end
68
-
69
68
  # Redirect either to referer back or to the desired path
70
69
  handle_block_result Controllers::Responses::Redirect do |result|
71
70
  # Map redirect flashes (if any) to Roda flash messages
@@ -84,13 +83,18 @@ module Karafka
84
83
  plugin :error_handler, classes: [
85
84
  ::Rdkafka::RdkafkaError,
86
85
  Errors::Ui::NotFoundError,
87
- Errors::Ui::ProOnlyError
86
+ Errors::Ui::ProOnlyError,
87
+ Errors::Ui::ForbiddenError
88
88
  ] do |e|
89
89
  @error = true
90
90
 
91
- if e.is_a?(Errors::Ui::ProOnlyError)
91
+ case e
92
+ when Errors::Ui::ProOnlyError
92
93
  response.status = 402
93
94
  view 'shared/exceptions/pro_only'
95
+ when Errors::Ui::ForbiddenError
96
+ response.status = 403
97
+ view 'shared/exceptions/not_allowed'
94
98
  else
95
99
  response.status = 404
96
100
  view 'shared/exceptions/not_found'
@@ -128,15 +132,17 @@ module Karafka
128
132
  # the query data. Query data takes priority over request params.
129
133
  # @param query_data [Hash] query params we want to add to the current path
130
134
  path :current do |query_data = {}|
131
- q = query_data
132
- .transform_values(&:to_s)
133
- .transform_keys(&:to_s)
134
- .then { |candidates| request.params.merge(candidates) }
135
- .select { |_, v| v }
136
- .map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }
137
- .join('&')
138
-
139
- [request.path, q].compact.delete_if(&:empty?).join('?')
135
+ # Merge existing request parameters with new query data
136
+ merged_params = request.params.deep_merge(query_data)
137
+
138
+ # Flatten the merged parameters
139
+ flattened_params = flatten_params('', merged_params)
140
+
141
+ # Build the query string from the flattened parameters
142
+ query_string = URI.encode_www_form(flattened_params)
143
+
144
+ # Construct the full path with query string
145
+ [request.path, query_string].compact.join('?')
140
146
  end
141
147
 
142
148
  # Sets appropriate template variables based on the response object and renders the