karafka-web 0.10.4 → 0.11.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 (479) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +54 -176
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +87 -43
  6. data/LICENSE +6 -2
  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/docker-compose.yml +1 -1
  11. data/gulpfile.js +0 -2
  12. data/karafka-web.gemspec +2 -2
  13. data/lib/karafka/web/config.rb +80 -9
  14. data/lib/karafka/web/contracts/config.rb +44 -5
  15. data/lib/karafka/web/errors.rb +10 -0
  16. data/lib/karafka/web/management/actions/create_initial_states.rb +6 -6
  17. data/lib/karafka/web/management/actions/create_topics.rb +30 -64
  18. data/lib/karafka/web/management/actions/delete_topics.rb +5 -5
  19. data/lib/karafka/web/management/actions/enable.rb +5 -5
  20. data/lib/karafka/web/pro/commanding/commands/base.rb +37 -13
  21. data/lib/karafka/web/pro/commanding/commands/consumers/quiet.rb +33 -0
  22. data/lib/karafka/web/pro/commanding/commands/consumers/stop.rb +32 -0
  23. data/lib/karafka/web/pro/commanding/commands/consumers/trace.rb +37 -0
  24. data/lib/karafka/web/pro/commanding/commands/partitions/pause.rb +30 -0
  25. data/lib/karafka/web/pro/commanding/commands/partitions/resume.rb +30 -0
  26. data/lib/karafka/web/pro/commanding/commands/partitions/seek.rb +30 -0
  27. data/lib/karafka/web/pro/commanding/config.rb +6 -10
  28. data/lib/karafka/web/pro/commanding/contracts/config.rb +2 -10
  29. data/lib/karafka/web/pro/commanding/dispatcher.rb +45 -24
  30. data/lib/karafka/web/pro/commanding/handlers/partitions/commands/base.rb +67 -0
  31. data/lib/karafka/web/pro/commanding/handlers/partitions/commands/pause.rb +44 -0
  32. data/lib/karafka/web/pro/commanding/handlers/partitions/commands/resume.rb +29 -0
  33. data/lib/karafka/web/pro/commanding/handlers/partitions/commands/seek.rb +86 -0
  34. data/lib/karafka/web/pro/commanding/handlers/partitions/executor.rb +56 -0
  35. data/lib/karafka/web/pro/commanding/handlers/partitions/listener.rb +55 -0
  36. data/lib/karafka/web/pro/commanding/handlers/partitions/tracker.rb +62 -0
  37. data/lib/karafka/web/pro/commanding/listener.rb +4 -12
  38. data/lib/karafka/web/pro/commanding/manager.rb +36 -24
  39. data/lib/karafka/web/pro/commanding/matcher.rb +7 -17
  40. data/lib/karafka/web/pro/commanding/request.rb +39 -0
  41. data/lib/karafka/web/pro/commanding.rb +2 -10
  42. data/lib/karafka/web/pro/loader.rb +13 -10
  43. data/lib/karafka/web/pro/ui/app.rb +31 -390
  44. data/lib/karafka/web/pro/ui/controllers/base_controller.rb +8 -10
  45. data/lib/karafka/web/pro/ui/controllers/cluster_controller.rb +2 -10
  46. data/lib/karafka/web/pro/ui/controllers/consumers/base_controller.rb +21 -0
  47. data/lib/karafka/web/pro/ui/controllers/consumers/commanding_controller.rb +148 -0
  48. data/lib/karafka/web/pro/ui/controllers/consumers/commands_controller.rb +96 -0
  49. data/lib/karafka/web/pro/ui/controllers/consumers/consumers_controller.rb +101 -0
  50. data/lib/karafka/web/pro/ui/controllers/consumers/controls_controller.rb +36 -0
  51. data/lib/karafka/web/pro/ui/controllers/consumers/jobs_controller.rb +57 -0
  52. data/lib/karafka/web/pro/ui/controllers/consumers/partitions/base_controller.rb +86 -0
  53. data/lib/karafka/web/pro/ui/controllers/consumers/partitions/offsets_controller.rb +75 -0
  54. data/lib/karafka/web/pro/ui/controllers/consumers/partitions/pauses_controller.rb +110 -0
  55. data/lib/karafka/web/pro/ui/controllers/dashboard_controller.rb +2 -10
  56. data/lib/karafka/web/pro/ui/controllers/dlq_controller.rb +2 -10
  57. data/lib/karafka/web/pro/ui/controllers/errors_controller.rb +3 -11
  58. data/lib/karafka/web/pro/ui/controllers/explorer/base_controller.rb +21 -0
  59. data/lib/karafka/web/pro/ui/controllers/explorer/explorer_controller.rb +215 -0
  60. data/lib/karafka/web/pro/ui/controllers/explorer/messages_controller.rb +145 -0
  61. data/lib/karafka/web/pro/ui/controllers/explorer/search_controller.rb +68 -0
  62. data/lib/karafka/web/pro/ui/controllers/health_controller.rb +2 -10
  63. data/lib/karafka/web/pro/ui/controllers/jobs_controller.rb +2 -10
  64. data/lib/karafka/web/pro/ui/controllers/recurring_tasks_controller.rb +12 -13
  65. data/lib/karafka/web/pro/ui/controllers/routing_controller.rb +2 -10
  66. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/base_controller.rb +2 -10
  67. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/explorer_controller.rb +8 -16
  68. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/messages_controller.rb +9 -15
  69. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/schedules_controller.rb +2 -10
  70. data/lib/karafka/web/pro/ui/controllers/status_controller.rb +2 -10
  71. data/lib/karafka/web/pro/ui/controllers/support_controller.rb +2 -10
  72. data/lib/karafka/web/pro/ui/controllers/topics/base_controller.rb +21 -0
  73. data/lib/karafka/web/pro/ui/controllers/topics/configs_controller.rb +86 -0
  74. data/lib/karafka/web/pro/ui/controllers/topics/distributions_controller.rb +91 -0
  75. data/lib/karafka/web/pro/ui/controllers/topics/offsets_controller.rb +55 -0
  76. data/lib/karafka/web/pro/ui/controllers/topics/replications_controller.rb +37 -0
  77. data/lib/karafka/web/pro/ui/controllers/topics/topics_controller.rb +101 -0
  78. data/lib/karafka/web/pro/ui/controllers/ux_controller.rb +2 -10
  79. data/lib/karafka/web/pro/ui/lib/branding/config.rb +2 -10
  80. data/lib/karafka/web/pro/ui/lib/branding/contracts/config.rb +2 -10
  81. data/lib/karafka/web/pro/ui/lib/branding.rb +2 -10
  82. data/lib/karafka/web/pro/ui/lib/features.rb +53 -0
  83. data/lib/karafka/web/pro/ui/lib/patterns_detector.rb +2 -10
  84. data/lib/karafka/web/pro/ui/lib/policies/config.rb +2 -10
  85. data/lib/karafka/web/pro/ui/lib/policies/contracts/config.rb +2 -10
  86. data/lib/karafka/web/pro/ui/lib/policies/messages.rb +2 -10
  87. data/lib/karafka/web/pro/ui/lib/policies/requests.rb +2 -10
  88. data/lib/karafka/web/pro/ui/lib/policies.rb +2 -10
  89. data/lib/karafka/web/pro/ui/lib/safe_runner.rb +5 -0
  90. data/lib/karafka/web/pro/ui/lib/search/config.rb +2 -10
  91. data/lib/karafka/web/pro/ui/lib/search/contracts/config.rb +2 -10
  92. data/lib/karafka/web/pro/ui/lib/search/contracts/form.rb +2 -10
  93. data/lib/karafka/web/pro/ui/lib/search/matchers/base.rb +2 -10
  94. data/lib/karafka/web/pro/ui/lib/search/matchers/raw_header_includes.rb +10 -11
  95. data/lib/karafka/web/pro/ui/lib/search/matchers/raw_key_includes.rb +2 -10
  96. data/lib/karafka/web/pro/ui/lib/search/matchers/raw_payload_includes.rb +23 -11
  97. data/lib/karafka/web/pro/ui/lib/search/normalizer.rb +2 -10
  98. data/lib/karafka/web/pro/ui/lib/search/runner.rb +3 -11
  99. data/lib/karafka/web/pro/ui/lib/search.rb +2 -10
  100. data/lib/karafka/web/pro/ui/routes/base.rb +19 -0
  101. data/lib/karafka/web/pro/ui/routes/cluster.rb +37 -0
  102. data/lib/karafka/web/pro/ui/routes/consumers.rb +145 -0
  103. data/lib/karafka/web/pro/ui/routes/dashboard.rb +25 -0
  104. data/lib/karafka/web/pro/ui/routes/dlq.rb +24 -0
  105. data/lib/karafka/web/pro/ui/routes/errors.rb +39 -0
  106. data/lib/karafka/web/pro/ui/routes/explorer.rb +118 -0
  107. data/lib/karafka/web/pro/ui/routes/health.rb +47 -0
  108. data/lib/karafka/web/pro/ui/routes/jobs.rb +33 -0
  109. data/lib/karafka/web/pro/ui/routes/recurring_tasks.rb +59 -0
  110. data/lib/karafka/web/pro/ui/routes/routing.rb +31 -0
  111. data/lib/karafka/web/pro/ui/routes/scheduled_messages.rb +75 -0
  112. data/lib/karafka/web/pro/ui/routes/status.rb +24 -0
  113. data/lib/karafka/web/pro/ui/routes/support.rb +24 -0
  114. data/lib/karafka/web/pro/ui/routes/topics.rb +90 -0
  115. data/lib/karafka/web/pro/ui/routes/ux.rb +24 -0
  116. data/lib/karafka/web/pro/ui/views/cluster/_breadcrumbs.erb +3 -0
  117. data/lib/karafka/web/pro/ui/views/cluster/_broker.erb +3 -0
  118. data/lib/karafka/web/pro/ui/views/cluster/_config.erb +3 -0
  119. data/lib/karafka/web/pro/ui/views/cluster/_tabs.erb +3 -0
  120. data/lib/karafka/web/pro/ui/views/cluster/index.erb +4 -1
  121. data/lib/karafka/web/pro/ui/views/cluster/show.erb +3 -0
  122. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_backtrace.erb +3 -0
  123. data/lib/karafka/web/pro/ui/views/consumers/commands/_breadcrumbs.erb +24 -0
  124. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_command.erb +22 -6
  125. data/lib/karafka/web/pro/ui/views/consumers/commands/_command_details.erb +4 -0
  126. data/lib/karafka/web/pro/ui/views/consumers/commands/_empty.erb +6 -0
  127. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_incompatible_schema.erb +3 -0
  128. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_metadata.erb +4 -1
  129. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_table.erb +5 -2
  130. data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/index.erb +7 -4
  131. data/lib/karafka/web/pro/ui/views/consumers/commands/show.erb +32 -0
  132. data/lib/karafka/web/pro/ui/views/consumers/consumers/_breadcrumbs.erb +46 -0
  133. data/lib/karafka/web/pro/ui/views/consumers/consumers/_consumer.erb +59 -0
  134. data/lib/karafka/web/pro/ui/views/consumers/consumers/_consumer_performance.erb +71 -0
  135. data/lib/karafka/web/pro/ui/views/consumers/consumers/_tabs.erb +38 -0
  136. data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_commands.erb +80 -0
  137. data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_consumer_group.erb +11 -0
  138. data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_metrics.erb +3 -0
  139. data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_no_subscriptions.erb +10 -0
  140. data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_partition.erb +16 -0
  141. data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_partition_edit_options.erb +33 -0
  142. data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_stopped.erb +3 -0
  143. data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_subscription_group.erb +7 -3
  144. data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_tabs.erb +7 -4
  145. data/lib/karafka/web/pro/ui/views/consumers/consumers/details.erb +15 -0
  146. data/lib/karafka/web/pro/ui/views/consumers/{index.erb → consumers/index.erb} +6 -3
  147. data/lib/karafka/web/pro/ui/views/consumers/{performance.erb → consumers/performance.erb} +6 -3
  148. data/lib/karafka/web/pro/ui/views/consumers/consumers/subscriptions.erb +24 -0
  149. data/lib/karafka/web/pro/ui/views/consumers/controls/_breadcrumbs.erb +16 -0
  150. data/lib/karafka/web/pro/ui/views/consumers/controls/_controls.erb +107 -0
  151. data/lib/karafka/web/pro/ui/views/consumers/{controls.erb → controls/index.erb} +8 -5
  152. data/lib/karafka/web/pro/ui/views/consumers/jobs/_breadcrumbs.erb +36 -0
  153. data/lib/karafka/web/pro/ui/views/consumers/{consumer → jobs}/_job.erb +3 -0
  154. data/lib/karafka/web/pro/ui/views/consumers/{consumer → jobs}/_no_jobs.erb +3 -0
  155. data/lib/karafka/web/pro/ui/views/consumers/{pending_jobs.erb → jobs/pending.erb} +7 -8
  156. data/lib/karafka/web/pro/ui/views/consumers/{running_jobs.erb → jobs/running.erb} +7 -8
  157. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_basics.erb +77 -0
  158. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_breadcrumbs.erb +58 -0
  159. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_form.erb +109 -0
  160. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_not_running_error.erb +16 -0
  161. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_running_warning.erb +15 -0
  162. data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/edit.erb +12 -0
  163. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_active_not_editable.erb +22 -0
  164. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_adjusting_warning.erb +27 -0
  165. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_breadcrumbs.erb +60 -0
  166. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_edit_form.erb +59 -0
  167. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_lrj_not_manageable.erb +24 -0
  168. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_new_form.erb +78 -0
  169. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_not_running.erb +16 -0
  170. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/edit.erb +20 -0
  171. data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/new.erb +16 -0
  172. data/lib/karafka/web/pro/ui/views/dashboard/index.erb +4 -1
  173. data/lib/karafka/web/pro/ui/views/dlq/_breadcrumbs.erb +3 -0
  174. data/lib/karafka/web/pro/ui/views/dlq/_no_topics.erb +3 -0
  175. data/lib/karafka/web/pro/ui/views/dlq/_topic.erb +4 -1
  176. data/lib/karafka/web/pro/ui/views/dlq/index.erb +3 -0
  177. data/lib/karafka/web/pro/ui/views/errors/_breadcrumbs.erb +3 -0
  178. data/lib/karafka/web/pro/ui/views/errors/_error.erb +3 -0
  179. data/lib/karafka/web/pro/ui/views/errors/_partition_option.erb +3 -0
  180. data/lib/karafka/web/pro/ui/views/errors/_selector.erb +3 -0
  181. data/lib/karafka/web/pro/ui/views/errors/_table.erb +4 -1
  182. data/lib/karafka/web/pro/ui/views/errors/index.erb +6 -3
  183. data/lib/karafka/web/pro/ui/views/errors/partition.erb +5 -2
  184. data/lib/karafka/web/pro/ui/views/errors/show.erb +3 -0
  185. data/lib/karafka/web/pro/ui/views/explorer/{_breadcrumbs.erb → explorer/_breadcrumbs.erb} +7 -4
  186. data/lib/karafka/web/pro/ui/views/explorer/{_failed_deserialization.erb → explorer/_failed_deserialization.erb} +3 -0
  187. data/lib/karafka/web/pro/ui/views/explorer/{_filtered.erb → explorer/_filtered.erb} +3 -0
  188. data/lib/karafka/web/pro/ui/views/explorer/{_message.erb → explorer/_message.erb} +4 -1
  189. data/lib/karafka/web/pro/ui/views/explorer/explorer/_no_topics.erb +4 -0
  190. data/lib/karafka/web/pro/ui/views/explorer/{_partition_option.erb → explorer/_partition_option.erb} +4 -1
  191. data/lib/karafka/web/pro/ui/views/explorer/{_selector.erb → explorer/_selector.erb} +4 -1
  192. data/lib/karafka/web/pro/ui/views/explorer/explorer/_topic.erb +13 -0
  193. data/lib/karafka/web/pro/ui/views/explorer/explorer/index.erb +17 -0
  194. data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_metadata.erb +10 -7
  195. data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_payload.erb +6 -3
  196. data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_resources_utilization.erb +7 -4
  197. data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_too_big_to_be_displayed.erb +3 -0
  198. data/lib/karafka/web/pro/ui/views/explorer/{messages → explorer/messages}/_detail.erb +3 -0
  199. data/lib/karafka/web/pro/ui/views/explorer/explorer/messages/_headers.erb +51 -0
  200. data/lib/karafka/web/pro/ui/views/explorer/{messages → explorer/messages}/_key.erb +3 -0
  201. data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_cleaned.erb +6 -0
  202. data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_empty.erb +6 -0
  203. data/lib/karafka/web/pro/ui/views/explorer/{partition → explorer/partition}/_messages.erb +4 -1
  204. data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_time_selector.erb +16 -0
  205. data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_timestamp_selector.erb +33 -0
  206. data/lib/karafka/web/pro/ui/views/explorer/{partition.erb → explorer/partition.erb} +24 -17
  207. data/lib/karafka/web/pro/ui/views/explorer/{show.erb → explorer/show.erb} +17 -19
  208. data/lib/karafka/web/pro/ui/views/explorer/{topic → explorer/topic}/_actions.erb +5 -2
  209. data/lib/karafka/web/pro/ui/views/explorer/explorer/topic/_empty.erb +6 -0
  210. data/lib/karafka/web/pro/ui/views/explorer/{topic → explorer/topic}/_limited.erb +3 -0
  211. data/lib/karafka/web/pro/ui/views/explorer/{topic.erb → explorer/topic.erb} +7 -4
  212. data/lib/karafka/web/pro/ui/views/explorer/messages/_breadcrumbs.erb +32 -0
  213. data/lib/karafka/web/pro/ui/views/explorer/messages/forward.erb +143 -0
  214. data/lib/karafka/web/pro/ui/views/explorer/search/_breadcrumbs.erb +4 -0
  215. data/lib/karafka/web/pro/ui/views/explorer/search/_fix_errors.erb +6 -0
  216. data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_metadata.erb +3 -0
  217. data/lib/karafka/web/pro/ui/views/explorer/search/_no_results.erb +6 -0
  218. data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_no_search_criteria.erb +3 -0
  219. data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_search_criteria.erb +3 -0
  220. data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_search_modal.erb +5 -2
  221. data/lib/karafka/web/pro/ui/views/explorer/search/_timeout.erb +6 -0
  222. data/lib/karafka/web/pro/ui/views/explorer/search/index.erb +32 -0
  223. data/lib/karafka/web/pro/ui/views/health/_breadcrumbs.erb +3 -0
  224. data/lib/karafka/web/pro/ui/views/health/_no_data.erb +3 -0
  225. data/lib/karafka/web/pro/ui/views/health/_partition.erb +16 -1
  226. data/lib/karafka/web/pro/ui/views/health/_partition_lags.erb +3 -0
  227. data/lib/karafka/web/pro/ui/views/health/_partition_offset.erb +3 -0
  228. data/lib/karafka/web/pro/ui/views/health/_partition_times.erb +3 -0
  229. data/lib/karafka/web/pro/ui/views/health/_table_metadata.erb +4 -1
  230. data/lib/karafka/web/pro/ui/views/health/_tabs.erb +3 -0
  231. data/lib/karafka/web/pro/ui/views/health/changes.erb +4 -1
  232. data/lib/karafka/web/pro/ui/views/health/cluster_lags.erb +3 -0
  233. data/lib/karafka/web/pro/ui/views/health/lags.erb +5 -2
  234. data/lib/karafka/web/pro/ui/views/health/offsets.erb +4 -1
  235. data/lib/karafka/web/pro/ui/views/health/overview.erb +8 -3
  236. data/lib/karafka/web/pro/ui/views/jobs/_job.erb +50 -38
  237. data/lib/karafka/web/pro/ui/views/jobs/_no_jobs.erb +3 -0
  238. data/lib/karafka/web/pro/ui/views/jobs/pending.erb +4 -1
  239. data/lib/karafka/web/pro/ui/views/jobs/running.erb +4 -1
  240. data/lib/karafka/web/pro/ui/views/recurring_tasks/_actions.erb +3 -0
  241. data/lib/karafka/web/pro/ui/views/recurring_tasks/_batch_actions.erb +3 -0
  242. data/lib/karafka/web/pro/ui/views/recurring_tasks/_breadcrumbs.erb +3 -0
  243. data/lib/karafka/web/pro/ui/views/recurring_tasks/_log.erb +3 -0
  244. data/lib/karafka/web/pro/ui/views/recurring_tasks/_not_active.erb +3 -0
  245. data/lib/karafka/web/pro/ui/views/recurring_tasks/_tabs.erb +3 -0
  246. data/lib/karafka/web/pro/ui/views/recurring_tasks/_task.erb +3 -0
  247. data/lib/karafka/web/pro/ui/views/recurring_tasks/logs.erb +3 -0
  248. data/lib/karafka/web/pro/ui/views/recurring_tasks/schedule.erb +3 -0
  249. data/lib/karafka/web/pro/ui/views/routing/_consumer_group.erb +3 -0
  250. data/lib/karafka/web/pro/ui/views/routing/_detail.erb +3 -0
  251. data/lib/karafka/web/pro/ui/views/routing/_topic.erb +3 -0
  252. data/lib/karafka/web/pro/ui/views/routing/index.erb +3 -0
  253. data/lib/karafka/web/pro/ui/views/routing/show.erb +3 -0
  254. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_breadcrumbs.erb +6 -3
  255. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_key.erb +3 -0
  256. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_message.erb +4 -1
  257. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_messages.erb +3 -0
  258. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/partition.erb +23 -16
  259. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/topic.erb +6 -3
  260. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_breadcrumbs.erb +3 -0
  261. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_no_groups.erb +3 -0
  262. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/index.erb +4 -1
  263. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/show.erb +3 -0
  264. data/lib/karafka/web/pro/ui/views/shared/_navigation.erb +25 -17
  265. data/lib/karafka/web/pro/ui/views/shared/_rdkafka_form_error_alert_box.erb +16 -0
  266. data/lib/karafka/web/pro/ui/views/shared/branding/_label.erb +3 -0
  267. data/lib/karafka/web/pro/ui/views/shared/branding/_notice.erb +3 -0
  268. data/lib/karafka/web/pro/ui/views/topics/configs/_breadcrumbs.erb +34 -0
  269. data/lib/karafka/web/pro/ui/views/topics/configs/_config.erb +26 -0
  270. data/lib/karafka/web/pro/ui/views/topics/configs/_delete_button.erb +13 -0
  271. data/lib/karafka/web/pro/ui/views/topics/configs/_edit_form.erb +50 -0
  272. data/lib/karafka/web/pro/ui/views/topics/configs/_edit_plan.erb +16 -0
  273. data/lib/karafka/web/pro/ui/views/topics/configs/_edit_warning.erb +12 -0
  274. data/lib/karafka/web/pro/ui/views/topics/configs/edit.erb +16 -0
  275. data/lib/karafka/web/pro/ui/views/topics/{config.erb → configs/index.erb} +9 -3
  276. data/lib/karafka/web/pro/ui/views/topics/distributions/_add_partitions_button.erb +13 -0
  277. data/lib/karafka/web/pro/ui/views/topics/{distribution → distributions}/_badges.erb +3 -0
  278. data/lib/karafka/web/pro/ui/views/topics/distributions/_breadcrumbs.erb +28 -0
  279. data/lib/karafka/web/pro/ui/views/topics/{distribution → distributions}/_chart.erb +3 -0
  280. data/lib/karafka/web/pro/ui/views/topics/distributions/_edit_form.erb +47 -0
  281. data/lib/karafka/web/pro/ui/views/topics/distributions/_edit_hints.erb +15 -0
  282. data/lib/karafka/web/pro/ui/views/topics/distributions/_edit_warnings.erb +14 -0
  283. data/lib/karafka/web/pro/ui/views/topics/distributions/_empty_partitions.erb +4 -0
  284. data/lib/karafka/web/pro/ui/views/topics/{distribution → distributions}/_limited.erb +3 -0
  285. data/lib/karafka/web/pro/ui/views/topics/distributions/_partition.erb +13 -0
  286. data/lib/karafka/web/pro/ui/views/topics/distributions/edit.erb +16 -0
  287. data/lib/karafka/web/pro/ui/views/topics/{distribution.erb → distributions/show.erb} +11 -7
  288. data/lib/karafka/web/pro/ui/views/topics/offsets/_breadcrumbs.erb +20 -0
  289. data/lib/karafka/web/pro/ui/views/topics/offsets/_partition.erb +13 -0
  290. data/lib/karafka/web/pro/ui/views/topics/{offsets.erb → offsets/show.erb} +6 -3
  291. data/lib/karafka/web/pro/ui/views/topics/replications/_breadcrumbs.erb +20 -0
  292. data/lib/karafka/web/pro/ui/views/topics/{_partition.erb → replications/_partition.erb} +4 -1
  293. data/lib/karafka/web/pro/ui/views/topics/{replication.erb → replications/show.erb} +6 -3
  294. data/lib/karafka/web/pro/ui/views/topics/topics/_breadcrumbs.erb +32 -0
  295. data/lib/karafka/web/pro/ui/views/topics/topics/_create_button.erb +13 -0
  296. data/lib/karafka/web/pro/ui/views/topics/topics/_create_hints.erb +15 -0
  297. data/lib/karafka/web/pro/ui/views/topics/topics/_delete_form.erb +36 -0
  298. data/lib/karafka/web/pro/ui/views/topics/topics/_delete_hints.erb +15 -0
  299. data/lib/karafka/web/pro/ui/views/topics/topics/_delete_warning.erb +13 -0
  300. data/lib/karafka/web/pro/ui/views/topics/topics/_new_form.erb +80 -0
  301. data/lib/karafka/web/pro/ui/views/topics/{_tabs.erb → topics/_tabs.erb} +7 -4
  302. data/lib/karafka/web/pro/ui/views/topics/topics/_topic.erb +12 -0
  303. data/lib/karafka/web/pro/ui/views/topics/topics/edit.erb +10 -0
  304. data/lib/karafka/web/pro/ui/views/topics/topics/index.erb +19 -0
  305. data/lib/karafka/web/pro/ui/views/topics/topics/new.erb +12 -0
  306. data/lib/karafka/web/processing/consumers/metrics.rb +1 -1
  307. data/lib/karafka/web/processing/consumers/state.rb +1 -1
  308. data/lib/karafka/web/processing/publisher.rb +4 -4
  309. data/lib/karafka/web/tracking/consumers/contracts/partition.rb +1 -0
  310. data/lib/karafka/web/tracking/consumers/listeners/pausing.rb +2 -2
  311. data/lib/karafka/web/tracking/consumers/listeners/transactions.rb +44 -0
  312. data/lib/karafka/web/tracking/consumers/reporter.rb +2 -2
  313. data/lib/karafka/web/tracking/consumers/sampler.rb +81 -14
  314. data/lib/karafka/web/tracking/helpers/sysconf.rb +33 -0
  315. data/lib/karafka/web/tracking/producers/reporter.rb +1 -1
  316. data/lib/karafka/web/ui/app.rb +19 -112
  317. data/lib/karafka/web/ui/base.rb +63 -4
  318. data/lib/karafka/web/ui/controllers/base_controller.rb +43 -1
  319. data/lib/karafka/web/ui/controllers/cluster_controller.rb +5 -2
  320. data/lib/karafka/web/ui/controllers/errors_controller.rb +1 -1
  321. data/lib/karafka/web/ui/controllers/requests/execution_wrapper.rb +52 -0
  322. data/lib/karafka/web/ui/controllers/requests/hookable.rb +99 -0
  323. data/lib/karafka/web/ui/controllers/requests/params.rb +39 -1
  324. data/lib/karafka/web/ui/controllers/responses/redirect.rb +0 -5
  325. data/lib/karafka/web/ui/controllers/status_controller.rb +3 -0
  326. data/lib/karafka/web/ui/helpers/application_helper.rb +10 -1
  327. data/lib/karafka/web/ui/helpers/paths_helper.rb +54 -10
  328. data/lib/karafka/web/ui/lib/admin.rb +1 -1
  329. data/lib/karafka/web/ui/lib/cache.rb +135 -0
  330. data/lib/karafka/web/ui/models/broker.rb +1 -2
  331. data/lib/karafka/web/ui/models/cluster_info.rb +15 -21
  332. data/lib/karafka/web/ui/models/consumers_metrics.rb +1 -1
  333. data/lib/karafka/web/ui/models/consumers_state.rb +1 -1
  334. data/lib/karafka/web/ui/models/counters.rb +1 -1
  335. data/lib/karafka/web/ui/models/health.rb +9 -7
  336. data/lib/karafka/web/ui/models/process.rb +14 -0
  337. data/lib/karafka/web/ui/models/processes.rb +2 -2
  338. data/lib/karafka/web/ui/models/recurring_tasks/schedule.rb +1 -1
  339. data/lib/karafka/web/ui/models/status.rb +27 -8
  340. data/lib/karafka/web/ui/models/topic.rb +1 -2
  341. data/lib/karafka/web/ui/public/javascripts/application.js +8 -98
  342. data/lib/karafka/web/ui/public/javascripts/application.min.js +12 -4
  343. data/lib/karafka/web/ui/public/javascripts/application.min.js.br +0 -0
  344. data/lib/karafka/web/ui/public/javascripts/application.min.js.gz +0 -0
  345. data/lib/karafka/web/ui/public/javascripts/components/action_confirmation_manager.js +30 -0
  346. data/lib/karafka/web/ui/public/javascripts/components/alerts.js +39 -0
  347. data/lib/karafka/web/ui/public/javascripts/components/button_lock_manager.js +50 -0
  348. data/lib/karafka/web/ui/public/javascripts/components/live_poll.js +71 -19
  349. data/lib/karafka/web/ui/public/javascripts/components/message_republish_manager.js +50 -0
  350. data/lib/karafka/web/ui/public/javascripts/components/page_title_tracker.js +21 -0
  351. data/lib/karafka/web/ui/public/javascripts/components/partition_redirect_manager.js +21 -0
  352. data/lib/karafka/web/ui/public/javascripts/components/time_ago_manager.js +25 -0
  353. data/lib/karafka/web/ui/public/javascripts/components/timestamp_selector.js +30 -0
  354. data/lib/karafka/web/ui/public/javascripts/libs/datepicker.js +2 -2
  355. data/lib/karafka/web/ui/public/stylesheets/application.css +30 -0
  356. data/lib/karafka/web/ui/public/stylesheets/application.min.css +5122 -13
  357. data/lib/karafka/web/ui/public/stylesheets/application.min.css.br +0 -0
  358. data/lib/karafka/web/ui/public/stylesheets/application.min.css.gz +0 -0
  359. data/lib/karafka/web/ui/public/stylesheets/libs/highlight_dark.min.css.gz +0 -0
  360. data/lib/karafka/web/ui/public/stylesheets/libs/highlight_light.min.css.gz +0 -0
  361. data/lib/karafka/web/ui/public/stylesheets/libs/tailwind.css +512 -213
  362. data/lib/karafka/web/ui/routes/assets.rb +53 -0
  363. data/lib/karafka/web/ui/routes/base.rb +36 -0
  364. data/lib/karafka/web/ui/routes/cluster.rb +28 -0
  365. data/lib/karafka/web/ui/routes/consumers.rb +35 -0
  366. data/lib/karafka/web/ui/routes/dashboard.rb +20 -0
  367. data/lib/karafka/web/ui/routes/errors.rb +26 -0
  368. data/lib/karafka/web/ui/routes/jobs.rb +28 -0
  369. data/lib/karafka/web/ui/routes/pro_only.rb +27 -0
  370. data/lib/karafka/web/ui/routes/routing.rb +26 -0
  371. data/lib/karafka/web/ui/routes/status.rb +19 -0
  372. data/lib/karafka/web/ui/routes/support.rb +19 -0
  373. data/lib/karafka/web/ui/routes/ux.rb +19 -0
  374. data/lib/karafka/web/ui/views/cluster/_partition.erb +2 -2
  375. data/lib/karafka/web/ui/views/cluster/brokers.erb +1 -1
  376. data/lib/karafka/web/ui/views/consumers/_breadcrumbs.erb +7 -1
  377. data/lib/karafka/web/ui/views/consumers/_consumer.erb +39 -30
  378. data/lib/karafka/web/ui/views/consumers/_incompatible.erb +13 -0
  379. data/lib/karafka/web/ui/views/consumers/_no_consumers.erb +2 -2
  380. data/lib/karafka/web/ui/views/consumers/_tabs.erb +4 -4
  381. data/lib/karafka/web/ui/views/consumers/index.erb +1 -1
  382. data/lib/karafka/web/ui/views/dashboard/_feature_pro.erb +1 -1
  383. data/lib/karafka/web/ui/views/dashboard/_not_enough_data.erb +2 -2
  384. data/lib/karafka/web/ui/views/dashboard/_ranges_selector.erb +1 -1
  385. data/lib/karafka/web/ui/views/dashboard/index.erb +6 -49
  386. data/lib/karafka/web/ui/views/errors/_detail.erb +3 -3
  387. data/lib/karafka/web/ui/views/errors/index.erb +1 -1
  388. data/lib/karafka/web/ui/views/jobs/_job.erb +38 -29
  389. data/lib/karafka/web/ui/views/jobs/pending.erb +1 -1
  390. data/lib/karafka/web/ui/views/jobs/running.erb +1 -1
  391. data/lib/karafka/web/ui/views/layout.erb +7 -5
  392. data/lib/karafka/web/ui/views/shared/_become_pro.erb +1 -1
  393. data/lib/karafka/web/ui/views/shared/_brand.erb +1 -1
  394. data/lib/karafka/web/ui/views/shared/_breadcrumbs.erb +1 -1
  395. data/lib/karafka/web/ui/views/shared/_content.erb +1 -1
  396. data/lib/karafka/web/ui/views/shared/_controls.erb +10 -3
  397. data/lib/karafka/web/ui/views/shared/_custom_nav.erb +9 -0
  398. data/lib/karafka/web/ui/views/shared/_flashes.erb +3 -5
  399. data/lib/karafka/web/ui/views/shared/_header.erb +25 -2
  400. data/lib/karafka/web/ui/views/shared/_navigation.erb +17 -15
  401. data/lib/karafka/web/ui/views/shared/alerts/_error.erb +8 -0
  402. data/lib/karafka/web/ui/views/shared/alerts/_info.erb +8 -0
  403. data/lib/karafka/web/ui/views/shared/alerts/_primary.erb +8 -0
  404. data/lib/karafka/web/ui/views/shared/alerts/_secondary.erb +8 -0
  405. data/lib/karafka/web/ui/views/shared/alerts/_success.erb +8 -0
  406. data/lib/karafka/web/ui/views/shared/alerts/_warning.erb +8 -0
  407. data/lib/karafka/web/ui/views/shared/exceptions/incompatible_schema.erb +34 -0
  408. data/lib/karafka/web/ui/views/shared/exceptions/not_allowed.erb +4 -0
  409. data/lib/karafka/web/ui/views/shared/exceptions/not_found.erb +5 -1
  410. data/lib/karafka/web/ui/views/shared/exceptions/pro_only.erb +4 -0
  411. data/lib/karafka/web/ui/views/shared/icons/_arrow_left.erb +3 -0
  412. data/lib/karafka/web/ui/views/shared/icons/_arrow_up_tray.erb +3 -0
  413. data/lib/karafka/web/ui/views/shared/icons/_clock.erb +3 -0
  414. data/lib/karafka/web/ui/views/shared/icons/_pencil.erb +3 -0
  415. data/lib/karafka/web/ui/views/shared/icons/_pencil_square.erb +3 -0
  416. data/lib/karafka/web/ui/views/shared/icons/_play_pause.erb +3 -0
  417. data/lib/karafka/web/ui/views/shared/icons/_plus.erb +3 -0
  418. data/lib/karafka/web/ui/views/shared/icons/_trash.erb +3 -0
  419. data/lib/karafka/web/ui/views/status/failures/_live_reporting.erb +1 -1
  420. data/lib/karafka/web/ui/views/status/failures/_partitions.erb +3 -3
  421. data/lib/karafka/web/ui/views/status/failures/_state_calculation.erb +2 -2
  422. data/lib/karafka/web/ui/views/status/info/_components.erb +6 -6
  423. data/lib/karafka/web/ui/views/status/show.erb +15 -0
  424. data/lib/karafka/web/ui/views/status/warnings/_consumers_schemas.erb +31 -0
  425. data/lib/karafka/web/ui/views/ux/_icons.erb +1 -1
  426. data/lib/karafka/web/ui/views/ux/_status_rows.erb +6 -0
  427. data/lib/karafka/web/version.rb +1 -1
  428. data/lib/karafka/web.rb +3 -0
  429. data/package-lock.json +776 -1208
  430. data/package.json +3 -4
  431. data/postcss.config.js +1 -2
  432. data/renovate.json +13 -1
  433. data/tailwind.config.js +0 -4
  434. data.tar.gz.sig +0 -0
  435. metadata +232 -108
  436. metadata.gz.sig +0 -0
  437. data/lib/karafka/web/pro/commanding/commands/quiet.rb +0 -34
  438. data/lib/karafka/web/pro/commanding/commands/stop.rb +0 -34
  439. data/lib/karafka/web/pro/commanding/commands/trace.rb +0 -41
  440. data/lib/karafka/web/pro/ui/controllers/commanding_controller.rb +0 -118
  441. data/lib/karafka/web/pro/ui/controllers/commands_controller.rb +0 -96
  442. data/lib/karafka/web/pro/ui/controllers/consumers_controller.rb +0 -138
  443. data/lib/karafka/web/pro/ui/controllers/explorer_controller.rb +0 -220
  444. data/lib/karafka/web/pro/ui/controllers/messages_controller.rb +0 -107
  445. data/lib/karafka/web/pro/ui/controllers/search_controller.rb +0 -73
  446. data/lib/karafka/web/pro/ui/controllers/topics_controller.rb +0 -130
  447. data/lib/karafka/web/pro/ui/views/commands/_breadcrumbs.erb +0 -21
  448. data/lib/karafka/web/pro/ui/views/commands/_command_details.erb +0 -1
  449. data/lib/karafka/web/pro/ui/views/commands/_empty.erb +0 -3
  450. data/lib/karafka/web/pro/ui/views/commands/show.erb +0 -33
  451. data/lib/karafka/web/pro/ui/views/consumers/_breadcrumbs.erb +0 -55
  452. data/lib/karafka/web/pro/ui/views/consumers/_consumer.erb +0 -47
  453. data/lib/karafka/web/pro/ui/views/consumers/_consumer_controls.erb +0 -95
  454. data/lib/karafka/web/pro/ui/views/consumers/_consumer_performance.erb +0 -59
  455. data/lib/karafka/web/pro/ui/views/consumers/_tabs.erb +0 -33
  456. data/lib/karafka/web/pro/ui/views/consumers/consumer/_commands.erb +0 -72
  457. data/lib/karafka/web/pro/ui/views/consumers/consumer/_consumer_group.erb +0 -8
  458. data/lib/karafka/web/pro/ui/views/consumers/consumer/_no_subscriptions.erb +0 -7
  459. data/lib/karafka/web/pro/ui/views/consumers/details.erb +0 -13
  460. data/lib/karafka/web/pro/ui/views/consumers/subscriptions.erb +0 -25
  461. data/lib/karafka/web/pro/ui/views/explorer/_no_topics.erb +0 -1
  462. data/lib/karafka/web/pro/ui/views/explorer/_topic.erb +0 -10
  463. data/lib/karafka/web/pro/ui/views/explorer/index.erb +0 -14
  464. data/lib/karafka/web/pro/ui/views/explorer/messages/_headers.erb +0 -33
  465. data/lib/karafka/web/pro/ui/views/explorer/partition/_cleaned.erb +0 -3
  466. data/lib/karafka/web/pro/ui/views/explorer/partition/_empty.erb +0 -3
  467. data/lib/karafka/web/pro/ui/views/explorer/topic/_empty.erb +0 -3
  468. data/lib/karafka/web/pro/ui/views/search/_breadcrumbs.erb +0 -1
  469. data/lib/karafka/web/pro/ui/views/search/_fix_errors.erb +0 -3
  470. data/lib/karafka/web/pro/ui/views/search/_no_results.erb +0 -3
  471. data/lib/karafka/web/pro/ui/views/search/_timeout.erb +0 -3
  472. data/lib/karafka/web/pro/ui/views/search/index.erb +0 -29
  473. data/lib/karafka/web/pro/ui/views/topics/_breadcrumbs.erb +0 -45
  474. data/lib/karafka/web/pro/ui/views/topics/_partition_offsets.erb +0 -10
  475. data/lib/karafka/web/pro/ui/views/topics/_topic.erb +0 -9
  476. data/lib/karafka/web/pro/ui/views/topics/distribution/_empty_partitions.erb +0 -1
  477. data/lib/karafka/web/pro/ui/views/topics/distribution/_partition.erb +0 -10
  478. data/lib/karafka/web/pro/ui/views/topics/index.erb +0 -14
  479. data/lib/karafka/web/ui/lib/ttl_cache.rb +0 -82
