karafka-web 0.10.4 → 0.11.0

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 (494) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -176
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +88 -44
  5. data/LICENSE +6 -2
  6. data/Rakefile +4 -0
  7. data/bin/verify_kafka_warnings +35 -0
  8. data/bin/verify_topics_naming +35 -0
  9. data/config/locales/pro_errors.yml +1 -0
  10. data/config/locales/slogans.yml +1 -1
  11. data/docker-compose.yml +1 -1
  12. data/gulpfile.js +0 -2
  13. data/karafka-web.gemspec +2 -7
  14. data/lib/karafka/web/config.rb +80 -9
  15. data/lib/karafka/web/contracts/config.rb +44 -5
  16. data/lib/karafka/web/errors.rb +10 -12
  17. data/lib/karafka/web/management/actions/create_initial_states.rb +6 -6
  18. data/lib/karafka/web/management/actions/create_topics.rb +30 -64
  19. data/lib/karafka/web/management/actions/delete_topics.rb +5 -5
  20. data/lib/karafka/web/management/actions/enable.rb +5 -5
  21. data/lib/karafka/web/pro/commanding/commands/base.rb +37 -13
  22. data/lib/karafka/web/pro/commanding/commands/consumers/quiet.rb +33 -0
  23. data/lib/karafka/web/pro/commanding/commands/consumers/stop.rb +32 -0
  24. data/lib/karafka/web/pro/commanding/commands/consumers/trace.rb +37 -0
  25. data/lib/karafka/web/pro/commanding/commands/partitions/pause.rb +30 -0
  26. data/lib/karafka/web/pro/commanding/commands/partitions/resume.rb +30 -0
  27. data/lib/karafka/web/pro/commanding/commands/partitions/seek.rb +30 -0
  28. data/lib/karafka/web/pro/commanding/config.rb +6 -10
  29. data/lib/karafka/web/pro/commanding/contracts/config.rb +2 -10
  30. data/lib/karafka/web/pro/commanding/dispatcher.rb +45 -24
  31. data/lib/karafka/web/pro/commanding/handlers/partitions/commands/base.rb +67 -0
  32. data/lib/karafka/web/pro/commanding/handlers/partitions/commands/pause.rb +44 -0
  33. data/lib/karafka/web/pro/commanding/handlers/partitions/commands/resume.rb +29 -0
  34. data/lib/karafka/web/pro/commanding/handlers/partitions/commands/seek.rb +86 -0
  35. data/lib/karafka/web/pro/commanding/handlers/partitions/executor.rb +56 -0
  36. data/lib/karafka/web/pro/commanding/handlers/partitions/listener.rb +55 -0
  37. data/lib/karafka/web/pro/commanding/handlers/partitions/tracker.rb +62 -0
  38. data/lib/karafka/web/pro/commanding/listener.rb +4 -12
  39. data/lib/karafka/web/pro/commanding/manager.rb +36 -24
  40. data/lib/karafka/web/pro/commanding/matcher.rb +7 -17
  41. data/lib/karafka/web/pro/commanding/request.rb +39 -0
  42. data/lib/karafka/web/pro/commanding.rb +2 -10
  43. data/lib/karafka/web/pro/loader.rb +13 -10
  44. data/lib/karafka/web/pro/ui/app.rb +31 -390
  45. data/lib/karafka/web/pro/ui/controllers/base_controller.rb +8 -10
  46. data/lib/karafka/web/pro/ui/controllers/cluster_controller.rb +2 -10
  47. data/lib/karafka/web/pro/ui/controllers/consumers/base_controller.rb +21 -0
  48. data/lib/karafka/web/pro/ui/controllers/consumers/commanding_controller.rb +148 -0
  49. data/lib/karafka/web/pro/ui/controllers/consumers/commands_controller.rb +96 -0
  50. data/lib/karafka/web/pro/ui/controllers/consumers/consumers_controller.rb +99 -0
  51. data/lib/karafka/web/pro/ui/controllers/consumers/controls_controller.rb +36 -0
  52. data/lib/karafka/web/pro/ui/controllers/consumers/jobs_controller.rb +57 -0
  53. data/lib/karafka/web/pro/ui/controllers/consumers/partitions/base_controller.rb +86 -0
  54. data/lib/karafka/web/pro/ui/controllers/consumers/partitions/offsets_controller.rb +75 -0
  55. data/lib/karafka/web/pro/ui/controllers/consumers/partitions/pauses_controller.rb +110 -0
  56. data/lib/karafka/web/pro/ui/controllers/dashboard_controller.rb +2 -10
  57. data/lib/karafka/web/pro/ui/controllers/dlq_controller.rb +2 -10
  58. data/lib/karafka/web/pro/ui/controllers/errors_controller.rb +11 -15
  59. data/lib/karafka/web/pro/ui/controllers/explorer/base_controller.rb +21 -0
  60. data/lib/karafka/web/pro/ui/controllers/explorer/explorer_controller.rb +225 -0
  61. data/lib/karafka/web/pro/ui/controllers/explorer/messages_controller.rb +145 -0
  62. data/lib/karafka/web/pro/ui/controllers/explorer/search_controller.rb +68 -0
  63. data/lib/karafka/web/pro/ui/controllers/health_controller.rb +2 -10
  64. data/lib/karafka/web/pro/ui/controllers/jobs_controller.rb +2 -10
  65. data/lib/karafka/web/pro/ui/controllers/recurring_tasks_controller.rb +12 -13
  66. data/lib/karafka/web/pro/ui/controllers/routing_controller.rb +2 -10
  67. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/base_controller.rb +2 -10
  68. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/explorer_controller.rb +8 -16
  69. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/messages_controller.rb +9 -15
  70. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/schedules_controller.rb +2 -10
  71. data/lib/karafka/web/pro/ui/controllers/status_controller.rb +2 -10
  72. data/lib/karafka/web/pro/ui/controllers/support_controller.rb +2 -10
  73. data/lib/karafka/web/pro/ui/controllers/topics/base_controller.rb +21 -0
  74. data/lib/karafka/web/pro/ui/controllers/topics/configs_controller.rb +86 -0
  75. data/lib/karafka/web/pro/ui/controllers/topics/distributions_controller.rb +91 -0
  76. data/lib/karafka/web/pro/ui/controllers/topics/offsets_controller.rb +55 -0
  77. data/lib/karafka/web/pro/ui/controllers/topics/replications_controller.rb +37 -0
  78. data/lib/karafka/web/pro/ui/controllers/topics/topics_controller.rb +101 -0
  79. data/lib/karafka/web/pro/ui/controllers/ux_controller.rb +2 -10
  80. data/lib/karafka/web/pro/ui/lib/branding/config.rb +2 -10
  81. data/lib/karafka/web/pro/ui/lib/branding/contracts/config.rb +2 -10
  82. data/lib/karafka/web/pro/ui/lib/branding.rb +2 -10
  83. data/lib/karafka/web/pro/ui/lib/features.rb +53 -0
  84. data/lib/karafka/web/pro/ui/lib/patterns_detector.rb +2 -10
  85. data/lib/karafka/web/pro/ui/lib/policies/config.rb +2 -10
  86. data/lib/karafka/web/pro/ui/lib/policies/contracts/config.rb +2 -10
  87. data/lib/karafka/web/pro/ui/lib/policies/messages.rb +2 -10
  88. data/lib/karafka/web/pro/ui/lib/policies/requests.rb +2 -10
  89. data/lib/karafka/web/pro/ui/lib/policies.rb +2 -10
  90. data/lib/karafka/web/pro/ui/lib/safe_runner.rb +5 -0
  91. data/lib/karafka/web/pro/ui/lib/search/config.rb +2 -10
  92. data/lib/karafka/web/pro/ui/lib/search/contracts/config.rb +2 -10
  93. data/lib/karafka/web/pro/ui/lib/search/contracts/form.rb +2 -10
  94. data/lib/karafka/web/pro/ui/lib/search/matchers/base.rb +2 -10
  95. data/lib/karafka/web/pro/ui/lib/search/matchers/raw_header_includes.rb +10 -11
  96. data/lib/karafka/web/pro/ui/lib/search/matchers/raw_key_includes.rb +2 -10
  97. data/lib/karafka/web/pro/ui/lib/search/matchers/raw_payload_includes.rb +23 -11
  98. data/lib/karafka/web/pro/ui/lib/search/normalizer.rb +2 -10
  99. data/lib/karafka/web/pro/ui/lib/search/runner.rb +3 -11
  100. data/lib/karafka/web/pro/ui/lib/search.rb +2 -10
  101. data/lib/karafka/web/pro/ui/routes/base.rb +19 -0
  102. data/lib/karafka/web/pro/ui/routes/cluster.rb +37 -0
  103. data/lib/karafka/web/pro/ui/routes/consumers.rb +145 -0
  104. data/lib/karafka/web/pro/ui/routes/dashboard.rb +25 -0
  105. data/lib/karafka/web/pro/ui/routes/dlq.rb +24 -0
  106. data/lib/karafka/web/pro/ui/routes/errors.rb +39 -0
  107. data/lib/karafka/web/pro/ui/routes/explorer.rb +118 -0
  108. data/lib/karafka/web/pro/ui/routes/health.rb +47 -0
  109. data/lib/karafka/web/pro/ui/routes/jobs.rb +33 -0
  110. data/lib/karafka/web/pro/ui/routes/recurring_tasks.rb +59 -0
  111. data/lib/karafka/web/pro/ui/routes/routing.rb +31 -0
  112. data/lib/karafka/web/pro/ui/routes/scheduled_messages.rb +75 -0
  113. data/lib/karafka/web/pro/ui/routes/status.rb +24 -0
  114. data/lib/karafka/web/pro/ui/routes/support.rb +24 -0
  115. data/lib/karafka/web/pro/ui/routes/topics.rb +90 -0
  116. data/lib/karafka/web/pro/ui/routes/ux.rb +24 -0
  117. data/lib/karafka/web/pro/ui/views/cluster/_breadcrumbs.erb +3 -0
  118. data/lib/karafka/web/pro/ui/views/cluster/_broker.erb +3 -0
  119. data/lib/karafka/web/pro/ui/views/cluster/_config.erb +3 -0
  120. data/lib/karafka/web/pro/ui/views/cluster/_tabs.erb +3 -0
  121. data/lib/karafka/web/pro/ui/views/cluster/index.erb +4 -1
  122. data/lib/karafka/web/pro/ui/views/cluster/show.erb +3 -0
  123. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_backtrace.erb +3 -0
  124. data/lib/karafka/web/pro/ui/views/consumers/commands/_breadcrumbs.erb +24 -0
  125. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_command.erb +22 -6
  126. data/lib/karafka/web/pro/ui/views/consumers/commands/_command_details.erb +4 -0
  127. data/lib/karafka/web/pro/ui/views/consumers/commands/_empty.erb +6 -0
  128. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_incompatible_schema.erb +3 -0
  129. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_metadata.erb +4 -1
  130. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_table.erb +5 -2
  131. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/index.erb +7 -4
  132. data/lib/karafka/web/pro/ui/views/consumers/commands/show.erb +32 -0
  133. data/lib/karafka/web/pro/ui/views/consumers/consumers/_breadcrumbs.erb +46 -0
  134. data/lib/karafka/web/pro/ui/views/consumers/{_consumer.erb → consumers/_consumer.erb} +4 -1
  135. data/lib/karafka/web/pro/ui/views/consumers/{_consumer_performance.erb → consumers/_consumer_performance.erb} +4 -1
  136. data/lib/karafka/web/pro/ui/views/consumers/consumers/_tabs.erb +38 -0
  137. data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_commands.erb +80 -0
  138. data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_consumer_group.erb +11 -0
  139. data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_metrics.erb +3 -0
  140. data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_no_subscriptions.erb +10 -0
  141. data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_partition.erb +16 -0
  142. data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_partition_edit_options.erb +33 -0
  143. data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_stopped.erb +3 -0
  144. data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_subscription_group.erb +7 -3
  145. data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_tabs.erb +7 -4
  146. data/lib/karafka/web/pro/ui/views/consumers/consumers/details.erb +15 -0
  147. data/lib/karafka/web/pro/ui/views/consumers/{index.erb → consumers/index.erb} +6 -3
  148. data/lib/karafka/web/pro/ui/views/consumers/{performance.erb → consumers/performance.erb} +6 -3
  149. data/lib/karafka/web/pro/ui/views/consumers/consumers/subscriptions.erb +24 -0
  150. data/lib/karafka/web/pro/ui/views/consumers/controls/_breadcrumbs.erb +16 -0
  151. data/lib/karafka/web/pro/ui/views/consumers/{_consumer_controls.erb → controls/_controls.erb} +10 -7
  152. data/lib/karafka/web/pro/ui/views/consumers/{controls.erb → controls/index.erb} +8 -5
  153. data/lib/karafka/web/pro/ui/views/consumers/jobs/_breadcrumbs.erb +36 -0
  154. data/lib/karafka/web/pro/ui/views/consumers/{consumer → jobs}/_job.erb +4 -2
  155. data/lib/karafka/web/pro/ui/views/consumers/jobs/_no_jobs.erb +6 -0
  156. data/lib/karafka/web/pro/ui/views/consumers/{pending_jobs.erb → jobs/pending.erb} +7 -8
  157. data/lib/karafka/web/pro/ui/views/consumers/{running_jobs.erb → jobs/running.erb} +7 -8
  158. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_basics.erb +77 -0
  159. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_breadcrumbs.erb +58 -0
  160. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_form.erb +109 -0
  161. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_not_running_error.erb +16 -0
  162. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_running_warning.erb +15 -0
  163. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/edit.erb +16 -0
  164. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_active_not_editable.erb +22 -0
  165. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_adjusting_warning.erb +27 -0
  166. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_breadcrumbs.erb +60 -0
  167. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_edit_form.erb +59 -0
  168. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_lrj_not_manageable.erb +24 -0
  169. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_new_form.erb +78 -0
  170. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_not_running.erb +16 -0
  171. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/edit.erb +24 -0
  172. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/new.erb +20 -0
  173. data/lib/karafka/web/pro/ui/views/dashboard/index.erb +4 -1
  174. data/lib/karafka/web/pro/ui/views/dlq/_breadcrumbs.erb +3 -0
  175. data/lib/karafka/web/pro/ui/views/dlq/_no_topics.erb +3 -0
  176. data/lib/karafka/web/pro/ui/views/dlq/_topic.erb +4 -1
  177. data/lib/karafka/web/pro/ui/views/dlq/index.erb +3 -0
  178. data/lib/karafka/web/pro/ui/views/errors/_breadcrumbs.erb +4 -6
  179. data/lib/karafka/web/pro/ui/views/errors/_error.erb +9 -1
  180. data/lib/karafka/web/pro/ui/views/errors/_partition_option.erb +3 -0
  181. data/lib/karafka/web/pro/ui/views/errors/_selector.erb +3 -0
  182. data/lib/karafka/web/pro/ui/views/errors/_table.erb +4 -1
  183. data/lib/karafka/web/pro/ui/views/errors/index.erb +6 -3
  184. data/lib/karafka/web/pro/ui/views/errors/partition.erb +5 -2
  185. data/lib/karafka/web/pro/ui/views/errors/show.erb +42 -33
  186. data/lib/karafka/web/pro/ui/views/explorer/{_breadcrumbs.erb → explorer/_breadcrumbs.erb} +7 -4
  187. data/lib/karafka/web/pro/ui/views/explorer/{_failed_deserialization.erb → explorer/_failed_deserialization.erb} +3 -0
  188. data/lib/karafka/web/pro/ui/views/explorer/{_filtered.erb → explorer/_filtered.erb} +3 -0
  189. data/lib/karafka/web/pro/ui/views/explorer/{_message.erb → explorer/_message.erb} +4 -1
  190. data/lib/karafka/web/pro/ui/views/explorer/explorer/_no_topics.erb +4 -0
  191. data/lib/karafka/web/pro/ui/views/explorer/{_partition_option.erb → explorer/_partition_option.erb} +4 -1
  192. data/lib/karafka/web/pro/ui/views/explorer/{_selector.erb → explorer/_selector.erb} +4 -1
  193. data/lib/karafka/web/pro/ui/views/explorer/explorer/_topic.erb +13 -0
  194. data/lib/karafka/web/pro/ui/views/explorer/explorer/index.erb +17 -0
  195. data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_metadata.erb +10 -7
  196. data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_payload.erb +6 -3
  197. data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_resources_utilization.erb +7 -4
  198. data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_too_big_to_be_displayed.erb +3 -0
  199. data/lib/karafka/web/pro/ui/views/explorer/{messages → explorer/messages}/_detail.erb +3 -0
  200. data/lib/karafka/web/pro/ui/views/explorer/explorer/messages/_headers.erb +51 -0
  201. data/lib/karafka/web/pro/ui/views/explorer/{messages → explorer/messages}/_key.erb +3 -0
  202. data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_cleaned.erb +6 -0
  203. data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_empty.erb +6 -0
  204. data/lib/karafka/web/pro/ui/views/explorer/{partition → explorer/partition}/_messages.erb +4 -1
  205. data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_time_selector.erb +16 -0
  206. data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_timestamp_selector.erb +33 -0
  207. data/lib/karafka/web/pro/ui/views/explorer/{partition.erb → explorer/partition.erb} +24 -17
  208. data/lib/karafka/web/pro/ui/views/explorer/explorer/show.erb +100 -0
  209. data/lib/karafka/web/pro/ui/views/explorer/{topic → explorer/topic}/_actions.erb +5 -2
  210. data/lib/karafka/web/pro/ui/views/explorer/explorer/topic/_empty.erb +6 -0
  211. data/lib/karafka/web/pro/ui/views/explorer/{topic → explorer/topic}/_limited.erb +3 -0
  212. data/lib/karafka/web/pro/ui/views/explorer/{topic.erb → explorer/topic.erb} +7 -4
  213. data/lib/karafka/web/pro/ui/views/explorer/messages/_breadcrumbs.erb +32 -0
  214. data/lib/karafka/web/pro/ui/views/explorer/messages/forward.erb +143 -0
  215. data/lib/karafka/web/pro/ui/views/explorer/search/_breadcrumbs.erb +4 -0
  216. data/lib/karafka/web/pro/ui/views/explorer/search/_fix_errors.erb +6 -0
  217. data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_metadata.erb +3 -0
  218. data/lib/karafka/web/pro/ui/views/explorer/search/_no_results.erb +6 -0
  219. data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_no_search_criteria.erb +3 -0
  220. data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_search_criteria.erb +3 -0
  221. data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_search_modal.erb +5 -2
  222. data/lib/karafka/web/pro/ui/views/explorer/search/_timeout.erb +6 -0
  223. data/lib/karafka/web/pro/ui/views/explorer/search/index.erb +32 -0
  224. data/lib/karafka/web/pro/ui/views/health/_breadcrumbs.erb +3 -0
  225. data/lib/karafka/web/pro/ui/views/health/_no_data.erb +3 -0
  226. data/lib/karafka/web/pro/ui/views/health/_partition.erb +16 -1
  227. data/lib/karafka/web/pro/ui/views/health/_partition_lags.erb +3 -0
  228. data/lib/karafka/web/pro/ui/views/health/_partition_offset.erb +3 -0
  229. data/lib/karafka/web/pro/ui/views/health/_partition_times.erb +3 -0
  230. data/lib/karafka/web/pro/ui/views/health/_table_metadata.erb +4 -1
  231. data/lib/karafka/web/pro/ui/views/health/_tabs.erb +3 -0
  232. data/lib/karafka/web/pro/ui/views/health/changes.erb +4 -1
  233. data/lib/karafka/web/pro/ui/views/health/cluster_lags.erb +3 -0
  234. data/lib/karafka/web/pro/ui/views/health/lags.erb +5 -2
  235. data/lib/karafka/web/pro/ui/views/health/offsets.erb +4 -1
  236. data/lib/karafka/web/pro/ui/views/health/overview.erb +8 -3
  237. data/lib/karafka/web/pro/ui/views/jobs/_job.erb +5 -3
  238. data/lib/karafka/web/pro/ui/views/jobs/_no_jobs.erb +3 -0
  239. data/lib/karafka/web/pro/ui/views/jobs/pending.erb +4 -1
  240. data/lib/karafka/web/pro/ui/views/jobs/running.erb +4 -1
  241. data/lib/karafka/web/pro/ui/views/recurring_tasks/_actions.erb +3 -0
  242. data/lib/karafka/web/pro/ui/views/recurring_tasks/_batch_actions.erb +3 -0
  243. data/lib/karafka/web/pro/ui/views/recurring_tasks/_breadcrumbs.erb +3 -0
  244. data/lib/karafka/web/pro/ui/views/recurring_tasks/_log.erb +3 -0
  245. data/lib/karafka/web/pro/ui/views/recurring_tasks/_not_active.erb +3 -0
  246. data/lib/karafka/web/pro/ui/views/recurring_tasks/_tabs.erb +3 -0
  247. data/lib/karafka/web/pro/ui/views/recurring_tasks/_task.erb +3 -0
  248. data/lib/karafka/web/pro/ui/views/recurring_tasks/logs.erb +3 -0
  249. data/lib/karafka/web/pro/ui/views/recurring_tasks/schedule.erb +3 -0
  250. data/lib/karafka/web/pro/ui/views/routing/_consumer_group.erb +3 -0
  251. data/lib/karafka/web/pro/ui/views/routing/_detail.erb +3 -0
  252. data/lib/karafka/web/pro/ui/views/routing/_topic.erb +3 -0
  253. data/lib/karafka/web/pro/ui/views/routing/index.erb +3 -0
  254. data/lib/karafka/web/pro/ui/views/routing/show.erb +3 -0
  255. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_breadcrumbs.erb +6 -3
  256. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_key.erb +3 -0
  257. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_message.erb +28 -115
  258. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_messages.erb +3 -0
  259. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/message/_cancel.erb +49 -0
  260. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/message/_compacted.erb +16 -0
  261. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/message/_schedule.erb +83 -0
  262. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/message/_tombstone.erb +69 -0
  263. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/message/_unknown.erb +26 -0
  264. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/partition.erb +23 -16
  265. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/topic.erb +6 -3
  266. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_breadcrumbs.erb +3 -0
  267. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_no_groups.erb +3 -0
  268. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/index.erb +4 -1
  269. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/show.erb +17 -1
  270. data/lib/karafka/web/pro/ui/views/shared/_navigation.erb +25 -17
  271. data/lib/karafka/web/pro/ui/views/shared/_rdkafka_form_error_alert_box.erb +16 -0
  272. data/lib/karafka/web/pro/ui/views/shared/branding/_label.erb +3 -0
  273. data/lib/karafka/web/pro/ui/views/shared/branding/_notice.erb +3 -0
  274. data/lib/karafka/web/pro/ui/views/topics/configs/_breadcrumbs.erb +34 -0
  275. data/lib/karafka/web/pro/ui/views/topics/configs/_config.erb +26 -0
  276. data/lib/karafka/web/pro/ui/views/topics/configs/_delete_button.erb +13 -0
  277. data/lib/karafka/web/pro/ui/views/topics/configs/_edit_form.erb +50 -0
  278. data/lib/karafka/web/pro/ui/views/topics/configs/_edit_plan.erb +16 -0
  279. data/lib/karafka/web/pro/ui/views/topics/configs/_edit_warning.erb +12 -0
  280. data/lib/karafka/web/pro/ui/views/topics/configs/edit.erb +16 -0
  281. data/lib/karafka/web/pro/ui/views/topics/{config.erb → configs/index.erb} +9 -3
  282. data/lib/karafka/web/pro/ui/views/topics/distributions/_add_partitions_button.erb +13 -0
  283. data/lib/karafka/web/pro/ui/views/topics/{distribution → distributions}/_badges.erb +3 -0
  284. data/lib/karafka/web/pro/ui/views/topics/distributions/_breadcrumbs.erb +28 -0
  285. data/lib/karafka/web/pro/ui/views/topics/{distribution → distributions}/_chart.erb +3 -0
  286. data/lib/karafka/web/pro/ui/views/topics/distributions/_edit_form.erb +47 -0
  287. data/lib/karafka/web/pro/ui/views/topics/distributions/_edit_hints.erb +15 -0
  288. data/lib/karafka/web/pro/ui/views/topics/distributions/_edit_warnings.erb +14 -0
  289. data/lib/karafka/web/pro/ui/views/topics/distributions/_empty_partitions.erb +4 -0
  290. data/lib/karafka/web/pro/ui/views/topics/{distribution → distributions}/_limited.erb +3 -0
  291. data/lib/karafka/web/pro/ui/views/topics/distributions/_partition.erb +13 -0
  292. data/lib/karafka/web/pro/ui/views/topics/distributions/edit.erb +16 -0
  293. data/lib/karafka/web/pro/ui/views/topics/{distribution.erb → distributions/show.erb} +11 -7
  294. data/lib/karafka/web/pro/ui/views/topics/offsets/_breadcrumbs.erb +20 -0
  295. data/lib/karafka/web/pro/ui/views/topics/offsets/_partition.erb +13 -0
  296. data/lib/karafka/web/pro/ui/views/topics/{offsets.erb → offsets/show.erb} +6 -3
  297. data/lib/karafka/web/pro/ui/views/topics/replications/_breadcrumbs.erb +20 -0
  298. data/lib/karafka/web/pro/ui/views/topics/{_partition.erb → replications/_partition.erb} +4 -1
  299. data/lib/karafka/web/pro/ui/views/topics/{replication.erb → replications/show.erb} +6 -3
  300. data/lib/karafka/web/pro/ui/views/topics/topics/_breadcrumbs.erb +32 -0
  301. data/lib/karafka/web/pro/ui/views/topics/topics/_create_button.erb +13 -0
  302. data/lib/karafka/web/pro/ui/views/topics/topics/_create_hints.erb +15 -0
  303. data/lib/karafka/web/pro/ui/views/topics/topics/_delete_form.erb +36 -0
  304. data/lib/karafka/web/pro/ui/views/topics/topics/_delete_hints.erb +15 -0
  305. data/lib/karafka/web/pro/ui/views/topics/topics/_delete_warning.erb +13 -0
  306. data/lib/karafka/web/pro/ui/views/topics/topics/_new_form.erb +80 -0
  307. data/lib/karafka/web/pro/ui/views/topics/{_tabs.erb → topics/_tabs.erb} +7 -4
  308. data/lib/karafka/web/pro/ui/views/topics/topics/_topic.erb +12 -0
  309. data/lib/karafka/web/pro/ui/views/topics/topics/edit.erb +10 -0
  310. data/lib/karafka/web/pro/ui/views/topics/topics/index.erb +19 -0
  311. data/lib/karafka/web/pro/ui/views/topics/topics/new.erb +12 -0
  312. data/lib/karafka/web/processing/consumer.rb +7 -7
  313. data/lib/karafka/web/processing/consumers/aggregators/state.rb +14 -14
  314. data/lib/karafka/web/processing/consumers/metrics.rb +1 -1
  315. data/lib/karafka/web/processing/consumers/state.rb +1 -1
  316. data/lib/karafka/web/processing/publisher.rb +4 -4
  317. data/lib/karafka/web/tracking/consumers/contracts/partition.rb +1 -0
  318. data/lib/karafka/web/tracking/consumers/listeners/errors.rb +1 -0
  319. data/lib/karafka/web/tracking/consumers/listeners/pausing.rb +2 -2
  320. data/lib/karafka/web/tracking/consumers/listeners/transactions.rb +44 -0
  321. data/lib/karafka/web/tracking/consumers/reporter.rb +2 -2
  322. data/lib/karafka/web/tracking/consumers/sampler.rb +81 -14
  323. data/lib/karafka/web/tracking/helpers/sysconf.rb +33 -0
  324. data/lib/karafka/web/tracking/producers/reporter.rb +1 -1
  325. data/lib/karafka/web/ui/app.rb +19 -112
  326. data/lib/karafka/web/ui/base.rb +60 -3
  327. data/lib/karafka/web/ui/controllers/base_controller.rb +43 -1
  328. data/lib/karafka/web/ui/controllers/cluster_controller.rb +5 -2
  329. data/lib/karafka/web/ui/controllers/errors_controller.rb +13 -4
  330. data/lib/karafka/web/ui/controllers/requests/execution_wrapper.rb +52 -0
  331. data/lib/karafka/web/ui/controllers/requests/hookable.rb +99 -0
  332. data/lib/karafka/web/ui/controllers/requests/params.rb +39 -1
  333. data/lib/karafka/web/ui/controllers/responses/redirect.rb +0 -5
  334. data/lib/karafka/web/ui/controllers/status_controller.rb +3 -0
  335. data/lib/karafka/web/ui/helpers/application_helper.rb +10 -71
  336. data/lib/karafka/web/ui/helpers/paths_helper.rb +54 -10
  337. data/lib/karafka/web/ui/helpers/time_helper.rb +82 -0
  338. data/lib/karafka/web/ui/helpers/topics_helper.rb +156 -0
  339. data/lib/karafka/web/ui/lib/admin.rb +1 -1
  340. data/lib/karafka/web/ui/lib/cache.rb +135 -0
  341. data/lib/karafka/web/ui/models/broker.rb +1 -2
  342. data/lib/karafka/web/ui/models/cluster_info.rb +15 -21
  343. data/lib/karafka/web/ui/models/consumers_metrics.rb +1 -1
  344. data/lib/karafka/web/ui/models/consumers_state.rb +1 -1
  345. data/lib/karafka/web/ui/models/counters.rb +1 -1
  346. data/lib/karafka/web/ui/models/health.rb +9 -7
  347. data/lib/karafka/web/ui/models/message.rb +20 -2
  348. data/lib/karafka/web/ui/models/process.rb +16 -0
  349. data/lib/karafka/web/ui/models/processes.rb +29 -8
  350. data/lib/karafka/web/ui/models/recurring_tasks/schedule.rb +1 -1
  351. data/lib/karafka/web/ui/models/status.rb +28 -9
  352. data/lib/karafka/web/ui/models/topic.rb +1 -2
  353. data/lib/karafka/web/ui/public/javascripts/application.js +8 -98
  354. data/lib/karafka/web/ui/public/javascripts/application.min.js +12 -4
  355. data/lib/karafka/web/ui/public/javascripts/application.min.js.br +0 -0
  356. data/lib/karafka/web/ui/public/javascripts/application.min.js.gz +0 -0
  357. data/lib/karafka/web/ui/public/javascripts/components/action_confirmation_manager.js +30 -0
  358. data/lib/karafka/web/ui/public/javascripts/components/alerts.js +39 -0
  359. data/lib/karafka/web/ui/public/javascripts/components/button_lock_manager.js +50 -0
  360. data/lib/karafka/web/ui/public/javascripts/components/live_poll.js +71 -19
  361. data/lib/karafka/web/ui/public/javascripts/components/message_republish_manager.js +50 -0
  362. data/lib/karafka/web/ui/public/javascripts/components/page_title_tracker.js +21 -0
  363. data/lib/karafka/web/ui/public/javascripts/components/partition_redirect_manager.js +21 -0
  364. data/lib/karafka/web/ui/public/javascripts/components/time_ago_manager.js +25 -0
  365. data/lib/karafka/web/ui/public/javascripts/components/timestamp_selector.js +30 -0
  366. data/lib/karafka/web/ui/public/javascripts/libs/datepicker.js +2 -2
  367. data/lib/karafka/web/ui/public/stylesheets/application.css +30 -0
  368. data/lib/karafka/web/ui/public/stylesheets/application.min.css +5110 -13
  369. data/lib/karafka/web/ui/public/stylesheets/application.min.css.br +0 -0
  370. data/lib/karafka/web/ui/public/stylesheets/application.min.css.gz +0 -0
  371. data/lib/karafka/web/ui/public/stylesheets/libs/highlight_dark.min.css.gz +0 -0
  372. data/lib/karafka/web/ui/public/stylesheets/libs/highlight_light.min.css.gz +0 -0
  373. data/lib/karafka/web/ui/public/stylesheets/libs/tailwind.css +507 -214
  374. data/lib/karafka/web/ui/routes/assets.rb +53 -0
  375. data/lib/karafka/web/ui/routes/base.rb +36 -0
  376. data/lib/karafka/web/ui/routes/cluster.rb +28 -0
  377. data/lib/karafka/web/ui/routes/consumers.rb +35 -0
  378. data/lib/karafka/web/ui/routes/dashboard.rb +20 -0
  379. data/lib/karafka/web/ui/routes/errors.rb +30 -0
  380. data/lib/karafka/web/ui/routes/jobs.rb +28 -0
  381. data/lib/karafka/web/ui/routes/pro_only.rb +27 -0
  382. data/lib/karafka/web/ui/routes/routing.rb +26 -0
  383. data/lib/karafka/web/ui/routes/status.rb +19 -0
  384. data/lib/karafka/web/ui/routes/support.rb +19 -0
  385. data/lib/karafka/web/ui/routes/ux.rb +19 -0
  386. data/lib/karafka/web/ui/views/cluster/_partition.erb +2 -2
  387. data/lib/karafka/web/ui/views/cluster/brokers.erb +1 -1
  388. data/lib/karafka/web/ui/views/consumers/_assignments_badges.erb +2 -7
  389. data/lib/karafka/web/ui/views/consumers/_breadcrumbs.erb +7 -1
  390. data/lib/karafka/web/ui/views/consumers/_consumer.erb +1 -1
  391. data/lib/karafka/web/ui/views/consumers/_no_consumers.erb +2 -2
  392. data/lib/karafka/web/ui/views/consumers/_tabs.erb +4 -4
  393. data/lib/karafka/web/ui/views/consumers/index.erb +1 -1
  394. data/lib/karafka/web/ui/views/dashboard/_feature_pro.erb +1 -1
  395. data/lib/karafka/web/ui/views/dashboard/_not_enough_data.erb +2 -2
  396. data/lib/karafka/web/ui/views/dashboard/_ranges_selector.erb +1 -1
  397. data/lib/karafka/web/ui/views/dashboard/index.erb +6 -49
  398. data/lib/karafka/web/ui/views/errors/_breadcrumbs.erb +3 -8
  399. data/lib/karafka/web/ui/views/errors/_detail.erb +3 -3
  400. data/lib/karafka/web/ui/views/errors/_error.erb +6 -1
  401. data/lib/karafka/web/ui/views/errors/index.erb +1 -1
  402. data/lib/karafka/web/ui/views/errors/show.erb +39 -33
  403. data/lib/karafka/web/ui/views/jobs/_job.erb +2 -3
  404. data/lib/karafka/web/ui/views/jobs/pending.erb +1 -1
  405. data/lib/karafka/web/ui/views/jobs/running.erb +1 -1
  406. data/lib/karafka/web/ui/views/layout.erb +7 -5
  407. data/lib/karafka/web/ui/views/shared/_become_pro.erb +1 -1
  408. data/lib/karafka/web/ui/views/shared/_brand.erb +1 -1
  409. data/lib/karafka/web/ui/views/shared/_breadcrumbs.erb +1 -1
  410. data/lib/karafka/web/ui/views/shared/_compacted_message_info.erb +16 -0
  411. data/lib/karafka/web/ui/views/shared/_content.erb +1 -1
  412. data/lib/karafka/web/ui/views/shared/_controls.erb +10 -3
  413. data/lib/karafka/web/ui/views/shared/_custom_nav.erb +9 -0
  414. data/lib/karafka/web/ui/views/shared/_flashes.erb +3 -5
  415. data/lib/karafka/web/ui/views/shared/_header.erb +25 -2
  416. data/lib/karafka/web/ui/views/shared/_navigation.erb +17 -15
  417. data/lib/karafka/web/ui/views/shared/alerts/_error.erb +8 -0
  418. data/lib/karafka/web/ui/views/shared/alerts/_info.erb +8 -0
  419. data/lib/karafka/web/ui/views/shared/alerts/_primary.erb +8 -0
  420. data/lib/karafka/web/ui/views/shared/alerts/_secondary.erb +8 -0
  421. data/lib/karafka/web/ui/views/shared/alerts/_success.erb +8 -0
  422. data/lib/karafka/web/ui/views/shared/alerts/_warning.erb +8 -0
  423. data/lib/karafka/web/ui/views/shared/exceptions/not_allowed.erb +4 -0
  424. data/lib/karafka/web/ui/views/shared/exceptions/not_found.erb +5 -1
  425. data/lib/karafka/web/ui/views/shared/exceptions/pro_only.erb +4 -0
  426. data/lib/karafka/web/ui/views/shared/icons/_arrow_left.erb +3 -0
  427. data/lib/karafka/web/ui/views/shared/icons/_arrow_up_tray.erb +3 -0
  428. data/lib/karafka/web/ui/views/shared/icons/_clock.erb +3 -0
  429. data/lib/karafka/web/ui/views/shared/icons/_pencil.erb +3 -0
  430. data/lib/karafka/web/ui/views/shared/icons/_pencil_square.erb +3 -0
  431. data/lib/karafka/web/ui/views/shared/icons/_play_pause.erb +3 -0
  432. data/lib/karafka/web/ui/views/shared/icons/_plus.erb +3 -0
  433. data/lib/karafka/web/ui/views/shared/icons/_trash.erb +3 -0
  434. data/lib/karafka/web/ui/views/status/failures/_live_reporting.erb +1 -1
  435. data/lib/karafka/web/ui/views/status/failures/_partitions.erb +3 -3
  436. data/lib/karafka/web/ui/views/status/failures/_state_calculation.erb +2 -2
  437. data/lib/karafka/web/ui/views/status/info/_components.erb +6 -6
  438. data/lib/karafka/web/ui/views/status/show.erb +15 -0
  439. data/lib/karafka/web/ui/views/status/warnings/_consumers_schemas.erb +31 -0
  440. data/lib/karafka/web/ui/views/ux/_icons.erb +1 -1
  441. data/lib/karafka/web/version.rb +1 -1
  442. data/lib/karafka/web.rb +3 -0
  443. data/package-lock.json +868 -1255
  444. data/package.json +6 -7
  445. data/postcss.config.js +1 -2
  446. data/renovate.json +20 -1
  447. data/tailwind.config.js +0 -4
  448. metadata +235 -135
  449. checksums.yaml.gz.sig +0 -0
  450. data/certs/cert.pem +0 -26
  451. data/lib/karafka/web/pro/commanding/commands/quiet.rb +0 -34
  452. data/lib/karafka/web/pro/commanding/commands/stop.rb +0 -34
  453. data/lib/karafka/web/pro/commanding/commands/trace.rb +0 -41
  454. data/lib/karafka/web/pro/ui/controllers/commanding_controller.rb +0 -118
  455. data/lib/karafka/web/pro/ui/controllers/commands_controller.rb +0 -96
  456. data/lib/karafka/web/pro/ui/controllers/consumers_controller.rb +0 -138
  457. data/lib/karafka/web/pro/ui/controllers/explorer_controller.rb +0 -220
  458. data/lib/karafka/web/pro/ui/controllers/messages_controller.rb +0 -107
  459. data/lib/karafka/web/pro/ui/controllers/search_controller.rb +0 -73
  460. data/lib/karafka/web/pro/ui/controllers/topics_controller.rb +0 -130
  461. data/lib/karafka/web/pro/ui/views/commands/_breadcrumbs.erb +0 -21
  462. data/lib/karafka/web/pro/ui/views/commands/_command_details.erb +0 -1
  463. data/lib/karafka/web/pro/ui/views/commands/_empty.erb +0 -3
  464. data/lib/karafka/web/pro/ui/views/commands/show.erb +0 -33
  465. data/lib/karafka/web/pro/ui/views/consumers/_breadcrumbs.erb +0 -55
  466. data/lib/karafka/web/pro/ui/views/consumers/_tabs.erb +0 -33
  467. data/lib/karafka/web/pro/ui/views/consumers/consumer/_commands.erb +0 -72
  468. data/lib/karafka/web/pro/ui/views/consumers/consumer/_consumer_group.erb +0 -8
  469. data/lib/karafka/web/pro/ui/views/consumers/consumer/_no_jobs.erb +0 -7
  470. data/lib/karafka/web/pro/ui/views/consumers/consumer/_no_subscriptions.erb +0 -7
  471. data/lib/karafka/web/pro/ui/views/consumers/details.erb +0 -13
  472. data/lib/karafka/web/pro/ui/views/consumers/subscriptions.erb +0 -25
  473. data/lib/karafka/web/pro/ui/views/explorer/_no_topics.erb +0 -1
  474. data/lib/karafka/web/pro/ui/views/explorer/_topic.erb +0 -10
  475. data/lib/karafka/web/pro/ui/views/explorer/index.erb +0 -14
  476. data/lib/karafka/web/pro/ui/views/explorer/messages/_headers.erb +0 -33
  477. data/lib/karafka/web/pro/ui/views/explorer/partition/_cleaned.erb +0 -3
  478. data/lib/karafka/web/pro/ui/views/explorer/partition/_empty.erb +0 -3
  479. data/lib/karafka/web/pro/ui/views/explorer/show.erb +0 -97
  480. data/lib/karafka/web/pro/ui/views/explorer/topic/_empty.erb +0 -3
  481. data/lib/karafka/web/pro/ui/views/search/_breadcrumbs.erb +0 -1
  482. data/lib/karafka/web/pro/ui/views/search/_fix_errors.erb +0 -3
  483. data/lib/karafka/web/pro/ui/views/search/_no_results.erb +0 -3
  484. data/lib/karafka/web/pro/ui/views/search/_timeout.erb +0 -3
  485. data/lib/karafka/web/pro/ui/views/search/index.erb +0 -29
  486. data/lib/karafka/web/pro/ui/views/topics/_breadcrumbs.erb +0 -45
  487. data/lib/karafka/web/pro/ui/views/topics/_partition_offsets.erb +0 -10
  488. data/lib/karafka/web/pro/ui/views/topics/_topic.erb +0 -9
  489. data/lib/karafka/web/pro/ui/views/topics/distribution/_empty_partitions.erb +0 -1
  490. data/lib/karafka/web/pro/ui/views/topics/distribution/_partition.erb +0 -10
  491. data/lib/karafka/web/pro/ui/views/topics/index.erb +0 -14
  492. data/lib/karafka/web/ui/lib/ttl_cache.rb +0 -82
  493. data.tar.gz.sig +0 -0
  494. metadata.gz.sig +0 -0
