karafka-web 0.10.3 → 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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +64 -176
- data/Gemfile +4 -0
- data/Gemfile.lock +88 -44
- 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 +3 -5
- data/lib/karafka/web/config.rb +86 -10
- data/lib/karafka/web/contracts/config.rb +45 -5
- data/lib/karafka/web/errors.rb +10 -0
- 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 +32 -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 +101 -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/consumers/_consumer.erb +59 -0
- data/lib/karafka/web/pro/ui/views/consumers/consumers/_consumer_performance.erb +71 -0
- 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/controls/_controls.erb +107 -0
- 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 +50 -38
- 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/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/errors.rb +38 -9
- 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 +2 -9
- data/lib/karafka/web/ui/app.rb +19 -112
- data/lib/karafka/web/ui/base.rb +63 -4
- 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 +14 -0
- data/lib/karafka/web/ui/models/processes.rb +2 -2
- data/lib/karafka/web/ui/models/recurring_tasks/schedule.rb +1 -1
- data/lib/karafka/web/ui/models/status.rb +27 -8
- 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 +15 -6
- 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/btn_toggle_manager.js +17 -7
- 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 +5123 -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 +512 -213
- 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 +39 -30
- data/lib/karafka/web/ui/views/consumers/_incompatible.erb +13 -0
- 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 +38 -29
- 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/incompatible_schema.erb +34 -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/ui/views/ux/_status_rows.erb +6 -0
- data/lib/karafka/web/version.rb +1 -1
- data/lib/karafka/web.rb +9 -1
- data/package-lock.json +799 -1226
- 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 +233 -109
- 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/_consumer.erb +0 -47
- data/lib/karafka/web/pro/ui/views/consumers/_consumer_controls.erb +0 -95
- data/lib/karafka/web/pro/ui/views/consumers/_consumer_performance.erb +0 -59
- 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
@@ -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
|
@@ -74,6 +74,20 @@ module Karafka
|
|
74
74
|
.flat_map(&:partitions)
|
75
75
|
.count
|
76
76
|
end
|
77
|
+
|
78
|
+
# @return [Boolean] consumer process data is only compatible if the version of its schema
|
79
|
+
# matches the Web UI version of the schema. Some users have gradual deployment where
|
80
|
+
# they slowly rollout new versions of consumers and for this time, we want to indicate
|
81
|
+
# which instances have incompatible schema. This will allow us to show those processes
|
82
|
+
# to indicate they exist, so users are not confused with them missing, but will also
|
83
|
+
# block all capabilities until the full update of all components.
|
84
|
+
#
|
85
|
+
# @note We do not differentiate between reporting older or newer against Web UI Puma
|
86
|
+
# instance. Any incompatibility will cause reporting of incompatible. That's for the
|
87
|
+
# sake of simplicity as the long term goal for user is anyhow to align those.
|
88
|
+
def schema_compatible?
|
89
|
+
schema_version == ::Karafka::Web::Tracking::Consumers::Sampler::SCHEMA_VERSION
|
90
|
+
end
|
77
91
|
end
|
78
92
|
end
|
79
93
|
end
|
@@ -45,7 +45,7 @@ module Karafka
|
|
45
45
|
.sort
|
46
46
|
|
47
47
|
Lib::Admin.read_topic(
|
48
|
-
::Karafka::Web.config.topics.consumers.reports,
|
48
|
+
::Karafka::Web.config.topics.consumers.reports.name,
|
49
49
|
0,
|
50
50
|
# We set 10k here because we start from the latest offset of the reports, hence
|
51
51
|
# we will never get this much. Do do not know however exactly how many reports
|
@@ -83,7 +83,7 @@ module Karafka
|
|
83
83
|
# @param processes [Array<Hash>]
|
84
84
|
# @return [Array<Hash>] sorted processes data
|
85
85
|
def sort_processes(processes)
|
86
|
-
processes.sort_by { |consumer| consumer[:process]
|
86
|
+
processes.sort_by { |consumer| consumer[:process].fetch(:id) }
|
87
87
|
end
|
88
88
|
end
|
89
89
|
end
|
@@ -22,7 +22,7 @@ module Karafka
|
|
22
22
|
# get it because requested topic/partition does not exist or nothing was present
|
23
23
|
def current
|
24
24
|
messages = Karafka::Admin.read_topic(
|
25
|
-
config.topics.schedules,
|
25
|
+
config.topics.schedules.name,
|
26
26
|
0,
|
27
27
|
# We work here with the assumption that users won't click so fast to load
|
28
28
|
# more than 20 commands prior to a state flush. If that happens, this will
|