@@ -40,6 +40,7 @@ module Karafka
40
40
  plugin :capture_erb
41
41
  plugin :content_for
42
42
  plugin :inject_erb
43
+ plugin :all_verbs
43
44
 
44
45
  # Based on
45
46
  # https://github.com/sidekiq/sidekiq/blob/ae6ca119/lib/sidekiq/web/application.rb#L8
@@ -70,7 +71,16 @@ module Karafka
70
71
  # Map redirect flashes (if any) to Roda flash messages
71
72
  result.flashes.each { |key, value| flash[key] = value }
72
73
 
73
- response.redirect result.back? ? request.referer : root_path(result.path)
74
+ path = case result.path
75
+ when :back
76
+ session[:current_path]
77
+ when :previous
78
+ session[:previous_path]
79
+ else
80
+ root_path(result.path)
81
+ end
82
+
83
+ response.redirect path || root_path
74
84
  end
75
85
 
76
86
  handle_block_result Controllers::Responses::File do |result|
@@ -84,7 +94,8 @@ module Karafka
84
94
  ::Rdkafka::RdkafkaError,
85
95
  Errors::Ui::NotFoundError,
86
96
  Errors::Ui::ProOnlyError,
87
- Errors::Ui::ForbiddenError
97
+ Errors::Ui::ForbiddenError,
98
+ Errors::Ui::IncompatibleSchemaError
88
99
  ] do |e|