@@ -11,122 +11,29 @@ module Karafka
11
11
 
12
12
  instance_exec(&CONTEXT_DETAILS)
13
13
 
14
+ # Sub-routes for given pieces of the Web UI
15
+ SUB_ROUTES = [
16
+ Routes::Assets,
17
+ Routes::Dashboard,
18
+ Routes::Consumers,
19
+ Routes::ProOnly,
20
+ Routes::Jobs,
21
+ Routes::Routing,
22
+ Routes::Cluster,
23
+ Routes::Errors,
24
+ Routes::Status,
25
+ Routes::Support,
26
+ Routes::Ux
27
+ ].freeze
28
+
29
+ private_constant :SUB_ROUTES
30
+
14
31
  route do |r|
15
32
  r.root { r.redirect root_path('dashboard') }
16
33
 
17
- # Serve current version specific assets to prevent users from fetching old assets
18
- # after upgrade
19
- r.on 'assets', Karafka::Web::VERSION do
20
- r.public
21
- end
22
-
23
- r.get 'dashboard' do
24
- @breadcrumbs = false
25
- controller = Controllers::DashboardController.new(params)
26
- controller.index
27
- end
28
-
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
-
40
- r.get String, 'subscriptions' do |_process_id|
41
- raise Errors::Ui::ProOnlyError
42
- end
43
-
44
- r.get do
45
- controller = Controllers::ConsumersController.new(params)
46
- controller.index
47
- end
48
- end
49
-
50
- %w[
51
- health
52
- explorer
53
- dlq
54
- ].each do |route|
55
- r.get route, [String, true], [String, true] do
56
- raise Errors::Ui::ProOnlyError
57
- end
58
- end
59
-
60
- r.on 'jobs' do
61
- controller = Controllers::JobsController.new(params)
62
-
63
- r.get 'running' do
64
- controller.running
65
- end
66
-
67
- r.get 'pending' do
68
- controller.pending
69
- end
70
-
71
- r.redirect root_path('jobs/running')
72
- end
73
-
74
- r.on 'routing' do
75
- controller = Controllers::RoutingController.new(params)
76
-
77
- r.get String do |topic_id|
78
- controller.show(topic_id)
79
- end
80
-
81
- r.get do
82
- controller.index
83
- end
84
- end
85
-
86
- r.on 'cluster' do
87
- controller = Controllers::ClusterController.new(params)
88
-
89
- r.get 'brokers' do
90
- controller.brokers
91
- end
92
-
93
- r.get 'replication' do
94
- controller.replication
95
- end
96
-
97
- r.redirect root_path('cluster/brokers')
98
- end
99
-
100
- r.on 'topics' do
101
- raise Errors::Ui::ProOnlyError
102
- end
103
-
104
- r.on 'errors' do
105
- controller = Controllers::ErrorsController.new(params)
106
-
107
- r.get Integer do |offset|
108
- controller.show(offset)
109
- end
110
-
111
- r.get do
112
- controller.index
113
- end
114
- end
115
-
116
- r.get 'status' do
117
- controller = Controllers::StatusController.new(params)
118
- controller.show
119
- end
120
-
121
- r.get 'ux' do
122
- controller = Controllers::UxController.new(params)
123
- controller.show
124
- end
34
+ SUB_ROUTES.each { |sub_route| sub_route.bind(self, r) }
125
35
 
