karafka-web 0.10.4 → 0.11.0.beta2
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +54 -176
- data/Gemfile +4 -0
- data/Gemfile.lock +87 -43
- data/LICENSE +6 -2
- data/bin/verify_kafka_warnings +35 -0
- data/bin/verify_topics_naming +35 -0
- data/config/locales/pro_errors.yml +1 -0
- data/docker-compose.yml +1 -1
- data/gulpfile.js +0 -2
- data/karafka-web.gemspec +2 -2
- data/lib/karafka/web/config.rb +80 -9
- data/lib/karafka/web/contracts/config.rb +44 -5
- data/lib/karafka/web/errors.rb +10 -12
- data/lib/karafka/web/management/actions/create_initial_states.rb +6 -6
- data/lib/karafka/web/management/actions/create_topics.rb +30 -64
- data/lib/karafka/web/management/actions/delete_topics.rb +5 -5
- data/lib/karafka/web/management/actions/enable.rb +5 -5
- data/lib/karafka/web/pro/commanding/commands/base.rb +37 -13
- data/lib/karafka/web/pro/commanding/commands/consumers/quiet.rb +33 -0
- data/lib/karafka/web/pro/commanding/commands/consumers/stop.rb +32 -0
- data/lib/karafka/web/pro/commanding/commands/consumers/trace.rb +37 -0
- data/lib/karafka/web/pro/commanding/commands/partitions/pause.rb +30 -0
- data/lib/karafka/web/pro/commanding/commands/partitions/resume.rb +30 -0
- data/lib/karafka/web/pro/commanding/commands/partitions/seek.rb +30 -0
- data/lib/karafka/web/pro/commanding/config.rb +6 -10
- data/lib/karafka/web/pro/commanding/contracts/config.rb +2 -10
- data/lib/karafka/web/pro/commanding/dispatcher.rb +45 -24
- data/lib/karafka/web/pro/commanding/handlers/partitions/commands/base.rb +67 -0
- data/lib/karafka/web/pro/commanding/handlers/partitions/commands/pause.rb +44 -0
- data/lib/karafka/web/pro/commanding/handlers/partitions/commands/resume.rb +29 -0
- data/lib/karafka/web/pro/commanding/handlers/partitions/commands/seek.rb +86 -0
- data/lib/karafka/web/pro/commanding/handlers/partitions/executor.rb +56 -0
- data/lib/karafka/web/pro/commanding/handlers/partitions/listener.rb +55 -0
- data/lib/karafka/web/pro/commanding/handlers/partitions/tracker.rb +62 -0
- data/lib/karafka/web/pro/commanding/listener.rb +4 -12
- data/lib/karafka/web/pro/commanding/manager.rb +36 -24
- data/lib/karafka/web/pro/commanding/matcher.rb +7 -17
- data/lib/karafka/web/pro/commanding/request.rb +39 -0
- data/lib/karafka/web/pro/commanding.rb +2 -10
- data/lib/karafka/web/pro/loader.rb +13 -10
- data/lib/karafka/web/pro/ui/app.rb +31 -390
- data/lib/karafka/web/pro/ui/controllers/base_controller.rb +8 -10
- data/lib/karafka/web/pro/ui/controllers/cluster_controller.rb +2 -10
- data/lib/karafka/web/pro/ui/controllers/consumers/base_controller.rb +21 -0
- data/lib/karafka/web/pro/ui/controllers/consumers/commanding_controller.rb +148 -0
- data/lib/karafka/web/pro/ui/controllers/consumers/commands_controller.rb +96 -0
- data/lib/karafka/web/pro/ui/controllers/consumers/consumers_controller.rb +99 -0
- data/lib/karafka/web/pro/ui/controllers/consumers/controls_controller.rb +36 -0
- data/lib/karafka/web/pro/ui/controllers/consumers/jobs_controller.rb +57 -0
- data/lib/karafka/web/pro/ui/controllers/consumers/partitions/base_controller.rb +86 -0
- data/lib/karafka/web/pro/ui/controllers/consumers/partitions/offsets_controller.rb +75 -0
- data/lib/karafka/web/pro/ui/controllers/consumers/partitions/pauses_controller.rb +110 -0
- data/lib/karafka/web/pro/ui/controllers/dashboard_controller.rb +2 -10
- data/lib/karafka/web/pro/ui/controllers/dlq_controller.rb +2 -10
- data/lib/karafka/web/pro/ui/controllers/errors_controller.rb +3 -11
- data/lib/karafka/web/pro/ui/controllers/explorer/base_controller.rb +21 -0
- data/lib/karafka/web/pro/ui/controllers/explorer/explorer_controller.rb +215 -0
- data/lib/karafka/web/pro/ui/controllers/explorer/messages_controller.rb +145 -0
- data/lib/karafka/web/pro/ui/controllers/explorer/search_controller.rb +68 -0
- data/lib/karafka/web/pro/ui/controllers/health_controller.rb +2 -10
- data/lib/karafka/web/pro/ui/controllers/jobs_controller.rb +2 -10
- data/lib/karafka/web/pro/ui/controllers/recurring_tasks_controller.rb +12 -13
- data/lib/karafka/web/pro/ui/controllers/routing_controller.rb +2 -10
- data/lib/karafka/web/pro/ui/controllers/scheduled_messages/base_controller.rb +2 -10
- data/lib/karafka/web/pro/ui/controllers/scheduled_messages/explorer_controller.rb +8 -16
- data/lib/karafka/web/pro/ui/controllers/scheduled_messages/messages_controller.rb +9 -15
- data/lib/karafka/web/pro/ui/controllers/scheduled_messages/schedules_controller.rb +2 -10
- data/lib/karafka/web/pro/ui/controllers/status_controller.rb +2 -10
- data/lib/karafka/web/pro/ui/controllers/support_controller.rb +2 -10
- data/lib/karafka/web/pro/ui/controllers/topics/base_controller.rb +21 -0
- data/lib/karafka/web/pro/ui/controllers/topics/configs_controller.rb +86 -0
- data/lib/karafka/web/pro/ui/controllers/topics/distributions_controller.rb +91 -0
- data/lib/karafka/web/pro/ui/controllers/topics/offsets_controller.rb +55 -0
- data/lib/karafka/web/pro/ui/controllers/topics/replications_controller.rb +37 -0
- data/lib/karafka/web/pro/ui/controllers/topics/topics_controller.rb +101 -0
- data/lib/karafka/web/pro/ui/controllers/ux_controller.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/branding/config.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/branding/contracts/config.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/branding.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/features.rb +53 -0
- data/lib/karafka/web/pro/ui/lib/patterns_detector.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/policies/config.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/policies/contracts/config.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/policies/messages.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/policies/requests.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/policies.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/safe_runner.rb +5 -0
- data/lib/karafka/web/pro/ui/lib/search/config.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/search/contracts/config.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/search/contracts/form.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/search/matchers/base.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/search/matchers/raw_header_includes.rb +10 -11
- data/lib/karafka/web/pro/ui/lib/search/matchers/raw_key_includes.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/search/matchers/raw_payload_includes.rb +23 -11
- data/lib/karafka/web/pro/ui/lib/search/normalizer.rb +2 -10
- data/lib/karafka/web/pro/ui/lib/search/runner.rb +3 -11
- data/lib/karafka/web/pro/ui/lib/search.rb +2 -10
- data/lib/karafka/web/pro/ui/routes/base.rb +19 -0
- data/lib/karafka/web/pro/ui/routes/cluster.rb +37 -0
- data/lib/karafka/web/pro/ui/routes/consumers.rb +145 -0
- data/lib/karafka/web/pro/ui/routes/dashboard.rb +25 -0
- data/lib/karafka/web/pro/ui/routes/dlq.rb +24 -0
- data/lib/karafka/web/pro/ui/routes/errors.rb +39 -0
- data/lib/karafka/web/pro/ui/routes/explorer.rb +118 -0
- data/lib/karafka/web/pro/ui/routes/health.rb +47 -0
- data/lib/karafka/web/pro/ui/routes/jobs.rb +33 -0
- data/lib/karafka/web/pro/ui/routes/recurring_tasks.rb +59 -0
- data/lib/karafka/web/pro/ui/routes/routing.rb +31 -0
- data/lib/karafka/web/pro/ui/routes/scheduled_messages.rb +75 -0
- data/lib/karafka/web/pro/ui/routes/status.rb +24 -0
- data/lib/karafka/web/pro/ui/routes/support.rb +24 -0
- data/lib/karafka/web/pro/ui/routes/topics.rb +90 -0
- data/lib/karafka/web/pro/ui/routes/ux.rb +24 -0
- data/lib/karafka/web/pro/ui/views/cluster/_breadcrumbs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/cluster/_broker.erb +3 -0
- data/lib/karafka/web/pro/ui/views/cluster/_config.erb +3 -0
- data/lib/karafka/web/pro/ui/views/cluster/_tabs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/cluster/index.erb +4 -1
- data/lib/karafka/web/pro/ui/views/cluster/show.erb +3 -0
- data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_backtrace.erb +3 -0
- data/lib/karafka/web/pro/ui/views/consumers/commands/_breadcrumbs.erb +24 -0
- data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_command.erb +22 -6
- data/lib/karafka/web/pro/ui/views/consumers/commands/_command_details.erb +4 -0
- data/lib/karafka/web/pro/ui/views/consumers/commands/_empty.erb +6 -0
- data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_incompatible_schema.erb +3 -0
- data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_metadata.erb +4 -1
- data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/_table.erb +5 -2
- data/lib/karafka/web/pro/ui/views/{commands → consumers/commands}/index.erb +7 -4
- data/lib/karafka/web/pro/ui/views/consumers/commands/show.erb +32 -0
- data/lib/karafka/web/pro/ui/views/consumers/consumers/_breadcrumbs.erb +46 -0
- data/lib/karafka/web/pro/ui/views/consumers/{_consumer.erb → consumers/_consumer.erb} +4 -1
- data/lib/karafka/web/pro/ui/views/consumers/{_consumer_performance.erb → consumers/_consumer_performance.erb} +4 -1
- data/lib/karafka/web/pro/ui/views/consumers/consumers/_tabs.erb +38 -0
- data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_commands.erb +80 -0
- data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_consumer_group.erb +11 -0
- data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_metrics.erb +3 -0
- data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_no_subscriptions.erb +10 -0
- data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_partition.erb +16 -0
- data/lib/karafka/web/pro/ui/views/consumers/consumers/consumer/_partition_edit_options.erb +33 -0
- data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_stopped.erb +3 -0
- data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_subscription_group.erb +7 -3
- data/lib/karafka/web/pro/ui/views/consumers/{consumer → consumers/consumer}/_tabs.erb +7 -4
- data/lib/karafka/web/pro/ui/views/consumers/consumers/details.erb +15 -0
- data/lib/karafka/web/pro/ui/views/consumers/{index.erb → consumers/index.erb} +6 -3
- data/lib/karafka/web/pro/ui/views/consumers/{performance.erb → consumers/performance.erb} +6 -3
- data/lib/karafka/web/pro/ui/views/consumers/consumers/subscriptions.erb +24 -0
- data/lib/karafka/web/pro/ui/views/consumers/controls/_breadcrumbs.erb +16 -0
- data/lib/karafka/web/pro/ui/views/consumers/{_consumer_controls.erb → controls/_controls.erb} +10 -7
- data/lib/karafka/web/pro/ui/views/consumers/{controls.erb → controls/index.erb} +8 -5
- data/lib/karafka/web/pro/ui/views/consumers/jobs/_breadcrumbs.erb +36 -0
- data/lib/karafka/web/pro/ui/views/consumers/{consumer → jobs}/_job.erb +3 -0
- data/lib/karafka/web/pro/ui/views/consumers/{consumer → jobs}/_no_jobs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/consumers/{pending_jobs.erb → jobs/pending.erb} +7 -8
- data/lib/karafka/web/pro/ui/views/consumers/{running_jobs.erb → jobs/running.erb} +7 -8
- data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_basics.erb +77 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_breadcrumbs.erb +58 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_form.erb +109 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_not_running_error.erb +16 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/_running_warning.erb +15 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/offsets/edit.erb +12 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_active_not_editable.erb +22 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_adjusting_warning.erb +27 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_breadcrumbs.erb +60 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_edit_form.erb +59 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_lrj_not_manageable.erb +24 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_new_form.erb +78 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/_not_running.erb +16 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/edit.erb +20 -0
- data/lib/karafka/web/pro/ui/views/consumers/partitions/pauses/new.erb +16 -0
- data/lib/karafka/web/pro/ui/views/dashboard/index.erb +4 -1
- data/lib/karafka/web/pro/ui/views/dlq/_breadcrumbs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/dlq/_no_topics.erb +3 -0
- data/lib/karafka/web/pro/ui/views/dlq/_topic.erb +4 -1
- data/lib/karafka/web/pro/ui/views/dlq/index.erb +3 -0
- data/lib/karafka/web/pro/ui/views/errors/_breadcrumbs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/errors/_error.erb +3 -0
- data/lib/karafka/web/pro/ui/views/errors/_partition_option.erb +3 -0
- data/lib/karafka/web/pro/ui/views/errors/_selector.erb +3 -0
- data/lib/karafka/web/pro/ui/views/errors/_table.erb +4 -1
- data/lib/karafka/web/pro/ui/views/errors/index.erb +6 -3
- data/lib/karafka/web/pro/ui/views/errors/partition.erb +5 -2
- data/lib/karafka/web/pro/ui/views/errors/show.erb +3 -0
- data/lib/karafka/web/pro/ui/views/explorer/{_breadcrumbs.erb → explorer/_breadcrumbs.erb} +7 -4
- data/lib/karafka/web/pro/ui/views/explorer/{_failed_deserialization.erb → explorer/_failed_deserialization.erb} +3 -0
- data/lib/karafka/web/pro/ui/views/explorer/{_filtered.erb → explorer/_filtered.erb} +3 -0
- data/lib/karafka/web/pro/ui/views/explorer/{_message.erb → explorer/_message.erb} +4 -1
- data/lib/karafka/web/pro/ui/views/explorer/explorer/_no_topics.erb +4 -0
- data/lib/karafka/web/pro/ui/views/explorer/{_partition_option.erb → explorer/_partition_option.erb} +4 -1
- data/lib/karafka/web/pro/ui/views/explorer/{_selector.erb → explorer/_selector.erb} +4 -1
- data/lib/karafka/web/pro/ui/views/explorer/explorer/_topic.erb +13 -0
- data/lib/karafka/web/pro/ui/views/explorer/explorer/index.erb +17 -0
- data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_metadata.erb +10 -7
- data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_payload.erb +6 -3
- data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_resources_utilization.erb +7 -4
- data/lib/karafka/web/pro/ui/views/explorer/{message → explorer/message}/_too_big_to_be_displayed.erb +3 -0
- data/lib/karafka/web/pro/ui/views/explorer/{messages → explorer/messages}/_detail.erb +3 -0
- data/lib/karafka/web/pro/ui/views/explorer/explorer/messages/_headers.erb +51 -0
- data/lib/karafka/web/pro/ui/views/explorer/{messages → explorer/messages}/_key.erb +3 -0
- data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_cleaned.erb +6 -0
- data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_empty.erb +6 -0
- data/lib/karafka/web/pro/ui/views/explorer/{partition → explorer/partition}/_messages.erb +4 -1
- data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_time_selector.erb +16 -0
- data/lib/karafka/web/pro/ui/views/explorer/explorer/partition/_timestamp_selector.erb +33 -0
- data/lib/karafka/web/pro/ui/views/explorer/{partition.erb → explorer/partition.erb} +24 -17
- data/lib/karafka/web/pro/ui/views/explorer/{show.erb → explorer/show.erb} +17 -19
- data/lib/karafka/web/pro/ui/views/explorer/{topic → explorer/topic}/_actions.erb +5 -2
- data/lib/karafka/web/pro/ui/views/explorer/explorer/topic/_empty.erb +6 -0
- data/lib/karafka/web/pro/ui/views/explorer/{topic → explorer/topic}/_limited.erb +3 -0
- data/lib/karafka/web/pro/ui/views/explorer/{topic.erb → explorer/topic.erb} +7 -4
- data/lib/karafka/web/pro/ui/views/explorer/messages/_breadcrumbs.erb +32 -0
- data/lib/karafka/web/pro/ui/views/explorer/messages/forward.erb +143 -0
- data/lib/karafka/web/pro/ui/views/explorer/search/_breadcrumbs.erb +4 -0
- data/lib/karafka/web/pro/ui/views/explorer/search/_fix_errors.erb +6 -0
- data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_metadata.erb +3 -0
- data/lib/karafka/web/pro/ui/views/explorer/search/_no_results.erb +6 -0
- data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_no_search_criteria.erb +3 -0
- data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_search_criteria.erb +3 -0
- data/lib/karafka/web/pro/ui/views/{search → explorer/search}/_search_modal.erb +5 -2
- data/lib/karafka/web/pro/ui/views/explorer/search/_timeout.erb +6 -0
- data/lib/karafka/web/pro/ui/views/explorer/search/index.erb +32 -0
- data/lib/karafka/web/pro/ui/views/health/_breadcrumbs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/health/_no_data.erb +3 -0
- data/lib/karafka/web/pro/ui/views/health/_partition.erb +16 -1
- data/lib/karafka/web/pro/ui/views/health/_partition_lags.erb +3 -0
- data/lib/karafka/web/pro/ui/views/health/_partition_offset.erb +3 -0
- data/lib/karafka/web/pro/ui/views/health/_partition_times.erb +3 -0
- data/lib/karafka/web/pro/ui/views/health/_table_metadata.erb +4 -1
- data/lib/karafka/web/pro/ui/views/health/_tabs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/health/changes.erb +4 -1
- data/lib/karafka/web/pro/ui/views/health/cluster_lags.erb +3 -0
- data/lib/karafka/web/pro/ui/views/health/lags.erb +5 -2
- data/lib/karafka/web/pro/ui/views/health/offsets.erb +4 -1
- data/lib/karafka/web/pro/ui/views/health/overview.erb +8 -3
- data/lib/karafka/web/pro/ui/views/jobs/_job.erb +4 -1
- data/lib/karafka/web/pro/ui/views/jobs/_no_jobs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/jobs/pending.erb +4 -1
- data/lib/karafka/web/pro/ui/views/jobs/running.erb +4 -1
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_actions.erb +3 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_batch_actions.erb +3 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_breadcrumbs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_log.erb +3 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_not_active.erb +3 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_tabs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/_task.erb +3 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/logs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/recurring_tasks/schedule.erb +3 -0
- data/lib/karafka/web/pro/ui/views/routing/_consumer_group.erb +3 -0
- data/lib/karafka/web/pro/ui/views/routing/_detail.erb +3 -0
- data/lib/karafka/web/pro/ui/views/routing/_topic.erb +3 -0
- data/lib/karafka/web/pro/ui/views/routing/index.erb +3 -0
- data/lib/karafka/web/pro/ui/views/routing/show.erb +3 -0
- data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_breadcrumbs.erb +6 -3
- data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_key.erb +3 -0
- data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_message.erb +4 -1
- data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_messages.erb +3 -0
- data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/partition.erb +23 -16
- data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/topic.erb +6 -3
- data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_breadcrumbs.erb +3 -0
- data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_no_groups.erb +3 -0
- data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/index.erb +4 -1
- data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/show.erb +3 -0
- data/lib/karafka/web/pro/ui/views/shared/_navigation.erb +25 -17
- data/lib/karafka/web/pro/ui/views/shared/_rdkafka_form_error_alert_box.erb +16 -0
- data/lib/karafka/web/pro/ui/views/shared/branding/_label.erb +3 -0
- data/lib/karafka/web/pro/ui/views/shared/branding/_notice.erb +3 -0
- data/lib/karafka/web/pro/ui/views/topics/configs/_breadcrumbs.erb +34 -0
- data/lib/karafka/web/pro/ui/views/topics/configs/_config.erb +26 -0
- data/lib/karafka/web/pro/ui/views/topics/configs/_delete_button.erb +13 -0
- data/lib/karafka/web/pro/ui/views/topics/configs/_edit_form.erb +50 -0
- data/lib/karafka/web/pro/ui/views/topics/configs/_edit_plan.erb +16 -0
- data/lib/karafka/web/pro/ui/views/topics/configs/_edit_warning.erb +12 -0
- data/lib/karafka/web/pro/ui/views/topics/configs/edit.erb +16 -0
- data/lib/karafka/web/pro/ui/views/topics/{config.erb → configs/index.erb} +9 -3
- data/lib/karafka/web/pro/ui/views/topics/distributions/_add_partitions_button.erb +13 -0
- data/lib/karafka/web/pro/ui/views/topics/{distribution → distributions}/_badges.erb +3 -0
- data/lib/karafka/web/pro/ui/views/topics/distributions/_breadcrumbs.erb +28 -0
- data/lib/karafka/web/pro/ui/views/topics/{distribution → distributions}/_chart.erb +3 -0
- data/lib/karafka/web/pro/ui/views/topics/distributions/_edit_form.erb +47 -0
- data/lib/karafka/web/pro/ui/views/topics/distributions/_edit_hints.erb +15 -0
- data/lib/karafka/web/pro/ui/views/topics/distributions/_edit_warnings.erb +14 -0
- data/lib/karafka/web/pro/ui/views/topics/distributions/_empty_partitions.erb +4 -0
- data/lib/karafka/web/pro/ui/views/topics/{distribution → distributions}/_limited.erb +3 -0
- data/lib/karafka/web/pro/ui/views/topics/distributions/_partition.erb +13 -0
- data/lib/karafka/web/pro/ui/views/topics/distributions/edit.erb +16 -0
- data/lib/karafka/web/pro/ui/views/topics/{distribution.erb → distributions/show.erb} +11 -7
- data/lib/karafka/web/pro/ui/views/topics/offsets/_breadcrumbs.erb +20 -0
- data/lib/karafka/web/pro/ui/views/topics/offsets/_partition.erb +13 -0
- data/lib/karafka/web/pro/ui/views/topics/{offsets.erb → offsets/show.erb} +6 -3
- data/lib/karafka/web/pro/ui/views/topics/replications/_breadcrumbs.erb +20 -0
- data/lib/karafka/web/pro/ui/views/topics/{_partition.erb → replications/_partition.erb} +4 -1
- data/lib/karafka/web/pro/ui/views/topics/{replication.erb → replications/show.erb} +6 -3
- data/lib/karafka/web/pro/ui/views/topics/topics/_breadcrumbs.erb +32 -0
- data/lib/karafka/web/pro/ui/views/topics/topics/_create_button.erb +13 -0
- data/lib/karafka/web/pro/ui/views/topics/topics/_create_hints.erb +15 -0
- data/lib/karafka/web/pro/ui/views/topics/topics/_delete_form.erb +36 -0
- data/lib/karafka/web/pro/ui/views/topics/topics/_delete_hints.erb +15 -0
- data/lib/karafka/web/pro/ui/views/topics/topics/_delete_warning.erb +13 -0
- data/lib/karafka/web/pro/ui/views/topics/topics/_new_form.erb +80 -0
- data/lib/karafka/web/pro/ui/views/topics/{_tabs.erb → topics/_tabs.erb} +7 -4
- data/lib/karafka/web/pro/ui/views/topics/topics/_topic.erb +12 -0
- data/lib/karafka/web/pro/ui/views/topics/topics/edit.erb +10 -0
- data/lib/karafka/web/pro/ui/views/topics/topics/index.erb +19 -0
- data/lib/karafka/web/pro/ui/views/topics/topics/new.erb +12 -0
- data/lib/karafka/web/processing/consumer.rb +7 -7
- data/lib/karafka/web/processing/consumers/aggregators/state.rb +14 -14
- data/lib/karafka/web/processing/consumers/metrics.rb +1 -1
- data/lib/karafka/web/processing/consumers/state.rb +1 -1
- data/lib/karafka/web/processing/publisher.rb +4 -4
- data/lib/karafka/web/tracking/consumers/contracts/partition.rb +1 -0
- data/lib/karafka/web/tracking/consumers/listeners/pausing.rb +2 -2
- data/lib/karafka/web/tracking/consumers/listeners/transactions.rb +44 -0
- data/lib/karafka/web/tracking/consumers/reporter.rb +2 -2
- data/lib/karafka/web/tracking/consumers/sampler.rb +81 -14
- data/lib/karafka/web/tracking/helpers/sysconf.rb +33 -0
- data/lib/karafka/web/tracking/producers/reporter.rb +1 -1
- data/lib/karafka/web/ui/app.rb +19 -112
- data/lib/karafka/web/ui/base.rb +58 -3
- data/lib/karafka/web/ui/controllers/base_controller.rb +43 -1
- data/lib/karafka/web/ui/controllers/cluster_controller.rb +5 -2
- data/lib/karafka/web/ui/controllers/errors_controller.rb +1 -1
- data/lib/karafka/web/ui/controllers/requests/execution_wrapper.rb +52 -0
- data/lib/karafka/web/ui/controllers/requests/hookable.rb +99 -0
- data/lib/karafka/web/ui/controllers/requests/params.rb +39 -1
- data/lib/karafka/web/ui/controllers/responses/redirect.rb +0 -5
- data/lib/karafka/web/ui/controllers/status_controller.rb +3 -0
- data/lib/karafka/web/ui/helpers/application_helper.rb +10 -1
- data/lib/karafka/web/ui/helpers/paths_helper.rb +54 -10
- data/lib/karafka/web/ui/lib/admin.rb +1 -1
- data/lib/karafka/web/ui/lib/cache.rb +135 -0
- data/lib/karafka/web/ui/models/broker.rb +1 -2
- data/lib/karafka/web/ui/models/cluster_info.rb +15 -21
- data/lib/karafka/web/ui/models/consumers_metrics.rb +1 -1
- data/lib/karafka/web/ui/models/consumers_state.rb +1 -1
- data/lib/karafka/web/ui/models/counters.rb +1 -1
- data/lib/karafka/web/ui/models/health.rb +9 -7
- data/lib/karafka/web/ui/models/process.rb +16 -0
- data/lib/karafka/web/ui/models/processes.rb +29 -8
- data/lib/karafka/web/ui/models/recurring_tasks/schedule.rb +1 -1
- data/lib/karafka/web/ui/models/status.rb +28 -9
- data/lib/karafka/web/ui/models/topic.rb +1 -2
- data/lib/karafka/web/ui/public/javascripts/application.js +8 -98
- data/lib/karafka/web/ui/public/javascripts/application.min.js +12 -4
- data/lib/karafka/web/ui/public/javascripts/application.min.js.br +0 -0
- data/lib/karafka/web/ui/public/javascripts/application.min.js.gz +0 -0
- data/lib/karafka/web/ui/public/javascripts/components/action_confirmation_manager.js +30 -0
- data/lib/karafka/web/ui/public/javascripts/components/alerts.js +39 -0
- data/lib/karafka/web/ui/public/javascripts/components/button_lock_manager.js +50 -0
- data/lib/karafka/web/ui/public/javascripts/components/live_poll.js +71 -19
- data/lib/karafka/web/ui/public/javascripts/components/message_republish_manager.js +50 -0
- data/lib/karafka/web/ui/public/javascripts/components/page_title_tracker.js +21 -0
- data/lib/karafka/web/ui/public/javascripts/components/partition_redirect_manager.js +21 -0
- data/lib/karafka/web/ui/public/javascripts/components/time_ago_manager.js +25 -0
- data/lib/karafka/web/ui/public/javascripts/components/timestamp_selector.js +30 -0
- data/lib/karafka/web/ui/public/javascripts/libs/datepicker.js +2 -2
- data/lib/karafka/web/ui/public/stylesheets/application.css +30 -0
- data/lib/karafka/web/ui/public/stylesheets/application.min.css +5122 -13
- data/lib/karafka/web/ui/public/stylesheets/application.min.css.br +0 -0
- data/lib/karafka/web/ui/public/stylesheets/application.min.css.gz +0 -0
- data/lib/karafka/web/ui/public/stylesheets/libs/highlight_dark.min.css.gz +0 -0
- data/lib/karafka/web/ui/public/stylesheets/libs/highlight_light.min.css.gz +0 -0
- data/lib/karafka/web/ui/public/stylesheets/libs/tailwind.css +507 -214
- data/lib/karafka/web/ui/routes/assets.rb +53 -0
- data/lib/karafka/web/ui/routes/base.rb +36 -0
- data/lib/karafka/web/ui/routes/cluster.rb +28 -0
- data/lib/karafka/web/ui/routes/consumers.rb +35 -0
- data/lib/karafka/web/ui/routes/dashboard.rb +20 -0
- data/lib/karafka/web/ui/routes/errors.rb +26 -0
- data/lib/karafka/web/ui/routes/jobs.rb +28 -0
- data/lib/karafka/web/ui/routes/pro_only.rb +27 -0
- data/lib/karafka/web/ui/routes/routing.rb +26 -0
- data/lib/karafka/web/ui/routes/status.rb +19 -0
- data/lib/karafka/web/ui/routes/support.rb +19 -0
- data/lib/karafka/web/ui/routes/ux.rb +19 -0
- data/lib/karafka/web/ui/views/cluster/_partition.erb +2 -2
- data/lib/karafka/web/ui/views/cluster/brokers.erb +1 -1
- data/lib/karafka/web/ui/views/consumers/_breadcrumbs.erb +7 -1
- data/lib/karafka/web/ui/views/consumers/_consumer.erb +1 -1
- data/lib/karafka/web/ui/views/consumers/_no_consumers.erb +2 -2
- data/lib/karafka/web/ui/views/consumers/_tabs.erb +4 -4
- data/lib/karafka/web/ui/views/consumers/index.erb +1 -1
- data/lib/karafka/web/ui/views/dashboard/_feature_pro.erb +1 -1
- data/lib/karafka/web/ui/views/dashboard/_not_enough_data.erb +2 -2
- data/lib/karafka/web/ui/views/dashboard/_ranges_selector.erb +1 -1
- data/lib/karafka/web/ui/views/dashboard/index.erb +6 -49
- data/lib/karafka/web/ui/views/errors/_detail.erb +3 -3
- data/lib/karafka/web/ui/views/errors/index.erb +1 -1
- data/lib/karafka/web/ui/views/jobs/_job.erb +1 -1
- data/lib/karafka/web/ui/views/jobs/pending.erb +1 -1
- data/lib/karafka/web/ui/views/jobs/running.erb +1 -1
- data/lib/karafka/web/ui/views/layout.erb +7 -5
- data/lib/karafka/web/ui/views/shared/_become_pro.erb +1 -1
- data/lib/karafka/web/ui/views/shared/_brand.erb +1 -1
- data/lib/karafka/web/ui/views/shared/_breadcrumbs.erb +1 -1
- data/lib/karafka/web/ui/views/shared/_content.erb +1 -1
- data/lib/karafka/web/ui/views/shared/_controls.erb +10 -3
- data/lib/karafka/web/ui/views/shared/_custom_nav.erb +9 -0
- data/lib/karafka/web/ui/views/shared/_flashes.erb +3 -5
- data/lib/karafka/web/ui/views/shared/_header.erb +25 -2
- data/lib/karafka/web/ui/views/shared/_navigation.erb +17 -15
- data/lib/karafka/web/ui/views/shared/alerts/_error.erb +8 -0
- data/lib/karafka/web/ui/views/shared/alerts/_info.erb +8 -0
- data/lib/karafka/web/ui/views/shared/alerts/_primary.erb +8 -0
- data/lib/karafka/web/ui/views/shared/alerts/_secondary.erb +8 -0
- data/lib/karafka/web/ui/views/shared/alerts/_success.erb +8 -0
- data/lib/karafka/web/ui/views/shared/alerts/_warning.erb +8 -0
- data/lib/karafka/web/ui/views/shared/exceptions/not_allowed.erb +4 -0
- data/lib/karafka/web/ui/views/shared/exceptions/not_found.erb +5 -1
- data/lib/karafka/web/ui/views/shared/exceptions/pro_only.erb +4 -0
- data/lib/karafka/web/ui/views/shared/icons/_arrow_left.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_arrow_up_tray.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_clock.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_pencil.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_pencil_square.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_play_pause.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_plus.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_trash.erb +3 -0
- data/lib/karafka/web/ui/views/status/failures/_live_reporting.erb +1 -1
- data/lib/karafka/web/ui/views/status/failures/_partitions.erb +3 -3
- data/lib/karafka/web/ui/views/status/failures/_state_calculation.erb +2 -2
- data/lib/karafka/web/ui/views/status/info/_components.erb +6 -6
- data/lib/karafka/web/ui/views/status/show.erb +15 -0
- data/lib/karafka/web/ui/views/status/warnings/_consumers_schemas.erb +31 -0
- data/lib/karafka/web/ui/views/ux/_icons.erb +1 -1
- data/lib/karafka/web/version.rb +1 -1
- data/lib/karafka/web.rb +3 -0
- data/package-lock.json +776 -1208
- data/package.json +3 -4
- data/postcss.config.js +1 -2
- data/renovate.json +13 -1
- data/tailwind.config.js +0 -4
- data.tar.gz.sig +0 -0
- metadata +225 -106
- metadata.gz.sig +0 -0
- data/lib/karafka/web/pro/commanding/commands/quiet.rb +0 -34
- data/lib/karafka/web/pro/commanding/commands/stop.rb +0 -34
- data/lib/karafka/web/pro/commanding/commands/trace.rb +0 -41
- data/lib/karafka/web/pro/ui/controllers/commanding_controller.rb +0 -118
- data/lib/karafka/web/pro/ui/controllers/commands_controller.rb +0 -96
- data/lib/karafka/web/pro/ui/controllers/consumers_controller.rb +0 -138
- data/lib/karafka/web/pro/ui/controllers/explorer_controller.rb +0 -220
- data/lib/karafka/web/pro/ui/controllers/messages_controller.rb +0 -107
- data/lib/karafka/web/pro/ui/controllers/search_controller.rb +0 -73
- data/lib/karafka/web/pro/ui/controllers/topics_controller.rb +0 -130
- data/lib/karafka/web/pro/ui/views/commands/_breadcrumbs.erb +0 -21
- data/lib/karafka/web/pro/ui/views/commands/_command_details.erb +0 -1
- data/lib/karafka/web/pro/ui/views/commands/_empty.erb +0 -3
- data/lib/karafka/web/pro/ui/views/commands/show.erb +0 -33
- data/lib/karafka/web/pro/ui/views/consumers/_breadcrumbs.erb +0 -55
- data/lib/karafka/web/pro/ui/views/consumers/_tabs.erb +0 -33
- data/lib/karafka/web/pro/ui/views/consumers/consumer/_commands.erb +0 -72
- data/lib/karafka/web/pro/ui/views/consumers/consumer/_consumer_group.erb +0 -8
- data/lib/karafka/web/pro/ui/views/consumers/consumer/_no_subscriptions.erb +0 -7
- data/lib/karafka/web/pro/ui/views/consumers/details.erb +0 -13
- data/lib/karafka/web/pro/ui/views/consumers/subscriptions.erb +0 -25
- data/lib/karafka/web/pro/ui/views/explorer/_no_topics.erb +0 -1
- data/lib/karafka/web/pro/ui/views/explorer/_topic.erb +0 -10
- data/lib/karafka/web/pro/ui/views/explorer/index.erb +0 -14
- data/lib/karafka/web/pro/ui/views/explorer/messages/_headers.erb +0 -33
- data/lib/karafka/web/pro/ui/views/explorer/partition/_cleaned.erb +0 -3
- data/lib/karafka/web/pro/ui/views/explorer/partition/_empty.erb +0 -3
- data/lib/karafka/web/pro/ui/views/explorer/topic/_empty.erb +0 -3
- data/lib/karafka/web/pro/ui/views/search/_breadcrumbs.erb +0 -1
- data/lib/karafka/web/pro/ui/views/search/_fix_errors.erb +0 -3
- data/lib/karafka/web/pro/ui/views/search/_no_results.erb +0 -3
- data/lib/karafka/web/pro/ui/views/search/_timeout.erb +0 -3
- data/lib/karafka/web/pro/ui/views/search/index.erb +0 -29
- data/lib/karafka/web/pro/ui/views/topics/_breadcrumbs.erb +0 -45
- data/lib/karafka/web/pro/ui/views/topics/_partition_offsets.erb +0 -10
- data/lib/karafka/web/pro/ui/views/topics/_topic.erb +0 -9
- data/lib/karafka/web/pro/ui/views/topics/distribution/_empty_partitions.erb +0 -1
- data/lib/karafka/web/pro/ui/views/topics/distribution/_partition.erb +0 -10
- data/lib/karafka/web/pro/ui/views/topics/index.erb +0 -14
- data/lib/karafka/web/ui/lib/ttl_cache.rb +0 -82
@@ -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
|
-
#
|
56
|
+
# @return [Array] whole cluster info
|
54
57
|
def cluster_info
|
55
|
-
@cluster_info ||= Models::ClusterInfo.fetch
|
58
|
+
@cluster_info ||= Models::ClusterInfo.fetch
|
56
59
|
end
|
57
60
|
|
58
61
|
# @param cluster_info [Rdkafka::Metadata] cluster metadata
|
@@ -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
|
-
|
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
|
@@ -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 =
|
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
|
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(
|
66
|
-
root_path(*['explorer',
|
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
|
#
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
module Web
|
5
|
+
module Ui
|
6
|
+
module Lib
|
7
|
+
# Thread-safe in-memory cache with metadata tracking.
|
8
|
+
#
|
9
|
+
# This cache supports storing computed values, tracking the last update time,
|
10
|
+
# and computing a hash of the contents for change detection.
|
11
|
+
# It's designed for ephemeral, per-instance caching in Karafka Web controllers or libs.
|
12
|
+
#
|
13
|
+
# The cache ensures safe concurrent access via a mutex and provides utilities
|
14
|
+
# for cache invalidation based on external session state (timestamp + hash).
|
15
|
+
#
|
16
|
+
# @note All cache operations are mutex-synchronized for thread safety.
|
17
|
+
#
|
18
|
+
# @note We do not have granular level caching because our Web UI cache is fairly simple
|
19
|
+
# and we do not want to overcomplicate things.
|
20
|
+
class Cache
|
21
|
+
# Initializes an empty cache instance
|
22
|
+
# @param ttl_ms [Integer] time to live of the whole cache. After this time cache will be
|
23
|
+
# cleaned whether or not it is expired.
|
24
|
+
def initialize(ttl_ms)
|
25
|
+
@ttl_ms = ttl_ms
|
26
|
+
@values = {}
|
27
|
+
@timestamp = nil
|
28
|
+
@hash = nil
|
29
|
+
@mutex = Mutex.new
|
30
|
+
end
|
31
|
+
|
32
|
+
# Fetches or computes and stores a value under the given key.
|
33
|
+
#
|
34
|
+
# If the key already exists, returns the cached value.
|
35
|
+
# Otherwise, computes it via the provided block, stores it,
|
36
|
+
# and updates metadata (timestamp + hash).
|
37
|
+
#
|
38
|
+
# @param key [Object] key to retrieve
|
39
|
+
# @yield block to compute the value if key is not present
|
40
|
+
# @return [Object] cached or computed value
|
41
|
+
def fetch(key)
|
42
|
+
@mutex.synchronize do
|
43
|
+
return @values[key] if @values.key?(key)
|
44
|
+
|
45
|
+
@values[key] = yield
|
46
|
+
@hash = Digest::SHA256.hexdigest(
|
47
|
+
@values.sort.to_h.to_json
|
48
|
+
)
|
49
|
+
@timestamp = Time.now.to_f
|
50
|
+
@values[key]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Clears the cache and resets metadata (timestamp and hash).
|
55
|
+
#
|
56
|
+
# If the mutex is already owned by the current thread, clears immediately.
|
57
|
+
# Otherwise, synchronizes first.
|
58
|
+
#
|
59
|
+
# @return [void]
|
60
|
+
def clear
|
61
|
+
cleaning = lambda do
|
62
|
+
@values.clear
|
63
|
+
@timestamp = nil
|
64
|
+
@hash = nil
|
65
|
+
end
|
66
|
+
|
67
|
+
return cleaning.call if @mutex.owned?
|
68
|
+
|
69
|
+
@mutex.synchronize do
|
70
|
+
cleaning.call
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Checks whether any values have been cached yet
|
75
|
+
#
|
76
|
+
# @return [Boolean] true if the cache has been written to
|
77
|
+
def exist?
|
78
|
+
!timestamp.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns the last update timestamp of the cache
|
82
|
+
#
|
83
|
+
# @return [Integer, nil] Unix timestamp or nil if never set
|
84
|
+
def timestamp
|
85
|
+
@mutex.synchronize { @timestamp }
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns the hash representing the current cached data state
|
89
|
+
#
|
90
|
+
# @return [String, nil] SHA256 hex digest or nil if never set
|
91
|
+
def hash
|
92
|
+
@mutex.synchronize { @hash }
|
93
|
+
end
|
94
|
+
|
95
|
+
# Clears the cache if the provided session hash and timestamp differ
|
96
|
+
#
|
97
|
+
# This is used to invalidate the cache if the external session data indicates
|
98
|
+
# a newer or inconsistent state.
|
99
|
+
#
|
100
|
+
# @param session_hash [String, nil] hash from the session or remote side
|
101
|
+
# @param session_timestamp [Integer, nil] timestamp from the session
|
102
|
+
# @return [Boolean] true if the cache was cleared, false otherwise
|
103
|
+
def clear_if_needed(session_hash, session_timestamp)
|
104
|
+
@mutex.synchronize do
|
105
|
+
return unless should_refresh?(session_hash, session_timestamp)
|
106
|
+
|
107
|
+
clear
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
# Determines whether the cache should be refreshed based on session data
|
114
|
+
#
|
115
|
+
# @param session_hash [String, nil]
|
116
|
+
# @param session_timestamp [Integer, nil]
|
117
|
+
# @return [Boolean] true if cache should be refreshed
|
118
|
+
def should_refresh?(session_hash, session_timestamp)
|
119
|
+
return true if @hash.nil? || @timestamp.nil?
|
120
|
+
return true if session_hash.nil? || session_timestamp.nil?
|
121
|
+
|
122
|
+
now = (Time.now.to_f * 1_000).to_i
|
123
|
+
|
124
|
+
return true if now - (@timestamp * 1_000) > @ttl_ms
|
125
|
+
|
126
|
+
return false if @hash == session_hash
|
127
|
+
return false if @timestamp > session_timestamp
|
128
|
+
|
129
|
+
true
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -9,8 +9,7 @@ module Karafka
|
|
9
9
|
class << self
|
10
10
|
# @return [Array<Broker>] all brokers in the cluster
|
11
11
|
def all
|
12
|
-
|
13
|
-
ClusterInfo.fetch(cached: false).brokers.map do |broker|
|
12
|
+
ClusterInfo.fetch.brokers.map do |broker|
|
14
13
|
new(broker)
|
15
14
|
end
|
16
15
|
end
|
@@ -10,26 +10,18 @@ module Karafka
|
|
10
10
|
class << self
|
11
11
|
# Gets us all the cluster metadata info
|
12
12
|
#
|
13
|
-
# @param cached [Boolean] should we use cached data (true by default)
|
14
13
|
# @return [Rdkafka::Metadata] cluster metadata info
|
15
|
-
def fetch
|
16
|
-
|
17
|
-
|
18
|
-
cluster_info = cache.read(:cluster_info)
|
19
|
-
|
20
|
-
if cluster_info.nil? || !cached
|
21
|
-
cluster_info = cache.write(:cluster_info, Lib::Admin.cluster_info)
|
14
|
+
def fetch
|
15
|
+
Karafka::Web.config.ui.cache.fetch(:cluster_info) do
|
16
|
+
Lib::Admin.cluster_info
|
22
17
|
end
|
23
|
-
|
24
|
-
cluster_info
|
25
18
|
end
|
26
19
|
|
27
20
|
# Returns us all the info about available topics from the cluster
|
28
21
|
#
|
29
|
-
# @param cached [Boolean] should we use cached data (true by default)
|
30
22
|
# @return [Array<Ui::Models::Topic>] topics details
|
31
|
-
def topics
|
32
|
-
fetch
|
23
|
+
def topics
|
24
|
+
fetch
|
33
25
|
.topics
|
34
26
|
.map { |topic| Topic.new(topic) }
|
35
27
|
end
|
@@ -37,19 +29,21 @@ module Karafka
|
|
37
29
|
# Fetches us details about particular topic
|
38
30
|
#
|
39
31
|
# @param topic_name [String] name of the topic we are looking for
|
40
|
-
# @param cached [Boolean] should we use cached data (true by default)
|
41
32
|
# @return [Ui::Models::Topic] topic details
|
42
|
-
def topic(topic_name
|
43
|
-
|
44
|
-
.
|
45
|
-
.
|
33
|
+
def topic(topic_name)
|
34
|
+
Lib::Admin
|
35
|
+
.topic_info(topic_name)
|
36
|
+
.then { |topic| Topic.new(topic) }
|
37
|
+
rescue Rdkafka::RdkafkaError => e
|
38
|
+
raise e unless e.code == :unknown_topic_or_part
|
39
|
+
|
40
|
+
raise(Web::Errors::Ui::NotFoundError, topic_name)
|
46
41
|
end
|
47
42
|
|
48
43
|
# @param topic_name [String] name of the topic we are looking for
|
49
|
-
# @param cached [Boolean] should we use cached data (true by default)
|
50
44
|
# @return [Integer] number of partitions in a given topic
|
51
|
-
def partitions_count(topic_name
|
52
|
-
topic(topic_name
|
45
|
+
def partitions_count(topic_name)
|
46
|
+
topic(topic_name).partition_count
|
53
47
|
end
|
54
48
|
end
|
55
49
|
end
|
@@ -33,7 +33,7 @@ module Karafka
|
|
33
33
|
# @return [::Karafka::Messages::Message, nil] most recent state or nil if none
|
34
34
|
def fetch
|
35
35
|
Lib::Admin.read_topic(
|
36
|
-
Karafka::Web.config.topics.consumers.metrics,
|
36
|
+
Karafka::Web.config.topics.consumers.metrics.name,
|
37
37
|
0,
|
38
38
|
# We need to take last two and not the last because in case of a transactional
|
39
39
|
# producer, the last one will match the transaction commit message
|
@@ -42,7 +42,7 @@ module Karafka
|
|
42
42
|
# @return [::Karafka::Messages::Message, nil] most recent state or nil if none
|
43
43
|
def fetch
|
44
44
|
Lib::Admin.read_topic(
|
45
|
-
Karafka::Web.config.topics.consumers.states,
|
45
|
+
Karafka::Web.config.topics.consumers.states.name,
|
46
46
|
0,
|
47
47
|
# We need to take last two and not the last because in case of a transactional
|
48
48
|
# producer, the last one will match the transaction commit message
|
@@ -32,7 +32,7 @@ module Karafka
|
|
32
32
|
MAX_ERROR_PARTITIONS.times do |partition|
|
33
33
|
begin
|
34
34
|
offsets = Lib::Admin.read_watermark_offsets(
|
35
|
-
::Karafka::Web.config.topics.errors,
|
35
|
+
::Karafka::Web.config.topics.errors.name,
|
36
36
|
partition
|
37
37
|
)
|
38
38
|
# We estimate that way instead of using `#cluster_info` to get the partitions count
|
@@ -50,15 +50,17 @@ module Karafka
|
|
50
50
|
# @param state [Hash]
|
51
51
|
# @param stats [Hash] hash where we will store all the aggregated data
|
52
52
|
def fetch_topics_data(state, stats)
|
53
|
-
iterate_partitions(state) do |process, consumer_group, topic, partition|
|
54
|
-
|
53
|
+
iterate_partitions(state) do |process, consumer_group, subscription_group, topic, partition|
|
54
|
+
cg_id = consumer_group.id
|
55
|
+
sg_id = subscription_group.id
|
55
56
|
t_name = topic.name
|
56
57
|
pt_id = partition.id
|
57
58
|
|
58
|
-
stats[
|
59
|
-
stats[
|
60
|
-
stats[
|
61
|
-
stats[
|
59
|
+
stats[cg_id] ||= { topics: {} }
|
60
|
+
stats[cg_id][:topics][t_name] ||= {}
|
61
|
+
stats[cg_id][:topics][t_name][pt_id] = partition
|
62
|
+
stats[cg_id][:topics][t_name][pt_id][:process] = process
|
63
|
+
stats[cg_id][:topics][t_name][pt_id][:subscription_group_id] = sg_id
|
62
64
|
end
|
63
65
|
end
|
64
66
|
|
@@ -99,7 +101,7 @@ module Karafka
|
|
99
101
|
consumer_group.subscription_groups.each do |subscription_group|
|
100
102
|
subscription_group.topics.each do |topic|
|
101
103
|
topic.partitions.each do |partition|
|
102
|
-
yield(process, consumer_group, topic, partition)
|
104
|
+
yield(process, consumer_group, subscription_group, topic, partition)
|
103
105
|
end
|
104
106
|
end
|
105
107
|
end
|