89
100
  @error = true
90
101
 
@@ -95,6 +106,9 @@ module Karafka
95
106
  when Errors::Ui::ForbiddenError
96
107
  response.status = 403
97
108
  view 'shared/exceptions/not_allowed'
109
+ when Errors::Ui::IncompatibleSchemaError
110
+ response.status = 422
111
+ view 'shared/exceptions/incompatible_schema'
98
112
  else
99
113
  response.status = 404
100
114
  view 'shared/exceptions/not_found'
@@ -109,9 +123,11 @@ module Karafka
109
123
 
110
124
  before do
111
125
  check_csrf!
126
+ store_paths_history(request, session)
112
127
  end
113
128
 
114
129
  plugin :class_matchers
130
+ plugin :symbol_matchers
115
131
 
116
132
  # Time matcher with optional hours, minutes and seconds
117
133
  TIME_MATCHER = %r{(\d{4}-\d{2}-\d{2}/?(\d{2})?(:\d{2})?(:\d{2})?)}
@@ -122,12 +138,22 @@ module Karafka
122
138
  # @note In case the date-time is invalid, raise and render 404
123
139
  # @note The time component is optional as `Time#parse` will fallback to lowest time
124
140
  # available, so we can build only date based lookups
125
- class_matcher(Time, TIME_MATCHER) do |datetime|
126
- [Time.parse(datetime)]
141
+ class_matcher(Time, TIME_MATCHER) do |*datetime|
142
+ [Time.parse(datetime[0])]
127
143
  rescue ArgumentError