126
- r.get 'support' do
127
- controller = Controllers::SupportController.new(params)
128
- controller.show
129
- end
36
+ nil
130
37
  end
131
38
  end
132
39
  end
@@ -7,6 +7,8 @@ module Karafka
7
7
  class Base < Roda
8
8
  include Helpers::PathsHelper
9
9
  include Helpers::ApplicationHelper
10
+ include Helpers::TimeHelper
11
+ include Helpers::TopicsHelper
10
12
  include Helpers::TailwindHelper
11
13
 
12
14
  # Details that need to be evaluated in the context of OSS or Pro web UI.
@@ -40,6 +42,7 @@ module Karafka
40
42
  plugin :capture_erb
41
43
  plugin :content_for
42
44
  plugin :inject_erb
45
+ plugin :all_verbs
43
46
 
44
47
  # Based on
45
48
  # https://github.com/sidekiq/sidekiq/blob/ae6ca119/lib/sidekiq/web/application.rb#L8
@@ -70,7 +73,16 @@ module Karafka
70
73
  # Map redirect flashes (if any) to Roda flash messages
71
74
  result.flashes.each { |key, value| flash[key] = value }
72
75
 
73
- response.redirect result.back? ? request.referer : root_path(result.path)
76
+ path = case result.path
77
+ when :back
78
+ session[:current_path]
79
+ when :previous
80
+ session[:previous_path]
81
+ else
82
+ root_path(result.path)
83
+ end
84
+
85
+ response.redirect path || root_path
74
86
  end
