karafka-web 0.9.2 → 0.10.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/ci.yml +30 -0
- data/.gitignore +2 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +84 -3
- data/Gemfile +1 -0
- data/Gemfile.lock +30 -25
- data/LICENSE +1 -1
- data/bin/build_assets +51 -0
- data/bin/release +6 -0
- data/config/locales/pro_errors.yml +18 -0
- data/docker-compose.yml +1 -1
- data/gulpfile.js +73 -0
- data/karafka-web.gemspec +7 -2
- data/lib/karafka/web/config.rb +9 -10
- data/lib/karafka/web/contracts/base.rb +2 -0
- data/lib/karafka/web/contracts/config.rb +2 -1
- data/lib/karafka/web/errors.rb +12 -0
- data/lib/karafka/web/inflector.rb +1 -1
- data/lib/karafka/web/management/actions/enable.rb +11 -0
- data/lib/karafka/web/management/migrations/consumers_metrics/0_set_initial.rb +39 -0
- data/lib/karafka/web/management/migrations/consumers_metrics/1699543515_fill_missing_received_and_sent_bytes.rb +28 -0
- data/lib/karafka/web/management/migrations/consumers_metrics/1700234522_introduce_waiting.rb +26 -0
- data/lib/karafka/web/management/migrations/consumers_metrics/1700234522_remove_processing.rb +26 -0
- data/lib/karafka/web/management/migrations/consumers_metrics/1704722380_split_listeners_into_active_and_paused.rb +38 -0
- data/lib/karafka/web/management/migrations/consumers_metrics/1706607960_introduce_lag_total.rb +40 -0
- data/lib/karafka/web/management/migrations/consumers_metrics/1706611396_rename_lag_total_to_lag_hybrid.rb +38 -0
- data/lib/karafka/web/management/migrations/consumers_metrics/1716218393_populate_jobs_metrics.rb +26 -0
- data/lib/karafka/web/management/migrations/consumers_states/0_set_initial.rb +46 -0
- data/lib/karafka/web/management/migrations/consumers_states/1699543515_fill_missing_received_and_sent_bytes.rb +25 -0
- data/lib/karafka/web/management/migrations/consumers_states/1700234522_introduce_waiting.rb +22 -0
- data/lib/karafka/web/management/migrations/consumers_states/1700234522_remove_processing.rb +22 -0
- data/lib/karafka/web/management/migrations/consumers_states/1704722380_split_listeners_into_active_and_paused.rb +34 -0
- data/lib/karafka/web/management/migrations/consumers_states/1706607960_introduce_lag_total.rb +24 -0
- data/lib/karafka/web/management/migrations/consumers_states/1706611396_rename_lag_total_to_lag_hybrid.rb +23 -0
- data/lib/karafka/web/management/migrations/consumers_states/1716218393_add_jobs_counter.rb +24 -0
- data/lib/karafka/web/management/migrator.rb +5 -5
- data/lib/karafka/web/pro/commanding/commands/base.rb +8 -0
- data/lib/karafka/web/pro/commanding/commands/quiet.rb +4 -1
- data/lib/karafka/web/pro/commanding/commands/stop.rb +4 -1
- data/lib/karafka/web/pro/loader.rb +8 -0
- data/lib/karafka/web/pro/ui/app.rb +44 -7
- data/lib/karafka/web/pro/ui/controllers/dlq_controller.rb +1 -1
- data/lib/karafka/web/pro/ui/controllers/errors_controller.rb +1 -0
- data/lib/karafka/web/pro/ui/controllers/explorer_controller.rb +6 -14
- data/lib/karafka/web/pro/ui/controllers/messages_controller.rb +5 -4
- data/lib/karafka/web/pro/ui/controllers/search_controller.rb +73 -0
- data/lib/karafka/web/pro/ui/controllers/support_controller.rb +26 -0
- data/lib/karafka/web/pro/ui/controllers/topics_controller.rb +31 -0
- data/lib/karafka/web/pro/ui/controllers/ux_controller.rb +26 -0
- data/lib/karafka/web/pro/ui/lib/policies/config.rb +39 -0
- data/lib/karafka/web/pro/ui/lib/policies/contracts/config.rb +46 -0
- data/lib/karafka/web/pro/ui/lib/policies/messages.rb +76 -0
- data/lib/karafka/web/pro/ui/lib/policies/requests.rb +36 -0
- data/lib/karafka/web/pro/ui/lib/policies.rb +34 -0
- data/lib/karafka/web/pro/ui/lib/safe_runner.rb +98 -0
- data/lib/karafka/web/pro/ui/lib/search/config.rb +53 -0
- data/lib/karafka/web/pro/ui/lib/search/contracts/config.rb +101 -0
- data/lib/karafka/web/pro/ui/lib/search/contracts/form.rb +111 -0
- data/lib/karafka/web/pro/ui/lib/search/matchers/base.rb +59 -0
- data/lib/karafka/web/pro/ui/lib/search/matchers/raw_header_includes.rb +57 -0
- data/lib/karafka/web/pro/ui/lib/search/matchers/raw_key_includes.rb +41 -0
- data/lib/karafka/web/pro/ui/lib/search/matchers/raw_payload_includes.rb +45 -0
- data/lib/karafka/web/pro/ui/lib/search/normalizer.rb +47 -0
- data/lib/karafka/web/pro/ui/lib/search/runner.rb +230 -0
- data/lib/karafka/web/pro/ui/lib/search.rb +36 -0
- data/lib/karafka/web/pro/ui/views/cluster/_breadcrumbs.erb +4 -4
- data/lib/karafka/web/pro/ui/views/cluster/_tabs.erb +14 -24
- data/lib/karafka/web/pro/ui/views/cluster/index.erb +20 -22
- data/lib/karafka/web/pro/ui/views/cluster/show.erb +21 -25
- data/lib/karafka/web/pro/ui/views/commands/_backtrace.erb +4 -19
- data/lib/karafka/web/pro/ui/views/commands/_breadcrumbs.erb +3 -3
- data/lib/karafka/web/pro/ui/views/commands/_command.erb +6 -6
- data/lib/karafka/web/pro/ui/views/commands/_command_details.erb +1 -11
- data/lib/karafka/web/pro/ui/views/commands/_incompatible_schema.erb +3 -14
- data/lib/karafka/web/pro/ui/views/commands/_metadata.erb +33 -42
- data/lib/karafka/web/pro/ui/views/commands/_table.erb +9 -3
- data/lib/karafka/web/pro/ui/views/commands/index.erb +18 -12
- data/lib/karafka/web/pro/ui/views/commands/show.erb +24 -29
- data/lib/karafka/web/pro/ui/views/consumers/_breadcrumbs.erb +8 -8
- data/lib/karafka/web/pro/ui/views/consumers/_consumer.erb +13 -23
- data/lib/karafka/web/pro/ui/views/consumers/_consumer_controls.erb +51 -35
- data/lib/karafka/web/pro/ui/views/consumers/_consumer_performance.erb +1 -1
- data/lib/karafka/web/pro/ui/views/consumers/_tabs.erb +28 -30
- data/lib/karafka/web/pro/ui/views/consumers/consumer/_commands.erb +68 -28
- data/lib/karafka/web/pro/ui/views/consumers/consumer/_job.erb +1 -1
- data/lib/karafka/web/pro/ui/views/consumers/consumer/_metrics.erb +114 -133
- data/lib/karafka/web/pro/ui/views/consumers/consumer/_partition.erb +4 -4
- data/lib/karafka/web/pro/ui/views/consumers/consumer/_stopped.erb +6 -9
- data/lib/karafka/web/pro/ui/views/consumers/consumer/_subscription_group.erb +116 -126
- data/lib/karafka/web/pro/ui/views/consumers/consumer/_tabs.erb +26 -31
- data/lib/karafka/web/pro/ui/views/consumers/controls.erb +53 -57
- data/lib/karafka/web/pro/ui/views/consumers/details.erb +4 -17
- data/lib/karafka/web/pro/ui/views/consumers/index.erb +31 -34
- data/lib/karafka/web/pro/ui/views/consumers/pending_jobs.erb +41 -46
- data/lib/karafka/web/pro/ui/views/consumers/performance.erb +43 -47
- data/lib/karafka/web/pro/ui/views/consumers/running_jobs.erb +41 -46
- data/lib/karafka/web/pro/ui/views/consumers/subscriptions.erb +14 -17
- data/lib/karafka/web/pro/ui/views/dashboard/index.erb +67 -76
- data/lib/karafka/web/pro/ui/views/dlq/_breadcrumbs.erb +1 -1
- data/lib/karafka/web/pro/ui/views/dlq/_no_topics.erb +1 -7
- data/lib/karafka/web/pro/ui/views/dlq/_topic.erb +7 -10
- data/lib/karafka/web/pro/ui/views/dlq/index.erb +8 -10
- data/lib/karafka/web/pro/ui/views/errors/_breadcrumbs.erb +3 -3
- data/lib/karafka/web/pro/ui/views/errors/_error.erb +8 -5
- data/lib/karafka/web/pro/ui/views/errors/_selector.erb +12 -0
- data/lib/karafka/web/pro/ui/views/errors/_table.erb +5 -4
- data/lib/karafka/web/pro/ui/views/errors/index.erb +50 -15
- data/lib/karafka/web/pro/ui/views/errors/partition.erb +61 -14
- data/lib/karafka/web/pro/ui/views/errors/show.erb +28 -46
- data/lib/karafka/web/pro/ui/views/explorer/_breadcrumbs.erb +11 -3
- data/lib/karafka/web/pro/ui/views/explorer/_failed_deserialization.erb +8 -3
- data/lib/karafka/web/pro/ui/views/explorer/_message.erb +12 -6
- data/lib/karafka/web/pro/ui/views/explorer/_no_topics.erb +1 -5
- data/lib/karafka/web/pro/ui/views/explorer/_selector.erb +12 -0
- data/lib/karafka/web/pro/ui/views/explorer/_topic.erb +6 -8
- data/lib/karafka/web/pro/ui/views/explorer/index.erb +13 -15
- data/lib/karafka/web/pro/ui/views/explorer/message/_metadata.erb +68 -32
- data/lib/karafka/web/pro/ui/views/explorer/message/_payload.erb +17 -16
- data/lib/karafka/web/pro/ui/views/explorer/message/_resources_utilization.erb +127 -0
- data/lib/karafka/web/pro/ui/views/explorer/message/_too_big_to_be_displayed.erb +20 -0
- data/lib/karafka/web/pro/ui/views/explorer/messages/_detail.erb +1 -1
- data/lib/karafka/web/pro/ui/views/explorer/partition/_cleaned.erb +3 -5
- data/lib/karafka/web/pro/ui/views/explorer/partition/_empty.erb +3 -5
- data/lib/karafka/web/pro/ui/views/explorer/partition/_messages.erb +6 -3
- data/lib/karafka/web/pro/ui/views/explorer/partition.erb +67 -46
- data/lib/karafka/web/pro/ui/views/explorer/show.erb +85 -21
- data/lib/karafka/web/pro/ui/views/explorer/topic/_actions.erb +27 -0
- data/lib/karafka/web/pro/ui/views/explorer/topic/_empty.erb +3 -5
- data/lib/karafka/web/pro/ui/views/explorer/topic/_limited.erb +8 -10
- data/lib/karafka/web/pro/ui/views/explorer/topic.erb +24 -44
- data/lib/karafka/web/pro/ui/views/health/_breadcrumbs.erb +7 -7
- data/lib/karafka/web/pro/ui/views/health/_no_data.erb +1 -7
- data/lib/karafka/web/pro/ui/views/health/_partition.erb +3 -3
- data/lib/karafka/web/pro/ui/views/health/_partition_lags.erb +3 -3
- data/lib/karafka/web/pro/ui/views/health/_partition_offset.erb +2 -2
- data/lib/karafka/web/pro/ui/views/health/_partition_times.erb +3 -7
- data/lib/karafka/web/pro/ui/views/health/_table_metadata.erb +8 -0
- data/lib/karafka/web/pro/ui/views/health/_tabs.erb +32 -49
- data/lib/karafka/web/pro/ui/views/health/changes.erb +51 -51
- data/lib/karafka/web/pro/ui/views/health/cluster_lags.erb +28 -41
- data/lib/karafka/web/pro/ui/views/health/lags.erb +52 -52
- data/lib/karafka/web/pro/ui/views/health/offsets.erb +55 -55
- data/lib/karafka/web/pro/ui/views/health/overview.erb +60 -60
- data/lib/karafka/web/pro/ui/views/jobs/_job.erb +1 -1
- data/lib/karafka/web/pro/ui/views/jobs/_no_jobs.erb +1 -7
- data/lib/karafka/web/pro/ui/views/jobs/pending.erb +36 -38
- data/lib/karafka/web/pro/ui/views/jobs/running.erb +36 -38
- data/lib/karafka/web/pro/ui/views/routing/_consumer_group.erb +7 -12
- data/lib/karafka/web/pro/ui/views/routing/_topic.erb +13 -11
- data/lib/karafka/web/pro/ui/views/routing/index.erb +7 -9
- data/lib/karafka/web/pro/ui/views/routing/show.erb +41 -33
- data/lib/karafka/web/pro/ui/views/search/_fix_errors.erb +3 -0
- data/lib/karafka/web/pro/ui/views/search/_metadata.erb +71 -0
- data/lib/karafka/web/pro/ui/views/search/_no_results.erb +3 -0
- data/lib/karafka/web/pro/ui/views/search/_no_search_criteria.erb +5 -0
- data/lib/karafka/web/pro/ui/views/search/_search_criteria.erb +37 -0
- data/lib/karafka/web/pro/ui/views/search/_search_modal.erb +139 -0
- data/lib/karafka/web/pro/ui/views/search/_timeout.erb +3 -0
- data/lib/karafka/web/pro/ui/views/search/index.erb +29 -0
- data/lib/karafka/web/pro/ui/views/shared/_navigation.erb +80 -28
- data/lib/karafka/web/pro/ui/views/topics/_breadcrumbs.erb +14 -6
- data/lib/karafka/web/pro/ui/views/topics/_partition_offsets.erb +10 -0
- data/lib/karafka/web/pro/ui/views/topics/_tabs.erb +26 -32
- data/lib/karafka/web/pro/ui/views/topics/_topic.erb +7 -10
- data/lib/karafka/web/pro/ui/views/topics/config.erb +21 -25
- data/lib/karafka/web/pro/ui/views/topics/distribution/_badges.erb +10 -5
- data/lib/karafka/web/pro/ui/views/topics/distribution/_chart.erb +3 -1
- data/lib/karafka/web/pro/ui/views/topics/distribution/_limited.erb +1 -1
- data/lib/karafka/web/pro/ui/views/topics/distribution.erb +34 -39
- data/lib/karafka/web/pro/ui/views/topics/index.erb +13 -15
- data/lib/karafka/web/pro/ui/views/topics/offsets.erb +24 -0
- data/lib/karafka/web/pro/ui/views/topics/replication.erb +20 -24
- data/lib/karafka/web/processing/consumers/aggregators/metrics.rb +1 -1
- data/lib/karafka/web/processing/consumers/aggregators/state.rb +1 -1
- data/lib/karafka/web/processing/consumers/contracts/aggregated_stats.rb +1 -0
- data/lib/karafka/web/tracking/consumers/contracts/report.rb +6 -0
- data/lib/karafka/web/tracking/consumers/listeners/connections.rb +8 -6
- data/lib/karafka/web/tracking/consumers/listeners/processing.rb +2 -0
- data/lib/karafka/web/tracking/consumers/listeners/tags.rb +1 -1
- data/lib/karafka/web/tracking/consumers/reporter.rb +6 -8
- data/lib/karafka/web/tracking/consumers/sampler.rb +16 -5
- data/lib/karafka/web/ui/app.rb +20 -1
- data/lib/karafka/web/ui/base.rb +26 -20
- data/lib/karafka/web/ui/controllers/base_controller.rb +6 -4
- data/lib/karafka/web/ui/controllers/dashboard_controller.rb +8 -0
- data/lib/karafka/web/ui/controllers/requests/params.rb +16 -2
- data/lib/karafka/web/ui/controllers/support_controller.rb +17 -0
- data/lib/karafka/web/ui/controllers/ux_controller.rb +17 -0
- data/lib/karafka/web/ui/helpers/application_helper.rb +75 -42
- data/lib/karafka/web/ui/helpers/paths_helper.rb +24 -0
- data/lib/karafka/web/ui/helpers/tailwind_helper.rb +90 -0
- data/lib/karafka/web/ui/lib/sorter.rb +1 -1
- data/lib/karafka/web/ui/models/metrics/aggregated.rb +1 -0
- data/lib/karafka/web/ui/models/metrics/charts/topics.rb +36 -20
- data/lib/karafka/web/ui/models/status.rb +28 -1
- data/lib/karafka/web/ui/public/images/calendar.svg +3 -0
- data/lib/karafka/web/ui/public/javascripts/application.js +39 -15
- data/lib/karafka/web/ui/public/javascripts/application.min.js +64 -0
- 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/charts/types/line.js +41 -9
- data/lib/karafka/web/ui/public/javascripts/components/btn_toggle_manager.js +37 -0
- data/lib/karafka/web/ui/public/javascripts/{live_poll.js → components/live_poll.js} +44 -8
- data/lib/karafka/web/ui/public/javascripts/{offset_datetime.js → components/offset_datetime.js} +1 -1
- data/lib/karafka/web/ui/public/javascripts/components/search.js +102 -0
- data/lib/karafka/web/ui/public/javascripts/components/tabs_manager.js +84 -0
- data/lib/karafka/web/ui/public/javascripts/components/theme_manager.js +59 -0
- data/lib/karafka/web/ui/public/javascripts/components/turbo_tracker.js +30 -0
- data/lib/karafka/web/ui/public/javascripts/libs/datepicker.js +2 -2
- data/lib/karafka/web/ui/public/javascripts/libs/turbo.js +6618 -0
- data/lib/karafka/web/ui/public/stylesheets/application.css +16 -113
- data/lib/karafka/web/ui/public/stylesheets/application.min.css +13 -0
- 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 +8 -0
- data/lib/karafka/web/ui/public/stylesheets/libs/highlight_dark.min.css.br +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.br +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 +391 -0
- data/lib/karafka/web/ui/views/cluster/_breadcrumbs.erb +3 -3
- data/lib/karafka/web/ui/views/cluster/_tabs.erb +14 -24
- data/lib/karafka/web/ui/views/cluster/brokers.erb +20 -22
- data/lib/karafka/web/ui/views/cluster/replication.erb +28 -32
- data/lib/karafka/web/ui/views/consumers/_assignments_badges.erb +1 -1
- data/lib/karafka/web/ui/views/consumers/_breadcrumbs.erb +5 -0
- data/lib/karafka/web/ui/views/consumers/_consumer.erb +9 -13
- data/lib/karafka/web/ui/views/consumers/_no_consumers.erb +2 -8
- data/lib/karafka/web/ui/views/consumers/_summary.erb +34 -45
- data/lib/karafka/web/ui/views/consumers/_tabs.erb +35 -0
- data/lib/karafka/web/ui/views/consumers/index.erb +31 -33
- data/lib/karafka/web/ui/views/dashboard/_counters.erb +76 -0
- data/lib/karafka/web/ui/views/dashboard/_feature_pro.erb +6 -2
- data/lib/karafka/web/ui/views/dashboard/_not_enough_data.erb +3 -15
- data/lib/karafka/web/ui/views/dashboard/_ranges_selector.erb +12 -12
- data/lib/karafka/web/ui/views/dashboard/index.erb +78 -52
- data/lib/karafka/web/ui/views/errors/_breadcrumbs.erb +2 -2
- data/lib/karafka/web/ui/views/errors/_detail.erb +1 -3
- data/lib/karafka/web/ui/views/errors/_error.erb +3 -5
- data/lib/karafka/web/ui/views/errors/index.erb +34 -44
- data/lib/karafka/web/ui/views/errors/show.erb +29 -47
- data/lib/karafka/web/ui/views/jobs/_breadcrumbs.erb +3 -3
- data/lib/karafka/web/ui/views/jobs/_job.erb +1 -1
- data/lib/karafka/web/ui/views/jobs/_no_jobs.erb +1 -7
- data/lib/karafka/web/ui/views/jobs/_tabs.erb +14 -24
- data/lib/karafka/web/ui/views/jobs/pending.erb +30 -32
- data/lib/karafka/web/ui/views/jobs/running.erb +30 -32
- data/lib/karafka/web/ui/views/layout.erb +37 -21
- data/lib/karafka/web/ui/views/routing/_breadcrumbs.erb +2 -2
- data/lib/karafka/web/ui/views/routing/_consumer_group.erb +7 -12
- data/lib/karafka/web/ui/views/routing/_topic.erb +3 -5
- data/lib/karafka/web/ui/views/routing/index.erb +7 -9
- data/lib/karafka/web/ui/views/routing/show.erb +30 -22
- data/lib/karafka/web/ui/views/shared/_become_pro.erb +8 -8
- data/lib/karafka/web/ui/views/shared/_brand.erb +2 -2
- data/lib/karafka/web/ui/views/shared/_breadcrumbs.erb +23 -0
- data/lib/karafka/web/ui/views/shared/_content.erb +2 -28
- data/lib/karafka/web/ui/views/shared/_controls.erb +15 -0
- data/lib/karafka/web/ui/views/shared/_flashes.erb +5 -7
- data/lib/karafka/web/ui/views/shared/_header.erb +14 -19
- data/lib/karafka/web/ui/views/shared/_navigation.erb +84 -28
- data/lib/karafka/web/ui/views/shared/_no_paginated_data.erb +5 -9
- data/lib/karafka/web/ui/views/shared/_pagination.erb +11 -11
- data/lib/karafka/web/ui/views/shared/_tab_nav.erb +4 -5
- data/lib/karafka/web/ui/views/shared/_title.erb +5 -0
- data/lib/karafka/web/ui/views/shared/alerts/_box_error.erb +15 -0
- data/lib/karafka/web/ui/views/shared/alerts/_box_info.erb +15 -0
- data/lib/karafka/web/ui/views/shared/alerts/_box_primary.erb +15 -0
- data/lib/karafka/web/ui/views/shared/alerts/_box_secondary.erb +15 -0
- data/lib/karafka/web/ui/views/shared/alerts/_box_success.erb +15 -0
- data/lib/karafka/web/ui/views/shared/alerts/_box_warning.erb +15 -0
- data/lib/karafka/web/ui/views/shared/alerts/_error.erb +4 -0
- data/lib/karafka/web/ui/views/shared/alerts/_info.erb +5 -2
- data/lib/karafka/web/ui/views/shared/alerts/_primary.erb +4 -0
- data/lib/karafka/web/ui/views/shared/alerts/_secondary.erb +4 -0
- data/lib/karafka/web/ui/views/shared/alerts/_success.erb +4 -0
- data/lib/karafka/web/ui/views/shared/alerts/_warning.erb +4 -0
- data/lib/karafka/web/ui/views/shared/charts/_line.erb +1 -1
- data/lib/karafka/web/ui/views/shared/exceptions/not_allowed.erb +14 -19
- data/lib/karafka/web/ui/views/shared/exceptions/not_found.erb +16 -21
- data/lib/karafka/web/ui/views/shared/exceptions/pro_only.erb +16 -28
- data/lib/karafka/web/ui/views/shared/icons/_arrow_down_on_square.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_arrow_down_tray.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_arrow_on_squares.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_arrow_path_rounded.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_arrow_uturn_right.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_arrows_right_left.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_blocks.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_book_open.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_bug.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_burger.erb +14 -0
- data/lib/karafka/web/ui/views/shared/icons/_calendar_days.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_chart_bar.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_check_badge.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_check_circle.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_circle_stack.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_cpu.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_document_glass.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_exclamation_triangle.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_eye.erb +4 -0
- data/lib/karafka/web/ui/views/shared/icons/_gear.erb +4 -0
- data/lib/karafka/web/ui/views/shared/icons/_github.erb +13 -0
- data/lib/karafka/web/ui/views/shared/icons/_globe.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_heart.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_home.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_info_circle.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_lifebuoy.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_light_bulb.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_list_bullets.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_magnifying_glass.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_moon.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_offices.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_pause.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_pause_circle.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_play_circle.erb +4 -0
- data/lib/karafka/web/ui/views/shared/icons/_question_circle.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_queue_list.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_refresh.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_slack.erb +16 -0
- data/lib/karafka/web/ui/views/shared/icons/_stop.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_sun.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_x_circle.erb +3 -0
- data/lib/karafka/web/ui/views/shared/icons/_x_mark.erb +3 -0
- data/lib/karafka/web/ui/views/status/_breadcrumbs.erb +1 -1
- data/lib/karafka/web/ui/views/status/_failure.erb +2 -13
- data/lib/karafka/web/ui/views/status/_halted.erb +2 -10
- data/lib/karafka/web/ui/views/status/_info.erb +2 -13
- data/lib/karafka/web/ui/views/status/_success.erb +2 -10
- data/lib/karafka/web/ui/views/status/_warning.erb +2 -13
- data/lib/karafka/web/ui/views/status/failures/_connection.erb +2 -2
- data/lib/karafka/web/ui/views/status/failures/_consumers_reports.erb +3 -3
- data/lib/karafka/web/ui/views/status/failures/_consumers_reports_schema_state.erb +4 -4
- data/lib/karafka/web/ui/views/status/failures/_enabled.erb +2 -2
- data/lib/karafka/web/ui/views/status/failures/_initial_consumers_metrics.erb +6 -6
- data/lib/karafka/web/ui/views/status/failures/_initial_consumers_state.erb +6 -6
- data/lib/karafka/web/ui/views/status/failures/_live_reporting.erb +2 -2
- data/lib/karafka/web/ui/views/status/failures/_materializing_lag.erb +11 -0
- 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/failures/_topics.erb +3 -3
- data/lib/karafka/web/ui/views/status/info/_components.erb +14 -41
- data/lib/karafka/web/ui/views/status/show.erb +165 -154
- data/lib/karafka/web/ui/views/status/warnings/_connection.erb +3 -3
- data/lib/karafka/web/ui/views/status/warnings/_pro_subscription.erb +2 -2
- data/lib/karafka/web/ui/views/status/warnings/_replication.erb +2 -2
- data/lib/karafka/web/ui/views/status/warnings/_routing_topics_presence.erb +1 -1
- data/lib/karafka/web/ui/views/support/_breadcrumbs.erb +5 -0
- data/lib/karafka/web/ui/views/support/show.erb +71 -0
- data/lib/karafka/web/ui/views/ux/_alerts.erb +25 -0
- data/lib/karafka/web/ui/views/ux/_badges.erb +21 -0
- data/lib/karafka/web/ui/views/ux/_breadcrumbs.erb +5 -0
- data/lib/karafka/web/ui/views/ux/_buttons.erb +47 -0
- data/lib/karafka/web/ui/views/ux/_card_detail.erb +15 -0
- data/lib/karafka/web/ui/views/ux/_card_metric.erb +123 -0
- data/lib/karafka/web/ui/views/ux/_card_summary.erb +72 -0
- data/lib/karafka/web/ui/views/ux/_card_support.erb +39 -0
- data/lib/karafka/web/ui/views/ux/_code.erb +9 -0
- data/lib/karafka/web/ui/views/ux/_data_table.erb +52 -0
- data/lib/karafka/web/ui/views/ux/_headers.erb +2 -0
- data/lib/karafka/web/ui/views/ux/_icons.erb +9 -0
- data/lib/karafka/web/ui/views/ux/_pagination.erb +32 -0
- data/lib/karafka/web/ui/views/ux/_row_table.erb +52 -0
- data/lib/karafka/web/ui/views/ux/_status_rows.erb +53 -0
- data/lib/karafka/web/ui/views/ux/_tabs.erb +14 -0
- data/lib/karafka/web/ui/views/ux/_text.erb +2 -0
- data/lib/karafka/web/ui/views/ux/_topic_tiles.erb +42 -0
- data/lib/karafka/web/ui/views/ux/show.erb +19 -0
- data/lib/karafka/web/version.rb +1 -1
- data/lib/karafka/web.rb +2 -0
- data/package-lock.json +4158 -0
- data/package.json +15 -0
- data/postcss.config.js +6 -0
- data/tailwind.config.js +16 -0
- data.tar.gz.sig +4 -0
- metadata +203 -51
- metadata.gz.sig +0 -0
- data/lib/karafka/web/management/migrations/0_set_initial_consumers_metrics.rb +0 -36
- data/lib/karafka/web/management/migrations/0_set_initial_consumers_state.rb +0 -43
- data/lib/karafka/web/management/migrations/1699543515_fill_missing_received_and_sent_bytes_in_consumers_metrics.rb +0 -26
- data/lib/karafka/web/management/migrations/1699543515_fill_missing_received_and_sent_bytes_in_consumers_state.rb +0 -23
- data/lib/karafka/web/management/migrations/1700234522_introduce_waiting_in_consumers_metrics.rb +0 -24
- data/lib/karafka/web/management/migrations/1700234522_introduce_waiting_in_consumers_state.rb +0 -20
- data/lib/karafka/web/management/migrations/1700234522_remove_processing_from_consumers_metrics.rb +0 -24
- data/lib/karafka/web/management/migrations/1700234522_remove_processing_from_consumers_state.rb +0 -20
- data/lib/karafka/web/management/migrations/1704722380_split_listeners_into_active_and_paused_in_metrics.rb +0 -36
- data/lib/karafka/web/management/migrations/1704722380_split_listeners_into_active_and_paused_in_states.rb +0 -32
- data/lib/karafka/web/management/migrations/1706607960_introduce_lag_total_in_metrics.rb +0 -38
- data/lib/karafka/web/management/migrations/1706607960_introduce_lag_total_in_states.rb +0 -22
- data/lib/karafka/web/management/migrations/1706611396_rename_lag_total_to_lag_hybrid_in_metrics.rb +0 -36
- data/lib/karafka/web/management/migrations/1706611396_rename_lag_total_to_lag_hybrid_in_states.rb +0 -21
- data/lib/karafka/web/pro/ui/views/cluster/brokers.erb +0 -27
- data/lib/karafka/web/pro/ui/views/commands/_details.erb +0 -26
- data/lib/karafka/web/pro/ui/views/consumers/_counters.erb +0 -72
- data/lib/karafka/web/pro/ui/views/consumers/consumer/_title.erb +0 -5
- data/lib/karafka/web/pro/ui/views/errors/_title_with_select.erb +0 -31
- data/lib/karafka/web/pro/ui/views/explorer/message/_message_actions.erb +0 -18
- data/lib/karafka/web/pro/ui/views/explorer/message/_payload_actions.erb +0 -19
- data/lib/karafka/web/pro/ui/views/explorer/partition/_details.erb +0 -35
- data/lib/karafka/web/pro/ui/views/explorer/topic/_details.erb +0 -23
- data/lib/karafka/web/pro/ui/views/health/_consumer_group_header.erb +0 -14
- data/lib/karafka/web/ui/controllers/responses/deny.rb +0 -15
- data/lib/karafka/web/ui/helpers/alerts_helper.rb +0 -23
- data/lib/karafka/web/ui/lib/safe_runner.rb +0 -59
- data/lib/karafka/web/ui/models/visibility_filter.rb +0 -49
- data/lib/karafka/web/ui/public/javascripts/libs/bootstrap.min.js +0 -6
- data/lib/karafka/web/ui/public/javascripts/tabs_manager.js +0 -57
- data/lib/karafka/web/ui/public/stylesheets/libs/bootstrap.min.css +0 -6
- data/lib/karafka/web/ui/views/consumers/_counters.erb +0 -62
- data/lib/karafka/web/ui/views/errors/_watermark_offsets.erb +0 -10
- data/lib/karafka/web/ui/views/shared/_feature_pro.erb +0 -4
- data/lib/karafka/web/ui/views/shared/_footer.erb +0 -22
- data/lib/karafka/web/ui/views/shared/_live_poll.erb +0 -7
- /data/lib/karafka/web/management/migrations/{0_base.rb → base.rb} +0 -0
- /data/lib/karafka/web/ui/public/javascripts/{charts.js → components/charts.js} +0 -0
- /data/lib/karafka/web/ui/public/stylesheets/libs/{highlight.min.css → highlight_light.min.css} +0 -0
|
@@ -66,16 +66,18 @@ module Karafka
|
|
|
66
66
|
Responses::File.new(content, file_name)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
#
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
# Raises the deny error so we can render a deny block
|
|
70
|
+
# We handle this that way so we can raise this from any place we want as long as within
|
|
71
|
+
# the Roda flow and not only from controllers
|
|
72
|
+
def deny!
|
|
73
|
+
raise Errors::Ui::ForbiddenError
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
# @param resources [Hash, Array, Lib::HashProxy] object for sorting
|
|
75
77
|
# @return [Hash, Array, Lib::HashProxy] sorted results
|
|
76
78
|
def refine(resources)
|
|
77
79
|
Lib::Sorter.new(
|
|
78
|
-
@params.
|
|
80
|
+
@params.current_sort,
|
|
79
81
|
allowed_attributes: self.class.sortable_attributes
|
|
80
82
|
).call(resources)
|
|
81
83
|
end
|
|
@@ -23,6 +23,14 @@ module Karafka
|
|
|
23
23
|
@aggregated, @params.current_range
|
|
24
24
|
)
|
|
25
25
|
|
|
26
|
+
@topics = Models::Metrics::Topics.new(
|
|
27
|
+
current_metrics.to_h.fetch(:consumer_groups)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
@topics_charts = Models::Metrics::Charts::Topics.new(
|
|
31
|
+
@topics, @params.current_range
|
|
32
|
+
)
|
|
33
|
+
|
|
26
34
|
render
|
|
27
35
|
end
|
|
28
36
|
end
|
|
@@ -24,9 +24,18 @@ module Karafka
|
|
|
24
24
|
@request_params = request_params
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
# @return [Hash] current search or empty if no search query present
|
|
28
|
+
def current_search
|
|
29
|
+
return @current_search if @current_search
|
|
30
|
+
|
|
31
|
+
search = @request_params['search']
|
|
32
|
+
|
|
33
|
+
@current_search = search.is_a?(Hash) ? search : {}
|
|
34
|
+
end
|
|
35
|
+
|
|
27
36
|
# @return [String] sort query value
|
|
28
|
-
def
|
|
29
|
-
@
|
|
37
|
+
def current_sort
|
|
38
|
+
@current_sort ||= @request_params['sort'].to_s.downcase
|
|
30
39
|
end
|
|
31
40
|
|
|
32
41
|
# @return [Integer] current page for paginated views
|
|
@@ -55,6 +64,11 @@ module Karafka
|
|
|
55
64
|
offset < -1 ? -1 : offset
|
|
56
65
|
end
|
|
57
66
|
end
|
|
67
|
+
|
|
68
|
+
# @return [Integer] currently selected partition or -1 if nothing provided
|
|
69
|
+
def current_partition
|
|
70
|
+
@current_partition ||= @request_params.fetch('partition', -1).to_i
|
|
71
|
+
end
|
|
58
72
|
end
|
|
59
73
|
end
|
|
60
74
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Karafka
|
|
4
|
+
module Web
|
|
5
|
+
module Ui
|
|
6
|
+
module Controllers
|
|
7
|
+
# Controller to display support page
|
|
8
|
+
class SupportController < BaseController
|
|
9
|
+
# Display the support page
|
|
10
|
+
def show
|
|
11
|
+
render
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Karafka
|
|
4
|
+
module Web
|
|
5
|
+
module Ui
|
|
6
|
+
module Controllers
|
|
7
|
+
# Controller to display UX components page
|
|
8
|
+
class UxController < BaseController
|
|
9
|
+
# Display the UX components page
|
|
10
|
+
def show
|
|
11
|
+
render
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -61,16 +61,16 @@ module Karafka
|
|
|
61
61
|
#
|
|
62
62
|
# @param status [String] status
|
|
63
63
|
# @return [String] background style
|
|
64
|
-
def
|
|
64
|
+
def status_badge(status)
|
|
65
65
|
case status
|
|
66
|
-
when 'initialized' then '
|
|
67
|
-
when 'supervising' then '
|
|
68
|
-
when 'running' then '
|
|
69
|
-
when 'quieting' then '
|
|
70
|
-
when 'quiet' then '
|
|
71
|
-
when 'stopping' then '
|
|
72
|
-
when 'stopped' then '
|
|
73
|
-
when 'terminated' then '
|
|
66
|
+
when 'initialized' then 'badge-success'
|
|
67
|
+
when 'supervising' then 'badge-success'
|
|
68
|
+
when 'running' then 'badge-success'
|
|
69
|
+
when 'quieting' then 'badge-warning'
|
|
70
|
+
when 'quiet' then 'badge-warning'
|
|
71
|
+
when 'stopping' then 'badge-warning'
|
|
72
|
+
when 'stopped' then 'badge-error'
|
|
73
|
+
when 'terminated' then 'badge-error'
|
|
74
74
|
else
|
|
75
75
|
raise ::Karafka::Errors::UnsupportedCaseError, status
|
|
76
76
|
end
|
|
@@ -80,10 +80,10 @@ module Karafka
|
|
|
80
80
|
#
|
|
81
81
|
# @param trend [Numeric] lag trend
|
|
82
82
|
# @return [String] bg classes
|
|
83
|
-
def
|
|
84
|
-
bg = '
|
|
85
|
-
bg ||= '
|
|
86
|
-
bg ||= '
|
|
83
|
+
def lag_trend_badge(trend)
|
|
84
|
+
bg = 'badge-success' if trend.negative?
|
|
85
|
+
bg ||= 'badge-warning' if trend.positive?
|
|
86
|
+
bg ||= 'badge-secondary'
|
|
87
87
|
bg
|
|
88
88
|
end
|
|
89
89
|
|
|
@@ -93,20 +93,20 @@ module Karafka
|
|
|
93
93
|
# @return [String] tags badges
|
|
94
94
|
def tags(tags_array)
|
|
95
95
|
tags_array
|
|
96
|
-
.map { |tag| %(<span class="badge
|
|
96
|
+
.map { |tag| %(<span class="badge badge-info">#{tag}</span>) }
|
|
97
97
|
.join(' ')
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
# Takes a kafka report state and recommends background style color
|
|
101
101
|
# @param state [String] state
|
|
102
102
|
# @return [String] background style
|
|
103
|
-
def
|
|
103
|
+
def kafka_state_badge(state)
|
|
104
104
|
case state
|
|
105
|
-
when 'up' then '
|
|
106
|
-
when 'active' then '
|
|
107
|
-
when 'steady' then '
|
|
105
|
+
when 'up' then 'badge-success'
|
|
106
|
+
when 'active' then 'badge-success'
|
|
107
|
+
when 'steady' then 'badge-success'
|
|
108
108
|
else
|
|
109
|
-
'
|
|
109
|
+
'badge-warning'
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
112
|
|
|
@@ -116,7 +116,7 @@ module Karafka
|
|
|
116
116
|
return '0' if !mem_kb || mem_kb.zero?
|
|
117
117
|
|
|
118
118
|
if mem_kb < 10_240
|
|
119
|
-
"#{number_with_delimiter(mem_kb)} KB"
|
|
119
|
+
"#{number_with_delimiter(mem_kb.round(4))} KB"
|
|
120
120
|
elsif mem_kb < 1_000_000
|
|
121
121
|
"#{number_with_delimiter((mem_kb / 1024.0).to_i)} MB"
|
|
122
122
|
else
|
|
@@ -151,6 +151,27 @@ module Karafka
|
|
|
151
151
|
%(<span title="#{stamp}">#{time}</span>)
|
|
152
152
|
end
|
|
153
153
|
|
|
154
|
+
# Converts raw second count into human readable form like "12.2 minutes". etc based on
|
|
155
|
+
# number of seconds
|
|
156
|
+
#
|
|
157
|
+
# @param seconds [Numeric] number of seconds
|
|
158
|
+
# @return [String] human readable time
|
|
159
|
+
def human_readable_time(seconds)
|
|
160
|
+
case seconds
|
|
161
|
+
when 0..59
|
|
162
|
+
"#{seconds.round(2)} seconds"
|
|
163
|
+
when 60..3_599
|
|
164
|
+
minutes = seconds / 60.0
|
|
165
|
+
"#{minutes.round(2)} minutes"
|
|
166
|
+
when 3_600..86_399
|
|
167
|
+
hours = seconds / 3_600.0
|
|
168
|
+
"#{hours.round(2)} hours"
|
|
169
|
+
else
|
|
170
|
+
days = seconds / 86_400.0
|
|
171
|
+
"#{days.round(2)} days"
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
154
175
|
# @param state [String] poll state
|
|
155
176
|
# @param state_ch [Integer] time until next change of the poll state
|
|
156
177
|
# (from paused to active)
|
|
@@ -162,12 +183,12 @@ module Karafka
|
|
|
162
183
|
# If state is active, there is no date of change
|
|
163
184
|
if state == 'active'
|
|
164
185
|
%(
|
|
165
|
-
<span class="badge #{
|
|
186
|
+
<span class="badge #{kafka_state_badge(state)}">#{state}</span>
|
|
166
187
|
)
|
|
167
188
|
elsif state_ch_in_seconds > year_in_seconds
|
|
168
189
|
%(
|
|
169
190
|
<span
|
|
170
|
-
class="badge #{
|
|
191
|
+
class="badge #{kafka_state_badge(state)}"
|
|
171
192
|
title="until manual resume"
|
|
172
193
|
>
|
|
173
194
|
#{state}
|
|
@@ -176,7 +197,7 @@ module Karafka
|
|
|
176
197
|
else
|
|
177
198
|
%(
|
|
178
199
|
<span
|
|
179
|
-
class="badge #{
|
|
200
|
+
class="badge #{kafka_state_badge(state)} time-title"
|
|
180
201
|
title="#{Time.now + state_ch_in_seconds}"
|
|
181
202
|
>
|
|
182
203
|
#{state}
|
|
@@ -191,7 +212,7 @@ module Karafka
|
|
|
191
212
|
def lag_with_label(lag)
|
|
192
213
|
if lag.negative?
|
|
193
214
|
title = 'Not available until first offset commit'
|
|
194
|
-
%(<span class="badge
|
|
215
|
+
%(<span class="badge badge-secondary" title="#{title}">N/A</span>)
|
|
195
216
|
else
|
|
196
217
|
lag.to_s
|
|
197
218
|
end
|
|
@@ -207,7 +228,7 @@ module Karafka
|
|
|
207
228
|
def offset_with_label(topic_name, partition_id, offset, explore: false)
|
|
208
229
|
if offset.negative?
|
|
209
230
|
title = 'Not available until first offset commit'
|
|
210
|
-
%(<span class="badge
|
|
231
|
+
%(<span class="badge badge-secondary" title="#{title}">N/A</span>)
|
|
211
232
|
elsif explore
|
|
212
233
|
path = explorer_path(topic_name, partition_id, offset)
|
|
213
234
|
%(<a href="#{path}">#{offset}</a>)
|
|
@@ -226,29 +247,34 @@ module Karafka
|
|
|
226
247
|
when :at_risk
|
|
227
248
|
'bg-warning bg-opacity-25'
|
|
228
249
|
when :stopped
|
|
229
|
-
'bg-
|
|
250
|
+
'bg-error bg-opacity-25'
|
|
251
|
+
else
|
|
252
|
+
raise ::Karafka::Errors::UnsupportedCaseError
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# @param details [::Karafka::Web::Ui::Models::Partition] partition information with
|
|
257
|
+
# lso risk state info
|
|
258
|
+
# @return [String] background classes for row marking
|
|
259
|
+
def lso_risk_state_badge(details)
|
|
260
|
+
case details.lso_risk_state
|
|
261
|
+
when :active
|
|
262
|
+
''
|
|
263
|
+
when :at_risk
|
|
264
|
+
'badge-warning'
|
|
265
|
+
when :stopped
|
|
266
|
+
'badge-error'
|
|
230
267
|
else
|
|
231
268
|
raise ::Karafka::Errors::UnsupportedCaseError
|
|
232
269
|
end
|
|
233
270
|
end
|
|
234
271
|
|
|
235
|
-
#
|
|
272
|
+
# Sets the particular page title
|
|
236
273
|
#
|
|
237
274
|
# @param title [String] page title
|
|
238
|
-
# @param hr [Boolean] should we add the hr tag at the end
|
|
239
275
|
# @return [String] title html
|
|
240
|
-
def view_title(title
|
|
241
|
-
|
|
242
|
-
<div class="container mb-5">
|
|
243
|
-
<div class="row">
|
|
244
|
-
<h3>
|
|
245
|
-
#{title}
|
|
246
|
-
</h3>
|
|
247
|
-
</div>
|
|
248
|
-
|
|
249
|
-
#{hr ? '<hr/>' : ''}
|
|
250
|
-
</div>
|
|
251
|
-
HTML
|
|
276
|
+
def view_title(title)
|
|
277
|
+
content_for(:title) { title }
|
|
252
278
|
end
|
|
253
279
|
|
|
254
280
|
# @param hash [Hash] we want to flatten
|
|
@@ -295,12 +321,12 @@ module Karafka
|
|
|
295
321
|
path = current_path(sort: desc)
|
|
296
322
|
full_name = "#{name} #{arrow_both}"
|
|
297
323
|
|
|
298
|
-
if params.
|
|
324
|
+
if params.current_sort == desc
|
|
299
325
|
path = current_path(sort: asc)
|
|
300
326
|
full_name = "#{name} #{rev ? arrow_up : arrow_down}"
|
|
301
327
|
end
|
|
302
328
|
|
|
303
|
-
if params.
|
|
329
|
+
if params.current_sort == asc
|
|
304
330
|
path = current_path(sort: desc)
|
|
305
331
|
full_name = "#{name} #{rev ? arrow_down : arrow_up}"
|
|
306
332
|
end
|
|
@@ -336,6 +362,13 @@ module Karafka
|
|
|
336
362
|
|
|
337
363
|
%(<span title="#{string}">#{truncated}</span>)
|
|
338
364
|
end
|
|
365
|
+
|
|
366
|
+
# Renders the svg icon out of our icon set
|
|
367
|
+
# @param name [String, Symbol] name of the icon
|
|
368
|
+
# @return [String] svg icon
|
|
369
|
+
def icon(name)
|
|
370
|
+
render "shared/icons/_#{name}"
|
|
371
|
+
end
|
|
339
372
|
end
|
|
340
373
|
end
|
|
341
374
|
end
|
|
@@ -6,6 +6,30 @@ module Karafka
|
|
|
6
6
|
module Helpers
|
|
7
7
|
# Helper for web ui paths builders
|
|
8
8
|
module PathsHelper
|
|
9
|
+
# Helper method to flatten nested hashes and arrays
|
|
10
|
+
# @param prefix [String] The prefix for nested keys, initially an empty string.
|
|
11
|
+
# @param hash [Hash, Array] The nested hash or array to be flattened.
|
|
12
|
+
# @param [Hash] result The hash to store the flattened key-value pairs.
|
|
13
|
+
# @return [Hash] The flattened hash with keys in bracket notation suitable for URL
|
|
14
|
+
# encoding.
|
|
15
|
+
def flatten_params(prefix, hash, result = {})
|
|
16
|
+
if hash.is_a?(Hash)
|
|
17
|
+
hash.each do |k, v|
|
|
18
|
+
new_prefix = prefix.empty? ? k.to_s : "#{prefix}[#{k}]"
|
|
19
|
+
flatten_params(new_prefix, v, result)
|
|
20
|
+
end
|
|
21
|
+
elsif hash.is_a?(Array)
|
|
22
|
+
hash.each_with_index do |v, i|
|
|
23
|
+
new_prefix = "#{prefix}[#{i}]"
|
|
24
|
+
flatten_params(new_prefix, v, result)
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
result[prefix] = hash.to_s
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
result
|
|
31
|
+
end
|
|
32
|
+
|
|
9
33
|
# Generates a full path with the root path out of the provided arguments
|
|
10
34
|
#
|
|
11
35
|
# @param args [Array<String, Numeric>] arguments that will make the path
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Karafka
|
|
4
|
+
module Web
|
|
5
|
+
module Ui
|
|
6
|
+
module Helpers
|
|
7
|
+
# Helper for generating tailwind rendering components with Ruby
|
|
8
|
+
# Simplifies many places in the UI
|
|
9
|
+
module TailwindHelper
|
|
10
|
+
# style types of components we support
|
|
11
|
+
TYPES = %i[
|
|
12
|
+
info
|
|
13
|
+
error
|
|
14
|
+
warning
|
|
15
|
+
success
|
|
16
|
+
primary
|
|
17
|
+
secondary
|
|
18
|
+
].freeze
|
|
19
|
+
|
|
20
|
+
# @return [Array<Symbol>] style types of components we support
|
|
21
|
+
def tailwind_types
|
|
22
|
+
TYPES
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Renders a plain badge
|
|
26
|
+
# @param content [String] badge content
|
|
27
|
+
# @param classes [String] extra css classes
|
|
28
|
+
# @return [String] badge html
|
|
29
|
+
def badge(content, classes: '')
|
|
30
|
+
%(<span class="badge #{classes}">#{content}</span>)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Renders a link to with button styling
|
|
34
|
+
# @param name [String] button name
|
|
35
|
+
# @param path [String] path to where to go
|
|
36
|
+
# @param classes [String] extra css classes
|
|
37
|
+
# @return [String] button link html
|
|
38
|
+
def link_button(name, path, classes: '')
|
|
39
|
+
%(<a href="#{path}" class="btn #{classes}">#{name}</a>)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Defines various methods for badges and links that simplify defining them without
|
|
43
|
+
# having to provide whole classes scopes always.
|
|
44
|
+
TYPES.each do |type|
|
|
45
|
+
define_method :"badge_#{type}" do |content, classes: ''|
|
|
46
|
+
badge(content, classes: "#{classes} badge-#{type}")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
define_method :"badge_#{type}_sm" do |content, classes: ''|
|
|
50
|
+
badge(content, classes: "#{classes} badge-#{type} badge-sm")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
define_method :"link_button_#{type}" do |name, path, classes: ''|
|
|
54
|
+
link_button(name, path, classes: "#{classes} btn-#{type}")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
define_method :"link_button_#{type}_sm" do |name, path, classes: ''|
|
|
58
|
+
link_button(name, path, classes: "#{classes} btn-#{type} btn-sm")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @param message [String] alert message
|
|
62
|
+
# @return [String] html with alert
|
|
63
|
+
define_method :"alert_#{type}" do |message|
|
|
64
|
+
partial(
|
|
65
|
+
"shared/alerts/#{type}",
|
|
66
|
+
locals: {
|
|
67
|
+
message: message
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @param message [String] alert message
|
|
73
|
+
# @return [String] html with alert
|
|
74
|
+
define_method :"alert_box_#{type}" do |title, description = nil, &block|
|
|
75
|
+
description = capture_erb(&block) if block
|
|
76
|
+
|
|
77
|
+
inject_erb partial(
|
|
78
|
+
"shared/alerts/box_#{type}",
|
|
79
|
+
locals: {
|
|
80
|
+
title: title,
|
|
81
|
+
description: description
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -33,7 +33,7 @@ module Karafka
|
|
|
33
33
|
@field = '' unless allowed_attributes.include?(@field)
|
|
34
34
|
|
|
35
35
|
# Things we have already seen and sorted. Prevents crashing on the circular
|
|
36
|
-
# dependencies sorting when same resources are present in different parts of the
|
|
36
|
+
# dependencies sorting when same resources are present in different parts of the tree
|
|
37
37
|
@seen = {}
|
|
38
38
|
end
|
|
39
39
|
|
|
@@ -47,48 +47,64 @@ module Karafka
|
|
|
47
47
|
per_topic.merge('total sum' => total.to_a).to_json
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
# @return [String] JSON with
|
|
51
|
-
#
|
|
52
|
-
def
|
|
53
|
-
topics = {}
|
|
50
|
+
# @return [String] JSON with per-topic, highest LSO freeze duration. Useful for
|
|
51
|
+
# debugging of issues arising from hanging transactions
|
|
52
|
+
def max_lso
|
|
53
|
+
topics = Hash.new { |h, k| h[k] = Hash.new { |h2, k2| h2[k2] = [] } }
|
|
54
54
|
|
|
55
55
|
@data.to_h.each do |topic, metrics|
|
|
56
56
|
topic_without_cg = topic.split('[').first
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
metrics.each do |current|
|
|
59
|
+
ls_offset_fd = current.last[:ls_offset_fd] || 0
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
# We convert this to seconds from milliseconds due to our Web UI precision
|
|
62
|
+
# Reporting is in ms for consistency
|
|
63
|
+
normalized_fd = (ls_offset_fd / 1_000.0).round
|
|
64
|
+
|
|
65
|
+
topics[topic_without_cg][current.first] << normalized_fd
|
|
63
66
|
end
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
topics.each_value(&:compact!)
|
|
70
|
+
topics.each_value { |metrics| metrics.transform_values!(&:max) }
|
|
71
|
+
topics.transform_values! { |values| values.to_a.sort_by!(&:first) }
|
|
67
72
|
topics.to_json
|
|
68
73
|
end
|
|
69
74
|
|
|
70
|
-
# @return [String] JSON with
|
|
71
|
-
#
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
# @return [String] JSON with producers pace that represents high-watermarks sum for
|
|
76
|
+
# each topic.
|
|
77
|
+
#
|
|
78
|
+
# @note There is a case where data reported (sum on a topic) is lower then the
|
|
79
|
+
# previous value. This can happen around rebalances because consumer may not
|
|
80
|
+
# have all watermark offsets reported. This may cause consumers not to report some
|
|
81
|
+
# of the partitions, effectively lowering the sum. Since high-watermark offsets can
|
|
82
|
+
# only move forward, we compensate this by assuming that a lower value than
|
|
83
|
+
# previous is an artefact of that type and we replace it with the max value we had
|
|
84
|
+
# effectively compensating for under-reporting
|
|
85
|
+
def pace
|
|
86
|
+
topics = {}
|
|
74
87
|
|
|
75
88
|
@data.to_h.each do |topic, metrics|
|
|
76
89
|
topic_without_cg = topic.split('[').first
|
|
77
90
|
|
|
78
|
-
|
|
79
|
-
|
|
91
|
+
# If we've already seen this topic data, we can skip
|
|
92
|
+
next if topics.include?(topic_without_cg)
|
|
80
93
|
|
|
81
|
-
|
|
82
|
-
# Reporting is in ms for consistency
|
|
83
|
-
normalized_fd = (ls_offset_fd / 1_000.0).round
|
|
94
|
+
max_pace = 0
|
|
84
95
|
|
|
85
|
-
|
|
96
|
+
topics[topic_without_cg] = metrics.map do |current|
|
|
97
|
+
# Pace may be empty when for a given moment in time we got no info on
|
|
98
|
+
# one of the topics. In such case we can compensate with max or 0
|
|
99
|
+
current_pace = current.last[:pace] || 0
|
|
100
|
+
|
|
101
|
+
max_pace = current_pace if current_pace > max_pace
|
|
102
|
+
|
|
103
|
+
[current.first, max_pace]
|
|
86
104
|
end
|
|
87
105
|
end
|
|
88
106
|
|
|
89
107
|
topics.each_value(&:compact!)
|
|
90
|
-
topics.each_value { |metrics| metrics.transform_values!(&:max) }
|
|
91
|
-
topics.transform_values! { |values| values.to_a.sort_by!(&:first) }
|
|
92
108
|
topics.to_json
|
|
93
109
|
end
|
|
94
110
|
end
|
|
@@ -209,10 +209,37 @@ module Karafka
|
|
|
209
209
|
)
|
|
210
210
|
end
|
|
211
211
|
|
|
212
|
+
# @return [Status::Step] Is there a significant lag in the reporting of aggregated data
|
|
213
|
+
# back to the Kafka. If yes, it means that the results in the Web UI will be delayed
|
|
214
|
+
# against the reality. Often it means, that there is over-saturation on the consumer
|
|
215
|
+
# that is materializing the states.
|
|
216
|
+
#
|
|
217
|
+
# @note Since both states and metrics are reported together, it is enough for us to check
|
|
218
|
+
# on one of them.
|
|
219
|
+
def materializing_lag
|
|
220
|
+
max_lag = (Web.config.tracking.interval * 2) / 1_000
|
|
221
|
+
|
|
222
|
+
details = { lag: 0, max_lag: max_lag }
|
|
223
|
+
|
|
224
|
+
status = if live_reporting.success?
|
|
225
|
+
lag = Time.now.to_f - @current_state.dispatched_at
|
|
226
|
+
details[:lag] = lag
|
|
227
|
+
|
|
228
|
+
lag > max_lag ? :failure : :success
|
|
229
|
+
else
|
|
230
|
+
:halted
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
Step.new(
|
|
234
|
+
status,
|
|
235
|
+
details
|
|
236
|
+
)
|
|
237
|
+
end
|
|
238
|
+
|
|
212
239
|
# @return [Status::Step] is there a subscription to our reports topic that is being
|
|
213
240
|
# consumed actively.
|
|
214
241
|
def state_calculation
|
|
215
|
-
if
|
|
242
|
+
if materializing_lag.success?
|
|
216
243
|
@subscriptions ||= Models::Health
|
|
217
244
|
.current(@current_state)
|
|
218
245
|
.values.map { |consumer_group| consumer_group[:topics] }
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
|
2
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5m-9-6h.008v.008H12v-.008ZM12 15h.008v.008H12V15Zm0 2.25h.008v.008H12v-.008ZM9.75 15h.008v.008H9.75V15Zm0 2.25h.008v.008H9.75v-.008ZM7.5 15h.008v.008H7.5V15Zm0 2.25h.008v.008H7.5v-.008Zm6.75-4.5h.008v.008h-.008v-.008Zm0 2.25h.008v.008h-.008V15Zm0 2.25h.008v.008h-.008v-.008Zm2.25-4.5h.008v.008H16.5v-.008Zm0 2.25h.008v.008H16.5V15Z" />
|
|
3
|
+
</svg>
|