128
144
  raise Errors::Ui::NotFoundError
129
145
  end
130
146
 
147
+ # Partitions ids cannot be bigger than 32 bit C int. We use this matcher to ensure we
148
+ # only support that big partition numbers. Otherwise librdkafka would crash.
149
+ symbol_matcher :partition_id, /(\d{1,14})/ do |value|
150
+ int_value = value.to_i
151
+
152
+ raise Errors::Ui::NotFoundError unless int_value.between?(0, 2_147_483_647)
153
+
154
+ [int_value]
155
+ end
156
+
131
157
  # Allows us to build current path with additional params + it merges existing params into
132
158
  # the query data. Query data takes priority over request params.
133
159
  # @param query_data [Hash] query params we want to add to the current path
@@ -145,6 +171,14 @@ module Karafka
145
171
  [request.path, query_string].compact.join('?')
146
172
  end
147
173
 
174
+ # Builds a consumer instance with all needed details
175
+ # @param consumer_class [Class]
176
+ def build(consumer_class)
177
+ Controllers::Requests::ExecutionWrapper.new(
178
+ consumer_class.new(params, session)
179
+ )
180
+ end
181
+
148
182
  # Sets appropriate template variables based on the response object and renders the
149
183
  # expected view
150
184
  # @param response [Karafka::Web::Ui::Controllers::Responses::Data] response data object