75
87
 
76
88
  handle_block_result Controllers::Responses::File do |result|
@@ -109,9 +121,11 @@ module Karafka
109
121
 
110
122
  before do
111
123
  check_csrf!
124
+ store_paths_history(request, session)
112
125
  end
113
126
 
114
127
  plugin :class_matchers
128
+ plugin :symbol_matchers
115
129
 
116
130
  # Time matcher with optional hours, minutes and seconds
117
131
  TIME_MATCHER = %r{(\d{4}-\d{2}-\d{2}/?(\d{2})?(:\d{2})?(:\d{2})?)}
@@ -122,12 +136,22 @@ module Karafka
122
136
  # @note In case the date-time is invalid, raise and render 404
123
137
  # @note The time component is optional as `Time#parse` will fallback to lowest time
124
138
  # available, so we can build only date based lookups
125
- class_matcher(Time, TIME_MATCHER) do |datetime|
126
- [Time.parse(datetime)]
139
+ class_matcher(Time, TIME_MATCHER) do |*datetime|
140
+ [Time.parse(datetime[0])]
127
141
  rescue ArgumentError
128
142
  raise Errors::Ui::NotFoundError
129
143
  end
130
144
 
145
+ # Partitions ids cannot be bigger than 32 bit C int. We use this matcher to ensure we
146
+ # only support that big partition numbers. Otherwise librdkafka would crash.
147
+ symbol_matcher :partition_id, /(\d{1,14})/ do |value|
148
+ int_value = value.to_i
149
+
150
+ raise Errors::Ui::NotFoundError unless int_value.between?(0, 2_147_483_647)
151
+
152
+ [int_value]
153
+ end
154
+
131
155
  # Allows us to build current path with additional params + it merges existing params into