@@ -162,6 +196,31 @@ module Karafka
162
196
  def params
163
197
  Controllers::Requests::Params.new(request.params)
164
198
  end
199
+
200
+ private
201
+
202
+ # Stores history about visited paths. Useful for redirecting users back when needed.
203
+ # @param request [Karafka::Web::Ui::App::RodaRequest]
204
+ # @param session [Object] session object (Rails or Rack)
205
+ def store_paths_history(request, session)
206
+ # Code below tracks previous paths so we can use it to redirect users back
207
+ return unless request.get?
208
+ return unless request.env['HTTP_ACCEPT']&.include?('text/html')
209
+
210
+ requested_path = request.path
211
+
212
+ if session[:current_path].nil?
213
+ session[:current_path] = requested_path
214
+
215
+ return
216
+ end
217
+
218
+ return if request.path == session[:current_path]
219
+
220
+ # When navigating to a different page
221
+ session[:previous_path] = session[:current_path]
222
+ session[:current_path] = requested_path
223
+ end
165
224
  end
166
225
  end
167
226
  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
@@ -49,7 +49,7 @@ module Karafka
49
49
 
50
50
  # @return [String] errors topic
51
51
  def errors_topic
52
- ::Karafka::Web.config.topics.errors
52
+ ::Karafka::Web.config.topics.errors.name
53
53
  end
54
54
  end
55
55
  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
@@ -223,13 +223,22 @@ module Karafka
223
223
  title = 'Not available until first offset commit'
224
224
  %(<span class="badge badge-secondary" title="#{title}">N/A</span>)
225
225
  elsif explore
226
- path = explorer_path(topic_name, partition_id, offset)
226
+ path = explorer_topics_path(topic_name, partition_id, offset)
227
227
  %(<a href="#{path}">#{offset}</a>)
228
228
  else
229
229
  offset.to_s
230
230
  end
231
231
  end
232
232
 
233
+ # Normalizes the metric value for display. Negative values coming from statistics usually
234
+ # mean, that the value is not (yet) available.
235
+ #
236
+ # @param value [Integer]
237
+ # @return [String] input value if not negative or N/A
238
+ def normalized_metric(value)
239
+ value.negative? ? 'N/A' : value.to_s
240
+ end
241
+
233
242
  # @param details [::Karafka::Web::Ui::Models::Partition] partition information with
234
243
  # lso risk state info
235
244
  # @return [String] background classes for row marking
@@ -6,6 +6,15 @@ module Karafka
6
6
  module Helpers
7
7
  # Helper for web ui paths builders
8
8
  module PathsHelper
9
+ # Method that can be used to have conditions in breadcrumbs, etc based on the action
10
+ # we're in
11
+ #
12
+ # @param args [Array<Symbol>] action names we want to check
13
+ # @return [Boolean] true if any matches the current action name
14
+ def action?(*args)
15
+ args.include?(@current_action_name)
16
+ end
17
+
9
18
  # Helper method to flatten nested hashes and arrays
10
19
  # @param prefix [String] The prefix for nested keys, initially an empty string.
11
20
  # @param hash [Hash, Array] The nested hash or array to be flattened.
@@ -54,16 +63,51 @@ module Karafka
54
63
 
55
64
  # Helps build explorer paths. We often link offsets to proper messages, etc so this
56
65
  # allows us to short-track this
57
- # @param topic_name [String, nil] name of the topic where we want to go within the
58
- # explorer or nil if we want to just go to the explorer root
59
- # @param partition_id [Integer, nil] partition we want to display in the explorer or nil
60
- # if we want to go to the topic root
61
- # @param offset [Integer, nil] offset of particular message or nil of we want to just go
62
- # to the partition root
63
- # @param action [String, nil] specific routed action or nil
66
+ # @param args [Array<String>] sub-paths
64
67
  # @return [String] path to the expected location
65
- def explorer_path(topic_name = nil, partition_id = nil, offset = nil, action = nil)
66
- root_path(*['explorer', topic_name, partition_id, offset, action].compact)
68
+ def explorer_path(*args)
69
+ root_path(*['explorer', args.compact].flatten)
70
+ end
71
+
72
+ # Generates routes for explorer topics paths
73
+ #
74
+ # @param args [Array<String>] sub-paths
75
+ # @return explorer topics path
76
+ def explorer_topics_path(*args)
77
+ explorer_path(*['topics', args.compact].flatten)
78
+ end
79
+
80
+ # Generates routes for explorer messages paths
81
+ #
82
+ # @param args [Array<String>] sub-paths
83
+ # @return [String] explorer messages path
84
+ def explorer_messages_path(*args)
85
+ explorer_path(*['messages', args.compact].flatten)
86
+ end
87
+
88
+ # Helps build topics paths
89
+ #
90
+ # @param args [Array<String>] path params for the topics scope
91
+ # @return [String] topics scope path
92
+ def topics_path(*args)
93
+ root_path('topics', *args)
94
+ end
95
+
96
+ # Helps build consumers paths
97
+ #
98
+ # @param args [Array<String>] path params for consumers scope
99
+ # @return [String] consumers scope path
100
+ def consumers_path(*args)
101
+ root_path('consumers', *args)
102
+ end
103
+
104
+ # Helps build per-consumer scope paths
105
+ #
106
+ # @param consumer_id [String] consumer process id
107
+ # @param args [Array<String>] other path components
108
+ # @return [String] per consumer specific path
109
+ def consumer_path(consumer_id, *args)
110
+ consumers_path(consumer_id, *args)
67
111
  end
68
112
 
69
113
  # Helps build scheduled messages paths.
@@ -80,7 +124,7 @@ module Karafka
80
124
  action = nil
81
125
  )
82
126
  root_path(
83
- *['scheduled_messages', 'explorer', topic_name, partition_id, offset, action].compact
127
+ *['scheduled_messages', 'explorer', 'topics', topic_name, partition_id, offset, action].compact
84
128
  )
85
129
  end
86
130
  end
@@ -17,7 +17,7 @@ module Karafka
17
17
  class << self
18
18
  extend Forwardable
19
19
 
20
- def_delegators ::Karafka::Admin, :read_watermark_offsets, :cluster_info
20
+ def_delegators ::Karafka::Admin, :read_watermark_offsets, :cluster_info, :topic_info
21
21
 
22
22
  # Allows us to read messages from the topic
23
23
  #