132
156
  # the query data. Query data takes priority over request params.
133
157
  # @param query_data [Hash] query params we want to add to the current path
@@ -145,6 +169,14 @@ module Karafka
145
169
  [request.path, query_string].compact.join('?')
146
170
  end
147
171
 
172
+ # Builds a consumer instance with all needed details
173
+ # @param consumer_class [Class]
174
+ def build(consumer_class)
175
+ Controllers::Requests::ExecutionWrapper.new(
176
+ consumer_class.new(params, session)
177
+ )
178
+ end
179
+
148
180
  # Sets appropriate template variables based on the response object and renders the
149
181
  # expected view
150
182
  # @param response [Karafka::Web::Ui::Controllers::Responses::Data] response data object
@@ -162,6 +194,31 @@ module Karafka
162
194
  def params
163
195
  Controllers::Requests::Params.new(request.params)
164
196
  end
197
+
198
+ private
199
+
200
+ # Stores history about visited paths. Useful for redirecting users back when needed.
201
+ # @param request [Karafka::Web::Ui::App::RodaRequest]
202
+ # @param session [Object] session object (Rails or Rack)
203
+ def store_paths_history(request, session)
204
+ # Code below tracks previous paths so we can use it to redirect users back
205
+ return unless request.get?
206
+ return unless request.env['HTTP_ACCEPT']&.include?('text/html')
207
+
208
+ requested_path = request.path
209
+
210
+ if session[:current_path].nil?
211
+ session[:current_path] = requested_path
212
+
213
+ return
214
+ end
215
+
216
+ return if request.path == session[:current_path]
217
+
218
+ # When navigating to a different page
219
+ session[:previous_path] = session[:current_path]
220
+ session[:current_path] = requested_path
221
+ end
165
222
  end
166
223
  end
167
224
  end
@@ -8,6 +8,9 @@ module Karafka
8
8
  # Base controller from which all the controllers should inherit.
9
9
  class BaseController
10
10
  include Web::Ui::Lib::Paginations
11
+ include Requests::Hookable
12
+
13
+ attr_reader :params, :session
11
14
 
12
15
  # Alias for easier referencing
13
16
  Models = Web::Ui::Models
@@ -19,9 +22,31 @@ module Karafka
19
22
 
20
23
  self.sortable_attributes = []
21
24
 
25
+ # Detect that the state of the cache has changed
26
+ before do
27
+ cache.clear_if_needed(
28
+ session[:cache_hash],
29
+ session[:cache_timestamp].to_i
30
+ )
31
+ end
32
+
33
+ after do
34
+ next unless cache.exist?
35
+
36
+ session[:cache_hash] = cache.hash
37
+ session[:cache_timestamp] = cache.timestamp.to_i
38
+ end
39
+
22
40
  # @param params [Karafka::Web::Ui::Controllers::Requests::Params] request parameters
23
- def initialize(params)
41
+ # @param session [Request::Session] request session (Rails or other framework)
42
+ def initialize(params, session)
24
43
  @params = params
44
+ @session = session
45
+ end
46
+
47
+ # @return [Karafka::Web::Ui::Lib::Cache] per-process cache instance
48
+ def cache
49
+ Karafka::Web.config.ui.cache
25
50
  end
26
51
 
27
52
  private
@@ -50,6 +75,9 @@ module Karafka
50
75
 
51
76
  attributes[:breadcrums_scope] = scope
52
77
 
78
+ @current_action_name = action.to_sym
79
+ @current_controller_name = base.join('-')
80
+
53
81
  instance_variables.each do |iv|
54
82
  next if iv.to_s.start_with?('@_')
55
83
  next if iv.to_s.start_with?('@params')
@@ -72,6 +100,20 @@ module Karafka
72
100
  Responses::Redirect.new(path, flashes)
73
101
  end
74
102
 
103
+ # Wraps the provided arguments inside a message with a `<strong>` tag to simplify flash
104
+ # messages building.
105
+ #
106
+ # @param message [String] message with `?` to be replaced.
107
+ # @param args [Array<Object>] arguments to use to replace `?` with strong
108
+ # @return [String] formatted string
109
+ def format_flash(message, *args)
110
+ args.each do |arg|
111
+ message = message.sub('?', "<strong>#{arg}</strong>")
112
+ end
113
+
114
+ message
115
+ end
116
+
75
117
  # Builds a file response object that will be used as a base to dispatch the file
76
118
  #
77
119
  # @param content [String] Payload we want to dispatch as a file
@@ -17,6 +17,9 @@ module Karafka
17
17
  in_sync_replica_brokers
18
18
  ].freeze
19
19
 
20
+ # Cluster state should always be fresh and not from cache
21
+ before { cache.clear }
22
+
20
23
  # Lists available brokers in the cluster
21
24
  def brokers
22
25
  @brokers = refine(cluster_info.brokers)
@@ -50,9 +53,9 @@ module Karafka
50
53
 
51
54
  private
52
55
 
53
- # Make sure, that for the cluster view we always get the most recent cluster state
56
+ # @return [Array] whole cluster info
54
57
  def cluster_info
55
- @cluster_info ||= Models::ClusterInfo.fetch(cached: false)
58
+ @cluster_info ||= Models::ClusterInfo.fetch
56
59
  end
57
60
 
58
61
  # @param cluster_info [Rdkafka::Metadata] cluster metadata
@@ -17,7 +17,8 @@ module Karafka
17
17
  previous_offset,
18
18
  @params.current_offset,
19
19
  next_offset,
20
- @error_messages.map(&:offset)
20
+ # If message is an array, it means it's a compacted dummy offset representation
21
+ @error_messages.map { |message| message.is_a?(Array) ? message.last : message.offset }
21
22
  )
22
23
 
23
24
  render
@@ -25,12 +26,20 @@ module Karafka
25
26
 
26
27
  # @param offset [Integer] given error message offset
27
28
  def show(offset)
29
+ @partition_id = 0
30
+ @offset = offset
31
+
32
+ watermark_offsets = Models::WatermarkOffsets.find(errors_topic, @partition_id)
33
+
28
34
  @error_message = Models::Message.find(
29
35
  errors_topic,
30
- 0,
31
- offset
36
+ @partition_id,
37
+ offset,
38
+ watermark_offsets: watermark_offsets
32
39
  )
33
40
 
41
+ paginate(offset, watermark_offsets.low, watermark_offsets.high)
42
+
34
43
  render
35
44
  end
36
45
 
@@ -49,7 +58,7 @@ module Karafka
49
58
 
50
59
  # @return [String] errors topic
51
60
  def errors_topic
52
- ::Karafka::Web.config.topics.errors
61
+ ::Karafka::Web.config.topics.errors.name
53
62
  end
54
63
  end
55
64
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Ui
6
+ module Controllers
7
+ module Requests
8
+ # @note This class is used internally by the Web UI to wrap controllers
9
+ # and inject execution hooks around any method call (before/after filters).
10
+ #
11
+ # ExecutionWrapper delegates all method calls to the provided controller instance.
12
+ # Before and after each invocation, it runs the controller's registered hooks.
13
+ #
14
+ # This allows for cleaner separation of concerns and reusable hook logic.
15
+ #
16
+ # @example
17
+ # controller = SomeController.new
18
+ # wrapper = ExecutionWrapper.new(controller)
19
+ # wrapper.call # will run before(:call), call, then after(:call)
20
+ class ExecutionWrapper
21
+ # @param controller [Object] a controller instance responding to method calls
22
+ def initialize(controller)
23
+ @controller = controller
24
+ end
25
+
26
+ # Delegates any method call to the controller and wraps it with before/after hooks
27
+ #
28
+ # @param method_name [Symbol] the name of the method being called
29
+ # @param args [Array] arguments passed to the method
30
+ # @param block [Proc] optional block passed to the method
31
+ # @return [Object] the result of the delegated controller method for Roda to operate on
32
+ def method_missing(method_name, *args, &block)
33
+ @controller.run_before_hooks(method_name)
34
+ result = @controller.public_send(method_name, *args, &block)
35
+ @controller.run_after_hooks(method_name)
36
+ result
37
+ end
38
+
39
+ # Properly supports respond_to? checks by delegating to the controller
40
+ #
41
+ # @param method_name [Symbol] the method name to check
42
+ # @param include_private [Boolean] whether to include private methods
43
+ # @return [Boolean] true if controller responds to the method
44
+ def respond_to_missing?(method_name, include_private = false)
45
+ @controller.respond_to?(method_name, include_private)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Ui
6
+ module Controllers
7
+ module Requests
8
+ # Adds before/after hook support for controller methods.
9
+ #
10
+ # This module allows registering callbacks that run before and after
11
+ # any named method (e.g., `call`, `show`) or for all methods.
12
+ #
13
+ # Hooks are inherited from parent controllers, making it easy to
14
+ # define shared behavior across a hierarchy.
15
+ #
16
+ # @example Adding hooks to a controller
17
+ # class MyController
18
+ # include Hookable
19
+ #
20
+ # before(:call) { puts "before call" }
21
+ # after(:call) { puts "after call" }
22
+ #
23
+ # def call
24
+ # run_before_hooks(:call)
25
+ # # actual logic
26
+ # run_after_hooks(:call)
27
+ # end
28
+ # end
29
+ module Hookable
30
+ # Hook into class inclusion to extend DSL
31
+ #
32
+ # @param base [Class] the class including this module
33
+ def self.included(base)
34
+ base.extend(ClassMethods)
35
+ end
36
+
37
+ # DSL methods for defining and inheriting hooks
38
+ module ClassMethods
39
+ # Inherit parent hooks into subclass
40
+ #
41
+ # @param subclass [Class] the subclass inheriting from base controller
42
+ def inherited(subclass)
43
+ super
44
+ subclass.before_hooks.concat(before_hooks)
45
+ subclass.after_hooks.concat(after_hooks)
46
+ end
47
+
48
+ # @return [Array] accumulated before hooks
49
+ def before_hooks
50
+ @before_hooks ||= []
51
+ end
52
+
53
+ # @return [Array] accumulated after hooks
54
+ def after_hooks
55
+ @after_hooks ||= []
56
+ end
57
+
58
+ # Register a before hook
59
+ #
60
+ # @param actions [Array<Symbol>] optional action names to match (e.g., :call)
61
+ # @param block [Proc]
62
+ # @yield a block to execute before matched actions
63
+ def before(*actions, &block)
64
+ before_hooks << [actions, block]
65
+ end
66
+
67
+ # Register an after hook
68
+ #
69
+ # @param actions [Array<Symbol>] optional action names to match (e.g., :call)
70
+ # @param block [Proc]
71
+ # @yield a block to execute after matched actions
72
+ def after(*actions, &block)
73
+ after_hooks << [actions, block]
74
+ end
75
+ end
76
+
77
+ # Run all before hooks matching the action
78
+ #
79
+ # @param action_name [Symbol] the method name being invoked
80
+ def run_before_hooks(action_name)
81
+ self.class.before_hooks.each do |actions, block|
82
+ instance_exec(&block) if actions.empty? || actions.include?(action_name)
83
+ end
84
+ end
85
+
86
+ # Run all after hooks matching the action
87
+ #
88
+ # @param action_name [Symbol] the method name being invoked
89
+ def run_after_hooks(action_name)
90
+ self.class.after_hooks.each do |actions, block|
91
+ instance_exec(&block) if actions.empty? || actions.include?(action_name)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -17,13 +17,51 @@ module Karafka
17
17
  days
18
18
  ].freeze
19
19
 
20
- private_constant :ALLOWED_RANGES
20
+ # What string values true can be in params
21
+ ALLOWED_BOOLEAN_TRUE = %w[
22
+ on
23
+ yes
24
+ true
25
+ ].freeze
26
+
27
+ private_constant :ALLOWED_RANGES, :ALLOWED_BOOLEAN_TRUE
21
28
 
22
29
  # @param request_params [Hash] raw hash with params
23
30
  def initialize(request_params)
24
31
  @request_params = request_params
25
32
  end
26
33
 
34
+ # @param key [String, Symbol] params key
35
+ # @return [Object] value of the requested param
36
+ def [](key)
37
+ fetch(key.to_s)
38
+ end
39
+
40
+ # @param args [Symbol, Object] key we want to fetch and other args for `Hash#fetch`
41
+ # @return [Object] fetched object
42
+ def fetch(*args)
43
+ args[0] = args[0].to_s
44
+ @request_params.fetch(*args)
45
+ end
46
+
47
+ # @param key [String, Symbol] params key
48
+ # @return [Integer] integer value of the key
49
+ def int(key)
50
+ self[key].to_i
51
+ end
52
+
53
+ # @param key [String, Symbol] params key
54
+ # @return [Boolean] boolean key value
55
+ def bool(key)
56
+ ALLOWED_BOOLEAN_TRUE.include?(self[key])
57
+ end
58
+
59
+ # @param key [String, Symbol] params key
60
+ # @return [String] stringified key value
61
+ def str(key)
62
+ self[key].to_s
63
+ end
64
+
27
65
  # @return [Hash] current search or empty if no search query present
28
66
  def current_search
29
67
  return @current_search if @current_search
@@ -16,11 +16,6 @@ module Karafka
16
16
  @path = path
17
17
  @flashes = flashes
18
18
  end
19
-
20
- # @return [Boolean] are we going back via referer and not explicit path
21
- def back?
22
- @path == :back
23
- end
24
19
  end
25
20
  end
26
21
  end
@@ -10,6 +10,9 @@ module Karafka
10
10
  # page where we check that everything is as expected and if not, we can provide some
11
11
  # helpful instructions on how to fix the issues.
12
12
  class StatusController < BaseController
13
+ # Fresh state is needed to generate always correct status
14
+ before { cache.clear }
15
+
13
16
  # Displays the Web UI setup status
14
17
  def show
15
18
  @status = Models::Status.new