From 1be7a13d6ac1816b0ff559ff304ae08b6793651f Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Mon, 31 May 2021 10:27:28 +0300 Subject: [PATCH] Revert "Merge branch '#100250' of github.com:Kunzetsov/kibana into #100250" This reverts commit 2e019f345694653f2e283bc57b9b44c06e762a1d, reversing changes made to 3d9d1d800637658f7ae2a8f593fee736d927d5fb. --- api_docs/apm.json | 14 +- api_docs/charts.json | 8 +- api_docs/core.json | 56 +- api_docs/core_application.json | 20 +- api_docs/core_saved_objects.json | 16 +- api_docs/data.json | 516 +++--- api_docs/data_field_formats.json | 20 +- api_docs/data_index_patterns.json | 146 +- api_docs/data_query.json | 40 +- api_docs/data_search.json | 14 +- api_docs/deprecations.mdx | 24 +- api_docs/embeddable.json | 8 +- api_docs/expressions.json | 48 +- api_docs/fleet.json | 1142 ++++--------- api_docs/home.json | 6 +- api_docs/kibana_react.json | 30 +- api_docs/kibana_utils.json | 48 +- api_docs/lens.json | 52 +- api_docs/licensing.json | 2 +- api_docs/maps.json | 380 ++--- api_docs/observability.json | 84 +- api_docs/presentation_util.json | 8 +- api_docs/reporting.json | 102 +- api_docs/rule_registry.json | 47 +- api_docs/spaces.json | 8 +- api_docs/triggers_actions_ui.json | 200 ++- api_docs/visualizations.json | 20 +- .../monorepo-packages.asciidoc | 1 - docs/user/alerting/rule-management.asciidoc | 9 + docs/user/dashboard/lens.asciidoc | 15 +- docs/user/introduction.asciidoc | 17 +- package.json | 5 +- packages/BUILD.bazel | 1 - .../build_arrow_fn_dec.ts | 5 +- .../src/api_docs/tests/api_doc_suite.test.ts | 7 - .../api_docs/tests/snapshots/plugin_a.json | 26 +- packages/kbn-io-ts-utils/BUILD.bazel | 85 - packages/kbn-io-ts-utils/package.json | 7 +- packages/kbn-io-ts-utils/tsconfig.json | 2 +- .../src/request/index.ts | 1 - .../index.mock.ts | 17 - .../index.test.ts | 126 -- .../summary_exception_list_schema/index.ts | 33 - .../index.test.ts | 94 -- .../exception_list_summary_schema/index.ts | 21 - .../src/response/index.ts | 1 - .../kbn-server-route-repository/package.json | 3 + .../aggregations/aggs_types/bucket_aggs.ts | 9 +- .../aggregations/aggs_types/common_schemas.ts | 29 - .../aggregations/aggs_types/metrics_aggs.ts | 3 +- .../apm_oss/common/index_pattern_constants.ts | 9 +- .../plugins/apm_oss}/public/assets/apm.png | Bin src/plugins/apm_oss/public/index.ts | 2 + src/plugins/apm_oss/server/index.ts | 18 + src/plugins/apm_oss/server/plugin.ts | 27 +- .../apm_oss}/server/tutorial/envs/on_prem.ts | 151 +- src/plugins/apm_oss/server/tutorial/index.ts | 84 + .../server/tutorial/index_pattern.json | 0 .../instructions/apm_agent_instructions.ts | 754 +++++++++ .../instructions/apm_server_instructions.ts | 70 +- src/plugins/charts/common/palette.test.ts | 25 +- src/plugins/charts/common/palette.ts | 60 +- .../public/services/palettes/helpers.test.ts | 307 ---- .../public/services/palettes/helpers.ts | 101 -- .../charts/public/services/palettes/mock.ts | 37 +- .../services/palettes/palettes.test.tsx | 111 +- .../public/services/palettes/palettes.tsx | 81 +- .../charts/public/services/palettes/types.ts | 27 +- .../components/controls/palette_picker.tsx | 4 +- .../common/index_patterns_utils.test.ts | 6 +- .../common/index_patterns_utils.ts | 6 +- .../application/components/index_pattern.js | 46 +- .../index_pattern_select.tsx | 31 +- .../application/components/palette_picker.tsx | 8 +- .../lib/get_split_by_terms_color.ts | 2 +- .../server/lib/get_vis_data.ts | 28 +- .../lib/cached_index_pattern_fetcher.ts | 9 +- .../response_processors/table/math.js | 4 +- .../vis_type_xy/public/vis_component.tsx | 2 +- x-pack/plugins/alerting/server/config.test.ts | 3 +- x-pack/plugins/alerting/server/config.ts | 1 - .../alerting/server/health/get_state.test.ts | 8 - x-pack/plugins/alerting/server/plugin.test.ts | 73 - x-pack/plugins/alerting/server/plugin.ts | 2 +- .../alerting/server/saved_objects/index.ts | 104 +- .../create_execution_handler.test.ts | 3 +- .../task_runner/create_execution_handler.ts | 3 +- .../task_runner/inject_action_params.test.ts | 60 +- .../task_runner/inject_action_params.ts | 12 +- .../VisitorBreakdownMap/useLayerList.ts | 2 +- .../VisitorBreakdownMap/useMapFilters.ts | 2 +- .../Links/DiscoverLinks/DiscoverLink.tsx | 2 +- .../create_static_index_pattern.ts | 6 +- x-pack/plugins/apm/server/plugin.ts | 39 +- .../tutorial/{envs => }/elastic_cloud.ts | 6 +- x-pack/plugins/apm/server/tutorial/index.ts | 117 -- .../instructions/apm_agent_instructions.ts | 931 ---------- .../canvas/public/functions/pie.test.js | 4 +- x-pack/plugins/canvas/public/functions/pie.ts | 2 +- .../canvas/public/functions/plot.test.js | 4 +- .../canvas/public/functions/plot/index.ts | 2 +- .../lib/enterprise_search_config_api.test.ts | 27 +- .../lib/enterprise_search_config_api.ts | 14 - .../settings_flyout/hosts_input.test.tsx | 68 - .../settings_flyout/hosts_input.tsx | 247 --- .../components/settings_flyout/index.tsx | 211 ++- .../applications/fleet/hooks/use_input.ts | 43 +- x-pack/plugins/index_management/kibana.json | 2 +- .../plugins/index_management/server/plugin.ts | 25 +- .../routes/api/component_templates/create.ts | 10 +- .../routes/api/component_templates/delete.ts | 6 +- .../routes/api/component_templates/get.ts | 10 +- .../component_templates/privileges.test.ts | 7 + .../api/component_templates/privileges.ts | 6 +- .../routes/api/component_templates/update.ts | 10 +- .../api/data_streams/register_delete_route.ts | 6 +- .../api/data_streams/register_get_route.ts | 22 +- .../api/indices/register_clear_cache_route.ts | 6 +- .../api/indices/register_close_route.ts | 6 +- .../api/indices/register_delete_route.ts | 6 +- .../api/indices/register_flush_route.ts | 6 +- .../api/indices/register_forcemerge_route.ts | 6 +- .../api/indices/register_freeze_route.ts | 6 +- .../routes/api/indices/register_list_route.ts | 39 +- .../routes/api/indices/register_open_route.ts | 6 +- .../api/indices/register_refresh_route.ts | 6 +- .../api/indices/register_reload_route.ts | 11 +- .../api/indices/register_unfreeze_route.ts | 6 +- .../api/mapping/register_mapping_route.ts | 6 +- .../api/settings/register_load_route.ts | 6 +- .../api/settings/register_update_route.ts | 6 +- .../routes/api/stats/register_stats_route.ts | 6 +- .../api/templates/register_create_route.ts | 6 +- .../api/templates/register_delete_route.ts | 6 +- .../api/templates/register_get_routes.ts | 55 +- .../api/templates/register_simulate_route.ts | 6 +- .../api/templates/register_update_route.ts | 6 +- .../index_management/server/services/index.ts | 2 + .../server/services/license.ts | 82 + .../plugins/index_management/server/types.ts | 3 +- .../log_stream/log_stream.stories.mdx | 24 +- x-pack/plugins/ingest_pipelines/kibana.json | 2 +- .../plugins/ingest_pipelines/server/index.ts | 5 +- .../plugins/ingest_pipelines/server/plugin.ts | 32 +- .../server/routes/api/create.ts | 5 +- .../server/routes/api/delete.ts | 6 +- .../server/routes/api/documents.ts | 5 +- .../ingest_pipelines/server/routes/api/get.ts | 41 +- .../server/routes/api/privileges.ts | 6 +- .../server/routes/api/simulate.ts | 5 +- .../server/routes/api/update.ts | 5 +- .../server/services/index.ts} | 2 +- .../server/services/license.ts | 84 + .../plugins/ingest_pipelines/server/types.ts | 4 + .../lens/public/app_plugin/app.test.tsx | 1164 ++++++++----- x-pack/plugins/lens/public/app_plugin/app.tsx | 533 +++++- .../lens/public/app_plugin/lens_top_nav.tsx | 199 +-- .../lens/public/app_plugin/mounter.test.tsx | 150 -- .../lens/public/app_plugin/mounter.tsx | 153 +- .../lens/public/app_plugin/time_range.ts | 84 + .../plugins/lens/public/app_plugin/types.ts | 57 +- .../__snapshots__/table_basic.test.tsx.snap | 21 - .../components/cell_value.test.tsx | 117 +- .../components/cell_value.tsx | 82 +- .../components/dimension_editor.scss | 7 - .../components/dimension_editor.test.tsx | 119 +- .../components/dimension_editor.tsx | 223 +-- .../components/palette_panel_container.scss | 53 - .../components/palette_panel_container.tsx | 112 -- .../components/shared_utils.tsx | 36 - .../components/table_basic.test.tsx | 56 - .../components/table_basic.tsx | 37 +- .../components/types.ts | 10 - .../datatable_visualization/expression.tsx | 19 +- .../public/datatable_visualization/index.ts | 11 +- .../transpose_helpers.ts | 22 +- .../visualization.test.tsx | 45 +- .../datatable_visualization/visualization.tsx | 93 +- .../config_panel/dimension_container.tsx | 124 +- .../editor_frame/config_panel/layer_panel.tsx | 5 +- .../editor_frame/editor_frame.test.tsx | 1501 +++++++++-------- .../editor_frame/editor_frame.tsx | 175 +- .../editor_frame_service/editor_frame/save.ts | 7 +- .../editor_frame/state_management.test.ts | 11 +- .../editor_frame/state_management.ts | 43 +- .../editor_frame/suggestion_helpers.ts | 8 +- .../workspace_panel/workspace_panel.test.tsx | 224 +-- .../workspace_panel/workspace_panel.tsx | 10 +- .../public/editor_frame_service/mocks.tsx | 5 +- .../public/editor_frame_service/service.tsx | 31 +- .../calculations/moving_average.tsx | 8 +- .../operations/definitions/helpers.tsx | 24 + .../operations/definitions/percentile.tsx | 2 +- .../definitions/ranges/advanced_editor.tsx | 3 +- .../definitions/ranges/range_editor.tsx | 2 +- .../definitions/terms/values_input.tsx | 2 +- x-pack/plugins/lens/public/mocks.tsx | 276 --- .../render_function.test.tsx | 2 +- .../pie_visualization/render_function.tsx | 2 +- .../pie_visualization/visualization.tsx | 2 +- .../coloring/color_stops.test.tsx | 156 -- .../coloring/color_stops.tsx | 294 ---- .../shared_components/coloring/constants.ts | 29 - .../shared_components/coloring/index.ts | 12 - .../coloring/palette_configuration.scss | 7 - .../coloring/palette_configuration.test.tsx | 185 -- .../coloring/palette_configuration.tsx | 340 ---- .../coloring/palette_picker.tsx | 109 -- .../shared_components/coloring/types.ts | 25 - .../shared_components/coloring/utils.test.ts | 399 ----- .../shared_components/coloring/utils.ts | 308 ---- .../shared_components/debounced_value.ts | 4 +- .../lens/public/shared_components/helpers.ts | 31 - .../lens/public/shared_components/index.ts | 3 - .../shared_components/palette_picker.tsx | 47 +- .../lens/public/state_management/app_slice.ts | 55 - .../external_context_middleware.ts | 103 -- .../lens/public/state_management/index.ts | 76 - .../time_range_middleware.test.ts | 198 --- .../state_management/time_range_middleware.ts | 61 - .../lens/public/state_management/types.ts | 42 - x-pack/plugins/lens/public/types.ts | 22 +- x-pack/plugins/lens/public/utils.ts | 30 - .../xy_visualization/color_assignment.ts | 2 +- .../public/xy_visualization/expression.tsx | 2 +- .../tooltip_wrapper.tsx | 0 .../visual_options_popover.tsx | 3 +- .../xy_visualization/visualization.test.ts | 16 +- .../public/xy_visualization/visualization.tsx | 19 +- .../xy_visualization/xy_config_panel.test.tsx | 4 - .../xy_visualization/xy_config_panel.tsx | 3 +- x-pack/plugins/lists/server/routes/index.ts | 1 - .../lists/server/routes/init_routes.ts | 4 - .../routes/summary_exception_list_route.ts | 76 - .../server/scripts/summary_exception_list.sh | 25 - .../exception_lists/exception_list_client.ts | 12 - .../exception_list_client_types.ts | 6 - .../get_exception_list_summary.ts | 93 - .../server/services/exception_lists/index.ts | 1 - x-pack/plugins/maps/public/kibana_services.ts | 2 +- .../ml/common/types/ml_url_generator.ts | 4 - .../alerting/ml_anomaly_alert_trigger.tsx | 2 +- .../severity_control/index.ts | 0 .../severity_control/severity_control.tsx | 84 + .../severity_control/styles.scss | 0 .../capabilities/check_capabilities.ts | 2 +- .../components/anomalies_table/links_menu.js | 3 +- .../select_interval/select_interval.tsx | 18 +- .../select_severity/select_severity.tsx | 27 +- .../severity_control/severity_control.tsx | 106 -- .../application/explorer/_explorer.scss | 8 + .../explorer/actions/load_explorer_data.ts | 14 +- .../application/explorer/anomaly_timeline.tsx | 152 +- .../public/application/explorer/explorer.js | 64 +- .../explorer_anomalies_container.tsx | 20 +- .../explorer/explorer_constants.ts | 1 - .../explorer/explorer_dashboard_service.ts | 7 - .../reducers/explorer_reducer/reducer.ts | 13 +- .../reducers/explorer_reducer/state.ts | 1 - .../explorer/swimlane_container.tsx | 13 +- .../components/custom_url_editor/utils.js | 16 +- .../components/access_denied_page.tsx | 6 +- .../components/insufficient_license_page.tsx | 82 - .../jobs_list_page/jobs_list_page.tsx | 12 +- .../application/routing/routes/explorer.tsx | 7 +- .../services/anomaly_timeline_service.ts | 15 +- .../services/ml_api_service/index.ts | 10 +- .../results_service/results_service.d.ts | 9 +- .../results_service/results_service.js | 25 +- .../_timeseriesexplorer.scss | 4 + .../timeseriesexplorer/timeseriesexplorer.js | 41 +- x-pack/plugins/ml/public/plugin.ts | 11 +- .../ml/server/routes/anomaly_detectors.ts | 1 - .../schemas/anomaly_detectors_schema.ts | 1 - .../shared/header_menu_portal.test.tsx | 26 - .../components/shared/header_menu_portal.tsx | 7 +- .../components/shared/page_template/README.md | 6 +- .../public/pages/alerts/alerts.stories.tsx | 6 +- x-pack/plugins/rule_registry/README.md | 3 - x-pack/plugins/rule_registry/server/index.ts | 1 - .../server/rule_data_client/index.ts | 4 +- .../create_persistence_rule_type_factory.ts | 112 -- .../security_solution/common/constants.ts | 13 - .../data_generators/base_data_generator.ts | 20 - .../data_generators/fleet_action_generator.ts | 62 - .../common/endpoint/generate_data.test.ts | 4 +- .../common/endpoint/generate_data.ts | 6 +- .../common/endpoint/index_data.ts | 45 - .../common/endpoint/types/actions.ts | 15 - .../common/endpoint/types/index.ts | 10 - .../common/experimental_features.ts | 1 - x-pack/plugins/security_solution/kibana.json | 1 - .../exceptions/use_add_exception.test.tsx | 18 +- .../exceptions/use_add_exception.tsx | 20 +- .../public/common/mock/global_state.ts | 1 - .../public/common/mock/test_providers.tsx | 26 +- .../alerts_table/default_config.tsx | 76 +- .../components/alerts_table/index.tsx | 32 +- .../alerts/use_signal_index.test.tsx | 31 +- .../alerts/use_signal_index.tsx | 13 +- .../detection_engine/detection_engine.tsx | 16 +- .../detection_engine/rules/details/index.tsx | 11 +- .../components/search_bar/index.tsx | 2 +- .../pages/event_filters/service/index.ts | 13 - .../event_filters/store/middleware.test.ts | 1 - .../management/pages/event_filters/types.ts | 2 - .../components/fleet_event_filters_card.tsx | 116 -- .../components/fleet_trusted_apps_card.tsx | 63 +- .../components/styled_components.tsx | 24 - ...mary.tsx => trusted_app_items_summary.tsx} | 46 +- .../index.tsx | 4 - .../view/trusted_apps_page.test.tsx | 17 +- .../trusted_apps/view/trusted_apps_page.tsx | 54 +- .../security_solution/public/plugin.tsx | 18 +- .../isometric_taxi_layout.test.ts.snap | 96 +- .../public/timelines/containers/helpers.ts | 12 +- .../timelines/containers/index.test.tsx | 5 - .../public/timelines/containers/index.tsx | 15 +- .../reference_rules/__mocks__/rule_type.ts | 76 - .../reference_rules/__mocks__/threshold.ts | 61 - .../reference_rules/eql.test.ts | 92 - .../detection_engine/reference_rules/eql.ts | 121 -- .../detection_engine/reference_rules/ml.ts | 70 - .../reference_rules/query.test.ts | 99 -- .../detection_engine/reference_rules/query.ts | 88 - .../scripts/create_reference_rule_eql.sh | 34 - .../scripts/create_reference_rule_query.sh | 34 - .../create_reference_rule_threshold.sh | 37 - .../reference_rules/threshold.test.ts | 132 -- .../reference_rules/threshold.ts | 206 --- .../routes/__mocks__/request_responses.ts | 66 - .../routes/index/read_index_route.ts | 16 +- .../routes/rules/create_rules_route.ts | 4 +- .../routes/rules/delete_rules_route.ts | 6 +- .../routes/rules/find_rules_route.test.ts | 4 +- .../routes/rules/find_rules_route.ts | 52 +- .../rules/find_rules_status_route.test.ts | 4 +- .../routes/rules/find_rules_status_route.ts | 49 +- .../routes/rules/patch_rules_route.ts | 7 +- .../routes/rules/read_rules_route.ts | 6 +- .../routes/rules/update_rules_route.ts | 7 +- .../routes/rules/utils.test.ts | 20 +- .../detection_engine/routes/rules/utils.ts | 43 +- .../signals/query_signals_route.test.ts | 4 +- .../routes/signals/query_signals_route.ts | 14 +- .../lib/detection_engine/routes/utils.test.ts | 6 +- .../lib/detection_engine/routes/utils.ts | 19 +- .../get_bulk_rule_actions_saved_object.ts | 40 - .../lib/detection_engine/rules/types.ts | 6 + .../schemas/rule_converters.ts | 41 +- .../rule_status_saved_objects_client.mock.ts | 1 - .../rule_status_saved_objects_client.ts | 51 - .../threshold/find_threshold_signals.ts | 2 +- .../detection_engine/signals/utils.test.ts | 23 - .../lib/detection_engine/signals/utils.ts | 15 +- .../security_solution/server/plugin.ts | 111 +- .../security_solution/server/routes/index.ts | 23 +- .../factory/hosts/details/index.test.tsx | 1 - .../translations/translations/ja-JP.json | 136 ++ .../translations/translations/zh-CN.json | 136 ++ x-pack/test/accessibility/apps/lens.ts | 23 - .../tests/create_threat_matching.ts | 93 +- .../tests/generating_signals.ts | 583 ++----- x-pack/test/functional/apps/lens/table.ts | 51 - .../exports/_7.12_import_saved_objects.ndjson | 34 + .../exports/_7.13_import_saved_objects.ndjson | 72 - .../import_saved_objects_between_versions.ts | 10 +- .../endpoint/resolver/signals/mappings.json | 9 +- .../resolver/winlogbeat/mappings.json | 9 +- .../test/functional/page_objects/lens_page.ts | 55 +- .../test/functional/services/ml/navigation.ts | 9 - .../apps/ml/permissions/full_ml_access.ts | 7 +- .../security_and_spaces/tests/index.ts | 1 - .../tests/summary_exception_lists.ts | 98 -- .../apis/resolver/entity.ts | 3 +- yarn.lock | 31 +- 376 files changed, 6657 insertions(+), 15128 deletions(-) delete mode 100644 packages/kbn-io-ts-utils/BUILD.bazel delete mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts delete mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts delete mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts delete mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts delete mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts delete mode 100644 src/core/server/saved_objects/service/lib/aggregations/aggs_types/common_schemas.ts rename packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts => src/plugins/apm_oss/common/index_pattern_constants.ts (66%) rename {x-pack/plugins/apm => src/plugins/apm_oss}/public/assets/apm.png (100%) rename {x-pack/plugins/apm => src/plugins/apm_oss}/server/tutorial/envs/on_prem.ts (52%) create mode 100644 src/plugins/apm_oss/server/tutorial/index.ts rename {x-pack/plugins/apm => src/plugins/apm_oss}/server/tutorial/index_pattern.json (100%) create mode 100644 src/plugins/apm_oss/server/tutorial/instructions/apm_agent_instructions.ts rename {x-pack/plugins/apm => src/plugins/apm_oss}/server/tutorial/instructions/apm_server_instructions.ts (66%) delete mode 100644 src/plugins/charts/public/services/palettes/helpers.test.ts delete mode 100644 src/plugins/charts/public/services/palettes/helpers.ts rename x-pack/plugins/apm/server/tutorial/{envs => }/elastic_cloud.ts (94%) delete mode 100644 x-pack/plugins/apm/server/tutorial/index.ts delete mode 100644 x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts delete mode 100644 x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.test.tsx delete mode 100644 x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.tsx create mode 100644 x-pack/plugins/index_management/server/services/license.ts rename x-pack/plugins/{apm/common/index_pattern_constants.ts => ingest_pipelines/server/services/index.ts} (77%) create mode 100644 x-pack/plugins/ingest_pipelines/server/services/license.ts delete mode 100644 x-pack/plugins/lens/public/app_plugin/mounter.test.tsx create mode 100644 x-pack/plugins/lens/public/app_plugin/time_range.ts delete mode 100644 x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.scss delete mode 100644 x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.scss delete mode 100644 x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.tsx delete mode 100644 x-pack/plugins/lens/public/datatable_visualization/components/shared_utils.tsx delete mode 100644 x-pack/plugins/lens/public/shared_components/coloring/color_stops.test.tsx delete mode 100644 x-pack/plugins/lens/public/shared_components/coloring/color_stops.tsx delete mode 100644 x-pack/plugins/lens/public/shared_components/coloring/constants.ts delete mode 100644 x-pack/plugins/lens/public/shared_components/coloring/index.ts delete mode 100644 x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.scss delete mode 100644 x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.test.tsx delete mode 100644 x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.tsx delete mode 100644 x-pack/plugins/lens/public/shared_components/coloring/palette_picker.tsx delete mode 100644 x-pack/plugins/lens/public/shared_components/coloring/types.ts delete mode 100644 x-pack/plugins/lens/public/shared_components/coloring/utils.test.ts delete mode 100644 x-pack/plugins/lens/public/shared_components/coloring/utils.ts delete mode 100644 x-pack/plugins/lens/public/shared_components/helpers.ts delete mode 100644 x-pack/plugins/lens/public/state_management/app_slice.ts delete mode 100644 x-pack/plugins/lens/public/state_management/external_context_middleware.ts delete mode 100644 x-pack/plugins/lens/public/state_management/index.ts delete mode 100644 x-pack/plugins/lens/public/state_management/time_range_middleware.test.ts delete mode 100644 x-pack/plugins/lens/public/state_management/time_range_middleware.ts delete mode 100644 x-pack/plugins/lens/public/state_management/types.ts rename x-pack/plugins/lens/public/{shared_components => xy_visualization}/tooltip_wrapper.tsx (100%) delete mode 100644 x-pack/plugins/lists/server/routes/summary_exception_list_route.ts delete mode 100755 x-pack/plugins/lists/server/scripts/summary_exception_list.sh delete mode 100644 x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts rename x-pack/plugins/ml/public/{application/components => alerting}/severity_control/index.ts (100%) create mode 100644 x-pack/plugins/ml/public/alerting/severity_control/severity_control.tsx rename x-pack/plugins/ml/public/{application/components => alerting}/severity_control/styles.scss (100%) delete mode 100644 x-pack/plugins/ml/public/application/components/severity_control/severity_control.tsx delete mode 100644 x-pack/plugins/ml/public/application/management/jobs_list/components/insufficient_license_page.tsx delete mode 100644 x-pack/plugins/observability/public/components/shared/header_menu_portal.test.tsx delete mode 100644 x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_factory.ts delete mode 100644 x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts delete mode 100644 x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx delete mode 100644 x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx rename x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/{exception_items_summary.tsx => trusted_app_items_summary.tsx} (52%) delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/rule_type.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/threshold.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.test.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.test.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts delete mode 100755 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_eql.sh delete mode 100755 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_query.sh delete mode 100755 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_threshold.sh delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.test.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/get_bulk_rule_actions_saved_object.ts create mode 100644 x-pack/test/functional/apps/saved_objects_management/exports/_7.12_import_saved_objects.ndjson delete mode 100644 x-pack/test/functional/apps/saved_objects_management/exports/_7.13_import_saved_objects.ndjson delete mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/summary_exception_lists.ts diff --git a/api_docs/apm.json b/api_docs/apm.json index 7eee0349fa349ef..95cc86814e99a0a 100644 --- a/api_docs/apm.json +++ b/api_docs/apm.json @@ -309,7 +309,7 @@ ], "source": { "path": "x-pack/plugins/apm/server/plugin.ts", - "lineNumber": 269 + "lineNumber": 270 }, "deprecated": false, "children": [ @@ -331,7 +331,7 @@ ], "source": { "path": "x-pack/plugins/apm/server/plugin.ts", - "lineNumber": 269 + "lineNumber": 270 }, "deprecated": false, "isRequired": true @@ -351,7 +351,7 @@ ], "source": { "path": "x-pack/plugins/apm/server/plugin.ts", - "lineNumber": 288 + "lineNumber": 289 }, "deprecated": false, "children": [], @@ -653,13 +653,7 @@ ">; delete: (deleteParams: { id: string; }) => Promise<", "DeleteResponse", ">; } | undefined>; }; start: () => Promise; }; ruleRegistry: { setup: ", - { - "pluginId": "ruleRegistry", - "scope": "server", - "docId": "kibRuleRegistryPluginApi", - "section": "def-server.RuleRegistryPluginSetupContract", - "text": "RuleRegistryPluginSetupContract" - }, + "RuleDataPluginService", "; start: () => Promise; }; security?: { setup: ", { "pluginId": "security", diff --git a/api_docs/charts.json b/api_docs/charts.json index 29c1c163d19a037..d74e0209d6395e3 100644 --- a/api_docs/charts.json +++ b/api_docs/charts.json @@ -179,9 +179,7 @@ "type": "Array", "tags": [], "label": "xValues", - "description": [ - "sorted and unquie x values" - ], + "description": [], "signature": [ "number[]" ], @@ -419,9 +417,7 @@ "type": "Object", "tags": [], "label": "splitSeriesAccessorFnMap", - "description": [ - "needed when using `splitSeriesAccessors` as `AccessorFn`" - ], + "description": [], "signature": [ "Map; readonly filebeat: { readonly base: string; readonly installation: string; readonly configuration: string; readonly elasticsearchOutput: string; readonly elasticsearchModule: string; readonly startup: string; readonly exportedFields: string; }; readonly auditbeat: { readonly base: string; }; readonly metricbeat: { readonly base: string; readonly configure: string; readonly httpEndpoint: string; readonly install: string; readonly start: string; }; readonly enterpriseSearch: { readonly base: string; readonly appSearchBase: string; readonly workplaceSearchBase: string; }; readonly heartbeat: { readonly base: string; }; readonly logstash: { readonly base: string; }; readonly functionbeat: { readonly base: string; }; readonly winlogbeat: { readonly base: string; }; readonly aggs: { readonly composite: string; readonly composite_missing_bucket: string; readonly date_histogram: string; readonly date_range: string; readonly date_format_pattern: string; readonly filter: string; readonly filters: string; readonly geohash_grid: string; readonly histogram: string; readonly ip_range: string; readonly range: string; readonly significant_terms: string; readonly terms: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; readonly min_bucket: string; readonly sum_bucket: string; readonly cardinality: string; readonly count: string; readonly cumulative_sum: string; readonly derivative: string; readonly geo_bounds: string; readonly geo_centroid: string; readonly max: string; readonly median: string; readonly min: string; readonly moving_avg: string; readonly percentile_ranks: string; readonly serial_diff: string; readonly std_dev: string; readonly sum: string; readonly top_hits: string; }; readonly runtimeFields: { readonly overview: string; readonly mapping: string; }; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; readonly painless: string; readonly painlessApi: string; readonly painlessLangSpec: string; readonly painlessSyntax: string; readonly painlessWalkthrough: string; readonly luceneExpressions: string; }; readonly search: { readonly sessions: string; }; readonly indexPatterns: { readonly introduction: string; readonly fieldFormattersNumber: string; readonly fieldFormattersString: string; readonly runtimeFields: string; }; readonly addData: string; readonly kibana: string; readonly upgradeAssistant: string; readonly elasticsearch: Record; readonly siem: { readonly guide: string; readonly gettingStarted: string; }; readonly query: { readonly eql: string; readonly kueryQuerySyntax: string; readonly luceneQuerySyntax: string; readonly percolate: string; readonly queryDsl: string; }; readonly date: { readonly dateMath: string; readonly dateMathIndexNames: string; }; readonly management: Record; readonly ml: Record; readonly transforms: Record; readonly visualize: Record; readonly apis: Readonly<{ bulkIndexAlias: string; byteSizeUnits: string; createAutoFollowPattern: string; createFollower: string; createIndex: string; createSnapshotLifecyclePolicy: string; createRoleMapping: string; createRoleMappingTemplates: string; createRollupJobsRequest: string; createApiKey: string; createPipeline: string; createTransformRequest: string; cronExpressions: string; executeWatchActionModes: string; indexExists: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; painlessExecuteAPIContexts: string; putComponentTemplateMetadata: string; putSnapshotLifecyclePolicy: string; putIndexTemplateV1: string; putWatch: string; simulatePipeline: string; timeUnits: string; updateTransform: string; }>; readonly observability: Record; readonly alerting: Record; readonly maps: Record; readonly monitoring: Record; readonly security: Readonly<{ apiKeyServiceSettings: string; clusterPrivileges: string; elasticsearchSettings: string; elasticsearchEnableSecurity: string; indicesPrivileges: string; kibanaTLS: string; kibanaPrivileges: string; mappingRoles: string; mappingRolesFieldRules: string; runAsPrivilege: string; }>; readonly watcher: Record; readonly ccs: Record; readonly plugins: Record; readonly snapshotRestore: Record; readonly ingest: Record; }" + "{ readonly canvas: { readonly guide: string; }; readonly dashboard: { readonly guide: string; readonly drilldowns: string; readonly drilldownsTriggerPicker: string; readonly urlDrilldownTemplateSyntax: string; readonly urlDrilldownVariables: string; }; readonly discover: Record; readonly filebeat: { readonly base: string; readonly installation: string; readonly configuration: string; readonly elasticsearchOutput: string; readonly elasticsearchModule: string; readonly startup: string; readonly exportedFields: string; }; readonly auditbeat: { readonly base: string; }; readonly metricbeat: { readonly base: string; readonly configure: string; readonly httpEndpoint: string; readonly install: string; readonly start: string; }; readonly enterpriseSearch: { readonly base: string; readonly appSearchBase: string; readonly workplaceSearchBase: string; }; readonly heartbeat: { readonly base: string; }; readonly logstash: { readonly base: string; }; readonly functionbeat: { readonly base: string; }; readonly winlogbeat: { readonly base: string; }; readonly aggs: { readonly composite: string; readonly composite_missing_bucket: string; readonly date_histogram: string; readonly date_range: string; readonly date_format_pattern: string; readonly filter: string; readonly filters: string; readonly geohash_grid: string; readonly histogram: string; readonly ip_range: string; readonly range: string; readonly significant_terms: string; readonly terms: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; readonly min_bucket: string; readonly sum_bucket: string; readonly cardinality: string; readonly count: string; readonly cumulative_sum: string; readonly derivative: string; readonly geo_bounds: string; readonly geo_centroid: string; readonly max: string; readonly median: string; readonly min: string; readonly moving_avg: string; readonly percentile_ranks: string; readonly serial_diff: string; readonly std_dev: string; readonly sum: string; readonly top_hits: string; }; readonly runtimeFields: { readonly overview: string; readonly mapping: string; }; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; readonly painless: string; readonly painlessApi: string; readonly painlessLangSpec: string; readonly painlessSyntax: string; readonly painlessWalkthrough: string; readonly luceneExpressions: string; }; readonly search: { readonly sessions: string; }; readonly indexPatterns: { readonly introduction: string; readonly fieldFormattersNumber: string; readonly fieldFormattersString: string; }; readonly addData: string; readonly kibana: string; readonly upgradeAssistant: string; readonly elasticsearch: Record; readonly siem: { readonly guide: string; readonly gettingStarted: string; }; readonly query: { readonly eql: string; readonly kueryQuerySyntax: string; readonly luceneQuerySyntax: string; readonly percolate: string; readonly queryDsl: string; }; readonly date: { readonly dateMath: string; readonly dateMathIndexNames: string; }; readonly management: Record; readonly ml: Record; readonly transforms: Record; readonly visualize: Record; readonly apis: Readonly<{ bulkIndexAlias: string; byteSizeUnits: string; createAutoFollowPattern: string; createFollower: string; createIndex: string; createSnapshotLifecyclePolicy: string; createRoleMapping: string; createRoleMappingTemplates: string; createRollupJobsRequest: string; createApiKey: string; createPipeline: string; createTransformRequest: string; cronExpressions: string; executeWatchActionModes: string; indexExists: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; painlessExecuteAPIContexts: string; putComponentTemplateMetadata: string; putSnapshotLifecyclePolicy: string; putIndexTemplateV1: string; putWatch: string; simulatePipeline: string; timeUnits: string; updateTransform: string; }>; readonly observability: Record; readonly alerting: Record; readonly maps: Record; readonly monitoring: Record; readonly security: Readonly<{ apiKeyServiceSettings: string; clusterPrivileges: string; elasticsearchSettings: string; elasticsearchEnableSecurity: string; indicesPrivileges: string; kibanaTLS: string; kibanaPrivileges: string; mappingRoles: string; mappingRolesFieldRules: string; runAsPrivilege: string; }>; readonly watcher: Record; readonly ccs: Record; readonly plugins: Record; readonly snapshotRestore: Record; readonly ingest: Record; }" ], "source": { "path": "src/core/public/doc_links/doc_links_service.ts", - "lineNumber": 412 + "lineNumber": 411 }, "deprecated": false } @@ -8748,9 +8748,7 @@ "type": "string", "tags": [], "label": "endpoint", - "description": [ - "- String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`." - ], + "description": [], "signature": [ "string" ], @@ -8767,9 +8765,7 @@ "type": "Object", "tags": [], "label": "clientParams", - "description": [ - "- A dictionary of parameters that will be passed directly to the Elasticsearch JS client." - ], + "description": [], "signature": [ "Record" ], @@ -8786,9 +8782,7 @@ "type": "Object", "tags": [], "label": "options", - "description": [ - "- Options that affect the way we call the API and process the result." - ], + "description": [], "signature": [ { "pluginId": "core", @@ -10809,7 +10803,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 96 + "lineNumber": 87 }, "deprecated": false, "children": [ @@ -10830,7 +10824,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 109 + "lineNumber": 100 }, "deprecated": false, "children": [ @@ -10846,7 +10840,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 109 + "lineNumber": 100 }, "deprecated": false, "isRequired": true @@ -10863,7 +10857,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 109 + "lineNumber": 100 }, "deprecated": false, "isRequired": true @@ -10882,7 +10876,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 109 + "lineNumber": 100 }, "deprecated": false, "isRequired": false @@ -10907,7 +10901,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 125 + "lineNumber": 116 }, "deprecated": false, "children": [ @@ -10923,7 +10917,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 125 + "lineNumber": 116 }, "deprecated": false, "isRequired": true @@ -10940,7 +10934,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 125 + "lineNumber": 116 }, "deprecated": false, "isRequired": true @@ -10959,7 +10953,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 125 + "lineNumber": 116 }, "deprecated": false, "isRequired": false @@ -10984,7 +10978,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 138 + "lineNumber": 129 }, "deprecated": false, "children": [ @@ -11000,7 +10994,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 138 + "lineNumber": 129 }, "deprecated": false, "isRequired": true @@ -11019,7 +11013,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 138 + "lineNumber": 129 }, "deprecated": false, "isRequired": false @@ -11044,7 +11038,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 154 + "lineNumber": 145 }, "deprecated": false, "children": [ @@ -11060,7 +11054,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 154 + "lineNumber": 145 }, "deprecated": false, "isRequired": true @@ -11079,7 +11073,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 154 + "lineNumber": 145 }, "deprecated": false, "isRequired": false @@ -19550,7 +19544,7 @@ "The os platform" ], "signature": [ - "\"linux\" | \"aix\" | \"android\" | \"darwin\" | \"freebsd\" | \"openbsd\" | \"sunos\" | \"win32\" | \"cygwin\" | \"netbsd\"" + "\"linux\" | \"aix\" | \"android\" | \"darwin\" | \"freebsd\" | \"openbsd\" | \"sunos\" | \"win32\" | \"cygwin\"" ], "source": { "path": "src/core/server/metrics/collectors/types.ts", @@ -22321,7 +22315,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 79 + "lineNumber": 70 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/core_application.json b/api_docs/core_application.json index e890b6f92a2ad67..13b110900ab5308 100644 --- a/api_docs/core_application.json +++ b/api_docs/core_application.json @@ -115,9 +115,7 @@ "type": "string", "tags": [], "label": "basePath", - "description": [ - "the URL path scope for the sub history" - ], + "description": [], "signature": [ "string" ], @@ -209,9 +207,7 @@ "type": "CompoundType", "tags": [], "label": "pathOrLocation", - "description": [ - "a string or location descriptor" - ], + "description": [], "signature": [ "string | ", "LocationDescriptorObject", @@ -270,9 +266,7 @@ "type": "CompoundType", "tags": [], "label": "pathOrLocation", - "description": [ - "a string or location descriptor" - ], + "description": [], "signature": [ "string | ", "LocationDescriptorObject", @@ -329,9 +323,7 @@ "type": "number", "tags": [], "label": "n", - "description": [ - "number of positions in the stack to go. Negative numbers indicate number of entries backward, positive\nnumbers for forwards. If passed 0, the current location will be reloaded. If `n` exceeds the number of\nentries available, this is a no-op." - ], + "description": [], "signature": [ "number" ], @@ -457,9 +449,7 @@ "type": "Function", "tags": [], "label": "listener", - "description": [ - "a function that receives location updates." - ], + "description": [], "signature": [ "(location: ", "Location", diff --git a/api_docs/core_saved_objects.json b/api_docs/core_saved_objects.json index adf0612a28faf87..f18d9d7cf127729 100644 --- a/api_docs/core_saved_objects.json +++ b/api_docs/core_saved_objects.json @@ -161,9 +161,7 @@ "type": "Array", "tags": [], "label": "objects", - "description": [ - "- [{ type, id, attributes, references, migrationVersion }]" - ], + "description": [], "signature": [ { "pluginId": "core", @@ -453,9 +451,7 @@ "type": "Array", "tags": [], "label": "objects", - "description": [ - "- an array ids, or an array of objects containing id and optionally type" - ], + "description": [], "signature": [ "{ id: string; type: string; }[]" ], @@ -9366,9 +9362,7 @@ "type": "string", "tags": [], "label": "namespace", - "description": [ - "The namespace ID, which must be either a non-empty string or `undefined`." - ], + "description": [], "signature": [ "string | undefined" ], @@ -9406,9 +9400,7 @@ "type": "string", "tags": [], "label": "namespace", - "description": [ - "The namespace string, which must be non-empty." - ], + "description": [], "signature": [ "string" ], diff --git a/api_docs/data.json b/api_docs/data.json index 1ba62ea99465498..ab5196934d855b5 100644 --- a/api_docs/data.json +++ b/api_docs/data.json @@ -5610,9 +5610,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -5650,9 +5648,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -5755,9 +5751,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -5795,9 +5789,7 @@ "type": "string", "tags": [], "label": "id", - "description": [ - "optionally clear a single id" - ], + "description": [], "signature": [ "string | undefined" ], @@ -5861,26 +5853,6 @@ "children": [], "returnComment": [] }, - { - "parentPluginId": "data", - "id": "def-public.IndexPatternsService.getDefaultId", - "type": "Function", - "tags": [], - "label": "getDefaultId", - "description": [ - "\nGet default index pattern id" - ], - "signature": [ - "() => Promise" - ], - "source": { - "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 206 - }, - "deprecated": false, - "children": [], - "returnComment": [] - }, { "parentPluginId": "data", "id": "def-public.IndexPatternsService.setDefault", @@ -5891,30 +5863,30 @@ "\nOptionally set default index pattern, unless force = true" ], "signature": [ - "(id: string | null, force?: boolean) => Promise" + "(id: string, force?: boolean) => Promise" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, "children": [ { "parentPluginId": "data", "id": "def-public.IndexPatternsService.setDefault.$1", - "type": "CompoundType", + "type": "string", "tags": [], "label": "id", "description": [], "signature": [ - "string | null" + "string" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, - "isRequired": false + "isRequired": true }, { "parentPluginId": "data", @@ -5928,7 +5900,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, "isRequired": true @@ -5958,7 +5930,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 227 + "lineNumber": 219 }, "deprecated": false, "children": [ @@ -5980,7 +5952,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 227 + "lineNumber": 219 }, "deprecated": false, "isRequired": true @@ -6028,7 +6000,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 243 + "lineNumber": 235 }, "deprecated": false, "children": [ @@ -6058,7 +6030,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 244 + "lineNumber": 236 }, "deprecated": false, "isRequired": true @@ -6082,7 +6054,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 245 + "lineNumber": 237 }, "deprecated": false, "isRequired": false @@ -6114,7 +6086,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 258 + "lineNumber": 250 }, "deprecated": false, "children": [ @@ -6136,7 +6108,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 258 + "lineNumber": 250 }, "deprecated": false, "isRequired": true @@ -6182,7 +6154,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "children": [ @@ -6192,9 +6164,7 @@ "type": "Array", "tags": [], "label": "fields", - "description": [ - ": FieldSpec[]" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -6207,7 +6177,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "isRequired": true @@ -6218,9 +6188,7 @@ "type": "Object", "tags": [], "label": "fieldAttrs", - "description": [ - ": FieldAttrs" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -6233,7 +6201,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "isRequired": false @@ -6274,7 +6242,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 351 + "lineNumber": 343 }, "deprecated": false, "children": [ @@ -6299,7 +6267,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 351 + "lineNumber": 343 }, "deprecated": false, "isRequired": true @@ -6331,7 +6299,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 473 + "lineNumber": 465 }, "deprecated": false, "children": [ @@ -6347,7 +6315,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 473 + "lineNumber": 465 }, "deprecated": false, "isRequired": true @@ -6385,7 +6353,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "children": [ @@ -6407,7 +6375,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "isRequired": true @@ -6424,7 +6392,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "isRequired": true @@ -6464,7 +6432,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "children": [ @@ -6486,7 +6454,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -6505,7 +6473,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -6524,7 +6492,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -6562,7 +6530,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "children": [ @@ -6584,7 +6552,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "isRequired": true @@ -6603,7 +6571,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "isRequired": true @@ -6633,7 +6601,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 558 + "lineNumber": 550 }, "deprecated": false, "children": [ @@ -6655,7 +6623,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 559 + "lineNumber": 551 }, "deprecated": false, "isRequired": true @@ -6672,7 +6640,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 560 + "lineNumber": 552 }, "deprecated": false, "isRequired": true @@ -6689,7 +6657,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 561 + "lineNumber": 553 }, "deprecated": false, "isRequired": true @@ -6711,7 +6679,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 644 + "lineNumber": 636 }, "deprecated": false, "children": [ @@ -6729,7 +6697,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 644 + "lineNumber": 636 }, "deprecated": false, "isRequired": true @@ -7649,7 +7617,7 @@ "plugin": "maps", "link": { "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 273 + "lineNumber": 266 } }, { @@ -8547,7 +8515,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 104 + "lineNumber": 103 }, "deprecated": false, "children": [ @@ -8563,7 +8531,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 104 + "lineNumber": 103 }, "deprecated": false, "isRequired": true @@ -8592,7 +8560,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 111 + "lineNumber": 110 }, "deprecated": false, "children": [ @@ -8608,7 +8576,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 111 + "lineNumber": 110 }, "deprecated": false, "isRequired": true @@ -10844,22 +10812,6 @@ "lineNumber": 23 }, "deprecated": false - }, - { - "parentPluginId": "data", - "id": "def-public.ApplyGlobalFilterActionContext.controlledBy", - "type": "string", - "tags": [], - "label": "controlledBy", - "description": [], - "signature": [ - "string | undefined" - ], - "source": { - "path": "src/plugins/data/public/actions/apply_filter_action.ts", - "lineNumber": 26 - }, - "deprecated": false } ], "initialIsOpen": false @@ -11537,29 +11489,29 @@ { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 12 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 10 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 45 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 360 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 10 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 12 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 367 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 45 } }, { @@ -14932,21 +14884,21 @@ "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 44 + "lineNumber": 40 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 60 + "lineNumber": 55 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 65 + "lineNumber": 60 } }, { @@ -15961,7 +15913,7 @@ "plugin": "maps", "link": { "path": "x-pack/plugins/maps/public/embeddable/types.ts", - "lineNumber": 45 + "lineNumber": 44 } }, { @@ -19747,7 +19699,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 42 + "lineNumber": 41 }, "deprecated": false, "initialIsOpen": false @@ -20233,7 +20185,7 @@ "section": "def-common.IndexPattern", "text": "IndexPattern" }, - " | null>; getDefaultId: () => Promise; setDefault: (id: string | null, force?: boolean) => Promise; getFieldsForWildcard: (options: ", + " | null>; setDefault: (id: string, force?: boolean) => Promise; getFieldsForWildcard: (options: ", { "pluginId": "data", "scope": "common", @@ -20359,7 +20311,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 650 + "lineNumber": 642 }, "deprecated": false, "initialIsOpen": false @@ -21103,7 +21055,7 @@ "description": [], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 53 + "lineNumber": 52 }, "deprecated": false }, @@ -21119,7 +21071,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 53 + "lineNumber": 52 }, "deprecated": false } @@ -21962,7 +21914,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 67 + "lineNumber": 66 }, "deprecated": false } @@ -21984,7 +21936,7 @@ "section": "def-common.Filter", "text": "Filter" }, - ") => { meta: { negate: boolean; alias: string | null; disabled: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", + ") => { meta: { negate: boolean; alias: string | null; disabled: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", { "pluginId": "data", "scope": "common", @@ -22029,7 +21981,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 78 + "lineNumber": 77 }, "deprecated": false } @@ -22095,7 +22047,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 95 + "lineNumber": 94 }, "deprecated": false } @@ -26143,7 +26095,7 @@ "section": "def-common.IndexPattern", "text": "IndexPattern" }, - " | null>; getDefaultId: () => Promise; setDefault: (id: string | null, force?: boolean) => Promise; getFieldsForWildcard: (options: ", + " | null>; setDefault: (id: string, force?: boolean) => Promise; getFieldsForWildcard: (options: ", { "pluginId": "data", "scope": "common", @@ -28478,9 +28430,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -28518,9 +28468,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -28623,9 +28571,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -28663,9 +28609,7 @@ "type": "string", "tags": [], "label": "id", - "description": [ - "optionally clear a single id" - ], + "description": [], "signature": [ "string | undefined" ], @@ -28729,26 +28673,6 @@ "children": [], "returnComment": [] }, - { - "parentPluginId": "data", - "id": "def-server.IndexPatternsService.getDefaultId", - "type": "Function", - "tags": [], - "label": "getDefaultId", - "description": [ - "\nGet default index pattern id" - ], - "signature": [ - "() => Promise" - ], - "source": { - "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 206 - }, - "deprecated": false, - "children": [], - "returnComment": [] - }, { "parentPluginId": "data", "id": "def-server.IndexPatternsService.setDefault", @@ -28759,30 +28683,30 @@ "\nOptionally set default index pattern, unless force = true" ], "signature": [ - "(id: string | null, force?: boolean) => Promise" + "(id: string, force?: boolean) => Promise" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, "children": [ { "parentPluginId": "data", "id": "def-server.IndexPatternsService.setDefault.$1", - "type": "CompoundType", + "type": "string", "tags": [], "label": "id", "description": [], "signature": [ - "string | null" + "string" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, - "isRequired": false + "isRequired": true }, { "parentPluginId": "data", @@ -28796,7 +28720,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, "isRequired": true @@ -28826,7 +28750,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 227 + "lineNumber": 219 }, "deprecated": false, "children": [ @@ -28848,7 +28772,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 227 + "lineNumber": 219 }, "deprecated": false, "isRequired": true @@ -28896,7 +28820,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 243 + "lineNumber": 235 }, "deprecated": false, "children": [ @@ -28926,7 +28850,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 244 + "lineNumber": 236 }, "deprecated": false, "isRequired": true @@ -28950,7 +28874,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 245 + "lineNumber": 237 }, "deprecated": false, "isRequired": false @@ -28982,7 +28906,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 258 + "lineNumber": 250 }, "deprecated": false, "children": [ @@ -29004,7 +28928,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 258 + "lineNumber": 250 }, "deprecated": false, "isRequired": true @@ -29050,7 +28974,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "children": [ @@ -29060,9 +28984,7 @@ "type": "Array", "tags": [], "label": "fields", - "description": [ - ": FieldSpec[]" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -29075,7 +28997,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "isRequired": true @@ -29086,9 +29008,7 @@ "type": "Object", "tags": [], "label": "fieldAttrs", - "description": [ - ": FieldAttrs" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -29101,7 +29021,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "isRequired": false @@ -29142,7 +29062,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 351 + "lineNumber": 343 }, "deprecated": false, "children": [ @@ -29167,7 +29087,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 351 + "lineNumber": 343 }, "deprecated": false, "isRequired": true @@ -29199,7 +29119,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 473 + "lineNumber": 465 }, "deprecated": false, "children": [ @@ -29215,7 +29135,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 473 + "lineNumber": 465 }, "deprecated": false, "isRequired": true @@ -29253,7 +29173,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "children": [ @@ -29275,7 +29195,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "isRequired": true @@ -29292,7 +29212,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "isRequired": true @@ -29332,7 +29252,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "children": [ @@ -29354,7 +29274,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -29373,7 +29293,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -29392,7 +29312,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -29430,7 +29350,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "children": [ @@ -29452,7 +29372,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "isRequired": true @@ -29471,7 +29391,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "isRequired": true @@ -29501,7 +29421,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 558 + "lineNumber": 550 }, "deprecated": false, "children": [ @@ -29523,7 +29443,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 559 + "lineNumber": 551 }, "deprecated": false, "isRequired": true @@ -29540,7 +29460,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 560 + "lineNumber": 552 }, "deprecated": false, "isRequired": true @@ -29557,7 +29477,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 561 + "lineNumber": 553 }, "deprecated": false, "isRequired": true @@ -29579,7 +29499,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 644 + "lineNumber": 636 }, "deprecated": false, "children": [ @@ -29597,7 +29517,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 644 + "lineNumber": 636 }, "deprecated": false, "isRequired": true @@ -29699,9 +29619,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -29739,9 +29657,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -29844,9 +29760,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -29884,9 +29798,7 @@ "type": "string", "tags": [], "label": "id", - "description": [ - "optionally clear a single id" - ], + "description": [], "signature": [ "string | undefined" ], @@ -29950,26 +29862,6 @@ "children": [], "returnComment": [] }, - { - "parentPluginId": "data", - "id": "def-server.IndexPatternsService.getDefaultId", - "type": "Function", - "tags": [], - "label": "getDefaultId", - "description": [ - "\nGet default index pattern id" - ], - "signature": [ - "() => Promise" - ], - "source": { - "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 206 - }, - "deprecated": false, - "children": [], - "returnComment": [] - }, { "parentPluginId": "data", "id": "def-server.IndexPatternsService.setDefault", @@ -29980,30 +29872,30 @@ "\nOptionally set default index pattern, unless force = true" ], "signature": [ - "(id: string | null, force?: boolean) => Promise" + "(id: string, force?: boolean) => Promise" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, "children": [ { "parentPluginId": "data", "id": "def-server.IndexPatternsService.setDefault.$1", - "type": "CompoundType", + "type": "string", "tags": [], "label": "id", "description": [], "signature": [ - "string | null" + "string" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, - "isRequired": false + "isRequired": true }, { "parentPluginId": "data", @@ -30017,7 +29909,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, "isRequired": true @@ -30047,7 +29939,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 227 + "lineNumber": 219 }, "deprecated": false, "children": [ @@ -30069,7 +29961,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 227 + "lineNumber": 219 }, "deprecated": false, "isRequired": true @@ -30117,7 +30009,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 243 + "lineNumber": 235 }, "deprecated": false, "children": [ @@ -30147,7 +30039,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 244 + "lineNumber": 236 }, "deprecated": false, "isRequired": true @@ -30171,7 +30063,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 245 + "lineNumber": 237 }, "deprecated": false, "isRequired": false @@ -30203,7 +30095,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 258 + "lineNumber": 250 }, "deprecated": false, "children": [ @@ -30225,7 +30117,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 258 + "lineNumber": 250 }, "deprecated": false, "isRequired": true @@ -30271,7 +30163,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "children": [ @@ -30281,9 +30173,7 @@ "type": "Array", "tags": [], "label": "fields", - "description": [ - ": FieldSpec[]" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -30296,7 +30186,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "isRequired": true @@ -30307,9 +30197,7 @@ "type": "Object", "tags": [], "label": "fieldAttrs", - "description": [ - ": FieldAttrs" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -30322,7 +30210,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "isRequired": false @@ -30363,7 +30251,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 351 + "lineNumber": 343 }, "deprecated": false, "children": [ @@ -30388,7 +30276,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 351 + "lineNumber": 343 }, "deprecated": false, "isRequired": true @@ -30420,7 +30308,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 473 + "lineNumber": 465 }, "deprecated": false, "children": [ @@ -30436,7 +30324,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 473 + "lineNumber": 465 }, "deprecated": false, "isRequired": true @@ -30474,7 +30362,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "children": [ @@ -30496,7 +30384,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "isRequired": true @@ -30513,7 +30401,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "isRequired": true @@ -30553,7 +30441,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "children": [ @@ -30575,7 +30463,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -30594,7 +30482,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -30613,7 +30501,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -30651,7 +30539,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "children": [ @@ -30673,7 +30561,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "isRequired": true @@ -30692,7 +30580,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "isRequired": true @@ -30722,7 +30610,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 558 + "lineNumber": 550 }, "deprecated": false, "children": [ @@ -30744,7 +30632,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 559 + "lineNumber": 551 }, "deprecated": false, "isRequired": true @@ -30761,7 +30649,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 560 + "lineNumber": 552 }, "deprecated": false, "isRequired": true @@ -30778,7 +30666,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 561 + "lineNumber": 553 }, "deprecated": false, "isRequired": true @@ -30800,7 +30688,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 644 + "lineNumber": 636 }, "deprecated": false, "children": [ @@ -30818,7 +30706,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 644 + "lineNumber": 636 }, "deprecated": false, "isRequired": true @@ -33409,29 +33297,29 @@ { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 12 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 10 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 45 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 360 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 10 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 12 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 367 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 45 } }, { @@ -36962,7 +36850,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 42 + "lineNumber": 41 }, "deprecated": false, "initialIsOpen": false @@ -37763,7 +37651,7 @@ "description": [], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 53 + "lineNumber": 52 }, "deprecated": false }, @@ -37779,7 +37667,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 53 + "lineNumber": 52 }, "deprecated": false } @@ -40998,7 +40886,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 53 + "lineNumber": 52 }, "deprecated": false, "children": [ @@ -41014,7 +40902,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 53 + "lineNumber": 52 }, "deprecated": false, "isRequired": true @@ -41031,7 +40919,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 53 + "lineNumber": 52 }, "deprecated": false, "isRequired": false @@ -42189,9 +42077,7 @@ "type": "Object", "tags": [], "label": "filter", - "description": [ - "The filter to clean" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -42407,7 +42293,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 95 + "lineNumber": 94 }, "deprecated": false, "children": [ @@ -42429,7 +42315,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 95 + "lineNumber": 94 }, "deprecated": false, "isRequired": true @@ -42465,7 +42351,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 92 + "lineNumber": 91 }, "deprecated": false, "children": [ @@ -42487,7 +42373,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 92 + "lineNumber": 91 }, "deprecated": false, "isRequired": true @@ -43685,7 +43571,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 104 + "lineNumber": 103 }, "deprecated": false, "children": [ @@ -43701,7 +43587,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 104 + "lineNumber": 103 }, "deprecated": false, "isRequired": true @@ -43781,7 +43667,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 67 + "lineNumber": 66 }, "deprecated": false, "children": [ @@ -43803,7 +43689,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 67 + "lineNumber": 66 }, "deprecated": false, "isRequired": true @@ -43832,7 +43718,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 111 + "lineNumber": 110 }, "deprecated": false, "children": [ @@ -43848,7 +43734,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 111 + "lineNumber": 110 }, "deprecated": false, "isRequired": true @@ -44368,7 +44254,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 98 + "lineNumber": 97 }, "deprecated": false, "children": [ @@ -44390,7 +44276,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 98 + "lineNumber": 97 }, "deprecated": false, "isRequired": true @@ -44583,7 +44469,7 @@ "section": "def-common.Filter", "text": "Filter" }, - ") => { meta: { disabled: boolean; alias: string | null; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", + ") => { meta: { disabled: boolean; alias: string | null; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", { "pluginId": "data", "scope": "common", @@ -44595,7 +44481,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 71 + "lineNumber": 70 }, "deprecated": false, "children": [ @@ -44617,7 +44503,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 71 + "lineNumber": 70 }, "deprecated": false, "isRequired": true @@ -44642,7 +44528,7 @@ "section": "def-common.Filter", "text": "Filter" }, - ") => { meta: { negate: boolean; alias: string | null; disabled: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", + ") => { meta: { negate: boolean; alias: string | null; disabled: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", { "pluginId": "data", "scope": "common", @@ -44654,7 +44540,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 78 + "lineNumber": 77 }, "deprecated": false, "children": [ @@ -44676,7 +44562,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 78 + "lineNumber": 77 }, "deprecated": false, "isRequired": true @@ -44721,7 +44607,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 85 + "lineNumber": 84 }, "deprecated": false, "children": [ @@ -44743,7 +44629,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 85 + "lineNumber": 84 }, "deprecated": false, "isRequired": true @@ -44779,7 +44665,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 101 + "lineNumber": 100 }, "deprecated": false, "children": [ @@ -44801,7 +44687,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 101 + "lineNumber": 100 }, "deprecated": false, "isRequired": true @@ -45266,7 +45152,7 @@ "description": [], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 48 + "lineNumber": 47 }, "deprecated": false, "children": [ @@ -45279,7 +45165,7 @@ "description": [], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 49 + "lineNumber": 48 }, "deprecated": false }, @@ -45292,7 +45178,7 @@ "description": [], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 50 + "lineNumber": 49 }, "deprecated": false } @@ -45885,7 +45771,7 @@ "label": "ExistsFilterMeta", "description": [], "signature": [ - "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" + "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" ], "source": { "path": "src/plugins/data/common/es_query/filters/exists_filter.ts", @@ -46001,7 +45887,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 42 + "lineNumber": 41 }, "deprecated": false, "initialIsOpen": false @@ -46014,7 +45900,7 @@ "label": "FilterMeta", "description": [], "signature": [ - "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" + "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", @@ -46292,7 +46178,7 @@ "label": "MissingFilterMeta", "description": [], "signature": [ - "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" + "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" ], "source": { "path": "src/plugins/data/common/es_query/filters/missing_filter.ts", @@ -46453,7 +46339,7 @@ "label": "QueryStringFilterMeta", "description": [], "signature": [ - "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" + "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" ], "source": { "path": "src/plugins/data/common/es_query/filters/query_string_filter.ts", diff --git a/api_docs/data_field_formats.json b/api_docs/data_field_formats.json index 1807c32a18389dc..6fe1b64bd555bba 100644 --- a/api_docs/data_field_formats.json +++ b/api_docs/data_field_formats.json @@ -1687,9 +1687,7 @@ "type": "Enum", "tags": [], "label": "fieldType", - "description": [ - "- the field type" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -1712,9 +1710,7 @@ "type": "Array", "tags": [], "label": "esTypes", - "description": [ - "- Array of ES data types" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -1763,9 +1759,7 @@ "type": "string", "tags": [], "label": "formatId", - "description": [ - "- the format id" - ], + "description": [], "signature": [ "string" ], @@ -1884,9 +1878,7 @@ "type": "Array", "tags": [], "label": "esTypes", - "description": [ - "- Array of ES data types" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -1949,9 +1941,7 @@ "type": "Array", "tags": [], "label": "esTypes", - "description": [ - "- Array of ES data types" - ], + "description": [], "signature": [ { "pluginId": "data", diff --git a/api_docs/data_index_patterns.json b/api_docs/data_index_patterns.json index 676ded76cb331be..6d9230cfb6a877d 100644 --- a/api_docs/data_index_patterns.json +++ b/api_docs/data_index_patterns.json @@ -3291,9 +3291,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -3331,9 +3329,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -3436,9 +3432,7 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [ - "Force refresh of index pattern list" - ], + "description": [], "signature": [ "boolean" ], @@ -3476,9 +3470,7 @@ "type": "string", "tags": [], "label": "id", - "description": [ - "optionally clear a single id" - ], + "description": [], "signature": [ "string | undefined" ], @@ -3542,26 +3534,6 @@ "children": [], "returnComment": [] }, - { - "parentPluginId": "data", - "id": "def-common.IndexPatternsService.getDefaultId", - "type": "Function", - "tags": [], - "label": "getDefaultId", - "description": [ - "\nGet default index pattern id" - ], - "signature": [ - "() => Promise" - ], - "source": { - "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 206 - }, - "deprecated": false, - "children": [], - "returnComment": [] - }, { "parentPluginId": "data", "id": "def-common.IndexPatternsService.setDefault", @@ -3572,30 +3544,30 @@ "\nOptionally set default index pattern, unless force = true" ], "signature": [ - "(id: string | null, force?: boolean) => Promise" + "(id: string, force?: boolean) => Promise" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, "children": [ { "parentPluginId": "data", "id": "def-common.IndexPatternsService.setDefault.$1", - "type": "CompoundType", + "type": "string", "tags": [], "label": "id", "description": [], "signature": [ - "string | null" + "string" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, - "isRequired": false + "isRequired": true }, { "parentPluginId": "data", @@ -3609,7 +3581,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 216 + "lineNumber": 208 }, "deprecated": false, "isRequired": true @@ -3639,7 +3611,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 227 + "lineNumber": 219 }, "deprecated": false, "children": [ @@ -3661,7 +3633,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 227 + "lineNumber": 219 }, "deprecated": false, "isRequired": true @@ -3709,7 +3681,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 243 + "lineNumber": 235 }, "deprecated": false, "children": [ @@ -3739,7 +3711,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 244 + "lineNumber": 236 }, "deprecated": false, "isRequired": true @@ -3763,7 +3735,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 245 + "lineNumber": 237 }, "deprecated": false, "isRequired": false @@ -3795,7 +3767,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 258 + "lineNumber": 250 }, "deprecated": false, "children": [ @@ -3817,7 +3789,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 258 + "lineNumber": 250 }, "deprecated": false, "isRequired": true @@ -3863,7 +3835,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "children": [ @@ -3873,9 +3845,7 @@ "type": "Array", "tags": [], "label": "fields", - "description": [ - ": FieldSpec[]" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -3888,7 +3858,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "isRequired": true @@ -3899,9 +3869,7 @@ "type": "Object", "tags": [], "label": "fieldAttrs", - "description": [ - ": FieldAttrs" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -3914,7 +3882,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 335 + "lineNumber": 327 }, "deprecated": false, "isRequired": false @@ -3955,7 +3923,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 351 + "lineNumber": 343 }, "deprecated": false, "children": [ @@ -3980,7 +3948,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 351 + "lineNumber": 343 }, "deprecated": false, "isRequired": true @@ -4012,7 +3980,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 473 + "lineNumber": 465 }, "deprecated": false, "children": [ @@ -4028,7 +3996,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 473 + "lineNumber": 465 }, "deprecated": false, "isRequired": true @@ -4066,7 +4034,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "children": [ @@ -4088,7 +4056,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "isRequired": true @@ -4105,7 +4073,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 492 + "lineNumber": 484 }, "deprecated": false, "isRequired": true @@ -4145,7 +4113,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "children": [ @@ -4167,7 +4135,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -4186,7 +4154,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -4205,7 +4173,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 517 + "lineNumber": 509 }, "deprecated": false, "isRequired": true @@ -4243,7 +4211,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "children": [ @@ -4265,7 +4233,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "isRequired": true @@ -4284,7 +4252,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 530 + "lineNumber": 522 }, "deprecated": false, "isRequired": true @@ -4314,7 +4282,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 558 + "lineNumber": 550 }, "deprecated": false, "children": [ @@ -4336,7 +4304,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 559 + "lineNumber": 551 }, "deprecated": false, "isRequired": true @@ -4353,7 +4321,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 560 + "lineNumber": 552 }, "deprecated": false, "isRequired": true @@ -4370,7 +4338,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 561 + "lineNumber": 553 }, "deprecated": false, "isRequired": true @@ -4392,7 +4360,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 644 + "lineNumber": 636 }, "deprecated": false, "children": [ @@ -4410,7 +4378,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 644 + "lineNumber": 636 }, "deprecated": false, "isRequired": true @@ -5548,29 +5516,29 @@ { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 12 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 10 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 45 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 360 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 10 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 12 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 367 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 45 } }, { @@ -8943,21 +8911,21 @@ "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 44 + "lineNumber": 40 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 60 + "lineNumber": 55 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 65 + "lineNumber": 60 } }, { @@ -9972,7 +9940,7 @@ "plugin": "maps", "link": { "path": "x-pack/plugins/maps/public/embeddable/types.ts", - "lineNumber": 45 + "lineNumber": 44 } }, { @@ -12531,7 +12499,7 @@ "section": "def-common.IndexPattern", "text": "IndexPattern" }, - " | null>; getDefaultId: () => Promise; setDefault: (id: string | null, force?: boolean) => Promise; getFieldsForWildcard: (options: ", + " | null>; setDefault: (id: string, force?: boolean) => Promise; getFieldsForWildcard: (options: ", { "pluginId": "data", "scope": "common", @@ -12657,7 +12625,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 650 + "lineNumber": 642 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/data_query.json b/api_docs/data_query.json index a9c171113695105..3e28da259b5e2f1 100644 --- a/api_docs/data_query.json +++ b/api_docs/data_query.json @@ -1056,9 +1056,7 @@ "type": "Object", "tags": [], "label": "stateContainer", - "description": [ - "to use for syncing" - ], + "description": [], "signature": [ { "pluginId": "kibanaUtils", @@ -1549,9 +1547,7 @@ "type": "Object", "tags": [], "label": "kbnUrlStateStorage", - "description": [ - "to use for syncing" - ], + "description": [], "signature": [ { "pluginId": "kibanaUtils", @@ -2567,9 +2563,7 @@ "type": "CompoundType", "tags": [], "label": "first", - "description": [ - "The first filter or filter array to compare" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -2601,9 +2595,7 @@ "type": "CompoundType", "tags": [], "label": "second", - "description": [ - "The second filter or filter array to compare" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -2635,9 +2627,7 @@ "type": "Object", "tags": [], "label": "comparatorOptions", - "description": [ - "Parameters to use for comparison" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -2716,9 +2706,7 @@ "type": "Array", "tags": [], "label": "existingFilters", - "description": [ - "- The filters to compare to" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -2742,9 +2730,7 @@ "type": "Array", "tags": [], "label": "filters", - "description": [ - "- The filters being added" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -2768,9 +2754,7 @@ "type": "Object", "tags": [], "label": "comparatorOptions", - "description": [ - "- Parameters to use for comparison" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -3148,9 +3132,7 @@ "type": "Array", "tags": [], "label": "filters", - "description": [ - "The filters to remove duplicates from" - ], + "description": [], "signature": [ { "pluginId": "data", @@ -3174,9 +3156,7 @@ "type": "Any", "tags": [], "label": "comparatorOptions", - "description": [ - "- Parameters to use for comparison" - ], + "description": [], "signature": [ "any" ], diff --git a/api_docs/data_search.json b/api_docs/data_search.json index d72ae79e79bd872..082553e94dcf422 100644 --- a/api_docs/data_search.json +++ b/api_docs/data_search.json @@ -10230,7 +10230,7 @@ "plugin": "maps", "link": { "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 273 + "lineNumber": 266 } }, { @@ -10506,7 +10506,7 @@ "section": "def-common.IndexPatternsService", "text": "IndexPatternsService" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"getDefaultId\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">, dependencies: ", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">, dependencies: ", { "pluginId": "data", "scope": "common", @@ -10562,7 +10562,7 @@ "section": "def-common.IndexPatternsService", "text": "IndexPatternsService" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"getDefaultId\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">" ], "source": { "path": "src/plugins/data/common/search/search_source/search_source_service.ts", @@ -11620,7 +11620,7 @@ "section": "def-common.IndexPatternsService", "text": "IndexPatternsService" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"getDefaultId\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">, searchSourceDependencies: ", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">, searchSourceDependencies: ", { "pluginId": "data", "scope": "common", @@ -11658,9 +11658,7 @@ "type": "Object", "tags": [], "label": "indexPatterns", - "description": [ - "The index patterns contract of the data plugin" - ], + "description": [], "signature": [ "Pick<", { @@ -11670,7 +11668,7 @@ "section": "def-common.IndexPatternsService", "text": "IndexPatternsService" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"getDefaultId\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">" ], "source": { "path": "src/plugins/data/common/search/search_source/create_search_source.ts", diff --git a/api_docs/deprecations.mdx b/api_docs/deprecations.mdx index 99edad62075bce0..9eee6d51d84ab9b 100644 --- a/api_docs/deprecations.mdx +++ b/api_docs/deprecations.mdx @@ -946,11 +946,11 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location | Remove By | | ---------------|-----------|-----------| | | [types.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L8) | - | -| | [types.ts#L45](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L45) | - | +| | [types.ts#L44](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L44) | - | +| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | +| | [es_source.ts#L360](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L360) | - | | | [es_doc_field.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L12) | - | | | [es_doc_field.ts#L45](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L45) | - | -| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | -| | [es_source.ts#L367](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L367) | - | | | [index_pattern_util.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L8) | - | | | [index_pattern_util.ts#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L15) | - | | | [index_pattern_util.ts#L49](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L49) | - | @@ -1041,10 +1041,10 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [create_source_editor.tsx#L35](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx#L35) | - | | | [get_docvalue_source_fields.test.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/get_docvalue_source_fields.test.ts#L10) | - | | | [get_docvalue_source_fields.test.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/get_docvalue_source_fields.test.ts#L12) | - | +| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | +| | [es_source.ts#L360](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L360) | - | | | [es_doc_field.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L12) | - | | | [es_doc_field.ts#L45](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L45) | - | -| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | -| | [es_source.ts#L367](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L367) | - | | | [index_pattern_util.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L8) | - | | | [index_pattern_util.ts#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L15) | - | | | [index_pattern_util.ts#L49](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L49) | - | @@ -1136,11 +1136,11 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [get_docvalue_source_fields.test.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/get_docvalue_source_fields.test.ts#L10) | - | | | [get_docvalue_source_fields.test.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/get_docvalue_source_fields.test.ts#L12) | - | | | [types.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L8) | - | -| | [types.ts#L45](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L45) | - | +| | [types.ts#L44](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L44) | - | +| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | +| | [es_source.ts#L360](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L360) | - | | | [es_doc_field.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L12) | - | | | [es_doc_field.ts#L45](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L45) | - | -| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | -| | [es_source.ts#L367](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L367) | - | | | [index_pattern_util.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L8) | - | | | [index_pattern_util.ts#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L15) | - | | | [index_pattern_util.ts#L49](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L49) | - | @@ -1612,9 +1612,9 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [types.ts#L41](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/details/types.ts#L41) | - | | | [index.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L12) | - | | | [index.tsx#L34](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L34) | - | -| | [middleware.ts#L44](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L44) | - | +| | [middleware.ts#L40](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L40) | - | +| | [middleware.ts#L55](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L55) | - | | | [middleware.ts#L60](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L60) | - | -| | [middleware.ts#L65](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L65) | - | | | [types.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L12) | - | | | [types.ts#L28](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L28) | - | | | [index.tsx#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx#L15) | - | @@ -1824,9 +1824,9 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [types.ts#L41](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/details/types.ts#L41) | - | | | [index.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L12) | - | | | [index.tsx#L34](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L34) | - | -| | [middleware.ts#L44](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L44) | - | +| | [middleware.ts#L40](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L40) | - | +| | [middleware.ts#L55](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L55) | - | | | [middleware.ts#L60](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L60) | - | -| | [middleware.ts#L65](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L65) | - | | | [types.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L12) | - | | | [types.ts#L28](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L28) | - | | | [index.tsx#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx#L15) | - | diff --git a/api_docs/embeddable.json b/api_docs/embeddable.json index d560148f35b1360..c9fee3570688c75 100644 --- a/api_docs/embeddable.json +++ b/api_docs/embeddable.json @@ -3847,9 +3847,7 @@ "type": "string", "tags": [], "label": "appId", - "description": [ - "- The id of the app to fetch the title for" - ], + "description": [], "signature": [ "string" ], @@ -4718,9 +4716,7 @@ "type": "CompoundType", "tags": [], "label": "props", - "description": [ - "- {@link EmbeddableRendererProps}" - ], + "description": [], "signature": [ { "pluginId": "embeddable", diff --git a/api_docs/expressions.json b/api_docs/expressions.json index e981414fe7bda9f..6d77161ae85a0ff 100644 --- a/api_docs/expressions.json +++ b/api_docs/expressions.json @@ -4875,9 +4875,7 @@ "type": "Object", "tags": [], "label": "state", - "description": [ - "expression AST to extract references from" - ], + "description": [], "signature": [ { "pluginId": "expressions", @@ -4956,9 +4954,7 @@ "type": "Object", "tags": [], "label": "state", - "description": [ - "expression AST to extract references from" - ], + "description": [], "signature": [ { "pluginId": "expressions", @@ -5021,9 +5017,7 @@ "type": "Object", "tags": [], "label": "state", - "description": [ - "expression AST to update" - ], + "description": [], "signature": [ { "pluginId": "expressions", @@ -5046,9 +5040,7 @@ "type": "Array", "tags": [], "label": "references", - "description": [ - "array of saved object references" - ], + "description": [], "signature": [ "SavedObjectReference", "[]" @@ -5104,9 +5096,7 @@ "type": "Object", "tags": [], "label": "state", - "description": [ - "expression AST to update" - ], + "description": [], "signature": [ { "pluginId": "kibanaUtils", @@ -5129,9 +5119,7 @@ "type": "string", "tags": [], "label": "version", - "description": [ - "defines which migration version to run" - ], + "description": [], "signature": [ "string" ], @@ -25777,9 +25765,7 @@ "type": "Object", "tags": [], "label": "state", - "description": [ - "expression AST to extract references from" - ], + "description": [], "signature": [ { "pluginId": "expressions", @@ -25858,9 +25844,7 @@ "type": "Object", "tags": [], "label": "state", - "description": [ - "expression AST to extract references from" - ], + "description": [], "signature": [ { "pluginId": "expressions", @@ -25923,9 +25907,7 @@ "type": "Object", "tags": [], "label": "state", - "description": [ - "expression AST to update" - ], + "description": [], "signature": [ { "pluginId": "expressions", @@ -25948,9 +25930,7 @@ "type": "Array", "tags": [], "label": "references", - "description": [ - "array of saved object references" - ], + "description": [], "signature": [ "SavedObjectReference", "[]" @@ -26006,9 +25986,7 @@ "type": "Object", "tags": [], "label": "state", - "description": [ - "expression AST to update" - ], + "description": [], "signature": [ { "pluginId": "kibanaUtils", @@ -26031,9 +26009,7 @@ "type": "string", "tags": [], "label": "version", - "description": [ - "defines which migration version to run" - ], + "description": [], "signature": [ "string" ], diff --git a/api_docs/fleet.json b/api_docs/fleet.json index 043dfcd16c2a798..389a56cccefc5b9 100644 --- a/api_docs/fleet.json +++ b/api_docs/fleet.json @@ -373,30 +373,6 @@ "lineNumber": 60 }, "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-public.NewPackagePolicy.vars", - "type": "Object", - "tags": [], - "label": "vars", - "description": [], - "signature": [ - "Record | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 61 - }, - "deprecated": false } ], "initialIsOpen": false @@ -1459,7 +1435,7 @@ "label": "integration_details_overview", "description": [], "signature": [ - "({ pkgkey, integration }: ", + "({ pkgkey }: ", "DynamicPagePathValues", ") => string" ], @@ -1474,7 +1450,7 @@ "id": "def-public.pagePathGetters.integration_details_overview.$1", "type": "Object", "tags": [], - "label": "{ pkgkey, integration }", + "label": "{ pkgkey }", "description": [], "signature": [ "DynamicPagePathValues" @@ -1497,13 +1473,13 @@ "label": "integration_details_policies", "description": [], "signature": [ - "({ pkgkey, integration }: ", + "({ pkgkey }: ", "DynamicPagePathValues", ") => string" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 82 + "lineNumber": 81 }, "deprecated": false, "children": [ @@ -1512,14 +1488,14 @@ "id": "def-public.pagePathGetters.integration_details_policies.$1", "type": "Object", "tags": [], - "label": "{ pkgkey, integration }", + "label": "{ pkgkey }", "description": [], "signature": [ "DynamicPagePathValues" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 82 + "lineNumber": 81 }, "deprecated": false, "isRequired": true @@ -1535,13 +1511,13 @@ "label": "integration_details_settings", "description": [], "signature": [ - "({ pkgkey, integration }: ", + "({ pkgkey }: ", "DynamicPagePathValues", ") => string" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 84 + "lineNumber": 82 }, "deprecated": false, "children": [ @@ -1550,14 +1526,14 @@ "id": "def-public.pagePathGetters.integration_details_settings.$1", "type": "Object", "tags": [], - "label": "{ pkgkey, integration }", + "label": "{ pkgkey }", "description": [], "signature": [ "DynamicPagePathValues" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 84 + "lineNumber": 82 }, "deprecated": false, "isRequired": true @@ -1573,13 +1549,13 @@ "label": "integration_details_custom", "description": [], "signature": [ - "({ pkgkey, integration }: ", + "({ pkgkey }: ", "DynamicPagePathValues", ") => string" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 86 + "lineNumber": 83 }, "deprecated": false, "children": [ @@ -1588,14 +1564,14 @@ "id": "def-public.pagePathGetters.integration_details_custom.$1", "type": "Object", "tags": [], - "label": "{ pkgkey, integration }", + "label": "{ pkgkey }", "description": [], "signature": [ "DynamicPagePathValues" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 86 + "lineNumber": 83 }, "deprecated": false, "isRequired": true @@ -1617,7 +1593,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 88 + "lineNumber": 84 }, "deprecated": false, "children": [ @@ -1633,7 +1609,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 88 + "lineNumber": 84 }, "deprecated": false, "isRequired": true @@ -1653,7 +1629,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 90 + "lineNumber": 86 }, "deprecated": false, "children": [], @@ -1671,7 +1647,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 91 + "lineNumber": 87 }, "deprecated": false, "children": [], @@ -1691,7 +1667,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 92 + "lineNumber": 88 }, "deprecated": false, "children": [ @@ -1707,7 +1683,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 92 + "lineNumber": 88 }, "deprecated": false, "isRequired": true @@ -1729,7 +1705,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 93 + "lineNumber": 89 }, "deprecated": false, "children": [ @@ -1745,7 +1721,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 93 + "lineNumber": 89 }, "deprecated": false, "isRequired": true @@ -1761,13 +1737,13 @@ "label": "add_integration_to_policy", "description": [], "signature": [ - "({ pkgkey, integration }: ", + "({ pkgkey }: ", "DynamicPagePathValues", ") => string" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 94 + "lineNumber": 90 }, "deprecated": false, "children": [ @@ -1776,14 +1752,14 @@ "id": "def-public.pagePathGetters.add_integration_to_policy.$1", "type": "Object", "tags": [], - "label": "{ pkgkey, integration }", + "label": "{ pkgkey }", "description": [], "signature": [ "DynamicPagePathValues" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 94 + "lineNumber": 90 }, "deprecated": false, "isRequired": true @@ -1805,7 +1781,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 96 + "lineNumber": 91 }, "deprecated": false, "children": [ @@ -1821,7 +1797,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 96 + "lineNumber": 91 }, "deprecated": false, "isRequired": true @@ -1841,7 +1817,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 98 + "lineNumber": 93 }, "deprecated": false, "children": [], @@ -1861,7 +1837,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 99 + "lineNumber": 94 }, "deprecated": false, "children": [ @@ -1877,7 +1853,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 99 + "lineNumber": 94 }, "deprecated": false, "isRequired": true @@ -1899,7 +1875,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 100 + "lineNumber": 95 }, "deprecated": false, "children": [ @@ -1915,7 +1891,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 100 + "lineNumber": 95 }, "deprecated": false, "isRequired": true @@ -1935,7 +1911,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 102 + "lineNumber": 97 }, "deprecated": false, "children": [], @@ -1953,7 +1929,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 103 + "lineNumber": 98 }, "deprecated": false, "children": [], @@ -4801,7 +4777,7 @@ ], "source": { "path": "x-pack/plugins/fleet/server/services/package_policy.ts", - "lineNumber": 655 + "lineNumber": 651 }, "deprecated": false, "initialIsOpen": false @@ -5400,350 +5376,70 @@ }, { "parentPluginId": "fleet", - "id": "def-common.doesPackageHaveIntegrations", + "id": "def-common.entries", "type": "Function", "tags": [], - "label": "doesPackageHaveIntegrations", + "label": "entries", "description": [], "signature": [ - "(pkgInfo: ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.Installed", - "text": "Installed" - }, - "> | ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.NotInstalled", - "text": "NotInstalled" - }, - "> | ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.Installed", - "text": "Installed" - }, - "> | ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.NotInstalled", - "text": "NotInstalled" - }, - "> | (Pick<", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.RegistryPackage", - "text": "RegistryPackage" - }, - ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\"> & { status: \"installed\"; savedObject: ", - "SavedObject", - "<", + "(o: T) => [keyof T, T[keyof T]][]" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/index.ts", + "lineNumber": 35 + }, + "deprecated": false, + "returnComment": [], + "children": [ { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.Installation", - "text": "Installation" - }, - ">; } & { integration?: string | undefined; id: string; }) | (Pick<", + "parentPluginId": "fleet", + "id": "def-common.o", + "type": "Uncategorized", + "tags": [], + "label": "o", + "description": [], + "signature": [ + "T" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/index.ts", + "lineNumber": 35 + }, + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.fullAgentPolicyToYaml", + "type": "Function", + "tags": [], + "label": "fullAgentPolicyToYaml", + "description": [], + "signature": [ + "(policy: ", { "pluginId": "fleet", "scope": "common", "docId": "kibFleetPluginApi", - "section": "def-common.RegistryPackage", - "text": "RegistryPackage" + "section": "def-common.FullAgentPolicy", + "text": "FullAgentPolicy" }, - ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\"> & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; })) => boolean" + ") => string" ], "source": { - "path": "x-pack/plugins/fleet/common/services/packages_with_integrations.ts", - "lineNumber": 9 + "path": "x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts", + "lineNumber": 28 }, "deprecated": false, "children": [ { "parentPluginId": "fleet", - "id": "def-common.doesPackageHaveIntegrations.$1", - "type": "CompoundType", + "id": "def-common.fullAgentPolicyToYaml.$1", + "type": "Object", "tags": [], - "label": "pkgInfo", - "description": [], - "signature": [ - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.Installed", - "text": "Installed" - }, - "> | ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.NotInstalled", - "text": "NotInstalled" - }, - "> | ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.Installed", - "text": "Installed" - }, - "> | ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.NotInstalled", - "text": "NotInstalled" - }, - "> | (Pick<", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.RegistryPackage", - "text": "RegistryPackage" - }, - ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\"> & { status: \"installed\"; savedObject: ", - "SavedObject", - "<", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.Installation", - "text": "Installation" - }, - ">; } & { integration?: string | undefined; id: string; }) | (Pick<", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.RegistryPackage", - "text": "RegistryPackage" - }, - ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\"> & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; })" - ], - "source": { - "path": "x-pack/plugins/fleet/common/services/packages_with_integrations.ts", - "lineNumber": 9 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.entries", - "type": "Function", - "tags": [], - "label": "entries", - "description": [], - "signature": [ - "(o: T) => [keyof T, T[keyof T]][]" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/index.ts", - "lineNumber": 35 - }, - "deprecated": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "fleet", - "id": "def-common.o", - "type": "Uncategorized", - "tags": [], - "label": "o", - "description": [], - "signature": [ - "T" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/index.ts", - "lineNumber": 35 - }, - "deprecated": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.fullAgentPolicyToYaml", - "type": "Function", - "tags": [], - "label": "fullAgentPolicyToYaml", - "description": [], - "signature": [ - "(policy: ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.FullAgentPolicy", - "text": "FullAgentPolicy" - }, - ") => string" - ], - "source": { - "path": "x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts", - "lineNumber": 28 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "fleet", - "id": "def-common.fullAgentPolicyToYaml.$1", - "type": "Object", - "tags": [], - "label": "policy", + "label": "policy", "description": [], "signature": [ { @@ -6131,7 +5827,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/services/package_to_package_policy.ts", - "lineNumber": 61 + "lineNumber": 46 }, "deprecated": false, "children": [ @@ -6153,7 +5849,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/services/package_to_package_policy.ts", - "lineNumber": 62 + "lineNumber": 47 }, "deprecated": false, "isRequired": true @@ -6809,7 +6505,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 236 + "lineNumber": 221 }, "deprecated": false, "children": [ @@ -6822,7 +6518,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 237 + "lineNumber": 222 }, "deprecated": false }, @@ -6838,7 +6534,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 238 + "lineNumber": 223 }, "deprecated": false }, @@ -6854,7 +6550,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 239 + "lineNumber": 224 }, "deprecated": false }, @@ -6885,7 +6581,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 240 + "lineNumber": 225 }, "deprecated": false }, @@ -6898,7 +6594,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 241 + "lineNumber": 226 }, "deprecated": false } @@ -7122,7 +6818,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 229 + "lineNumber": 214 }, "deprecated": false, "children": [ @@ -7135,7 +6831,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 230 + "lineNumber": 215 }, "deprecated": false }, @@ -7148,7 +6844,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 231 + "lineNumber": 216 }, "deprecated": false }, @@ -7161,7 +6857,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 232 + "lineNumber": 217 }, "deprecated": false } @@ -7609,7 +7305,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 38 + "lineNumber": 33 }, "deprecated": false, "children": [ @@ -7625,7 +7321,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 39 + "lineNumber": 34 }, "deprecated": false }, @@ -7641,7 +7337,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 40 + "lineNumber": 35 }, "deprecated": false } @@ -8040,7 +7736,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 335 + "lineNumber": 320 }, "deprecated": false, "children": [ @@ -8053,7 +7749,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 336 + "lineNumber": 321 }, "deprecated": false }, @@ -8066,7 +7762,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 337 + "lineNumber": 322 }, "deprecated": false }, @@ -8114,7 +7810,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 338 + "lineNumber": 323 }, "deprecated": false }, @@ -8130,7 +7826,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 339 + "lineNumber": 324 }, "deprecated": false } @@ -10069,7 +9765,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", - "lineNumber": 17 + "lineNumber": 18 }, "deprecated": false, "children": [ @@ -10081,11 +9777,11 @@ "label": "query", "description": [], "signature": [ - "{ experimental?: boolean | undefined; include_policy_templates?: boolean | undefined; }" + "{ experimental?: boolean | undefined; }" ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", - "lineNumber": 18 + "lineNumber": 19 }, "deprecated": false } @@ -11214,10 +10910,18 @@ "pluginId": "fleet", "scope": "common", "docId": "kibFleetPluginApi", - "section": "def-common.PackageListItem", - "text": "PackageListItem" + "section": "def-common.Installable", + "text": "Installable" }, - "[]" + ">[]" ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", @@ -11403,7 +11107,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 409 + "lineNumber": 391 }, "deprecated": false, "children": [ @@ -11416,7 +11120,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 410 + "lineNumber": 392 }, "deprecated": false }, @@ -11432,7 +11136,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 411 + "lineNumber": 393 }, "deprecated": false }, @@ -11448,7 +11152,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 412 + "lineNumber": 394 }, "deprecated": false }, @@ -11464,7 +11168,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 416 + "lineNumber": 398 }, "deprecated": false }, @@ -11480,7 +11184,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 417 + "lineNumber": 399 }, "deprecated": false }, @@ -11496,7 +11200,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 418 + "lineNumber": 400 }, "deprecated": false } @@ -11512,7 +11216,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 402 + "lineNumber": 384 }, "deprecated": false, "children": [ @@ -11528,7 +11232,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 403 + "lineNumber": 385 }, "deprecated": false } @@ -11555,7 +11259,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 357 + "lineNumber": 339 }, "deprecated": false, "children": [ @@ -11578,7 +11282,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 358 + "lineNumber": 340 }, "deprecated": false }, @@ -11601,7 +11305,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 359 + "lineNumber": 341 }, "deprecated": false }, @@ -11624,7 +11328,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 360 + "lineNumber": 342 }, "deprecated": false }, @@ -11640,7 +11344,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 361 + "lineNumber": 343 }, "deprecated": false }, @@ -11653,7 +11357,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 362 + "lineNumber": 344 }, "deprecated": false }, @@ -11666,7 +11370,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 363 + "lineNumber": 345 }, "deprecated": false }, @@ -11682,7 +11386,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 364 + "lineNumber": 346 }, "deprecated": false }, @@ -11695,7 +11399,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 365 + "lineNumber": 347 }, "deprecated": false }, @@ -11708,7 +11412,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 366 + "lineNumber": 348 }, "deprecated": false }, @@ -11724,7 +11428,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 367 + "lineNumber": 349 }, "deprecated": false } @@ -12623,30 +12327,6 @@ "lineNumber": 60 }, "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.NewPackagePolicy.vars", - "type": "Object", - "tags": [], - "label": "vars", - "description": [], - "signature": [ - "Record | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 61 - }, - "deprecated": false } ], "initialIsOpen": false @@ -12912,11 +12592,11 @@ "section": "def-common.NewPackagePolicy", "text": "NewPackagePolicy" }, - ", \"enabled\" | \"description\" | \"name\" | \"package\" | \"namespace\" | \"policy_id\" | \"output_id\" | \"vars\">" + ", \"enabled\" | \"description\" | \"name\" | \"package\" | \"namespace\" | \"policy_id\" | \"output_id\">" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 68 + "lineNumber": 67 }, "deprecated": false, "children": [ @@ -12929,7 +12609,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 69 + "lineNumber": 68 }, "deprecated": false }, @@ -12952,7 +12632,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 70 + "lineNumber": 69 }, "deprecated": false }, @@ -12968,7 +12648,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 71 + "lineNumber": 70 }, "deprecated": false }, @@ -12981,7 +12661,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 72 + "lineNumber": 71 }, "deprecated": false }, @@ -12994,7 +12674,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 73 + "lineNumber": 72 }, "deprecated": false }, @@ -13007,7 +12687,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 74 + "lineNumber": 73 }, "deprecated": false }, @@ -13020,7 +12700,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 75 + "lineNumber": 74 }, "deprecated": false }, @@ -13033,7 +12713,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 76 + "lineNumber": 75 }, "deprecated": false } @@ -13127,7 +12807,7 @@ "section": "def-common.NewPackagePolicyInput", "text": "NewPackagePolicyInput" }, - ", \"type\" | \"enabled\" | \"config\" | \"vars\" | \"keep_enabled\">" + ", \"type\" | \"enabled\" | \"config\" | \"keep_enabled\" | \"vars\">" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", @@ -13303,7 +12983,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 61 + "lineNumber": 60 }, "deprecated": false, "children": [ @@ -13316,7 +12996,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 62 + "lineNumber": 61 }, "deprecated": false }, @@ -13332,7 +13012,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 63 + "lineNumber": 62 }, "deprecated": false }, @@ -13348,7 +13028,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 64 + "lineNumber": 63 }, "deprecated": false }, @@ -13364,7 +13044,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 65 + "lineNumber": 64 }, "deprecated": false } @@ -13600,40 +13280,17 @@ }, { "parentPluginId": "fleet", - "id": "def-common.PackageSpecManifest.vars", - "type": "Array", + "id": "def-common.PackageSpecManifest.owner", + "type": "Object", "tags": [], - "label": "vars", - "description": [], - "signature": [ - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.RegistryVarsEntry", - "text": "RegistryVarsEntry" - }, - "[] | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 25 - }, - "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.PackageSpecManifest.owner", - "type": "Object", - "tags": [], - "label": "owner", + "label": "owner", "description": [], "signature": [ "{ github: string; }" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 26 + "lineNumber": 25 }, "deprecated": false } @@ -13649,7 +13306,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 68 + "lineNumber": 67 }, "deprecated": false, "children": [ @@ -13662,7 +13319,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 69 + "lineNumber": 68 }, "deprecated": false }, @@ -13675,7 +13332,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 70 + "lineNumber": 69 }, "deprecated": false }, @@ -13691,7 +13348,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 71 + "lineNumber": 70 }, "deprecated": false }, @@ -13707,7 +13364,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 72 + "lineNumber": 71 }, "deprecated": false } @@ -13723,7 +13380,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 370 + "lineNumber": 352 }, "deprecated": false, "children": [ @@ -13736,7 +13393,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 371 + "lineNumber": 353 }, "deprecated": false } @@ -14330,7 +13987,7 @@ "section": "def-common.NewPackagePolicy", "text": "NewPackagePolicy" }, - ", \"enabled\" | \"description\" | \"name\" | \"namespace\" | \"policy_id\" | \"output_id\" | \"vars\">> & { name: string; package: Partial<", + ", \"enabled\" | \"description\" | \"name\" | \"namespace\" | \"policy_id\" | \"output_id\">> & { name: string; package: Partial<", { "pluginId": "fleet", "scope": "common", @@ -14586,7 +14243,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 281 + "lineNumber": 266 }, "deprecated": false, "children": [ @@ -14599,7 +14256,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 282 + "lineNumber": 267 }, "deprecated": false }, @@ -14615,7 +14272,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 283 + "lineNumber": 268 }, "deprecated": false }, @@ -14631,7 +14288,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 284 + "lineNumber": 269 }, "deprecated": false }, @@ -14644,7 +14301,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 285 + "lineNumber": 270 }, "deprecated": false }, @@ -14657,7 +14314,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 286 + "lineNumber": 271 }, "deprecated": false }, @@ -14670,7 +14327,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 287 + "lineNumber": 272 }, "deprecated": false }, @@ -14693,7 +14350,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 288 + "lineNumber": 273 }, "deprecated": false }, @@ -14706,7 +14363,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 289 + "lineNumber": 274 }, "deprecated": false }, @@ -14719,7 +14376,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 290 + "lineNumber": 275 }, "deprecated": false }, @@ -14730,12 +14387,9 @@ "tags": [], "label": "[RegistryDataStreamKeys.ingest_pipeline]", "description": [], - "signature": [ - "string | undefined" - ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 291 + "lineNumber": 276 }, "deprecated": false }, @@ -14758,7 +14412,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 292 + "lineNumber": 277 }, "deprecated": false }, @@ -14774,7 +14428,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 293 + "lineNumber": 278 }, "deprecated": false } @@ -14790,7 +14444,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 296 + "lineNumber": 281 }, "deprecated": false, "children": [ @@ -14806,7 +14460,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 297 + "lineNumber": 282 }, "deprecated": false }, @@ -14822,7 +14476,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 298 + "lineNumber": 283 }, "deprecated": false } @@ -14836,29 +14490,25 @@ "tags": [], "label": "RegistryImage", "description": [], - "signature": [ - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.RegistryImage", - "text": "RegistryImage" - }, - " extends ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.PackageSpecIcon", - "text": "PackageSpecIcon" - } - ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 126 + "lineNumber": 121 }, "deprecated": false, "children": [ + { + "parentPluginId": "fleet", + "id": "def-common.RegistryImage.src", + "type": "string", + "tags": [], + "label": "src", + "description": [], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "lineNumber": 122 + }, + "deprecated": false + }, { "parentPluginId": "fleet", "id": "def-common.RegistryImage.path", @@ -14868,7 +14518,55 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 127 + "lineNumber": 123 + }, + "deprecated": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.RegistryImage.title", + "type": "string", + "tags": [], + "label": "title", + "description": [], + "signature": [ + "string | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "lineNumber": 124 + }, + "deprecated": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.RegistryImage.size", + "type": "string", + "tags": [], + "label": "size", + "description": [], + "signature": [ + "string | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "lineNumber": 125 + }, + "deprecated": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.RegistryImage.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "lineNumber": 126 }, "deprecated": false } @@ -14884,7 +14582,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 168 + "lineNumber": 154 }, "deprecated": false, "children": [ @@ -14897,7 +14595,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 169 + "lineNumber": 155 }, "deprecated": false }, @@ -14910,7 +14608,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 170 + "lineNumber": 156 }, "deprecated": false }, @@ -14923,7 +14621,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 171 + "lineNumber": 157 }, "deprecated": false }, @@ -14939,7 +14637,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 172 + "lineNumber": 158 }, "deprecated": false }, @@ -14955,23 +14653,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 173 - }, - "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.RegistryInput.RegistryInputKeys.input_group", - "type": "CompoundType", - "tags": [], - "label": "[RegistryInputKeys.input_group]", - "description": [], - "signature": [ - "\"metrics\" | \"logs\" | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 174 + "lineNumber": 159 }, "deprecated": false }, @@ -14994,7 +14676,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 175 + "lineNumber": 160 }, "deprecated": false } @@ -15010,7 +14692,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 143 + "lineNumber": 137 }, "deprecated": false, "children": [ @@ -15023,7 +14705,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 144 + "lineNumber": 138 }, "deprecated": false }, @@ -15036,7 +14718,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 145 + "lineNumber": 139 }, "deprecated": false }, @@ -15049,85 +14731,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 146 - }, - "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.RegistryPolicyTemplate.RegistryPolicyTemplateKeys.icons", - "type": "Array", - "tags": [], - "label": "[RegistryPolicyTemplateKeys.icons]", - "description": [], - "signature": [ - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.RegistryImage", - "text": "RegistryImage" - }, - "[] | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 147 - }, - "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.RegistryPolicyTemplate.RegistryPolicyTemplateKeys.screenshots", - "type": "Array", - "tags": [], - "label": "[RegistryPolicyTemplateKeys.screenshots]", - "description": [], - "signature": [ - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.RegistryImage", - "text": "RegistryImage" - }, - "[] | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 148 - }, - "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.RegistryPolicyTemplate.RegistryPolicyTemplateKeys.categories", - "type": "Array", - "tags": [], - "label": "[RegistryPolicyTemplateKeys.categories]", - "description": [], - "signature": [ - "(\"custom\" | \"security\" | \"monitoring\" | \"cloud\" | \"kubernetes\" | \"aws\" | \"azure\" | \"config_management\" | \"containers\" | \"crm\" | \"datastore\" | \"elastic_stack\" | \"google_cloud\" | \"languages\" | \"message_queue\" | \"network\" | \"notification\" | \"os_system\" | \"productivity\" | \"support\" | \"ticketing\" | \"version_control\" | \"web\" | undefined)[] | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 149 - }, - "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.RegistryPolicyTemplate.RegistryPolicyTemplateKeys.data_streams", - "type": "Array", - "tags": [], - "label": "[RegistryPolicyTemplateKeys.data_streams]", - "description": [], - "signature": [ - "string[] | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 150 + "lineNumber": 140 }, "deprecated": false }, @@ -15150,23 +14754,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 151 - }, - "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.RegistryPolicyTemplate.RegistryPolicyTemplateKeys.readme", - "type": "string", - "tags": [], - "label": "[RegistryPolicyTemplateKeys.readme]", - "description": [], - "signature": [ - "string | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 152 + "lineNumber": 141 }, "deprecated": false }, @@ -15182,7 +14770,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 153 + "lineNumber": 142 }, "deprecated": false } @@ -15198,7 +14786,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 187 + "lineNumber": 172 }, "deprecated": false, "children": [ @@ -15211,7 +14799,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 188 + "lineNumber": 173 }, "deprecated": false }, @@ -15224,7 +14812,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 189 + "lineNumber": 174 }, "deprecated": false }, @@ -15240,7 +14828,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 190 + "lineNumber": 175 }, "deprecated": false }, @@ -15256,7 +14844,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 191 + "lineNumber": 176 }, "deprecated": false }, @@ -15279,7 +14867,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 192 + "lineNumber": 177 }, "deprecated": false }, @@ -15292,7 +14880,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 193 + "lineNumber": 178 }, "deprecated": false } @@ -15308,7 +14896,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 317 + "lineNumber": 302 }, "deprecated": false, "children": [ @@ -15321,7 +14909,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 318 + "lineNumber": 303 }, "deprecated": false }, @@ -15337,7 +14925,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 319 + "lineNumber": 304 }, "deprecated": false }, @@ -15353,7 +14941,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 320 + "lineNumber": 305 }, "deprecated": false }, @@ -15369,7 +14957,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 321 + "lineNumber": 306 }, "deprecated": false }, @@ -15385,7 +14973,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 322 + "lineNumber": 307 }, "deprecated": false }, @@ -15401,7 +14989,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 323 + "lineNumber": 308 }, "deprecated": false }, @@ -15417,7 +15005,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 324 + "lineNumber": 309 }, "deprecated": false }, @@ -15429,11 +15017,11 @@ "label": "[RegistryVarsEntryKeys.default]", "description": [], "signature": [ - "string | boolean | string[] | undefined" + "string | string[] | undefined" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 325 + "lineNumber": 310 }, "deprecated": false }, @@ -15449,7 +15037,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 326 + "lineNumber": 311 }, "deprecated": false } @@ -15465,7 +15053,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 198 + "lineNumber": 183 }, "deprecated": false, "children": [ @@ -15478,7 +15066,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 199 + "lineNumber": 184 }, "deprecated": false } @@ -15574,7 +15162,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 421 + "lineNumber": 403 }, "deprecated": false, "children": [ @@ -15587,7 +15175,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 422 + "lineNumber": 404 }, "deprecated": false }, @@ -15609,7 +15197,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 423 + "lineNumber": 405 }, "deprecated": false } @@ -15728,7 +15316,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 64 + "lineNumber": 63 }, "deprecated": false, "children": [ @@ -15744,7 +15332,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 65 + "lineNumber": 64 }, "deprecated": false } @@ -15762,7 +15350,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 81 + "lineNumber": 76 }, "deprecated": false, "initialIsOpen": false @@ -15776,7 +15364,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 31 + "lineNumber": 26 }, "deprecated": false, "initialIsOpen": false @@ -15790,7 +15378,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 56 + "lineNumber": 51 }, "deprecated": false, "initialIsOpen": false @@ -15804,7 +15392,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 70 + "lineNumber": 65 }, "deprecated": false, "initialIsOpen": false @@ -15818,7 +15406,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 266 + "lineNumber": 251 }, "deprecated": false, "initialIsOpen": false @@ -15832,7 +15420,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 156 + "lineNumber": 145 }, "deprecated": false, "initialIsOpen": false @@ -15846,7 +15434,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 130 + "lineNumber": 129 }, "deprecated": false, "initialIsOpen": false @@ -15860,7 +15448,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 178 + "lineNumber": 163 }, "deprecated": false, "initialIsOpen": false @@ -15874,7 +15462,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 302 + "lineNumber": 287 }, "deprecated": false, "initialIsOpen": false @@ -16213,7 +15801,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 50 + "lineNumber": 45 }, "deprecated": false, "initialIsOpen": false @@ -16413,7 +16001,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 94 + "lineNumber": 89 }, "deprecated": false, "initialIsOpen": false @@ -16444,7 +16032,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 385 + "lineNumber": 367 }, "deprecated": false, "initialIsOpen": false @@ -16510,7 +16098,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 244 + "lineNumber": 229 }, "deprecated": false, "initialIsOpen": false @@ -16542,7 +16130,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 51 + "lineNumber": 46 }, "deprecated": false, "initialIsOpen": false @@ -16591,7 +16179,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 243 + "lineNumber": 228 }, "deprecated": false, "initialIsOpen": false @@ -16639,7 +16227,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 228 + "lineNumber": 213 }, "deprecated": false, "initialIsOpen": false @@ -16663,7 +16251,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 227 + "lineNumber": 212 }, "deprecated": false, "initialIsOpen": false @@ -16694,7 +16282,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 90 + "lineNumber": 85 }, "deprecated": false, "initialIsOpen": false @@ -16728,7 +16316,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 400 + "lineNumber": 382 }, "deprecated": false, "initialIsOpen": false @@ -16762,7 +16350,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 48 + "lineNumber": 43 }, "deprecated": false, "initialIsOpen": false @@ -16794,7 +16382,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 255 + "lineNumber": 240 }, "deprecated": false, "initialIsOpen": false @@ -16859,7 +16447,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 261 + "lineNumber": 246 }, "deprecated": false, "initialIsOpen": false @@ -16941,7 +16529,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 46 + "lineNumber": 41 }, "deprecated": false, "initialIsOpen": false @@ -16968,7 +16556,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 390 + "lineNumber": 372 }, "deprecated": false, "initialIsOpen": false @@ -17190,7 +16778,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 374 + "lineNumber": 356 }, "deprecated": false, "initialIsOpen": false @@ -17221,7 +16809,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 92 + "lineNumber": 87 }, "deprecated": false, "initialIsOpen": false @@ -17238,7 +16826,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 29 + "lineNumber": 24 }, "deprecated": false, "initialIsOpen": false @@ -17265,7 +16853,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 376 + "lineNumber": 358 }, "deprecated": false, "initialIsOpen": false @@ -17282,7 +16870,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 44 + "lineNumber": 39 }, "deprecated": false, "initialIsOpen": false @@ -17299,7 +16887,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 43 + "lineNumber": 38 }, "deprecated": false, "initialIsOpen": false @@ -17331,7 +16919,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 250 + "lineNumber": 235 }, "deprecated": false, "initialIsOpen": false @@ -17358,7 +16946,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 387 + "lineNumber": 369 }, "deprecated": false, "initialIsOpen": false @@ -17439,7 +17027,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 260 + "lineNumber": 245 }, "deprecated": false, "initialIsOpen": false @@ -17490,7 +17078,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 381 + "lineNumber": 363 }, "deprecated": false, "initialIsOpen": false @@ -17621,7 +17209,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 394 + "lineNumber": 376 }, "deprecated": false, "initialIsOpen": false @@ -17733,7 +17321,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 353 + "lineNumber": 335 }, "deprecated": false, "initialIsOpen": false @@ -17750,14 +17338,22 @@ "pluginId": "fleet", "scope": "common", "docId": "kibFleetPluginApi", - "section": "def-common.PackageListItem", - "text": "PackageListItem" + "section": "def-common.Installable", + "text": "Installable" }, - "[]" + ">[]" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 346 + "lineNumber": 331 }, "deprecated": false, "initialIsOpen": false @@ -17770,7 +17366,14 @@ "label": "PackageListItem", "description": [], "signature": [ - "(Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installed", + "text": "Installed" + }, + " & { status: \"installed\"; savedObject: ", - "SavedObject", - "<", + ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\">> | ", { "pluginId": "fleet", "scope": "common", "docId": "kibFleetPluginApi", - "section": "def-common.Installation", - "text": "Installation" + "section": "def-common.NotInstalled", + "text": "NotInstalled" }, - ">; } & { integration?: string | undefined; id: string; }) | (Pick<", + " & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; })" + ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\">>" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 347 + "lineNumber": 333 }, "deprecated": false, "initialIsOpen": false @@ -17854,19 +17455,11 @@ "section": "def-common.PackagePolicyInput", "text": "PackagePolicyInput" }, - "[]; policy_id: string; output_id: string; vars?: Record | undefined; revision: number; }" + "[]; policy_id: string; output_id: string; revision: number; }" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 79 + "lineNumber": 78 }, "deprecated": false, "initialIsOpen": false @@ -17916,7 +17509,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 352 + "lineNumber": 334 }, "deprecated": false, "initialIsOpen": false @@ -17933,7 +17526,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 29 + "lineNumber": 28 }, "deprecated": false, "initialIsOpen": false @@ -17950,7 +17543,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 54 + "lineNumber": 53 }, "deprecated": false, "initialIsOpen": false @@ -18074,23 +17667,6 @@ "deprecated": false, "initialIsOpen": false }, - { - "parentPluginId": "fleet", - "id": "def-common.RegistryInputGroup", - "type": "Type", - "tags": [], - "label": "RegistryInputGroup", - "description": [], - "signature": [ - "\"metrics\" | \"logs\"" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 166 - }, - "deprecated": false, - "initialIsOpen": false - }, { "parentPluginId": "fleet", "id": "def-common.RegistryPackage", @@ -18118,7 +17694,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 98 + "lineNumber": 93 }, "deprecated": false, "initialIsOpen": false @@ -18135,7 +17711,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 125 + "lineNumber": 120 }, "deprecated": false, "initialIsOpen": false @@ -18184,7 +17760,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 207 + "lineNumber": 192 }, "deprecated": false, "initialIsOpen": false @@ -18209,7 +17785,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 205 + "lineNumber": 190 }, "deprecated": false, "initialIsOpen": false @@ -18226,7 +17802,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 301 + "lineNumber": 286 }, "deprecated": false, "initialIsOpen": false @@ -18260,7 +17836,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 398 + "lineNumber": 380 }, "deprecated": false, "initialIsOpen": false @@ -18277,7 +17853,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 235 + "lineNumber": 220 }, "deprecated": false, "initialIsOpen": false @@ -18294,7 +17870,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 196 + "lineNumber": 181 }, "deprecated": false, "initialIsOpen": false @@ -18311,7 +17887,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 197 + "lineNumber": 182 }, "deprecated": false, "initialIsOpen": false @@ -18342,7 +17918,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 223 + "lineNumber": 208 }, "deprecated": false, "initialIsOpen": false @@ -18359,7 +17935,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 49 + "lineNumber": 44 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/home.json b/api_docs/home.json index a1039beb8d3a244..2aa23c1b756dfaf 100644 --- a/api_docs/home.json +++ b/api_docs/home.json @@ -1070,7 +1070,7 @@ }, ") => void; getSampleDatasets: () => ", "Writable", - "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; defaultIndex: string; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>[]; addSavedObjectsToSampleDataset: (id: string, savedObjects: ", + "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>[]; addSavedObjectsToSampleDataset: (id: string, savedObjects: ", "SavedObject", "[]) => void; addAppLinksToSampleDataset: (id: string, appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]) => void; replacePanelInSampleDatasetDashboard: ({ sampleDataId, dashboardId, oldEmbeddableId, embeddableId, embeddableType, embeddableConfig, }: ", "SampleDatasetDashboardPanel", @@ -1093,7 +1093,7 @@ "signature": [ "() => ", "Writable", - "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; defaultIndex: string; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>" + "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>" ], "source": { "path": "src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts", @@ -1426,7 +1426,7 @@ }, ") => void; getSampleDatasets: () => ", "Writable", - "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; defaultIndex: string; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>[]; addSavedObjectsToSampleDataset: (id: string, savedObjects: ", + "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>[]; addSavedObjectsToSampleDataset: (id: string, savedObjects: ", "SavedObject", "[]) => void; addAppLinksToSampleDataset: (id: string, appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]) => void; replacePanelInSampleDatasetDashboard: ({ sampleDataId, dashboardId, oldEmbeddableId, embeddableId, embeddableType, embeddableConfig, }: ", "SampleDatasetDashboardPanel", diff --git a/api_docs/kibana_react.json b/api_docs/kibana_react.json index 98537d71d7b0196..9e144147e6919d7 100644 --- a/api_docs/kibana_react.json +++ b/api_docs/kibana_react.json @@ -1055,7 +1055,7 @@ "label": "KibanaPageTemplate", "description": [], "signature": [ - "({ template, pageHeader, children, isEmptyState, restrictWidth, bottomBar, bottomBarProps, pageSideBar, solutionNav, ...rest }: React.PropsWithChildren<", + "({ template, pageHeader, children, isEmptyState, restrictWidth, bottomBar, bottomBarProps, ...rest }: React.PropsWithChildren<", { "pluginId": "kibanaReact", "scope": "public", @@ -1067,7 +1067,7 @@ ], "source": { "path": "src/plugins/kibana_react/public/page_template/page_template.tsx", - "lineNumber": 37 + "lineNumber": 22 }, "deprecated": false, "children": [ @@ -1076,7 +1076,7 @@ "id": "def-public.KibanaPageTemplate.$1", "type": "CompoundType", "tags": [], - "label": "{\n template,\n pageHeader,\n children,\n isEmptyState,\n restrictWidth = true,\n bottomBar,\n bottomBarProps,\n pageSideBar,\n solutionNav,\n ...rest\n}", + "label": "{\n template,\n pageHeader,\n children,\n isEmptyState,\n restrictWidth = true,\n bottomBar,\n bottomBarProps,\n ...rest\n}", "description": [], "signature": [ "React.PropsWithChildren<", @@ -1091,7 +1091,7 @@ ], "source": { "path": "src/plugins/kibana_react/public/page_template/page_template.tsx", - "lineNumber": 37 + "lineNumber": 22 }, "deprecated": false, "isRequired": true @@ -1581,9 +1581,7 @@ "type": "CompoundType", "tags": [], "label": "ReactComp", - "description": [ - "A React component." - ], + "description": [], "signature": [ "React.ComponentType" ], @@ -1669,9 +1667,7 @@ "type": "CompoundType", "tags": [], "label": "node", - "description": [ - "to get a mount point for" - ], + "description": [], "signature": [ "React.ReactNode" ], @@ -3940,9 +3936,7 @@ "type": "Type", "tags": [], "label": "KibanaPageTemplateProps", - "description": [ - "\nA thin wrapper around EuiPageTemplate with a few Kibana specific additions" - ], + "description": [], "signature": [ "(Pick<", "EuiPageProps", @@ -3966,9 +3960,7 @@ "EuiPageContentProps", " | undefined; pageContentBodyProps?: ", "EuiPageContentBodyProps", - " | undefined; } & { isEmptyState?: boolean | undefined; solutionNav?: ", - "KibanaPageTemplateSolutionNavProps", - " | undefined; }) | (Pick<", + " | undefined; } & { isEmptyState?: boolean | undefined; }) | (Pick<", "EuiPageProps", ", \"children\" | \"onClick\" | \"onChange\" | \"color\" | \"onKeyDown\" | \"title\" | \"id\" | \"defaultChecked\" | \"defaultValue\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"className\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"hidden\" | \"lang\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"style\" | \"tabIndex\" | \"translate\" | \"radioGroup\" | \"role\" | \"about\" | \"datatype\" | \"inlist\" | \"prefix\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"security\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-label\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onError\" | \"onErrorCapture\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"css\" | \"data-test-subj\" | \"grow\" | \"direction\" | \"restrictWidth\"> & ", "DisambiguateSet", @@ -3998,13 +3990,11 @@ "EuiPageContentProps", " | undefined; pageContentBodyProps?: ", "EuiPageContentBodyProps", - " | undefined; } & { isEmptyState?: boolean | undefined; solutionNav?: ", - "KibanaPageTemplateSolutionNavProps", - " | undefined; })" + " | undefined; } & { isEmptyState?: boolean | undefined; })" ], "source": { "path": "src/plugins/kibana_react/public/page_template/page_template.tsx", - "lineNumber": 23 + "lineNumber": 12 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/kibana_utils.json b/api_docs/kibana_utils.json index 66eefa9097bfb14..173348ea2f2638d 100644 --- a/api_docs/kibana_utils.json +++ b/api_docs/kibana_utils.json @@ -2551,9 +2551,7 @@ "type": "Object", "tags": [], "label": "storage", - "description": [ - "- Option {@link Storage} to use for storing state. By default window.sessionStorage." - ], + "description": [], "signature": [ "Storage" ], @@ -2618,9 +2616,7 @@ "type": "Function", "tags": [], "label": "accessor", - "description": [ - "Asynchronous start service accessor provided by platform." - ], + "description": [], "signature": [ { "pluginId": "core", @@ -3627,9 +3623,7 @@ "type": "Object", "tags": [], "label": "promise", - "description": [ - "Promise to convert to 3-tuple." - ], + "description": [], "signature": [ "Promise" ], @@ -4693,9 +4687,7 @@ "type": "Uncategorized", "tags": [], "label": "container", - "description": [ - "- {@link StateContainer} which state to track." - ], + "description": [], "signature": [ "Container" ], @@ -4712,9 +4704,7 @@ "type": "Function", "tags": [], "label": "selector", - "description": [ - "- Function used to pick parts of state." - ], + "description": [], "signature": [ "(state: ", { @@ -4739,9 +4729,7 @@ "type": "Function", "tags": [], "label": "comparator", - "description": [ - "- {@link Comparator} function used to memoize previous result, to not\nre-render React component if state did not change. By default uses\n`fast-deep-equal` package." - ], + "description": [], "signature": [ { "pluginId": "kibanaUtils", @@ -4805,9 +4793,7 @@ "type": "Uncategorized", "tags": [], "label": "container", - "description": [ - "- {@link StateContainer} which state to track." - ], + "description": [], "signature": [ "Container" ], @@ -10020,9 +10006,7 @@ "type": "Object", "tags": [], "label": "promise", - "description": [ - "Promise to convert to 3-tuple." - ], + "description": [], "signature": [ "Promise" ], @@ -10085,9 +10069,7 @@ "type": "Uncategorized", "tags": [], "label": "container", - "description": [ - "- {@link StateContainer} which state to track." - ], + "description": [], "signature": [ "Container" ], @@ -10104,9 +10086,7 @@ "type": "Function", "tags": [], "label": "selector", - "description": [ - "- Function used to pick parts of state." - ], + "description": [], "signature": [ "(state: ", { @@ -10131,9 +10111,7 @@ "type": "Function", "tags": [], "label": "comparator", - "description": [ - "- {@link Comparator} function used to memoize previous result, to not\nre-render React component if state did not change. By default uses\n`fast-deep-equal` package." - ], + "description": [], "signature": [ { "pluginId": "kibanaUtils", @@ -10197,9 +10175,7 @@ "type": "Uncategorized", "tags": [], "label": "container", - "description": [ - "- {@link StateContainer} which state to track." - ], + "description": [], "signature": [ "Container" ], diff --git a/api_docs/lens.json b/api_docs/lens.json index 196361f65682b97..f81dbe4217f2879 100644 --- a/api_docs/lens.json +++ b/api_docs/lens.json @@ -1353,7 +1353,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 474 + "lineNumber": 473 }, "deprecated": false, "children": [ @@ -1369,7 +1369,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 475 + "lineNumber": 474 }, "deprecated": false }, @@ -1391,7 +1391,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 476 + "lineNumber": 475 }, "deprecated": false }, @@ -1407,7 +1407,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 477 + "lineNumber": 476 }, "deprecated": false }, @@ -1423,7 +1423,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 478 + "lineNumber": 477 }, "deprecated": false }, @@ -1440,7 +1440,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 479 + "lineNumber": 478 }, "deprecated": false }, @@ -1457,7 +1457,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 480 + "lineNumber": 479 }, "deprecated": false }, @@ -1480,7 +1480,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 481 + "lineNumber": 480 }, "deprecated": false }, @@ -1496,7 +1496,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 482 + "lineNumber": 481 }, "deprecated": false }, @@ -1512,7 +1512,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 483 + "lineNumber": 482 }, "deprecated": false }, @@ -1528,7 +1528,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 484 + "lineNumber": 483 }, "deprecated": false }, @@ -1551,7 +1551,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 485 + "lineNumber": 484 }, "deprecated": false }, @@ -1574,7 +1574,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 486 + "lineNumber": 485 }, "deprecated": false }, @@ -1597,7 +1597,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 487 + "lineNumber": 486 }, "deprecated": false }, @@ -1613,23 +1613,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 488 - }, - "deprecated": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.fillOpacity", - "type": "number", - "tags": [], - "label": "fillOpacity", - "description": [], - "signature": [ - "number | undefined" - ], - "source": { - "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 489 + "lineNumber": 487 }, "deprecated": false }, @@ -1645,7 +1629,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 490 + "lineNumber": 488 }, "deprecated": false } @@ -2109,7 +2093,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts", - "lineNumber": 498 + "lineNumber": 497 }, "deprecated": false, "initialIsOpen": false @@ -2296,7 +2280,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 471 + "lineNumber": 470 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/licensing.json b/api_docs/licensing.json index 1451cff869f47a1..873f40bd301a1c4 100644 --- a/api_docs/licensing.json +++ b/api_docs/licensing.json @@ -3088,7 +3088,7 @@ "plugin": "reporting", "link": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 226 + "lineNumber": 228 } }, { diff --git a/api_docs/maps.json b/api_docs/maps.json index d418518dcb0d2c5..a8c582800fc3b94 100644 --- a/api_docs/maps.json +++ b/api_docs/maps.json @@ -57,7 +57,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 95 + "lineNumber": 90 }, "deprecated": false, "children": [ @@ -70,7 +70,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 98 + "lineNumber": 93 }, "deprecated": false }, @@ -86,7 +86,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 118 + "lineNumber": 110 }, "deprecated": false, "children": [ @@ -102,7 +102,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 118 + "lineNumber": 110 }, "deprecated": false, "isRequired": true @@ -125,7 +125,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 118 + "lineNumber": 110 }, "deprecated": false, "isRequired": true @@ -165,7 +165,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 118 + "lineNumber": 110 }, "deprecated": false, "isRequired": false @@ -194,7 +194,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 200 + "lineNumber": 184 }, "deprecated": false, "children": [ @@ -216,7 +216,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 201 + "lineNumber": 185 }, "deprecated": false, "isRequired": true @@ -238,7 +238,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 206 + "lineNumber": 190 }, "deprecated": false, "children": [], @@ -258,7 +258,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 214 + "lineNumber": 198 }, "deprecated": false, "children": [], @@ -276,7 +276,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 219 + "lineNumber": 203 }, "deprecated": false, "children": [], @@ -294,7 +294,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 223 + "lineNumber": 207 }, "deprecated": false, "children": [], @@ -314,7 +314,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 227 + "lineNumber": 211 }, "deprecated": false, "children": [ @@ -330,7 +330,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 227 + "lineNumber": 211 }, "deprecated": false, "isRequired": true @@ -352,7 +352,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 231 + "lineNumber": 215 }, "deprecated": false, "children": [ @@ -368,7 +368,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 231 + "lineNumber": 215 }, "deprecated": false, "isRequired": true @@ -395,7 +395,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 235 + "lineNumber": 219 }, "deprecated": false, "children": [], @@ -413,51 +413,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 239 - }, - "deprecated": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "maps", - "id": "def-public.MapEmbeddable._getFilters", - "type": "Function", - "tags": [], - "label": "_getFilters", - "description": [], - "signature": [ - "() => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataPluginApi", - "section": "def-common.Filter", - "text": "Filter" - }, - "[]" - ], - "source": { - "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 283 - }, - "deprecated": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "maps", - "id": "def-public.MapEmbeddable._getSearchSessionId", - "type": "Function", - "tags": [], - "label": "_getSearchSessionId", - "description": [], - "signature": [ - "() => string | undefined" - ], - "source": { - "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 291 + "lineNumber": 223 }, "deprecated": false, "children": [], @@ -475,7 +431,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 301 + "lineNumber": 255 }, "deprecated": false, "children": [ @@ -488,7 +444,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 301 + "lineNumber": 255 }, "deprecated": false, "children": [ @@ -501,7 +457,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 301 + "lineNumber": 255 }, "deprecated": false } @@ -530,7 +486,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 321 + "lineNumber": 277 }, "deprecated": false, "children": [ @@ -552,7 +508,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 321 + "lineNumber": 277 }, "deprecated": false, "isRequired": true @@ -572,7 +528,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 331 + "lineNumber": 287 }, "deprecated": false, "children": [ @@ -588,7 +544,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 331 + "lineNumber": 287 }, "deprecated": false, "isRequired": false @@ -610,7 +566,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 349 + "lineNumber": 305 }, "deprecated": false, "children": [ @@ -626,7 +582,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 349 + "lineNumber": 305 }, "deprecated": false, "isRequired": true @@ -648,7 +604,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 375 + "lineNumber": 331 }, "deprecated": false, "children": [ @@ -665,7 +621,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 375 + "lineNumber": 331 }, "deprecated": false, "isRequired": true @@ -693,7 +649,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 392 + "lineNumber": 348 }, "deprecated": false, "children": [ @@ -709,7 +665,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 392 + "lineNumber": 348 }, "deprecated": false, "isRequired": true @@ -726,7 +682,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 392 + "lineNumber": 348 }, "deprecated": false, "isRequired": true @@ -749,7 +705,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 392 + "lineNumber": 348 }, "deprecated": false, "isRequired": false @@ -777,7 +733,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 406 + "lineNumber": 362 }, "deprecated": false, "children": [ @@ -800,7 +756,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 406 + "lineNumber": 362 }, "deprecated": false, "isRequired": true @@ -817,7 +773,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 406 + "lineNumber": 362 }, "deprecated": false, "isRequired": true @@ -845,7 +801,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 418 + "lineNumber": 374 }, "deprecated": false, "children": [], @@ -871,43 +827,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 439 - }, - "deprecated": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "maps", - "id": "def-public.MapEmbeddable.setMapExtentFilter", - "type": "Function", - "tags": [], - "label": "setMapExtentFilter", - "description": [], - "signature": [ - "() => void" - ], - "source": { - "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 450 - }, - "deprecated": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "maps", - "id": "def-public.MapEmbeddable.clearMapExtentFilter", - "type": "Function", - "tags": [], - "label": "clearMapExtentFilter", - "description": [], - "signature": [ - "() => void" - ], - "source": { - "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 487 + "lineNumber": 395 }, "deprecated": false, "children": [], @@ -925,7 +845,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 501 + "lineNumber": 406 }, "deprecated": false, "children": [], @@ -943,7 +863,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 517 + "lineNumber": 422 }, "deprecated": false, "children": [], @@ -961,7 +881,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 523 + "lineNumber": 428 }, "deprecated": false, "children": [], @@ -1377,7 +1297,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/types.ts", - "lineNumber": 42 + "lineNumber": 41 }, "deprecated": false, "initialIsOpen": false @@ -1409,7 +1329,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/types.ts", - "lineNumber": 44 + "lineNumber": 43 }, "deprecated": false, "initialIsOpen": false @@ -1615,7 +1535,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 67 + "lineNumber": 66 }, "deprecated": false, "children": [ @@ -1631,7 +1551,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 67 + "lineNumber": 66 }, "deprecated": false, "isRequired": true @@ -1652,7 +1572,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 64 + "lineNumber": 63 }, "deprecated": false, "children": [ @@ -1668,7 +1588,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 64 + "lineNumber": 63 }, "deprecated": false, "isRequired": true @@ -1689,7 +1609,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 61 + "lineNumber": 60 }, "deprecated": false, "children": [], @@ -1707,7 +1627,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 23 + "lineNumber": 22 }, "deprecated": false, "children": [ @@ -1723,7 +1643,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 24 + "lineNumber": 23 }, "deprecated": false } @@ -1743,22 +1663,6 @@ }, "deprecated": false, "children": [ - { - "parentPluginId": "maps", - "id": "def-common.CreateDocSourceResp.indexPatternId", - "type": "string", - "tags": [], - "label": "indexPatternId", - "description": [], - "signature": [ - "string | undefined" - ], - "source": { - "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 9 - }, - "deprecated": false - }, { "parentPluginId": "maps", "id": "def-common.CreateDocSourceResp.success", @@ -1768,7 +1672,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 10 + "lineNumber": 9 }, "deprecated": false }, @@ -1784,7 +1688,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 11 + "lineNumber": 10 }, "deprecated": false } @@ -1800,7 +1704,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 14 + "lineNumber": 13 }, "deprecated": false, "children": [ @@ -1816,7 +1720,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 15 + "lineNumber": 14 }, "deprecated": false }, @@ -1832,7 +1736,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 18 + "lineNumber": 17 }, "deprecated": false } @@ -1848,7 +1752,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 27 + "lineNumber": 26 }, "deprecated": false, "children": [ @@ -1861,7 +1765,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 28 + "lineNumber": 27 }, "deprecated": false }, @@ -1877,7 +1781,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 29 + "lineNumber": 28 }, "deprecated": false }, @@ -1893,7 +1797,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 30 + "lineNumber": 29 }, "deprecated": false } @@ -1911,7 +1815,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 164 + "lineNumber": 163 }, "deprecated": false, "initialIsOpen": false @@ -1925,7 +1829,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 212 + "lineNumber": 211 }, "deprecated": false, "initialIsOpen": false @@ -1939,7 +1843,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 293 + "lineNumber": 292 }, "deprecated": false, "initialIsOpen": false @@ -1953,7 +1857,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 157 + "lineNumber": 156 }, "deprecated": false, "initialIsOpen": false @@ -1967,7 +1871,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 124 + "lineNumber": 123 }, "deprecated": false, "initialIsOpen": false @@ -1981,7 +1885,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 132 + "lineNumber": 131 }, "deprecated": false, "initialIsOpen": false @@ -1995,7 +1899,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 97 + "lineNumber": 96 }, "deprecated": false, "initialIsOpen": false @@ -2009,7 +1913,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 256 + "lineNumber": 255 }, "deprecated": false, "initialIsOpen": false @@ -2023,7 +1927,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 138 + "lineNumber": 137 }, "deprecated": false, "initialIsOpen": false @@ -2037,7 +1941,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 181 + "lineNumber": 180 }, "deprecated": false, "initialIsOpen": false @@ -2051,7 +1955,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 268 + "lineNumber": 267 }, "deprecated": false, "initialIsOpen": false @@ -2065,7 +1969,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 225 + "lineNumber": 224 }, "deprecated": false, "initialIsOpen": false @@ -2079,7 +1983,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 206 + "lineNumber": 205 }, "deprecated": false, "initialIsOpen": false @@ -2093,7 +1997,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 71 + "lineNumber": 70 }, "deprecated": false, "initialIsOpen": false @@ -2107,7 +2011,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 275 + "lineNumber": 274 }, "deprecated": false, "initialIsOpen": false @@ -2121,7 +2025,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 288 + "lineNumber": 287 }, "deprecated": false, "initialIsOpen": false @@ -2135,7 +2039,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 261 + "lineNumber": 260 }, "deprecated": false, "initialIsOpen": false @@ -2149,7 +2053,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 175 + "lineNumber": 174 }, "deprecated": false, "initialIsOpen": false @@ -2163,7 +2067,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 249 + "lineNumber": 248 }, "deprecated": false, "initialIsOpen": false @@ -2177,7 +2081,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 80 + "lineNumber": 79 }, "deprecated": false, "initialIsOpen": false @@ -2191,7 +2095,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 201 + "lineNumber": 200 }, "deprecated": false, "initialIsOpen": false @@ -2205,7 +2109,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 220 + "lineNumber": 219 }, "deprecated": false, "initialIsOpen": false @@ -2219,7 +2123,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 281 + "lineNumber": 280 }, "deprecated": false, "initialIsOpen": false @@ -2233,7 +2137,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 234 + "lineNumber": 233 }, "deprecated": false, "initialIsOpen": false @@ -2252,7 +2156,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 163 + "lineNumber": 162 }, "deprecated": false, "initialIsOpen": false @@ -2266,7 +2170,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 45 + "lineNumber": 44 }, "deprecated": false, "initialIsOpen": false @@ -2348,7 +2252,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 217 + "lineNumber": 216 }, "deprecated": false, "initialIsOpen": false @@ -2362,7 +2266,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 195 + "lineNumber": 194 }, "deprecated": false, "initialIsOpen": false @@ -2379,7 +2283,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 199 + "lineNumber": 198 }, "deprecated": false, "initialIsOpen": false @@ -2396,7 +2300,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 113 + "lineNumber": 112 }, "deprecated": false, "initialIsOpen": false @@ -2413,7 +2317,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 232 + "lineNumber": 231 }, "deprecated": false, "initialIsOpen": false @@ -2430,7 +2334,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 117 + "lineNumber": 116 }, "deprecated": false, "initialIsOpen": false @@ -2447,7 +2351,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 116 + "lineNumber": 115 }, "deprecated": false, "initialIsOpen": false @@ -2464,7 +2368,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 115 + "lineNumber": 114 }, "deprecated": false, "initialIsOpen": false @@ -2481,7 +2385,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 193 + "lineNumber": 192 }, "deprecated": false, "initialIsOpen": false @@ -2498,7 +2402,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 297 + "lineNumber": 296 }, "deprecated": false, "initialIsOpen": false @@ -2753,7 +2657,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 308 + "lineNumber": 307 }, "deprecated": false, "initialIsOpen": false @@ -2770,7 +2674,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 309 + "lineNumber": 308 }, "deprecated": false, "initialIsOpen": false @@ -2787,7 +2691,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 307 + "lineNumber": 306 }, "deprecated": false, "initialIsOpen": false @@ -2804,7 +2708,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 130 + "lineNumber": 129 }, "deprecated": false, "initialIsOpen": false @@ -2821,7 +2725,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 119 + "lineNumber": 118 }, "deprecated": false, "initialIsOpen": false @@ -2838,7 +2742,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 120 + "lineNumber": 119 }, "deprecated": false, "initialIsOpen": false @@ -2863,7 +2767,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 301 + "lineNumber": 300 }, "deprecated": false, "initialIsOpen": false @@ -2894,7 +2798,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 104 + "lineNumber": 103 }, "deprecated": false, "initialIsOpen": false @@ -2911,7 +2815,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 190 + "lineNumber": 189 }, "deprecated": false, "initialIsOpen": false @@ -2928,7 +2832,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 189 + "lineNumber": 188 }, "deprecated": false, "initialIsOpen": false @@ -2947,20 +2851,6 @@ "deprecated": false, "initialIsOpen": false }, - { - "parentPluginId": "maps", - "id": "def-common.INDEX_FEATURE_PATH", - "type": "string", - "tags": [], - "label": "INDEX_FEATURE_PATH", - "description": [], - "source": { - "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 44 - }, - "deprecated": false, - "initialIsOpen": false - }, { "parentPluginId": "maps", "id": "def-common.INDEX_META_DATA_CREATED_BY", @@ -2973,7 +2863,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 303 + "lineNumber": 302 }, "deprecated": false, "initialIsOpen": false @@ -3035,7 +2925,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 101 + "lineNumber": 100 }, "deprecated": false, "initialIsOpen": false @@ -3052,7 +2942,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 56 + "lineNumber": 55 }, "deprecated": false, "initialIsOpen": false @@ -3069,7 +2959,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 53 + "lineNumber": 52 }, "deprecated": false, "initialIsOpen": false @@ -3086,7 +2976,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 52 + "lineNumber": 51 }, "deprecated": false, "initialIsOpen": false @@ -3103,7 +2993,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 150 + "lineNumber": 149 }, "deprecated": false, "initialIsOpen": false @@ -3120,7 +3010,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 149 + "lineNumber": 148 }, "deprecated": false, "initialIsOpen": false @@ -3185,7 +3075,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 305 + "lineNumber": 304 }, "deprecated": false, "initialIsOpen": false @@ -3202,7 +3092,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 111 + "lineNumber": 110 }, "deprecated": false, "initialIsOpen": false @@ -3219,7 +3109,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 122 + "lineNumber": 121 }, "deprecated": false, "initialIsOpen": false @@ -3236,7 +3126,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 103 + "lineNumber": 102 }, "deprecated": false, "initialIsOpen": false @@ -3253,7 +3143,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 110 + "lineNumber": 109 }, "deprecated": false, "initialIsOpen": false @@ -3270,7 +3160,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 48 + "lineNumber": 47 }, "deprecated": false, "initialIsOpen": false @@ -3287,7 +3177,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 47 + "lineNumber": 46 }, "deprecated": false, "initialIsOpen": false @@ -3304,7 +3194,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 49 + "lineNumber": 48 }, "deprecated": false, "initialIsOpen": false @@ -3321,7 +3211,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 58 + "lineNumber": 57 }, "deprecated": false, "initialIsOpen": false @@ -3338,7 +3228,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 218 + "lineNumber": 217 }, "deprecated": false, "initialIsOpen": false @@ -3355,7 +3245,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 148 + "lineNumber": 147 }, "deprecated": false, "initialIsOpen": false @@ -3372,7 +3262,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 299 + "lineNumber": 298 }, "deprecated": false, "initialIsOpen": false @@ -3386,7 +3276,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 108 + "lineNumber": 107 }, "deprecated": false, "initialIsOpen": false @@ -3403,7 +3293,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 105 + "lineNumber": 104 }, "deprecated": false, "initialIsOpen": false @@ -3417,7 +3307,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 107 + "lineNumber": 106 }, "deprecated": false, "initialIsOpen": false @@ -3431,7 +3321,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 106 + "lineNumber": 105 }, "deprecated": false, "initialIsOpen": false @@ -3448,7 +3338,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 266 + "lineNumber": 265 }, "deprecated": false, "initialIsOpen": false @@ -3465,7 +3355,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 188 + "lineNumber": 187 }, "deprecated": false, "initialIsOpen": false @@ -3482,7 +3372,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 192 + "lineNumber": 191 }, "deprecated": false, "initialIsOpen": false @@ -3499,7 +3389,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 114 + "lineNumber": 113 }, "deprecated": false, "initialIsOpen": false @@ -3515,7 +3405,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 152 + "lineNumber": 151 }, "deprecated": false, "children": [ @@ -3531,7 +3421,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 153 + "lineNumber": 152 }, "deprecated": false }, @@ -3547,7 +3437,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 154 + "lineNumber": 153 }, "deprecated": false } diff --git a/api_docs/observability.json b/api_docs/observability.json index fc645dd7e2e6b81..a80e8e44fe665ea 100644 --- a/api_docs/observability.json +++ b/api_docs/observability.json @@ -170,7 +170,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 36 + "lineNumber": 34 }, "deprecated": false, "children": [ @@ -186,7 +186,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 36 + "lineNumber": 34 }, "deprecated": false, "isRequired": true @@ -283,7 +283,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 16 + "lineNumber": 14 }, "deprecated": false, "children": [ @@ -299,7 +299,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 16 + "lineNumber": 14 }, "deprecated": false, "isRequired": true @@ -322,7 +322,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 26 + "lineNumber": 24 }, "deprecated": false, "children": [ @@ -338,7 +338,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 26 + "lineNumber": 24 }, "deprecated": false, "isRequired": true @@ -1050,7 +1050,7 @@ "label": "unsafe", "description": [], "signature": [ - "{ alertingExperience: { enabled: boolean; }; cases: { enabled: boolean; }; }" + "{ alertingExperience: { enabled: boolean; }; }" ], "source": { "path": "x-pack/plugins/observability/public/index.ts", @@ -2040,7 +2040,7 @@ "description": [], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 42 + "lineNumber": 40 }, "deprecated": false, "children": [ @@ -2062,7 +2062,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 43 + "lineNumber": 41 }, "deprecated": false }, @@ -2084,7 +2084,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 44 + "lineNumber": 42 }, "deprecated": false }, @@ -2107,7 +2107,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 45 + "lineNumber": 43 }, "deprecated": false } @@ -2123,7 +2123,7 @@ "description": [], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 48 + "lineNumber": 46 }, "deprecated": false, "children": [ @@ -2146,7 +2146,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 49 + "lineNumber": 47 }, "deprecated": false }, @@ -2168,7 +2168,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 50 + "lineNumber": 48 }, "deprecated": false }, @@ -2190,7 +2190,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 51 + "lineNumber": 49 }, "deprecated": false }, @@ -2212,7 +2212,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 52 + "lineNumber": 50 }, "deprecated": false } @@ -2838,7 +2838,7 @@ "METRIC_TYPE" ], "source": { - "path": "node_modules/@kbn/analytics/target_types/metrics/index.d.ts", + "path": "node_modules/@kbn/analytics/target/types/metrics/index.d.ts", "lineNumber": 10 }, "deprecated": false, @@ -3142,15 +3142,11 @@ "section": "def-public.AlertTypeModel", "text": "AlertTypeModel" }, - " & { format: Formatter; }) => void; getFormatter: (typeId: string) => Formatter | undefined; }; isAlertingExperienceEnabled: () => boolean; navigation: { registerSections: (sections$: ", - "Observable", - "<", - "NavigationSection", - "[]>) => void; }; }" + " & { format: Formatter; }) => void; getFormatter: (typeId: string) => Formatter | undefined; }; isAlertingExperienceEnabled: () => boolean; }" ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 40 + "lineNumber": 38 }, "deprecated": false, "lifecycle": "setup", @@ -3164,13 +3160,11 @@ "label": "ObservabilityPublicStart", "description": [], "signature": [ - "{ navigation: { PageTemplate: (pageTemplateProps: ", - "WrappedPageTemplateProps", - ") => JSX.Element; }; }" + "void" ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 55 + "lineNumber": 53 }, "deprecated": false, "lifecycle": "start", @@ -3437,7 +3431,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 35 + "lineNumber": 25 }, "deprecated": false, "children": [ @@ -3453,7 +3447,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 35 + "lineNumber": 25 }, "deprecated": false, "isRequired": false @@ -3476,7 +3470,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 21 + "lineNumber": 11 }, "deprecated": false, "children": [ @@ -3492,7 +3486,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 21 + "lineNumber": 11 }, "deprecated": false, "isRequired": false @@ -3509,7 +3503,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 21 + "lineNumber": 11 }, "deprecated": false, "isRequired": false @@ -3526,7 +3520,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 21 + "lineNumber": 11 }, "deprecated": false, "isRequired": true @@ -3867,15 +3861,7 @@ "Type", "; end: ", "Type", - "; status: ", - "UnionC", - "<[", - "LiteralC", - "<\"all\">, ", - "LiteralC", - "<\"open\">, ", - "LiteralC", - "<\"closed\">]>; }>, ", + "; }>, ", "PartialC", "<{ kuery: ", "StringC", @@ -3942,11 +3928,11 @@ "label": "ObservabilityConfig", "description": [], "signature": [ - "{ readonly enabled: boolean; readonly annotations: Readonly<{} & { enabled: boolean; index: string; }>; readonly unsafe: Readonly<{} & { cases: Readonly<{} & { enabled: boolean; }>; alertingExperience: Readonly<{} & { enabled: boolean; }>; }>; }" + "{ readonly enabled: boolean; readonly annotations: Readonly<{} & { enabled: boolean; index: string; }>; readonly unsafe: Readonly<{} & { alertingExperience: Readonly<{} & { enabled: boolean; }>; }>; }" ], "source": { "path": "x-pack/plugins/observability/server/index.ts", - "lineNumber": 35 + "lineNumber": 34 }, "deprecated": false, "initialIsOpen": false @@ -3988,15 +3974,7 @@ "Type", "; end: ", "Type", - "; status: ", - "UnionC", - "<[", - "LiteralC", - "<\"all\">, ", - "LiteralC", - "<\"open\">, ", - "LiteralC", - "<\"closed\">]>; }>, ", + "; }>, ", "PartialC", "<{ kuery: ", "StringC", diff --git a/api_docs/presentation_util.json b/api_docs/presentation_util.json index bde8373e4450e01..ee045dfd830fbe6 100644 --- a/api_docs/presentation_util.json +++ b/api_docs/presentation_util.json @@ -528,9 +528,7 @@ "type": "CompoundType", "tags": [], "label": "Component", - "description": [ - "A component deferred by `React.lazy`" - ], + "description": [], "signature": [ "React.ComponentType

" ], @@ -547,9 +545,7 @@ "type": "CompoundType", "tags": [], "label": "fallback", - "description": [ - "A fallback component to render while things load; default is `EuiLoadingSpinner`" - ], + "description": [], "signature": [ "React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)> | null" ], diff --git a/api_docs/reporting.json b/api_docs/reporting.json index b2529f510bc2ed2..e8cea57b24902c7 100644 --- a/api_docs/reporting.json +++ b/api_docs/reporting.json @@ -911,10 +911,10 @@ "children": [ { "parentPluginId": "reporting", - "id": "def-server.ReportingCore.getContract", + "id": "def-server.ReportingCore.getStartContract", "type": "Function", "tags": [], - "label": "getContract", + "label": "getStartContract", "description": [], "signature": [ "() => ", @@ -1010,7 +1010,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 90 + "lineNumber": 92 }, "deprecated": false, "children": [ @@ -1026,7 +1026,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 90 + "lineNumber": 92 }, "deprecated": false, "isRequired": true @@ -1048,7 +1048,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 104 + "lineNumber": 106 }, "deprecated": false, "children": [ @@ -1064,7 +1064,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 104 + "lineNumber": 106 }, "deprecated": false, "isRequired": true @@ -1084,7 +1084,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 117 + "lineNumber": 119 }, "deprecated": false, "children": [], @@ -1102,7 +1102,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 128 + "lineNumber": 130 }, "deprecated": false, "children": [], @@ -1120,7 +1120,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 135 + "lineNumber": 137 }, "deprecated": false, "children": [], @@ -1146,7 +1146,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 142 + "lineNumber": 144 }, "deprecated": false, "children": [ @@ -1168,7 +1168,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 142 + "lineNumber": 144 }, "deprecated": false, "isRequired": true @@ -1190,7 +1190,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 151 + "lineNumber": 153 }, "deprecated": false, "children": [], @@ -1215,7 +1215,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 185 + "lineNumber": 187 }, "deprecated": false, "children": [], @@ -1233,7 +1233,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 197 + "lineNumber": 199 }, "deprecated": false, "children": [], @@ -1253,7 +1253,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 204 + "lineNumber": 206 }, "deprecated": false, "children": [], @@ -1272,7 +1272,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 212 + "lineNumber": 214 }, "deprecated": false, "children": [], @@ -1302,7 +1302,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 216 + "lineNumber": 218 }, "deprecated": false, "children": [ @@ -1321,7 +1321,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 216 + "lineNumber": 218 }, "deprecated": false, "isRequired": true @@ -1343,7 +1343,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 220 + "lineNumber": 222 }, "deprecated": false, "children": [], @@ -1363,7 +1363,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 224 + "lineNumber": 226 }, "deprecated": false, "children": [], @@ -1383,7 +1383,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 234 + "lineNumber": 236 }, "deprecated": false, "children": [], @@ -1401,7 +1401,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 240 + "lineNumber": 242 }, "deprecated": false, "children": [], @@ -1420,7 +1420,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 248 + "lineNumber": 250 }, "deprecated": false, "children": [], @@ -1454,7 +1454,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 260 + "lineNumber": 262 }, "deprecated": false, "children": [ @@ -1478,7 +1478,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 260 + "lineNumber": 262 }, "deprecated": false, "isRequired": true @@ -1508,7 +1508,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 266 + "lineNumber": 268 }, "deprecated": false, "children": [ @@ -1531,7 +1531,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 266 + "lineNumber": 268 }, "deprecated": false, "isRequired": true @@ -1548,7 +1548,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 266 + "lineNumber": 268 }, "deprecated": false, "isRequired": true @@ -1578,7 +1578,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 280 + "lineNumber": 282 }, "deprecated": false, "children": [ @@ -1594,7 +1594,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 280 + "lineNumber": 282 }, "deprecated": false, "isRequired": true @@ -1611,7 +1611,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 280 + "lineNumber": 282 }, "deprecated": false, "isRequired": false @@ -1628,7 +1628,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 280 + "lineNumber": 282 }, "deprecated": false, "isRequired": true @@ -1666,7 +1666,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 300 + "lineNumber": 302 }, "deprecated": false, "children": [ @@ -1689,7 +1689,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 300 + "lineNumber": 302 }, "deprecated": false, "isRequired": true @@ -1706,7 +1706,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 300 + "lineNumber": 302 }, "deprecated": false, "isRequired": true @@ -1734,7 +1734,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 310 + "lineNumber": 312 }, "deprecated": false, "children": [], @@ -1760,7 +1760,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 315 + "lineNumber": 317 }, "deprecated": false, "children": [], @@ -1778,7 +1778,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 320 + "lineNumber": 322 }, "deprecated": false, "children": [ @@ -1794,7 +1794,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 320 + "lineNumber": 322 }, "deprecated": false, "isRequired": true @@ -1814,7 +1814,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 324 + "lineNumber": 326 }, "deprecated": false, "children": [ @@ -1830,7 +1830,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 324 + "lineNumber": 326 }, "deprecated": false, "isRequired": true @@ -1850,7 +1850,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 328 + "lineNumber": 330 }, "deprecated": false, "children": [], @@ -1918,7 +1918,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 26 + "lineNumber": 25 }, "deprecated": false, "children": [ @@ -1934,7 +1934,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 31 + "lineNumber": 30 }, "deprecated": false, "children": [ @@ -1959,7 +1959,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 31 + "lineNumber": 30 }, "deprecated": false, "isRequired": true @@ -2002,7 +2002,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 35 + "lineNumber": 34 }, "deprecated": false, "children": [ @@ -2025,7 +2025,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 35 + "lineNumber": 34 }, "deprecated": false, "isRequired": true @@ -2048,7 +2048,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 35 + "lineNumber": 34 }, "deprecated": false, "isRequired": true @@ -2091,7 +2091,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 88 + "lineNumber": 87 }, "deprecated": false, "children": [ @@ -2113,7 +2113,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 88 + "lineNumber": 87 }, "deprecated": false, "isRequired": true @@ -2136,7 +2136,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 88 + "lineNumber": 87 }, "deprecated": false, "isRequired": true diff --git a/api_docs/rule_registry.json b/api_docs/rule_registry.json index cd1f4994c1da611..63a50f8fbd42f56 100644 --- a/api_docs/rule_registry.json +++ b/api_docs/rule_registry.json @@ -695,8 +695,8 @@ "{ readonly enabled: boolean; readonly index: string; readonly write: Readonly<{} & { enabled: boolean; }>; }" ], "source": { - "path": "x-pack/plugins/rule_registry/server/config.ts", - "lineNumber": 20 + "path": "x-pack/plugins/rule_registry/server/index.ts", + "lineNumber": 28 }, "deprecated": false, "initialIsOpen": false @@ -706,49 +706,18 @@ "setup": { "parentPluginId": "ruleRegistry", "id": "def-server.RuleRegistryPluginSetupContract", - "type": "Interface", + "type": "Type", "tags": [], "label": "RuleRegistryPluginSetupContract", "description": [], + "signature": [ + "RuleDataPluginService" + ], "source": { "path": "x-pack/plugins/rule_registry/server/plugin.ts", - "lineNumber": 22 + "lineNumber": 12 }, "deprecated": false, - "children": [ - { - "parentPluginId": "ruleRegistry", - "id": "def-server.RuleRegistryPluginSetupContract.ruleDataService", - "type": "Object", - "tags": [], - "label": "ruleDataService", - "description": [], - "signature": [ - "RuleDataPluginService" - ], - "source": { - "path": "x-pack/plugins/rule_registry/server/plugin.ts", - "lineNumber": 23 - }, - "deprecated": false - }, - { - "parentPluginId": "ruleRegistry", - "id": "def-server.RuleRegistryPluginSetupContract.eventLogService", - "type": "Object", - "tags": [], - "label": "eventLogService", - "description": [], - "signature": [ - "IEventLogService" - ], - "source": { - "path": "x-pack/plugins/rule_registry/server/plugin.ts", - "lineNumber": 24 - }, - "deprecated": false - } - ], "lifecycle": "setup", "initialIsOpen": true }, @@ -764,7 +733,7 @@ ], "source": { "path": "x-pack/plugins/rule_registry/server/plugin.ts", - "lineNumber": 27 + "lineNumber": 13 }, "deprecated": false, "lifecycle": "start", diff --git a/api_docs/spaces.json b/api_docs/spaces.json index 2f2d79c2379d581..5225e8cebbeb5a0 100644 --- a/api_docs/spaces.json +++ b/api_docs/spaces.json @@ -1210,7 +1210,7 @@ "plugin": "reporting", "link": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 269 + "lineNumber": 271 } }, { @@ -2030,21 +2030,21 @@ "plugin": "reporting", "link": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 267 + "lineNumber": 269 } }, { "plugin": "reporting", "link": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 289 + "lineNumber": 291 } }, { "plugin": "reporting", "link": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 301 + "lineNumber": 303 } }, { diff --git a/api_docs/triggers_actions_ui.json b/api_docs/triggers_actions_ui.json index de7a13b3080fe01..cade40cf39c7381 100644 --- a/api_docs/triggers_actions_ui.json +++ b/api_docs/triggers_actions_ui.json @@ -45,7 +45,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 80 + "lineNumber": 77 }, "deprecated": false, "children": [ @@ -61,7 +61,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 91 + "lineNumber": 88 }, "deprecated": false, "children": [], @@ -94,7 +94,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 96 + "lineNumber": 93 }, "deprecated": false, "children": [ @@ -117,7 +117,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 96 + "lineNumber": 93 }, "deprecated": false, "isRequired": true @@ -134,7 +134,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 96 + "lineNumber": 93 }, "deprecated": false, "isRequired": true @@ -161,7 +161,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 172 + "lineNumber": 169 }, "deprecated": false, "children": [], @@ -179,7 +179,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 206 + "lineNumber": 203 }, "deprecated": false, "children": [], @@ -228,6 +228,44 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.AlertAdd", + "type": "Function", + "tags": [], + "label": "AlertAdd", + "description": [], + "signature": [ + "(props: ", + "AlertAddProps", + ">) => JSX.Element" + ], + "source": { + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/index.tsx", + "lineNumber": 11 + }, + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.props", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "T" + ], + "source": { + "path": "x-pack/plugins/triggers_actions_ui/public/application/lib/suspended_component_with_props.tsx", + "lineNumber": 16 + }, + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "triggersActionsUi", "id": "def-public.AlertConditions", @@ -308,6 +346,44 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.AlertEdit", + "type": "Function", + "tags": [], + "label": "AlertEdit", + "description": [], + "signature": [ + "(props: ", + "AlertEditProps", + ">) => JSX.Element" + ], + "source": { + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/index.tsx", + "lineNumber": 17 + }, + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.props", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "T" + ], + "source": { + "path": "x-pack/plugins/triggers_actions_ui/public/application/lib/suspended_component_with_props.tsx", + "lineNumber": 16 + }, + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "triggersActionsUi", "id": "def-public.ConnectorAddFlyout", @@ -442,7 +518,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira.tsx", - "lineNumber": 62 + "lineNumber": 63 }, "deprecated": false, "children": [], @@ -469,7 +545,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient.tsx", - "lineNumber": 67 + "lineNumber": 68 }, "deprecated": false, "children": [], @@ -676,7 +752,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow.tsx", - "lineNumber": 63 + "lineNumber": 64 }, "deprecated": false, "children": [], @@ -703,7 +779,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow.tsx", - "lineNumber": 98 + "lineNumber": 99 }, "deprecated": false, "children": [], @@ -1383,7 +1459,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 235 + "lineNumber": 234 }, "deprecated": false, "children": [ @@ -1396,7 +1472,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 236 + "lineNumber": 235 }, "deprecated": false }, @@ -1409,7 +1485,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 237 + "lineNumber": 236 }, "deprecated": false }, @@ -1422,7 +1498,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 238 + "lineNumber": 237 }, "deprecated": false }, @@ -1446,7 +1522,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 239 + "lineNumber": 238 }, "deprecated": false }, @@ -1469,7 +1545,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 240 + "lineNumber": 239 }, "deprecated": false, "returnComment": [], @@ -1486,7 +1562,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 240 + "lineNumber": 239 }, "deprecated": false } @@ -1512,7 +1588,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 241 + "lineNumber": 240 }, "deprecated": false, "returnComment": [], @@ -1544,7 +1620,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 244 + "lineNumber": 243 }, "deprecated": false }, @@ -1560,7 +1636,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 245 + "lineNumber": 244 }, "deprecated": false } @@ -1586,7 +1662,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 213 + "lineNumber": 212 }, "deprecated": false, "children": [ @@ -1602,7 +1678,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 218 + "lineNumber": 217 }, "deprecated": false }, @@ -1615,7 +1691,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 219 + "lineNumber": 218 }, "deprecated": false }, @@ -1628,7 +1704,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 220 + "lineNumber": 219 }, "deprecated": false }, @@ -1644,7 +1720,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 221 + "lineNumber": 220 }, "deprecated": false }, @@ -1660,7 +1736,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 222 + "lineNumber": 221 }, "deprecated": false, "returnComment": [], @@ -1677,7 +1753,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 222 + "lineNumber": 221 }, "deprecated": false }, @@ -1693,7 +1769,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 222 + "lineNumber": 221 }, "deprecated": false } @@ -1719,7 +1795,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 223 + "lineNumber": 222 }, "deprecated": false, "returnComment": [], @@ -1736,7 +1812,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 224 + "lineNumber": 223 }, "deprecated": false }, @@ -1760,7 +1836,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 225 + "lineNumber": 224 }, "deprecated": false } @@ -1784,7 +1860,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 227 + "lineNumber": 226 }, "deprecated": false }, @@ -1797,7 +1873,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 228 + "lineNumber": 227 }, "deprecated": false }, @@ -1820,7 +1896,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 229 + "lineNumber": 228 }, "deprecated": false }, @@ -1836,7 +1912,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 230 + "lineNumber": 229 }, "deprecated": false }, @@ -1858,7 +1934,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 231 + "lineNumber": 230 }, "deprecated": false }, @@ -1880,7 +1956,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 232 + "lineNumber": 231 }, "deprecated": false } @@ -2022,7 +2098,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 248 + "lineNumber": 247 }, "deprecated": false, "children": [ @@ -2038,7 +2114,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 249 + "lineNumber": 248 }, "deprecated": false } @@ -2407,7 +2483,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 128 + "lineNumber": 127 }, "deprecated": false, "children": [ @@ -2423,7 +2499,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 129 + "lineNumber": 128 }, "deprecated": false } @@ -2455,7 +2531,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 80 + "lineNumber": 79 }, "deprecated": false, "initialIsOpen": false @@ -2505,7 +2581,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 162 + "lineNumber": 161 }, "deprecated": false, "initialIsOpen": false @@ -2561,7 +2637,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 65 + "lineNumber": 64 }, "deprecated": false, "initialIsOpen": false @@ -2578,7 +2654,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 180 + "lineNumber": 179 }, "deprecated": false, "initialIsOpen": false @@ -2619,7 +2695,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 41 + "lineNumber": 40 }, "deprecated": false, "initialIsOpen": false @@ -2677,7 +2753,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 69 + "lineNumber": 68 }, "deprecated": false, "initialIsOpen": false @@ -3706,7 +3782,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 44 + "lineNumber": 41 }, "deprecated": false, "children": [ @@ -3725,7 +3801,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 45 + "lineNumber": 42 }, "deprecated": false }, @@ -3750,7 +3826,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 46 + "lineNumber": 43 }, "deprecated": false } @@ -3767,7 +3843,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 49 + "lineNumber": 46 }, "deprecated": false, "children": [ @@ -3786,7 +3862,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 50 + "lineNumber": 47 }, "deprecated": false }, @@ -3811,7 +3887,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 51 + "lineNumber": 48 }, "deprecated": false }, @@ -3831,7 +3907,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 52 + "lineNumber": 49 }, "deprecated": false, "returnComment": [], @@ -3872,7 +3948,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 53 + "lineNumber": 50 }, "deprecated": false } @@ -3894,7 +3970,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 55 + "lineNumber": 52 }, "deprecated": false, "returnComment": [], @@ -3929,7 +4005,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 56 + "lineNumber": 53 }, "deprecated": false } @@ -3951,7 +4027,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 58 + "lineNumber": 55 }, "deprecated": false, "returnComment": [], @@ -3984,7 +4060,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 59 + "lineNumber": 56 }, "deprecated": false } @@ -4006,7 +4082,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 61 + "lineNumber": 58 }, "deprecated": false, "returnComment": [], @@ -4039,7 +4115,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 62 + "lineNumber": 59 }, "deprecated": false } diff --git a/api_docs/visualizations.json b/api_docs/visualizations.json index 0df428a158a3da1..bea890f00e0ed2a 100644 --- a/api_docs/visualizations.json +++ b/api_docs/visualizations.json @@ -85,15 +85,7 @@ "label": "getSupportedTriggers", "description": [], "signature": [ - "((params?: ", - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.VisParams", - "text": "VisParams" - }, - " | undefined) => string[]) | undefined" + "(() => string[]) | undefined" ], "source": { "path": "src/plugins/visualizations/public/vis_types/base_vis_type.ts", @@ -3335,15 +3327,7 @@ "\nIf given, it will return the supported triggers for this vis." ], "signature": [ - "((params?: ", - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.VisParams", - "text": "VisParams" - }, - " | undefined) => string[]) | undefined" + "(() => string[]) | undefined" ], "source": { "path": "src/plugins/visualizations/public/vis_types/types.ts", diff --git a/docs/developer/getting-started/monorepo-packages.asciidoc b/docs/developer/getting-started/monorepo-packages.asciidoc index dbfbe90ec9263e8..4e8bbf76eaacb0a 100644 --- a/docs/developer/getting-started/monorepo-packages.asciidoc +++ b/docs/developer/getting-started/monorepo-packages.asciidoc @@ -80,7 +80,6 @@ yarn kbn watch-bazel - @kbn/eslint-plugin-eslint - @kbn/expect - @kbn/i18n -- @kbn/io-ts-utils - @kbn/legacy-logging - @kbn/logging - @kbn/mapbox-gl diff --git a/docs/user/alerting/rule-management.asciidoc b/docs/user/alerting/rule-management.asciidoc index b908bd03b099274..e47858f58cd1a6c 100644 --- a/docs/user/alerting/rule-management.asciidoc +++ b/docs/user/alerting/rule-management.asciidoc @@ -57,6 +57,15 @@ These operations can also be performed in bulk by multi-selecting rules and clic [role="screenshot"] image:images/bulk-mute-disable.png[The Manage rules button lets you mute/unmute, enable/disable, and delete in bulk] +[float] +[[importing-and-exporting-rules]] +=== Importing and exporting rules + +To import and export rules, use the <>. +After the succesful import the proper banner will be displayed: +[role="screenshot"] +image::images/rules-imported-banner.png[Rules import banner, width=50%] + [float] === Required permissions diff --git a/docs/user/dashboard/lens.asciidoc b/docs/user/dashboard/lens.asciidoc index 1f3b4c429f70459..613432908df3d3e 100644 --- a/docs/user/dashboard/lens.asciidoc +++ b/docs/user/dashboard/lens.asciidoc @@ -4,19 +4,8 @@ To create visualizations with *Lens*, you drag and drop data fields onto the visualization builder, then *Lens* uses heuristics to apply each field. -++++ - - -
-++++ +[role="screenshot"] +image:dashboard/images/lens.png[Lens] [float] [[lens-required-choices]] diff --git a/docs/user/introduction.asciidoc b/docs/user/introduction.asciidoc index 38435708aaf9977..8a0dd5e4e2a2baa 100644 --- a/docs/user/introduction.asciidoc +++ b/docs/user/introduction.asciidoc @@ -20,20 +20,6 @@ Manage your indices and ingest pipelines, monitor the health of your Elastic Stack cluster, and control which users have access to which features. -++++ - - -
-++++ - *{kib} is for administrators, analysts, and business users.* As an admin, your role is to manage the Elastic Stack, from creating your deployment to getting {es} data into {kib}, and then @@ -57,6 +43,9 @@ If you’re not ready to use your own data, you can add a sample data set. The home page provides access to the *Enterprise Search*, *Observability*, and *Security* solutions, and everything you need to visualize and analyze your data. +[role="screenshot"] +image::images/home-page.png[Kibana home page] + To access all of {kib} features, use the main menu. Open this menu by clicking the menu icon. To keep the main menu visible at all times, click *Dock navigation*. diff --git a/package.json b/package.json index f41c85c4c7b8055..1369b1d105aa45f 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "@kbn/mapbox-gl": "link:bazel-bin/packages/kbn-mapbox-gl/npm_module", "@kbn/i18n": "link:bazel-bin/packages/kbn-i18n/npm_module", "@kbn/interpreter": "link:packages/kbn-interpreter", - "@kbn/io-ts-utils": "link:bazel-bin/packages/kbn-io-ts-utils/npm_module", + "@kbn/io-ts-utils": "link:packages/kbn-io-ts-utils", "@kbn/legacy-logging": "link:bazel-bin/packages/kbn-legacy-logging/npm_module", "@kbn/logging": "link:bazel-bin/packages/kbn-logging/npm_module", "@kbn/monaco": "link:bazel-bin/packages/kbn-monaco/npm_module", @@ -161,7 +161,6 @@ "@mapbox/mapbox-gl-draw": "1.3.0", "@mapbox/mapbox-gl-rtl-text": "0.2.3", "@mapbox/vector-tile": "1.3.1", - "@reduxjs/toolkit": "^1.5.1", "@scant/router": "^0.1.1", "@slack/webhook": "^5.0.4", "@turf/along": "6.0.1", @@ -174,7 +173,6 @@ "@turf/distance": "6.0.1", "@turf/helpers": "6.0.1", "@turf/length": "^6.0.2", - "@types/redux-logger": "^3.0.8", "JSONStream": "1.3.5", "abort-controller": "^3.0.0", "abortcontroller-polyfill": "^1.4.0", @@ -367,7 +365,6 @@ "redux": "^4.0.5", "redux-actions": "^2.6.5", "redux-devtools-extension": "^2.13.8", - "redux-logger": "^3.0.6", "redux-observable": "^1.2.0", "redux-saga": "^1.1.3", "redux-thunk": "^2.3.0", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index de3498da1a69769..c885666f7a916e4 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -22,7 +22,6 @@ filegroup( "//packages/kbn-eslint-plugin-eslint:build", "//packages/kbn-expect:build", "//packages/kbn-i18n:build", - "//packages/kbn-io-ts-utils:build", "//packages/kbn-legacy-logging:build", "//packages/kbn-logging:build", "//packages/kbn-mapbox-gl:build", diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts index c714165a0922c02..bcbb9cf3e7bbe05 100644 --- a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts @@ -19,7 +19,7 @@ import { import { AnchorLink, ApiDeclaration, TypeKind } from '../types'; import { buildApiDecsForParameters } from './build_parameter_decs'; import { getSignature } from './get_signature'; -import { getJSDocReturnTagComment, getJSDocs } from './js_doc_utils'; +import { getJSDocReturnTagComment } from './js_doc_utils'; import { buildBasicApiDeclaration } from './build_basic_api_declaration'; /** @@ -66,8 +66,7 @@ export function getArrowFunctionDec( anchorLink, currentPluginId, log, - captureReferences, - getJSDocs(node) + captureReferences ), // need to override the signature - use the initializer, not the node. signature: getSignature(initializer, plugins, log), diff --git a/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts b/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts index ff71b0efc79d1c5..cdf1e5b718ccaf3 100644 --- a/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts +++ b/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts @@ -46,8 +46,6 @@ function fnIsCorrect(fn: ApiDeclaration | undefined) { expect(p1!.isRequired).toBe(true); expect(p1!.signature?.length).toBe(1); expect(linkCount(p1!.signature!)).toBe(0); - expect(p1?.description).toBeDefined(); - expect(p1?.description?.length).toBe(1); const p2 = fn?.children!.find((c) => c.label === 'b'); expect(p2).toBeDefined(); @@ -55,15 +53,12 @@ function fnIsCorrect(fn: ApiDeclaration | undefined) { expect(p2!.type).toBe(TypeKind.NumberKind); expect(p2!.signature?.length).toBe(1); expect(linkCount(p2!.signature!)).toBe(0); - expect(p2?.description?.length).toBe(1); const p3 = fn?.children!.find((c) => c.label === 'c'); expect(p3).toBeDefined(); expect(p3!.isRequired).toBe(true); expect(p3!.type).toBe(TypeKind.ArrayKind); expect(linkCount(p3!.signature!)).toBe(1); - expect(p3?.description).toBeDefined(); - expect(p3?.description?.length).toBe(1); const p4 = fn?.children!.find((c) => c.label === 'd'); expect(p4).toBeDefined(); @@ -71,7 +66,6 @@ function fnIsCorrect(fn: ApiDeclaration | undefined) { expect(p4!.type).toBe(TypeKind.CompoundTypeKind); expect(p4!.signature?.length).toBe(1); expect(linkCount(p4!.signature!)).toBe(1); - expect(p4?.description?.length).toBe(1); const p5 = fn?.children!.find((c) => c.label === 'e'); expect(p5).toBeDefined(); @@ -79,7 +73,6 @@ function fnIsCorrect(fn: ApiDeclaration | undefined) { expect(p5!.type).toBe(TypeKind.StringKind); expect(p5!.signature?.length).toBe(1); expect(linkCount(p5!.signature!)).toBe(0); - expect(p5?.description?.length).toBe(1); } beforeAll(() => { diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json index 7d8a90c3aad77ad..deb40d875b44282 100644 --- a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json +++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json @@ -165,9 +165,7 @@ "type": "CompoundType", "tags": [], "label": "a", - "description": [ - "im a string" - ], + "description": [], "signature": [ { "pluginId": "pluginA", @@ -294,9 +292,7 @@ "type": "string", "tags": [], "label": "a", - "description": [ - "The letter A" - ], + "description": [], "signature": [ "string" ], @@ -313,9 +309,7 @@ "type": "number", "tags": [], "label": "b", - "description": [ - "Feed me to the function" - ], + "description": [], "signature": [ "number | undefined" ], @@ -332,9 +326,7 @@ "type": "Array", "tags": [], "label": "c", - "description": [ - "So many params" - ], + "description": [], "signature": [ { "pluginId": "pluginA", @@ -358,9 +350,7 @@ "type": "CompoundType", "tags": [], "label": "d", - "description": [ - "a great param" - ], + "description": [], "signature": [ { "pluginId": "pluginA", @@ -383,9 +373,7 @@ "type": "string", "tags": [], "label": "e", - "description": [ - "Another comment" - ], + "description": [], "signature": [ "string | undefined" ], @@ -598,7 +586,7 @@ "section": "def-public.ImAType", "text": "ImAType" }, - ", e?: string | undefined) => ", + ", e: string | undefined) => ", { "pluginId": "pluginA", "scope": "public", diff --git a/packages/kbn-io-ts-utils/BUILD.bazel b/packages/kbn-io-ts-utils/BUILD.bazel deleted file mode 100644 index 6b26173fe8f369c..000000000000000 --- a/packages/kbn-io-ts-utils/BUILD.bazel +++ /dev/null @@ -1,85 +0,0 @@ -load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") -load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") - -PKG_BASE_NAME = "kbn-io-ts-utils" -PKG_REQUIRE_NAME = "@kbn/io-ts-utils" - -SOURCE_FILES = glob( - [ - "src/**/*.ts", - ], - exclude = [ - "**/*.test.*" - ], -) - -SRCS = SOURCE_FILES - -filegroup( - name = "srcs", - srcs = SRCS, -) - -NPM_MODULE_EXTRA_FILES = [ - "package.json", -] - -SRC_DEPS = [ - "@npm//fp-ts", - "@npm//io-ts", - "@npm//lodash", - "@npm//tslib", -] - -TYPES_DEPS = [ - "@npm//@types/jest", - "@npm//@types/lodash", - "@npm//@types/node", -] - -DEPS = SRC_DEPS + TYPES_DEPS - -ts_config( - name = "tsconfig", - src = "tsconfig.json", - deps = [ - "//:tsconfig.base.json", - ], -) - -ts_project( - name = "tsc", - args = ['--pretty'], - srcs = SRCS, - deps = DEPS, - declaration = True, - declaration_map = True, - incremental = True, - out_dir = "target", - source_map = True, - root_dir = "src", - tsconfig = ":tsconfig", -) - -js_library( - name = PKG_BASE_NAME, - srcs = NPM_MODULE_EXTRA_FILES, - deps = DEPS + [":tsc"], - package_name = PKG_REQUIRE_NAME, - visibility = ["//visibility:public"], -) - -pkg_npm( - name = "npm_module", - deps = [ - ":%s" % PKG_BASE_NAME, - ] -) - -filegroup( - name = "build", - srcs = [ - ":npm_module", - ], - visibility = ["//visibility:public"], -) diff --git a/packages/kbn-io-ts-utils/package.json b/packages/kbn-io-ts-utils/package.json index 9d22277f27c0144..4d6f02d3f85a621 100644 --- a/packages/kbn-io-ts-utils/package.json +++ b/packages/kbn-io-ts-utils/package.json @@ -4,5 +4,10 @@ "types": "./target/index.d.ts", "version": "1.0.0", "license": "SSPL-1.0 OR Elastic License 2.0", - "private": true + "private": true, + "scripts": { + "build": "../../node_modules/.bin/tsc", + "kbn:bootstrap": "yarn build", + "kbn:watch": "yarn build --watch" + } } diff --git a/packages/kbn-io-ts-utils/tsconfig.json b/packages/kbn-io-ts-utils/tsconfig.json index 7b8f25527549923..6c67518e2107340 100644 --- a/packages/kbn-io-ts-utils/tsconfig.json +++ b/packages/kbn-io-ts-utils/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { - "incremental": true, + "incremental": false, "outDir": "./target", "stripInternal": false, "declaration": true, diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts index 3d3c41aed5a72a4..2c71afd9e066e2d 100644 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts +++ b/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts @@ -31,7 +31,6 @@ export * from './read_exception_list_item_schema'; export * from './read_exception_list_schema'; export * from './read_list_item_schema'; export * from './read_list_schema'; -export * from './summary_exception_list_schema'; export * from './update_endpoint_list_item_schema'; export * from './update_exception_list_item_schema'; export * from './update_exception_list_item_validation'; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts deleted file mode 100644 index 384f093d0884aac..000000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { ID, LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; - -import { SummaryExceptionListSchema } from '.'; - -export const getSummaryExceptionListSchemaMock = (): SummaryExceptionListSchema => ({ - id: ID, - list_id: LIST_ID, - namespace_type: NAMESPACE_TYPE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts deleted file mode 100644 index ade015b0d26bfac..000000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { left } from 'fp-ts/lib/Either'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getSummaryExceptionListSchemaMock } from './index.mock'; -import { SummaryExceptionListSchema, summaryExceptionListSchema } from '.'; - -describe('summary_exception_list_schema', () => { - test('it should validate a typical exception list request', () => { - const payload = getSummaryExceptionListSchemaMock(); - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "list_id"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.list_id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "namespace_type" but default to "single"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.namespace_type; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getSummaryExceptionListSchemaMock()); - }); - - test('it should accept an undefined for "id", "list_id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.id; - delete payload.namespace_type; - delete payload.list_id; - const output = getSummaryExceptionListSchemaMock(); - delete output.id; - delete output.list_id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should accept an undefined for "id", "list_id"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.id; - delete payload.list_id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.id; - delete payload.namespace_type; - const output = getSummaryExceptionListSchemaMock(); - delete output.id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should accept an undefined for "list_id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.namespace_type; - delete payload.list_id; - const output = getSummaryExceptionListSchemaMock(); - delete output.list_id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: SummaryExceptionListSchema & { - extraKey?: string; - } = getSummaryExceptionListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts deleted file mode 100644 index 990091882df7bdc..000000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import * as t from 'io-ts'; - -import { NamespaceType } from '../../common/default_namespace'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; -import { list_id } from '../../common/list_id'; -import { namespace_type } from '../../common/namespace_type'; - -export const summaryExceptionListSchema = t.exact( - t.partial({ - id, - list_id, - namespace_type, // defaults to 'single' if not set during decode - }) -); - -export type SummaryExceptionListSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type SummaryExceptionListSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'namespace_type' -> & { - namespace_type: NamespaceType; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts deleted file mode 100644 index ea086f427451d6f..000000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getListSummaryResponseMock } from './index.mock'; -import { ExceptionListSummarySchema, exceptionListSummarySchema } from '.'; - -describe('list_summary_schema', () => { - test('it should validate a typical list summary response', () => { - const payload = getListSummaryResponseMock(); - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "windows"', () => { - const payload = getListSummaryResponseMock(); - // @ts-expect-error - delete payload.windows; - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "windows"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "linux"', () => { - const payload = getListSummaryResponseMock(); - // @ts-expect-error - delete payload.linux; - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "linux"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "macos"', () => { - const payload = getListSummaryResponseMock(); - // @ts-expect-error - delete payload.macos; - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "macos"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "total"', () => { - const payload = getListSummaryResponseMock(); - // @ts-expect-error - delete payload.total; - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "total"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ExceptionListSummarySchema & { - extraKey?: string; - } = getListSummaryResponseMock(); - payload.extraKey = 'some new value'; - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts deleted file mode 100644 index 4c0cc8301dbf7e1..000000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; -import * as t from 'io-ts'; - -export const exceptionListSummarySchema = t.exact( - t.type({ - windows: PositiveInteger, - linux: PositiveInteger, - macos: PositiveInteger, - total: PositiveInteger, - }) -); - -export type ExceptionListSummarySchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts index dc29bdf16ab48a7..005e753ccf1b391 100644 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts +++ b/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts @@ -16,6 +16,5 @@ export * from './found_list_item_schema'; export * from './found_list_schema'; export * from './list_item_schema'; export * from './list_schema'; -export * from './exception_list_summary_schema'; export * from './list_item_index_exist_schema'; export * from './search_list_item_schema'; diff --git a/packages/kbn-server-route-repository/package.json b/packages/kbn-server-route-repository/package.json index 4ae625d83a7003e..ce1ca02d0c4f6b1 100644 --- a/packages/kbn-server-route-repository/package.json +++ b/packages/kbn-server-route-repository/package.json @@ -9,5 +9,8 @@ "build": "../../node_modules/.bin/tsc", "kbn:bootstrap": "yarn build", "kbn:watch": "yarn build --watch" + }, + "dependencies": { + "@kbn/io-ts-utils": "link:../kbn-io-ts-utils" } } diff --git a/src/core/server/saved_objects/service/lib/aggregations/aggs_types/bucket_aggs.ts b/src/core/server/saved_objects/service/lib/aggregations/aggs_types/bucket_aggs.ts index cf27505e8f073cc..186962b568792fa 100644 --- a/src/core/server/saved_objects/service/lib/aggregations/aggs_types/bucket_aggs.ts +++ b/src/core/server/saved_objects/service/lib/aggregations/aggs_types/bucket_aggs.ts @@ -7,7 +7,6 @@ */ import { schema as s, ObjectType } from '@kbn/config-schema'; -import { sortOrderSchema } from './common_schemas'; /** * Schemas for the Bucket aggregations. @@ -86,12 +85,6 @@ export const bucketAggsSchemas: Record = { min_doc_count: s.maybe(s.number({ min: 1 })), size: s.maybe(s.number()), show_term_doc_count_error: s.maybe(s.boolean()), - order: s.maybe( - s.oneOf([ - sortOrderSchema, - s.recordOf(s.string(), sortOrderSchema), - s.arrayOf(s.recordOf(s.string(), sortOrderSchema)), - ]) - ), + order: s.maybe(s.oneOf([s.literal('asc'), s.literal('desc')])), }), }; diff --git a/src/core/server/saved_objects/service/lib/aggregations/aggs_types/common_schemas.ts b/src/core/server/saved_objects/service/lib/aggregations/aggs_types/common_schemas.ts deleted file mode 100644 index 92a3096374687dc..000000000000000 --- a/src/core/server/saved_objects/service/lib/aggregations/aggs_types/common_schemas.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { schema as s } from '@kbn/config-schema'; - -// note: these schemas are not exhaustive. See the `Sort` type of `@elastic/elasticsearch` if you need to enhance it. -const fieldSchema = s.string(); -export const sortOrderSchema = s.oneOf([s.literal('asc'), s.literal('desc'), s.literal('_doc')]); -const sortModeSchema = s.oneOf([ - s.literal('min'), - s.literal('max'), - s.literal('sum'), - s.literal('avg'), - s.literal('median'), -]); -const fieldSortSchema = s.object({ - missing: s.maybe(s.oneOf([s.string(), s.number(), s.boolean()])), - mode: s.maybe(sortModeSchema), - order: s.maybe(sortOrderSchema), - // nested and unmapped_type not implemented yet -}); -const sortContainerSchema = s.recordOf(s.string(), s.oneOf([sortOrderSchema, fieldSortSchema])); -const sortCombinationsSchema = s.oneOf([fieldSchema, sortContainerSchema]); -export const sortSchema = s.oneOf([sortCombinationsSchema, s.arrayOf(sortCombinationsSchema)]); diff --git a/src/core/server/saved_objects/service/lib/aggregations/aggs_types/metrics_aggs.ts b/src/core/server/saved_objects/service/lib/aggregations/aggs_types/metrics_aggs.ts index fb7e25fae19f29f..c05ae67cd2164e3 100644 --- a/src/core/server/saved_objects/service/lib/aggregations/aggs_types/metrics_aggs.ts +++ b/src/core/server/saved_objects/service/lib/aggregations/aggs_types/metrics_aggs.ts @@ -7,7 +7,6 @@ */ import { schema as s, ObjectType } from '@kbn/config-schema'; -import { sortSchema } from './common_schemas'; /** * Schemas for the metrics Aggregations @@ -69,7 +68,7 @@ export const metricsAggsSchemas: Record = { stored_fields: s.maybe(s.oneOf([s.string(), s.arrayOf(s.string())])), from: s.maybe(s.number()), size: s.maybe(s.number()), - sort: s.maybe(sortSchema), + sort: s.maybe(s.oneOf([s.literal('asc'), s.literal('desc')])), seq_no_primary_term: s.maybe(s.boolean()), version: s.maybe(s.boolean()), track_scores: s.maybe(s.boolean()), diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts b/src/plugins/apm_oss/common/index_pattern_constants.ts similarity index 66% rename from packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts rename to src/plugins/apm_oss/common/index_pattern_constants.ts index 6b7ce27d071948a..c35e20ebd58e275 100644 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts +++ b/src/plugins/apm_oss/common/index_pattern_constants.ts @@ -6,11 +6,4 @@ * Side Public License, v 1. */ -import { ExceptionListSummarySchema } from '.'; - -export const getListSummaryResponseMock = (): ExceptionListSummarySchema => ({ - windows: 0, - linux: 1, - macos: 2, - total: 3, -}); +export const APM_STATIC_INDEX_PATTERN_ID = 'apm_static_index_pattern_id'; diff --git a/x-pack/plugins/apm/public/assets/apm.png b/src/plugins/apm_oss/public/assets/apm.png similarity index 100% rename from x-pack/plugins/apm/public/assets/apm.png rename to src/plugins/apm_oss/public/assets/apm.png diff --git a/src/plugins/apm_oss/public/index.ts b/src/plugins/apm_oss/public/index.ts index fea8ac4a8a1e42f..d5fcabbe146a96c 100644 --- a/src/plugins/apm_oss/public/index.ts +++ b/src/plugins/apm_oss/public/index.ts @@ -14,3 +14,5 @@ export function plugin() { return new ApmOssPlugin(); } export { ApmOssPluginSetup, ApmOssPluginStart } from './types'; + +export { APM_STATIC_INDEX_PATTERN_ID } from '../common/index_pattern_constants'; diff --git a/src/plugins/apm_oss/server/index.ts b/src/plugins/apm_oss/server/index.ts index 1424cb1c7126fb8..a02e28201a1b901 100644 --- a/src/plugins/apm_oss/server/index.ts +++ b/src/plugins/apm_oss/server/index.ts @@ -7,6 +7,7 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import apmIndexPattern from './tutorial/index_pattern.json'; import { PluginInitializerContext } from '../../../core/server'; import { APMOSSPlugin } from './plugin'; @@ -31,3 +32,20 @@ export function plugin(initializerContext: PluginInitializerContext) { export type APMOSSConfig = TypeOf; export { APMOSSPluginSetup } from './plugin'; + +export { apmIndexPattern }; + +export { APM_STATIC_INDEX_PATTERN_ID } from '../common/index_pattern_constants'; + +export { + createNodeAgentInstructions, + createDjangoAgentInstructions, + createFlaskAgentInstructions, + createRailsAgentInstructions, + createRackAgentInstructions, + createJsAgentInstructions, + createGoAgentInstructions, + createJavaAgentInstructions, + createDotNetAgentInstructions, + createPhpAgentInstructions, +} from './tutorial/instructions/apm_agent_instructions'; diff --git a/src/plugins/apm_oss/server/plugin.ts b/src/plugins/apm_oss/server/plugin.ts index 02a8ac38be2a398..e504d5f0b9a9fa0 100644 --- a/src/plugins/apm_oss/server/plugin.ts +++ b/src/plugins/apm_oss/server/plugin.ts @@ -6,18 +6,38 @@ * Side Public License, v 1. */ +import { Plugin, CoreSetup, PluginInitializerContext } from 'src/core/server'; import { Observable } from 'rxjs'; -import { Plugin, PluginInitializerContext } from 'src/core/server'; import { APMOSSConfig } from './'; +import { HomeServerPluginSetup, TutorialProvider } from '../../home/server'; +import { tutorialProvider } from './tutorial'; export class APMOSSPlugin implements Plugin { constructor(private readonly initContext: PluginInitializerContext) { this.initContext = initContext; } - public setup() { + public setup(core: CoreSetup, plugins: { home: HomeServerPluginSetup }) { const config$ = this.initContext.config.create(); + const config = this.initContext.config.get(); - return { config, config$ }; + + const apmTutorialProvider = tutorialProvider({ + indexPatternTitle: config.indexPattern, + indices: { + errorIndices: config.errorIndices, + metricsIndices: config.metricsIndices, + onboardingIndices: config.onboardingIndices, + sourcemapIndices: config.sourcemapIndices, + transactionIndices: config.transactionIndices, + }, + }); + plugins.home.tutorials.registerTutorial(apmTutorialProvider); + + return { + config, + config$, + getRegisteredTutorialProvider: () => apmTutorialProvider, + }; } start() {} @@ -27,4 +47,5 @@ export class APMOSSPlugin implements Plugin { export interface APMOSSPluginSetup { config: APMOSSConfig; config$: Observable; + getRegisteredTutorialProvider(): TutorialProvider; } diff --git a/x-pack/plugins/apm/server/tutorial/envs/on_prem.ts b/src/plugins/apm_oss/server/tutorial/envs/on_prem.ts similarity index 52% rename from x-pack/plugins/apm/server/tutorial/envs/on_prem.ts rename to src/plugins/apm_oss/server/tutorial/envs/on_prem.ts index a0e96f563381cfa..7d261abb0cc018d 100644 --- a/x-pack/plugins/apm/server/tutorial/envs/on_prem.ts +++ b/src/plugins/apm_oss/server/tutorial/envs/on_prem.ts @@ -1,12 +1,13 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import { i18n } from '@kbn/i18n'; -import { INSTRUCTION_VARIANT } from '../../../../../../src/plugins/home/server'; +import { INSTRUCTION_VARIANT } from '../../../../home/server'; import { createWindowsServerInstructions, createEditConfig, @@ -49,46 +50,31 @@ export function onPremInstructions({ return { instructionSets: [ { - title: i18n.translate('xpack.apm.tutorial.apmServer.title', { + title: i18n.translate('apmOss.tutorial.apmServer.title', { defaultMessage: 'APM Server', }), callOut: { - title: i18n.translate('xpack.apm.tutorial.apmServer.callOut.title', { + title: i18n.translate('apmOss.tutorial.apmServer.callOut.title', { defaultMessage: 'Important: Updating to 7.0 or higher', }), - message: i18n.translate( - 'xpack.apm.tutorial.apmServer.callOut.message', - { - defaultMessage: `Please make sure your APM Server is updated to 7.0 or higher. \ + message: i18n.translate('apmOss.tutorial.apmServer.callOut.message', { + defaultMessage: `Please make sure your APM Server is updated to 7.0 or higher. \ You can also migrate your 6.x data with the migration assistant found in Kibana's management section.`, - } - ), + }), iconType: 'alert', }, instructionVariants: [ { id: INSTRUCTION_VARIANT.OSX, - instructions: [ - createDownloadServerOsx(), - EDIT_CONFIG, - START_SERVER_UNIX, - ], + instructions: [createDownloadServerOsx(), EDIT_CONFIG, START_SERVER_UNIX], }, { id: INSTRUCTION_VARIANT.DEB, - instructions: [ - createDownloadServerDeb(), - EDIT_CONFIG, - START_SERVER_UNIX_SYSV, - ], + instructions: [createDownloadServerDeb(), EDIT_CONFIG, START_SERVER_UNIX_SYSV], }, { id: INSTRUCTION_VARIANT.RPM, - instructions: [ - createDownloadServerRpm(), - EDIT_CONFIG, - START_SERVER_UNIX_SYSV, - ], + instructions: [createDownloadServerRpm(), EDIT_CONFIG, START_SERVER_UNIX_SYSV], }, { id: INSTRUCTION_VARIANT.WINDOWS, @@ -96,38 +82,23 @@ export function onPremInstructions({ }, ], statusCheck: { - title: i18n.translate( - 'xpack.apm.tutorial.apmServer.statusCheck.title', - { - defaultMessage: 'APM Server status', - } - ), - text: i18n.translate( - 'xpack.apm.tutorial.apmServer.statusCheck.text', - { - defaultMessage: - 'Make sure APM Server is running before you start implementing the APM agents.', - } - ), - btnLabel: i18n.translate( - 'xpack.apm.tutorial.apmServer.statusCheck.btnLabel', - { - defaultMessage: 'Check APM Server status', - } - ), - success: i18n.translate( - 'xpack.apm.tutorial.apmServer.statusCheck.successMessage', - { - defaultMessage: 'You have correctly setup APM Server', - } - ), - error: i18n.translate( - 'xpack.apm.tutorial.apmServer.statusCheck.errorMessage', - { - defaultMessage: - 'No APM Server detected. Please make sure it is running and you have updated to 7.0 or higher.', - } - ), + title: i18n.translate('apmOss.tutorial.apmServer.statusCheck.title', { + defaultMessage: 'APM Server status', + }), + text: i18n.translate('apmOss.tutorial.apmServer.statusCheck.text', { + defaultMessage: + 'Make sure APM Server is running before you start implementing the APM agents.', + }), + btnLabel: i18n.translate('apmOss.tutorial.apmServer.statusCheck.btnLabel', { + defaultMessage: 'Check APM Server status', + }), + success: i18n.translate('apmOss.tutorial.apmServer.statusCheck.successMessage', { + defaultMessage: 'You have correctly setup APM Server', + }), + error: i18n.translate('apmOss.tutorial.apmServer.statusCheck.errorMessage', { + defaultMessage: + 'No APM Server detected. Please make sure it is running and you have updated to 7.0 or higher.', + }), esHitsCheck: { index: onboardingIndices, query: { @@ -142,7 +113,7 @@ export function onPremInstructions({ }, }, { - title: i18n.translate('xpack.apm.tutorial.apmAgents.title', { + title: i18n.translate('apmOss.tutorial.apmAgents.title', { defaultMessage: 'APM Agents', }), instructionVariants: [ @@ -188,56 +159,30 @@ export function onPremInstructions({ }, ], statusCheck: { - title: i18n.translate( - 'xpack.apm.tutorial.apmAgents.statusCheck.title', - { - defaultMessage: 'Agent status', - } - ), - text: i18n.translate( - 'xpack.apm.tutorial.apmAgents.statusCheck.text', - { - defaultMessage: - 'Make sure your application is running and the agents are sending data.', - } - ), - btnLabel: i18n.translate( - 'xpack.apm.tutorial.apmAgents.statusCheck.btnLabel', - { - defaultMessage: 'Check agent status', - } - ), - success: i18n.translate( - 'xpack.apm.tutorial.apmAgents.statusCheck.successMessage', - { - defaultMessage: - 'Data successfully received from one or more agents', - } - ), - error: i18n.translate( - 'xpack.apm.tutorial.apmAgents.statusCheck.errorMessage', - { - defaultMessage: 'No data has been received from agents yet', - } - ), + title: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.title', { + defaultMessage: 'Agent status', + }), + text: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.text', { + defaultMessage: + 'Make sure your application is running and the agents are sending data.', + }), + btnLabel: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.btnLabel', { + defaultMessage: 'Check agent status', + }), + success: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.successMessage', { + defaultMessage: 'Data successfully received from one or more agents', + }), + error: i18n.translate('apmOss.tutorial.apmAgents.statusCheck.errorMessage', { + defaultMessage: 'No data has been received from agents yet', + }), esHitsCheck: { - index: [ - errorIndices, - transactionIndices, - metricsIndices, - sourcemapIndices, - ], + index: [errorIndices, transactionIndices, metricsIndices, sourcemapIndices], query: { bool: { filter: [ { terms: { - 'processor.event': [ - 'error', - 'transaction', - 'metric', - 'sourcemap', - ], + 'processor.event': ['error', 'transaction', 'metric', 'sourcemap'], }, }, { range: { 'observer.version_major': { gte: 7 } } }, diff --git a/src/plugins/apm_oss/server/tutorial/index.ts b/src/plugins/apm_oss/server/tutorial/index.ts new file mode 100644 index 000000000000000..ce7fec406e7ac00 --- /dev/null +++ b/src/plugins/apm_oss/server/tutorial/index.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import { onPremInstructions } from './envs/on_prem'; +import apmIndexPattern from './index_pattern.json'; +import { ArtifactsSchema, TutorialsCategory } from '../../../../../src/plugins/home/server'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../common/index_pattern_constants'; + +const apmIntro = i18n.translate('apmOss.tutorial.introduction', { + defaultMessage: 'Collect in-depth performance metrics and errors from inside your applications.', +}); +const moduleName = 'apm'; + +export const tutorialProvider = ({ + indexPatternTitle, + indices, +}: { + indexPatternTitle: string; + indices: { + errorIndices: string; + transactionIndices: string; + metricsIndices: string; + sourcemapIndices: string; + onboardingIndices: string; + }; +}) => () => { + const savedObjects = [ + { + ...apmIndexPattern, + id: APM_STATIC_INDEX_PATTERN_ID, + attributes: { + ...apmIndexPattern.attributes, + title: indexPatternTitle, + }, + }, + ]; + + const artifacts: ArtifactsSchema = { + dashboards: [ + { + id: '8d3ed660-7828-11e7-8c47-65b845b5cfb3', + linkLabel: i18n.translate('apmOss.tutorial.specProvider.artifacts.dashboards.linkLabel', { + defaultMessage: 'APM dashboard', + }), + isOverview: true, + }, + ], + }; + + return { + id: 'apm', + name: i18n.translate('apmOss.tutorial.specProvider.name', { + defaultMessage: 'APM', + }), + moduleName, + category: TutorialsCategory.OTHER, + shortDescription: apmIntro, + longDescription: i18n.translate('apmOss.tutorial.specProvider.longDescription', { + defaultMessage: + 'Application Performance Monitoring (APM) collects in-depth \ +performance metrics and errors from inside your application. \ +It allows you to monitor the performance of thousands of applications in real time. \ +[Learn more]({learnMoreLink}).', + values: { + learnMoreLink: + '{config.docs.base_url}guide/en/apm/get-started/{config.docs.version}/index.html', + }, + }), + euiIconType: 'apmApp', + artifacts, + onPrem: onPremInstructions(indices), + previewImagePath: '/plugins/apmOss/assets/apm.png', + savedObjects, + savedObjectsInstallMsg: i18n.translate('apmOss.tutorial.specProvider.savedObjectsInstallMsg', { + defaultMessage: 'An APM index pattern is required for some features in the APM UI.', + }), + }; +}; diff --git a/x-pack/plugins/apm/server/tutorial/index_pattern.json b/src/plugins/apm_oss/server/tutorial/index_pattern.json similarity index 100% rename from x-pack/plugins/apm/server/tutorial/index_pattern.json rename to src/plugins/apm_oss/server/tutorial/index_pattern.json diff --git a/src/plugins/apm_oss/server/tutorial/instructions/apm_agent_instructions.ts b/src/plugins/apm_oss/server/tutorial/instructions/apm_agent_instructions.ts new file mode 100644 index 000000000000000..ba2b062870cf681 --- /dev/null +++ b/src/plugins/apm_oss/server/tutorial/instructions/apm_agent_instructions.ts @@ -0,0 +1,754 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; + +export const createNodeAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.nodeClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.nodeClient.install.textPre', { + defaultMessage: 'Install the APM agent for Node.js as a dependency to your application.', + }), + commands: ['npm install elastic-apm-node --save'], + }, + { + title: i18n.translate('apmOss.tutorial.nodeClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.nodeClient.configure.textPre', { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the `serviceName`. \ +This agent supports a variety of frameworks but can also be used with your custom stack.', + }), + commands: `// ${i18n.translate( + 'apmOss.tutorial.nodeClient.configure.commands.addThisToTheFileTopComment', + { + defaultMessage: 'Add this to the VERY top of the first file loaded in your app', + } + )} +var apm = require('elastic-apm-node').start({curlyOpen} + + // ${i18n.translate( + 'apmOss.tutorial.nodeClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Override the service name from package.json', + } + )} + // ${i18n.translate('apmOss.tutorial.nodeClient.configure.commands.allowedCharactersComment', { + defaultMessage: 'Allowed characters: a-z, A-Z, 0-9, -, _, and space', + })} + serviceName: '', + + // ${i18n.translate( + 'apmOss.tutorial.nodeClient.configure.commands.useIfApmRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a secret token', + } + )} + secretToken: '${secretToken}', + + // ${i18n.translate( + 'apmOss.tutorial.nodeClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: 'Set the custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + serverUrl: '${apmServerUrl}', + + // ${i18n.translate( + 'apmOss.tutorial.nodeClient.configure.commands.setCustomServiceEnvironmentComment', + { + defaultMessage: 'Set the service environment', + } + )} + environment: 'production' +{curlyClose})`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.nodeClient.configure.textPost', { + defaultMessage: + 'See [the documentation]({documentationLink}) for advanced usage, including how to use with \ +[Babel/ES Modules]({babelEsModulesLink}).', + values: { + documentationLink: '{config.docs.base_url}guide/en/apm/agent/nodejs/current/index.html', + babelEsModulesLink: + '{config.docs.base_url}guide/en/apm/agent/nodejs/current/advanced-setup.html#es-modules', + }, + }), + }, +]; + +export const createDjangoAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.djangoClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.djangoClient.install.textPre', { + defaultMessage: 'Install the APM agent for Python as a dependency.', + }), + commands: ['$ pip install elastic-apm'], + }, + { + title: i18n.translate('apmOss.tutorial.djangoClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.djangoClient.configure.textPre', { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the `SERVICE_NAME`.', + }), + commands: `# ${i18n.translate( + 'apmOss.tutorial.djangoClient.configure.commands.addAgentComment', + { + defaultMessage: 'Add the agent to the installed apps', + } + )} +INSTALLED_APPS = ( + 'elasticapm.contrib.django', + # ... +) + +ELASTIC_APM = {curlyOpen} + # ${i18n.translate( + 'apmOss.tutorial.djangoClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Set the required service name. Allowed characters:', + } + )} + # ${i18n.translate('apmOss.tutorial.djangoClient.configure.commands.allowedCharactersComment', { + defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', + })} + 'SERVICE_NAME': '', + + # ${i18n.translate( + 'apmOss.tutorial.djangoClient.configure.commands.useIfApmServerRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a secret token', + } + )} + 'SECRET_TOKEN': '${secretToken}', + + # ${i18n.translate( + 'apmOss.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: 'Set the custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + 'SERVER_URL': '${apmServerUrl}', + + # ${i18n.translate( + 'apmOss.tutorial.djangoClient.configure.commands.setServiceEnvironmentComment', + { + defaultMessage: 'Set the service environment', + } + )} + 'ENVIRONMENT': 'production', +{curlyClose} + +# ${i18n.translate('apmOss.tutorial.djangoClient.configure.commands.addTracingMiddlewareComment', { + defaultMessage: 'To send performance metrics, add our tracing middleware:', + })} +MIDDLEWARE = ( + 'elasticapm.contrib.django.middleware.TracingMiddleware', + #... +)`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.djangoClient.configure.textPost', { + defaultMessage: 'See the [documentation]({documentationLink}) for advanced usage.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/python/current/django-support.html', + }, + }), + }, +]; + +export const createFlaskAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.flaskClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.flaskClient.install.textPre', { + defaultMessage: 'Install the APM agent for Python as a dependency.', + }), + commands: ['$ pip install elastic-apm[flask]'], + }, + { + title: i18n.translate('apmOss.tutorial.flaskClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.flaskClient.configure.textPre', { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the `SERVICE_NAME`.', + }), + commands: `# ${i18n.translate( + 'apmOss.tutorial.flaskClient.configure.commands.initializeUsingEnvironmentVariablesComment', + { + defaultMessage: 'initialize using environment variables', + } + )} +from elasticapm.contrib.flask import ElasticAPM +app = Flask(__name__) +apm = ElasticAPM(app) + +# ${i18n.translate('apmOss.tutorial.flaskClient.configure.commands.configureElasticApmComment', { + defaultMessage: "or configure to use ELASTIC_APM in your application's settings", + })} +from elasticapm.contrib.flask import ElasticAPM +app.config['ELASTIC_APM'] = {curlyOpen} + # ${i18n.translate( + 'apmOss.tutorial.flaskClient.configure.commands.setRequiredServiceNameComment', + { + defaultMessage: 'Set the required service name. Allowed characters:', + } + )} + # ${i18n.translate('apmOss.tutorial.flaskClient.configure.commands.allowedCharactersComment', { + defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', + })} + 'SERVICE_NAME': '', + + # ${i18n.translate( + 'apmOss.tutorial.flaskClient.configure.commands.useIfApmServerRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a secret token', + } + )} + 'SECRET_TOKEN': '${secretToken}', + + # ${i18n.translate( + 'apmOss.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment', + { + defaultMessage: 'Set the custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + 'SERVER_URL': '${apmServerUrl}', + + # ${i18n.translate( + 'apmOss.tutorial.flaskClient.configure.commands.setServiceEnvironmentComment', + { + defaultMessage: 'Set the service environment', + } + )} + 'ENVIRONMENT': 'production', +{curlyClose} + +apm = ElasticAPM(app)`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.flaskClient.configure.textPost', { + defaultMessage: 'See the [documentation]({documentationLink}) for advanced usage.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/python/current/flask-support.html', + }, + }), + }, +]; + +export const createRailsAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.railsClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.railsClient.install.textPre', { + defaultMessage: 'Add the agent to your Gemfile.', + }), + commands: [`gem 'elastic-apm'`], + }, + { + title: i18n.translate('apmOss.tutorial.railsClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.railsClient.configure.textPre', { + defaultMessage: + 'APM is automatically started when your app boots. Configure the agent, by creating the config file {configFile}', + values: { configFile: '`config/elastic_apm.yml`' }, + }), + commands: `# config/elastic_apm.yml: + +# Set the service name - allowed characters: a-z, A-Z, 0-9, -, _ and space +# Defaults to the name of your Rails app +service_name: 'my-service' + +# Use if APM Server requires a secret token +secret_token: '${secretToken}' + +# Set the custom APM Server URL (default: http://localhost:8200) +server_url: '${apmServerUrl || 'http://localhost:8200'}' + +# Set the service environment +environment: 'production'`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.railsClient.configure.textPost', { + defaultMessage: + 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', + values: { + documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html', + }, + }), + }, +]; + +export const createRackAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.rackClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.rackClient.install.textPre', { + defaultMessage: 'Add the agent to your Gemfile.', + }), + commands: [`gem 'elastic-apm'`], + }, + { + title: i18n.translate('apmOss.tutorial.rackClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.rackClient.configure.textPre', { + defaultMessage: + 'For Rack or a compatible framework (e.g. Sinatra), include the middleware in your app and start the agent.', + }), + commands: `# config.ru + require 'sinatra/base' + + class MySinatraApp < Sinatra::Base + use ElasticAPM::Middleware + + # ... + end + + ElasticAPM.start( + app: MySinatraApp, # ${i18n.translate( + 'apmOss.tutorial.rackClient.configure.commands.requiredComment', + { + defaultMessage: 'required', + } + )} + config_file: '' # ${i18n.translate( + 'apmOss.tutorial.rackClient.configure.commands.optionalComment', + { + defaultMessage: 'optional, defaults to config/elastic_apm.yml', + } + )} + ) + + run MySinatraApp + + at_exit {curlyOpen} ElasticAPM.stop {curlyClose}`.split('\n'), + }, + { + title: i18n.translate('apmOss.tutorial.rackClient.createConfig.title', { + defaultMessage: 'Create config file', + }), + textPre: i18n.translate('apmOss.tutorial.rackClient.createConfig.textPre', { + defaultMessage: 'Create a config file {configFile}:', + values: { configFile: '`config/elastic_apm.yml`' }, + }), + commands: `# config/elastic_apm.yml: + +# ${i18n.translate('apmOss.tutorial.rackClient.createConfig.commands.setServiceNameComment', { + defaultMessage: 'Set the service name - allowed characters: a-z, A-Z, 0-9, -, _ and space', + })} +# ${i18n.translate( + 'apmOss.tutorial.rackClient.createConfig.commands.defaultsToTheNameOfRackAppClassComment', + { + defaultMessage: "Defaults to the name of your Rack app's class.", + } + )} +service_name: 'my-service' + +# ${i18n.translate( + 'apmOss.tutorial.rackClient.createConfig.commands.useIfApmServerRequiresTokenComment', + { + defaultMessage: 'Use if APM Server requires a token', + } + )} +secret_token: '${secretToken}' + +# ${i18n.translate('apmOss.tutorial.rackClient.createConfig.commands.setCustomApmServerComment', { + defaultMessage: 'Set custom APM Server URL (default: {defaultServerUrl})', + values: { defaultServerUrl: 'http://localhost:8200' }, + })} +server_url: '${apmServerUrl || 'http://localhost:8200'}', + +# ${i18n.translate('apmOss.tutorial.rackClient.createConfig.commands.setServiceEnvironment', { + defaultMessage: 'Set the service environment', + })} +environment: 'production'`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.rackClient.createConfig.textPost', { + defaultMessage: + 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', + values: { + documentationLink: '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html', + }, + }), + }, +]; + +export const createJsAgentInstructions = (apmServerUrl = '') => [ + { + title: i18n.translate('apmOss.tutorial.jsClient.enableRealUserMonitoring.title', { + defaultMessage: 'Enable Real User Monitoring support in APM Server', + }), + textPre: i18n.translate('apmOss.tutorial.jsClient.enableRealUserMonitoring.textPre', { + defaultMessage: + 'APM Server disables RUM support by default. See the [documentation]({documentationLink}) \ +for details on how to enable RUM support.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/server/{config.docs.version}/configuration-rum.html', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.jsClient.installDependency.title', { + defaultMessage: 'Set up the Agent as a dependency', + }), + textPre: i18n.translate('apmOss.tutorial.jsClient.installDependency.textPre', { + defaultMessage: + 'You can install the Agent as a dependency to your application with \ +`npm install @elastic/apm-rum --save`.\n\n\ +The Agent can then be initialized and configured in your application like this:', + }), + commands: `import {curlyOpen} init as initApm {curlyClose} from '@elastic/apm-rum' +var apm = initApm({curlyOpen} + + // ${i18n.translate( + 'apmOss.tutorial.jsClient.installDependency.commands.setRequiredServiceNameComment', + { + defaultMessage: + 'Set required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)', + } + )} + serviceName: 'your-app-name', + + // ${i18n.translate( + 'apmOss.tutorial.jsClient.installDependency.commands.setCustomApmServerUrlComment', + { + defaultMessage: 'Set custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + } + )} + serverUrl: '${apmServerUrl}', + + // ${i18n.translate( + 'apmOss.tutorial.jsClient.installDependency.commands.setServiceVersionComment', + { + defaultMessage: 'Set the service version (required for source map feature)', + } + )} + serviceVersion: '', + + // ${i18n.translate( + 'apmOss.tutorial.jsClient.installDependency.commands.setServiceEnvironmentComment', + { + defaultMessage: 'Set the service environment', + } + )} + environment: 'production' +{curlyClose})`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.jsClient.installDependency.textPost', { + defaultMessage: + 'Framework integrations, like React or Angular, have custom dependencies. \ +See the [integration documentation]({docLink}) for more information.', + values: { + docLink: + '{config.docs.base_url}guide/en/apm/agent/rum-js/current/framework-integrations.html', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.jsClient.scriptTags.title', { + defaultMessage: 'Set up the Agent with Script Tags', + }), + textPre: i18n.translate('apmOss.tutorial.jsClient.scriptTags.textPre', { + defaultMessage: + "Alternatively, you can use Script tags to set up and configure the Agent. \ +Add a ` + +`.split('\n'), + }, +]; + +export const createGoAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.goClient.install.title', { + defaultMessage: 'Install the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.goClient.install.textPre', { + defaultMessage: 'Install the APM agent packages for Go.', + }), + commands: ['go get go.elastic.co/apm'], + }, + { + title: i18n.translate('apmOss.tutorial.goClient.configure.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.goClient.configure.textPre', { + defaultMessage: + 'Agents are libraries that run inside of your application process. \ +APM services are created programmatically based on the executable \ +file name, or the `ELASTIC_APM_SERVICE_NAME` environment variable.', + }), + commands: `# ${i18n.translate( + 'apmOss.tutorial.goClient.configure.commands.initializeUsingEnvironmentVariablesComment', + { + defaultMessage: 'Initialize using environment variables:', + } + )} + +# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.setServiceNameComment', { + defaultMessage: 'Set the service name. Allowed characters: # a-z, A-Z, 0-9, -, _, and space.', + })} +# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.usedExecutableNameComment', { + defaultMessage: + 'If ELASTIC_APM_SERVICE_NAME is not specified, the executable name will be used.', + })} +export ELASTIC_APM_SERVICE_NAME= + +# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.setCustomApmServerUrlComment', { + defaultMessage: 'Set custom APM Server URL (default: {defaultApmServerUrl})', + values: { defaultApmServerUrl: 'http://localhost:8200' }, + })} +export ELASTIC_APM_SERVER_URL=${apmServerUrl} + +# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.useIfApmRequiresTokenComment', { + defaultMessage: 'Use if APM Server requires a secret token', + })} +export ELASTIC_APM_SECRET_TOKEN=${secretToken} + +# ${i18n.translate('apmOss.tutorial.goClient.configure.commands.setServiceEnvironment', { + defaultMessage: 'Set the service environment', + })} +export ELASTIC_APM_ENVIRONMENT= +`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.goClient.configure.textPost', { + defaultMessage: 'See the [documentation]({documentationLink}) for advanced configuration.', + values: { + documentationLink: '{config.docs.base_url}guide/en/apm/agent/go/current/configuration.html', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.goClient.instrument.title', { + defaultMessage: 'Instrument your application', + }), + textPre: i18n.translate('apmOss.tutorial.goClient.instrument.textPre', { + defaultMessage: + 'Instrument your Go application by using one of the provided instrumentation modules or \ +by using the tracer API directly.', + }), + commands: `\ +import ( + "net/http" + + "go.elastic.co/apm/module/apmhttp" +) + +func main() {curlyOpen} + mux := http.NewServeMux() + ... + http.ListenAndServe(":8080", apmhttp.Wrap(mux)) +{curlyClose} +`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.goClient.instrument.textPost', { + defaultMessage: + 'See the [documentation]({documentationLink}) for a detailed \ +guide to instrumenting Go source code.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/go/current/instrumenting-source.html', + }, + }), + }, +]; + +export const createJavaAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.javaClient.download.title', { + defaultMessage: 'Download the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.javaClient.download.textPre', { + defaultMessage: + 'Download the agent jar from [Maven Central]({mavenCentralLink}). \ +Do **not** add the agent as a dependency to your application.', + values: { + mavenCentralLink: 'http://search.maven.org/#search%7Cga%7C1%7Ca%3Aelastic-apm-agent', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.javaClient.startApplication.title', { + defaultMessage: 'Start your application with the javaagent flag', + }), + textPre: i18n.translate('apmOss.tutorial.javaClient.startApplication.textPre', { + defaultMessage: + 'Add the `-javaagent` flag and configure the agent with system properties.\n\n \ +* Set the required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)\n \ +* Set the custom APM Server URL (default: {customApmServerUrl})\n \ +* Set the APM Server secret token\n \ +* Set the service environment\n \ +* Set the base package of your application', + values: { customApmServerUrl: 'http://localhost:8200' }, + }), + commands: `java -javaagent:/path/to/elastic-apm-agent-.jar \\ + -Delastic.apm.service_name=my-application \\ + -Delastic.apm.server_urls=${apmServerUrl || 'http://localhost:8200'} \\ + -Delastic.apm.secret_token=${secretToken} \\ + -Delastic.apm.environment=production \\ + -Delastic.apm.application_packages=org.example \\ + -jar my-application.jar`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.javaClient.startApplication.textPost', { + defaultMessage: + 'See the [documentation]({documentationLink}) for configuration options and advanced \ +usage.', + values: { + documentationLink: '{config.docs.base_url}guide/en/apm/agent/java/current/index.html', + }, + }), + }, +]; + +export const createDotNetAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.dotNetClient.download.title', { + defaultMessage: 'Download the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.dotNetClient.download.textPre', { + defaultMessage: + 'Add the the agent package(s) from [NuGet]({allNuGetPackagesLink}) to your .NET application. There are multiple \ + NuGet packages available for different use cases. \n\nFor an ASP.NET Core application with Entity Framework \ + Core download the [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}) package. This package will automatically add every \ + agent component to your application. \n\n In case you would like to minimize the dependencies, you can use the \ + [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) package for just \ + ASP.NET Core monitoring or the [Elastic.Apm.EfCore]({efCorePackageLink}) package for just Entity Framework Core monitoring. \n\n \ + In case you only want to use the public Agent API for manual instrumentation use the [Elastic.Apm]({elasticApmPackageLink}) package.', + values: { + allNuGetPackagesLink: 'https://www.nuget.org/packages?q=Elastic.apm', + netCoreAllApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm.NetCoreAll', + aspNetCorePackageLink: 'https://www.nuget.org/packages/Elastic.Apm.AspNetCore', + efCorePackageLink: 'https://www.nuget.org/packages/Elastic.Apm.EntityFrameworkCore', + elasticApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.dotNetClient.configureApplication.title', { + defaultMessage: 'Add the agent to the application', + }), + textPre: i18n.translate('apmOss.tutorial.dotNetClient.configureApplication.textPre', { + defaultMessage: + 'In case of ASP.NET Core with the `Elastic.Apm.NetCoreAll` package, call the `UseAllElasticApm` \ + method in the `Configure` method within the `Startup.cs` file.', + }), + commands: `public class Startup +{curlyOpen} + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + {curlyOpen} + app.UseAllElasticApm(Configuration); + //…rest of the method + {curlyClose} + //…rest of the class +{curlyClose}`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.dotNetClient.configureApplication.textPost', { + defaultMessage: + 'Passing an `IConfiguration` instance is optional and by doing so, the agent will read config settings through this \ + `IConfiguration` instance (e.g. from the `appsettings.json` file).', + }), + }, + { + title: i18n.translate('apmOss.tutorial.dotNetClient.configureAgent.title', { + defaultMessage: 'Sample appsettings.json file:', + }), + commands: `{curlyOpen} + "ElasticApm": {curlyOpen} + "SecretToken": "${secretToken}", + "ServerUrls": "${ + apmServerUrl || 'http://localhost:8200' + }", //Set custom APM Server URL (default: http://localhost:8200) + "ServiceName": "MyApp", //allowed characters: a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application + "Environment": "production", // Set the service environment + {curlyClose} +{curlyClose}`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.dotNetClient.configureAgent.textPost', { + defaultMessage: + 'In case you don’t pass an `IConfiguration` instance to the agent (e.g. in case of non ASP.NET Core applications) \ + you can also configure the agent through environment variables. \n \ + See [the documentation]({documentationLink}) for advanced usage.', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/dotnet/current/configuration.html', + }, + }), + }, +]; + +export const createPhpAgentInstructions = (apmServerUrl = '', secretToken = '') => [ + { + title: i18n.translate('apmOss.tutorial.phpClient.download.title', { + defaultMessage: 'Download the APM agent', + }), + textPre: i18n.translate('apmOss.tutorial.phpClient.download.textPre', { + defaultMessage: + 'Download the package corresponding to your platform from [GitHub releases]({githubReleasesLink}).', + values: { + githubReleasesLink: 'https://github.com/elastic/apm-agent-php/releases', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.phpClient.installPackage.title', { + defaultMessage: 'Install the downloaded package', + }), + textPre: i18n.translate('apmOss.tutorial.phpClient.installPackage.textPre', { + defaultMessage: 'For example on Alpine Linux using APK package:', + }), + commands: ['apk add --allow-untrusted .apk'], + textPost: i18n.translate('apmOss.tutorial.phpClient.installPackage.textPost', { + defaultMessage: + 'See the [documentation]({documentationLink}) for installation commands on other supported platforms and advanced installation.', + values: { + documentationLink: '{config.docs.base_url}guide/en/apm/agent/php/current/setup.html', + }, + }), + }, + { + title: i18n.translate('apmOss.tutorial.phpClient.configureAgent.title', { + defaultMessage: 'Configure the agent', + }), + textPre: i18n.translate('apmOss.tutorial.phpClient.configureAgent.textPre', { + defaultMessage: + 'APM is automatically started when your app boots. Configure the agent either via `php.ini` file:', + }), + commands: `elastic_apm.server_url=http://localhost:8200 +elastic_apm.service_name="My service" +`.split('\n'), + textPost: i18n.translate('apmOss.tutorial.phpClient.configure.textPost', { + defaultMessage: + 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', + values: { + documentationLink: + '{config.docs.base_url}guide/en/apm/agent/php/current/configuration.html', + }, + }), + }, +]; diff --git a/x-pack/plugins/apm/server/tutorial/instructions/apm_server_instructions.ts b/src/plugins/apm_oss/server/tutorial/instructions/apm_server_instructions.ts similarity index 66% rename from x-pack/plugins/apm/server/tutorial/instructions/apm_server_instructions.ts rename to src/plugins/apm_oss/server/tutorial/instructions/apm_server_instructions.ts index c2fc7b1774f65fd..eee93d8dc9fd1ad 100644 --- a/x-pack/plugins/apm/server/tutorial/instructions/apm_server_instructions.ts +++ b/src/plugins/apm_oss/server/tutorial/instructions/apm_server_instructions.ts @@ -1,17 +1,18 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import { i18n } from '@kbn/i18n'; export const createEditConfig = () => ({ - title: i18n.translate('xpack.apm.tutorial.editConfig.title', { + title: i18n.translate('apmOss.tutorial.editConfig.title', { defaultMessage: 'Edit the configuration', }), - textPre: i18n.translate('xpack.apm.tutorial.editConfig.textPre', { + textPre: i18n.translate('apmOss.tutorial.editConfig.textPre', { defaultMessage: "If you're using an X-Pack secured version of Elastic Stack, you must specify \ credentials in the `apm-server.yml` config file.", @@ -25,10 +26,10 @@ credentials in the `apm-server.yml` config file.", }); const createStartServer = () => ({ - title: i18n.translate('xpack.apm.tutorial.startServer.title', { + title: i18n.translate('apmOss.tutorial.startServer.title', { defaultMessage: 'Start APM Server', }), - textPre: i18n.translate('xpack.apm.tutorial.startServer.textPre', { + textPre: i18n.translate('apmOss.tutorial.startServer.textPre', { defaultMessage: 'The server processes and stores application performance metrics in Elasticsearch.', }), @@ -55,7 +56,7 @@ export function createStartServerUnix() { } const createDownloadServerTitle = () => - i18n.translate('xpack.apm.tutorial.downloadServer.title', { + i18n.translate('apmOss.tutorial.downloadServer.title', { defaultMessage: 'Download and unpack APM Server', }); @@ -74,9 +75,8 @@ export const createDownloadServerDeb = () => ({ 'curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-{config.kibana.version}-amd64.deb', 'sudo dpkg -i apm-server-{config.kibana.version}-amd64.deb', ], - textPost: i18n.translate('xpack.apm.tutorial.downloadServerTitle', { - defaultMessage: - 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', + textPost: i18n.translate('apmOss.tutorial.downloadServerTitle', { + defaultMessage: 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', values: { downloadPageLink: '{config.docs.base_url}downloads/apm/apm-server', }, @@ -89,9 +89,8 @@ export const createDownloadServerRpm = () => ({ 'curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-{config.kibana.version}-x86_64.rpm', 'sudo rpm -vi apm-server-{config.kibana.version}-x86_64.rpm', ], - textPost: i18n.translate('xpack.apm.tutorial.downloadServerRpm', { - defaultMessage: - 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', + textPost: i18n.translate('apmOss.tutorial.downloadServerRpm', { + defaultMessage: 'Looking for the 32-bit packages? See the [Download page]({downloadPageLink}).', values: { downloadPageLink: '{config.docs.base_url}downloads/apm/apm-server', }, @@ -104,41 +103,32 @@ export function createWindowsServerInstructions() { return [ { title: createDownloadServerTitle(), - textPre: i18n.translate( - 'xpack.apm.tutorial.windowsServerInstructions.textPre', - { - defaultMessage: - '1. Download the APM Server Windows zip file from the \ + textPre: i18n.translate('apmOss.tutorial.windowsServerInstructions.textPre', { + defaultMessage: + '1. Download the APM Server Windows zip file from the \ [Download page]({downloadPageLink}).\n2. Extract the contents of \ the zip file into {zipFileExtractFolder}.\n3. Rename the {apmServerDirectory} \ directory to `APM-Server`.\n4. Open a PowerShell prompt as an Administrator \ (right-click the PowerShell icon and select \ **Run As Administrator**). If you are running Windows XP, you might need to download and install \ PowerShell.\n5. From the PowerShell prompt, run the following commands to install APM Server as a Windows service:', - values: { - downloadPageLink: 'https://www.elastic.co/downloads/apm/apm-server', - zipFileExtractFolder: '`C:\\Program Files`', - apmServerDirectory: '`apm-server-{config.kibana.version}-windows`', - }, - } - ), - commands: [ - `cd 'C:\\Program Files\\APM-Server'`, - `.\\install-service-apm-server.ps1`, - ], - textPost: i18n.translate( - 'xpack.apm.tutorial.windowsServerInstructions.textPost', - { - defaultMessage: - 'Note: If script execution is disabled on your system, \ + values: { + downloadPageLink: 'https://www.elastic.co/downloads/apm/apm-server', + zipFileExtractFolder: '`C:\\Program Files`', + apmServerDirectory: '`apm-server-{config.kibana.version}-windows`', + }, + }), + commands: [`cd 'C:\\Program Files\\APM-Server'`, `.\\install-service-apm-server.ps1`], + textPost: i18n.translate('apmOss.tutorial.windowsServerInstructions.textPost', { + defaultMessage: + 'Note: If script execution is disabled on your system, \ you need to set the execution policy for the current session \ to allow the script to run. For example: {command}.', - values: { - command: - '`PowerShell.exe -ExecutionPolicy UnRestricted -File .\\install-service-apm-server.ps1`', - }, - } - ), + values: { + command: + '`PowerShell.exe -ExecutionPolicy UnRestricted -File .\\install-service-apm-server.ps1`', + }, + }), }, createEditConfig(), { diff --git a/src/plugins/charts/common/palette.test.ts b/src/plugins/charts/common/palette.test.ts index 86ba74d409cc6ec..0a26d71a9b9d533 100644 --- a/src/plugins/charts/common/palette.test.ts +++ b/src/plugins/charts/common/palette.test.ts @@ -12,14 +12,13 @@ import { systemPalette, PaletteOutput, CustomPaletteState, - CustomPaletteArguments, } from './palette'; import { functionWrapper } from 'src/plugins/expressions/common/expression_functions/specs/tests/utils'; describe('palette', () => { const fn = functionWrapper(palette()) as ( context: null, - args?: Partial + args?: { color?: string[]; gradient?: boolean; reverse?: boolean } ) => PaletteOutput; it('results a palette', () => { @@ -40,18 +39,6 @@ describe('palette', () => { }); }); - describe('stop', () => { - it('sets stops', () => { - const result = fn(null, { color: ['red', 'green', 'blue'], stop: [1, 2, 3] }); - expect(result.params!.stops).toEqual([1, 2, 3]); - }); - - it('defaults to pault_tor_14 colors', () => { - const result = fn(null); - expect(result.params!.colors).toEqual(defaultCustomColors); - }); - }); - describe('gradient', () => { it('sets gradient', () => { let result = fn(null, { gradient: true }); @@ -82,16 +69,6 @@ describe('palette', () => { const result = fn(null); expect(result.params!.colors).toEqual(defaultCustomColors); }); - - it('keeps the stops order pristine when set', () => { - const stops = [1, 2, 3]; - const result = fn(null, { - color: ['red', 'green', 'blue'], - stop: [1, 2, 3], - reverse: true, - }); - expect(result.params!.stops).toEqual(stops); - }); }); }); }); diff --git a/src/plugins/charts/common/palette.ts b/src/plugins/charts/common/palette.ts index 78c6fcc81202846..c9232b22cfae144 100644 --- a/src/plugins/charts/common/palette.ts +++ b/src/plugins/charts/common/palette.ts @@ -14,21 +14,11 @@ export interface CustomPaletteArguments { color?: string[]; gradient: boolean; reverse?: boolean; - stop?: number[]; - range?: 'number' | 'percent'; - rangeMin?: number; - rangeMax?: number; - continuity?: 'above' | 'below' | 'all' | 'none'; } export interface CustomPaletteState { colors: string[]; gradient: boolean; - stops: number[]; - range: 'number' | 'percent'; - rangeMin: number; - rangeMax: number; - continuity?: 'above' | 'below' | 'all' | 'none'; } export interface SystemPaletteArguments { @@ -93,35 +83,6 @@ export function palette(): ExpressionFunctionDefinition< }), required: false, }, - stop: { - multi: true, - types: ['number'], - help: i18n.translate('charts.functions.palette.args.stopHelpText', { - defaultMessage: - 'The palette color stops. When used, it must be associated with each color.', - }), - required: false, - }, - continuity: { - types: ['string'], - options: ['above', 'below', 'all', 'none'], - default: 'above', - help: '', - }, - rangeMin: { - types: ['number'], - help: '', - }, - rangeMax: { - types: ['number'], - help: '', - }, - range: { - types: ['string'], - options: ['number', 'percent'], - default: 'percent', - help: '', - }, gradient: { types: ['boolean'], default: false, @@ -140,32 +101,15 @@ export function palette(): ExpressionFunctionDefinition< }, }, fn: (input, args) => { - const { - color, - continuity, - reverse, - gradient, - stop, - range, - rangeMin = 0, - rangeMax = 100, - } = args; + const { color, reverse, gradient } = args; const colors = ([] as string[]).concat(color || defaultCustomColors); - const stops = ([] as number[]).concat(stop || []); - if (stops.length > 0 && colors.length !== stops.length) { - throw Error('When stop is used, each color must have an associated stop value.'); - } + return { type: 'palette', name: 'custom', params: { colors: reverse ? colors.reverse() : colors, - stops, - range: range ?? 'percent', gradient, - continuity, - rangeMin, - rangeMax, }, }; }, diff --git a/src/plugins/charts/public/services/palettes/helpers.test.ts b/src/plugins/charts/public/services/palettes/helpers.test.ts deleted file mode 100644 index 90f5745570cc8ba..000000000000000 --- a/src/plugins/charts/public/services/palettes/helpers.test.ts +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { workoutColorForValue } from './helpers'; -import { CustomPaletteState } from '../..'; - -describe('workoutColorForValue', () => { - it('should return no color for empty value', () => { - expect( - workoutColorForValue( - undefined, - { - continuity: 'above', - colors: ['red', 'green', 'blue', 'yellow'], - range: 'number', - gradient: false, - rangeMin: 0, - rangeMax: 200, - stops: [], - }, - { min: 0, max: 200 } - ) - ).toBeUndefined(); - }); - - describe('range: "number"', () => { - const DEFAULT_PROPS: CustomPaletteState = { - continuity: 'above', - colors: ['red', 'green', 'blue', 'yellow'], - range: 'number', - gradient: false, - rangeMin: 0, - rangeMax: 200, - stops: [], - }; - it('find the right color for predefined palettes', () => { - expect(workoutColorForValue(123, DEFAULT_PROPS, { min: 0, max: 200 })).toBe('blue'); - }); - - it('find the right color for custom stops palettes', () => { - expect( - workoutColorForValue( - 50, - { - ...DEFAULT_PROPS, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBe('blue'); - }); - - it('find the right color for custom stops palettes when value is higher than rangeMax', () => { - expect( - workoutColorForValue( - 123, - { - ...DEFAULT_PROPS, - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBe('yellow'); - expect( - workoutColorForValue( - 123, - { - ...DEFAULT_PROPS, - continuity: 'all', - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBe('yellow'); - }); - - it('returns no color if the value if higher than rangeMax and continuity is nor "above" or "all"', () => { - expect( - workoutColorForValue( - 123, - { - ...DEFAULT_PROPS, - continuity: 'below', - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBeUndefined(); - expect( - workoutColorForValue( - 123, - { - ...DEFAULT_PROPS, - continuity: 'none', - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBeUndefined(); - }); - - it('find the right color for custom stops palettes when value is lower than rangeMin', () => { - expect( - workoutColorForValue( - 10, - { - ...DEFAULT_PROPS, - continuity: 'below', - rangeMin: 20, - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBe('red'); - expect( - workoutColorForValue( - 10, - { - ...DEFAULT_PROPS, - continuity: 'all', - rangeMin: 20, - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBe('red'); - }); - - it('returns no color if the value if lower than rangeMin and continuity is nor "below" or "all"', () => { - expect( - workoutColorForValue( - 0, - { - ...DEFAULT_PROPS, - rangeMin: 10, - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBeUndefined(); - expect( - workoutColorForValue( - 0, - { - ...DEFAULT_PROPS, - continuity: 'none', - rangeMin: 10, - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBeUndefined(); - }); - }); - - describe('range: "percent"', () => { - const DEFAULT_PROPS: CustomPaletteState = { - continuity: 'above', - colors: ['red', 'green', 'blue', 'yellow'], - range: 'percent', - gradient: false, - rangeMin: 0, - rangeMax: 100, - stops: [], - }; - it('find the right color for predefined palettes', () => { - expect(workoutColorForValue(123, DEFAULT_PROPS, { min: 0, max: 200 })).toBe('blue'); - }); - - it('find the right color for custom stops palettes', () => { - expect( - workoutColorForValue( - 113, - { - ...DEFAULT_PROPS, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBe('blue'); // 113/200 ~ 56% - }); - - it('find the right color for custom stops palettes when value is higher than rangeMax', () => { - expect( - workoutColorForValue( - 123, - { - ...DEFAULT_PROPS, - rangeMax: 90, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBe('yellow'); - expect( - workoutColorForValue( - 123, - { - ...DEFAULT_PROPS, - continuity: 'all', - rangeMax: 90, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBe('yellow'); - }); - - it('returns no color if the value if higher than rangeMax and continuity is nor "above" or "all"', () => { - expect( - workoutColorForValue( - 190, - { - ...DEFAULT_PROPS, - continuity: 'below', - rangeMax: 90, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBeUndefined(); - expect( - workoutColorForValue( - 190, - { - ...DEFAULT_PROPS, - continuity: 'none', - rangeMax: 90, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBeUndefined(); - }); - - it('find the right color for custom stops palettes when value is lower than rangeMin', () => { - expect( - workoutColorForValue( - 10, - { - ...DEFAULT_PROPS, - continuity: 'below', - rangeMin: 20, - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBe('red'); - expect( - workoutColorForValue( - 10, - { - ...DEFAULT_PROPS, - continuity: 'all', - rangeMin: 20, - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBe('red'); - }); - - it('returns no color if the value if lower than rangeMin and continuity is nor "below" or "all"', () => { - expect( - workoutColorForValue( - 0, - { - ...DEFAULT_PROPS, - continuity: 'above', - rangeMin: 10, - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBeUndefined(); - expect( - workoutColorForValue( - 0, - { - ...DEFAULT_PROPS, - continuity: 'none', - rangeMin: 10, - rangeMax: 100, - stops: [20, 40, 60, 80], - }, - { min: 0, max: 200 } - ) - ).toBeUndefined(); - }); - }); -}); diff --git a/src/plugins/charts/public/services/palettes/helpers.ts b/src/plugins/charts/public/services/palettes/helpers.ts deleted file mode 100644 index d4b1e98f94cc8a8..000000000000000 --- a/src/plugins/charts/public/services/palettes/helpers.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { CustomPaletteState } from '../..'; - -function findColorSegment( - value: number, - comparison: (value: number, bucket: number) => number, - colors: string[], - rangeMin: number, - rangeMax: number -) { - // assume uniform distribution within the provided range, can ignore stops - const step = (rangeMax - rangeMin) / colors.length; - - // what about values in range - const index = colors.findIndex((c, i) => comparison(value, rangeMin + (1 + i) * step) <= 0); - return colors[index] || colors[0]; -} - -function findColorsByStops( - value: number, - comparison: (value: number, bucket: number) => number, - colors: string[], - stops: number[] -) { - const index = stops.findIndex((s) => comparison(value, s) < 0); - return colors[index] || colors[0]; -} - -function getNormalizedValueByRange( - value: number, - { range }: CustomPaletteState, - minMax: { min: number; max: number } -) { - let result = value; - if (range === 'percent') { - result = (100 * (value - minMax.min)) / (minMax.max - minMax.min); - } - // for a range of 1 value the formulas above will divide by 0, so here's a safety guard - if (Number.isNaN(result)) { - return 1; - } - return result; -} - -/** - * When stops are empty, it is assumed a predefined palette, so colors are distributed uniformly in the whole data range - * When stops are passed, then rangeMin/rangeMax are used as reference for user defined limits: - * continuity is defined over rangeMin/rangeMax, not these stops values (rangeMin/rangeMax are computed from user's stop inputs) - */ -export function workoutColorForValue( - value: number | undefined, - params: CustomPaletteState, - minMax: { min: number; max: number } -) { - if (value == null) { - return; - } - const { colors, stops, range = 'percent', continuity = 'above', rangeMax, rangeMin } = params; - // ranges can be absolute numbers or percentages - // normalized the incoming value to the same format as range to make easier comparisons - const normalizedValue = getNormalizedValueByRange(value, params, minMax); - const dataRangeArguments = range === 'percent' ? [0, 100] : [minMax.min, minMax.max]; - const comparisonFn = (v: number, threshold: number) => v - threshold; - - // if steps are defined consider the specific rangeMax/Min as data boundaries - const maxRange = stops.length ? rangeMax : dataRangeArguments[1]; - const minRange = stops.length ? rangeMin : dataRangeArguments[0]; - - // in case of shorter rangers, extends the steps on the sides to cover the whole set - if (comparisonFn(normalizedValue, maxRange) > 0) { - if (continuity === 'above' || continuity === 'all') { - return colors[colors.length - 1]; - } - return; - } - if (comparisonFn(normalizedValue, minRange) < 0) { - if (continuity === 'below' || continuity === 'all') { - return colors[0]; - } - return; - } - - if (stops.length) { - return findColorsByStops(normalizedValue, comparisonFn, colors, stops); - } - - return findColorSegment( - normalizedValue, - comparisonFn, - colors, - dataRangeArguments[0], - dataRangeArguments[1] - ); -} diff --git a/src/plugins/charts/public/services/palettes/mock.ts b/src/plugins/charts/public/services/palettes/mock.ts index e94f47477ab11ef..1c112ec800c922f 100644 --- a/src/plugins/charts/public/services/palettes/mock.ts +++ b/src/plugins/charts/public/services/palettes/mock.ts @@ -14,8 +14,8 @@ export const getPaletteRegistry = () => { const mockPalette1: jest.Mocked = { id: 'default', title: 'My Palette', - getCategoricalColor: jest.fn((_: SeriesLayer[]) => 'black'), - getCategoricalColors: jest.fn((num: number) => ['red', 'black']), + getColor: jest.fn((_: SeriesLayer[]) => 'black'), + getColors: jest.fn((num: number) => ['red', 'black']), toExpression: jest.fn(() => ({ type: 'expression', chain: [ @@ -33,32 +33,8 @@ export const getPaletteRegistry = () => { const mockPalette2: jest.Mocked = { id: 'mocked', title: 'Mocked Palette', - getCategoricalColor: jest.fn((_: SeriesLayer[]) => 'blue'), - getCategoricalColors: jest.fn((num: number) => ['blue', 'yellow']), - toExpression: jest.fn(() => ({ - type: 'expression', - chain: [ - { - type: 'function', - function: 'system_palette', - arguments: { - name: ['mocked'], - }, - }, - ], - })), - }; - - const mockPalette3: jest.Mocked = { - id: 'custom', - title: 'Custom Mocked Palette', - getCategoricalColor: jest.fn((_: SeriesLayer[]) => 'blue'), - getCategoricalColors: jest.fn((num: number) => ['blue', 'yellow']), - getColorForValue: jest.fn( - (num: number | undefined, state: unknown, minMax: { min: number; max: number }) => - num == null || num < 1 ? undefined : 'blue' - ), - canDynamicColoring: true, + getColor: jest.fn((_: SeriesLayer[]) => 'blue'), + getColors: jest.fn((num: number) => ['blue', 'yellow']), toExpression: jest.fn(() => ({ type: 'expression', chain: [ @@ -74,9 +50,8 @@ export const getPaletteRegistry = () => { }; return { - get: (name: string) => - name === 'custom' ? mockPalette3 : name !== 'default' ? mockPalette2 : mockPalette1, - getAll: () => [mockPalette1, mockPalette2, mockPalette3], + get: (name: string) => (name !== 'default' ? mockPalette2 : mockPalette1), + getAll: () => [mockPalette1, mockPalette2], }; }; diff --git a/src/plugins/charts/public/services/palettes/palettes.test.tsx b/src/plugins/charts/public/services/palettes/palettes.test.tsx index 8cb477b0e0838bf..8f495df7f882af8 100644 --- a/src/plugins/charts/public/services/palettes/palettes.test.tsx +++ b/src/plugins/charts/public/services/palettes/palettes.test.tsx @@ -19,14 +19,14 @@ describe('palettes', () => { it('should return different colors based on behind text flag', () => { const palette = palettes.default; - const color1 = palette.getCategoricalColor([ + const color1 = palette.getColor([ { name: 'abc', rankAtDepth: 0, totalSeriesAtDepth: 5, }, ]); - const color2 = palette.getCategoricalColor( + const color2 = palette.getColor( [ { name: 'abc', @@ -44,14 +44,14 @@ describe('palettes', () => { it('should return different colors based on rank at current series', () => { const palette = palettes.default; - const color1 = palette.getCategoricalColor([ + const color1 = palette.getColor([ { name: 'abc', rankAtDepth: 0, totalSeriesAtDepth: 5, }, ]); - const color2 = palette.getCategoricalColor([ + const color2 = palette.getColor([ { name: 'abc', rankAtDepth: 1, @@ -64,7 +64,7 @@ describe('palettes', () => { it('should return the same color for different positions on outer series layers', () => { const palette = palettes.default; - const color1 = palette.getCategoricalColor([ + const color1 = palette.getColor([ { name: 'abc', rankAtDepth: 0, @@ -76,7 +76,7 @@ describe('palettes', () => { totalSeriesAtDepth: 2, }, ]); - const color2 = palette.getCategoricalColor([ + const color2 = palette.getColor([ { name: 'abc', rankAtDepth: 0, @@ -96,7 +96,7 @@ describe('palettes', () => { it('should return different colors based on behind text flag', () => { const palette = palettes.default; - const color1 = palette.getCategoricalColor( + const color1 = palette.getColor( [ { name: 'abc', @@ -108,7 +108,7 @@ describe('palettes', () => { syncColors: true, } ); - const color2 = palette.getCategoricalColor( + const color2 = palette.getColor( [ { name: 'abc', @@ -127,7 +127,7 @@ describe('palettes', () => { it('should return different colors for different keys', () => { const palette = palettes.default; - const color1 = palette.getCategoricalColor( + const color1 = palette.getColor( [ { name: 'abc', @@ -139,7 +139,7 @@ describe('palettes', () => { syncColors: true, } ); - const color2 = palette.getCategoricalColor( + const color2 = palette.getColor( [ { name: 'def', @@ -157,7 +157,7 @@ describe('palettes', () => { it('should return the same color for the same key, irregardless of rank', () => { const palette = palettes.default; - const color1 = palette.getCategoricalColor( + const color1 = palette.getColor( [ { name: 'hij', @@ -169,7 +169,7 @@ describe('palettes', () => { syncColors: true, } ); - const color2 = palette.getCategoricalColor( + const color2 = palette.getColor( [ { name: 'hij', @@ -187,7 +187,7 @@ describe('palettes', () => { it('should return the same color for different positions on outer series layers', () => { const palette = palettes.default; - const color1 = palette.getCategoricalColor( + const color1 = palette.getColor( [ { name: 'klm', @@ -204,7 +204,7 @@ describe('palettes', () => { syncColors: true, } ); - const color2 = palette.getCategoricalColor( + const color2 = palette.getColor( [ { name: 'klm', @@ -227,7 +227,7 @@ describe('palettes', () => { it('should return the same index of the behind text palette for same key', () => { const palette = palettes.default; - const color1 = palette.getCategoricalColor( + const color1 = palette.getColor( [ { name: 'klm', @@ -244,7 +244,7 @@ describe('palettes', () => { syncColors: true, } ); - const color2 = palette.getCategoricalColor( + const color2 = palette.getColor( [ { name: 'klm', @@ -273,15 +273,15 @@ describe('palettes', () => { const palette = palettes.warm; it('should use the whole gradient', () => { - const wholePalette = palette.getCategoricalColors(10); - const color1 = palette.getCategoricalColor([ + const wholePalette = palette.getColors(10); + const color1 = palette.getColor([ { name: 'abc', rankAtDepth: 0, totalSeriesAtDepth: 10, }, ]); - const color2 = palette.getCategoricalColor([ + const color2 = palette.getColor([ { name: 'def', rankAtDepth: 9, @@ -304,7 +304,7 @@ describe('palettes', () => { describe('syncColors: false', () => { it('should not query legacy color service', () => { - palette.getCategoricalColor( + palette.getColor( [ { name: 'abc', @@ -323,7 +323,7 @@ describe('palettes', () => { it('should respect the advanced settings color mapping', () => { const configColorGetter = colorsServiceMock.mappedColors.getColorFromConfig as jest.Mock; configColorGetter.mockImplementation(() => 'blue'); - const result = palette.getCategoricalColor( + const result = palette.getColor( [ { name: 'abc', @@ -345,7 +345,7 @@ describe('palettes', () => { }); it('should return a color from the legacy palette based on position of first series', () => { - const result = palette.getCategoricalColor( + const result = palette.getColor( [ { name: 'abc', @@ -368,7 +368,7 @@ describe('palettes', () => { describe('syncColors: true', () => { it('should query legacy color service', () => { - palette.getCategoricalColor( + palette.getColor( [ { name: 'abc', @@ -387,7 +387,7 @@ describe('palettes', () => { it('should respect the advanced settings color mapping', () => { const configColorGetter = colorsServiceMock.mappedColors.getColorFromConfig as jest.Mock; configColorGetter.mockImplementation(() => 'blue'); - const result = palette.getCategoricalColor( + const result = palette.getColor( [ { name: 'abc', @@ -409,7 +409,7 @@ describe('palettes', () => { }); it('should always use root series', () => { - palette.getCategoricalColor( + palette.getColor( [ { name: 'abc', @@ -437,7 +437,7 @@ describe('palettes', () => { describe('custom palette', () => { const palette = palettes.custom; it('should return different colors based on rank at current series', () => { - const color1 = palette.getCategoricalColor( + const color1 = palette.getColor( [ { name: 'abc', @@ -450,7 +450,7 @@ describe('palettes', () => { colors: ['#00ff00', '#000000'], } ); - const color2 = palette.getCategoricalColor( + const color2 = palette.getColor( [ { name: 'abc', @@ -467,7 +467,7 @@ describe('palettes', () => { }); it('should return the same color for different positions on outer series layers', () => { - const color1 = palette.getCategoricalColor( + const color1 = palette.getColor( [ { name: 'abc', @@ -485,7 +485,7 @@ describe('palettes', () => { colors: ['#00ff00', '#000000'], } ); - const color2 = palette.getCategoricalColor( + const color2 = palette.getColor( [ { name: 'abc', @@ -507,7 +507,7 @@ describe('palettes', () => { }); it('should use passed in colors', () => { - const color = palette.getCategoricalColor( + const color = palette.getColor( [ { name: 'abc', @@ -523,56 +523,5 @@ describe('palettes', () => { ); expect(color).toEqual('#00ff00'); }); - - // just an integration test here. More in depth tests on the subject can be found on the helper file - it('should return a color for the given value with its domain', () => { - expect( - palette.getColorForValue!( - 0, - { colors: ['red', 'green', 'blue'], stops: [], gradient: false }, - { min: 0, max: 100 } - ) - ).toBe('red'); - }); - - it('should return a color for the given value with its domain based on custom stops', () => { - expect( - palette.getColorForValue!( - 60, - { - colors: ['red', 'green', 'blue'], - stops: [10, 50, 100], - range: 'percent', - gradient: false, - rangeMin: 0, - rangeMax: 100, - }, - { min: 0, max: 100 } - ) - ).toBe('blue'); - }); - - // just make sure to not have broken anything - it('should work with only legacy arguments, filling with default values the new ones', () => { - expect(palette.toExpression({ colors: [], gradient: false })).toEqual({ - type: 'expression', - chain: [ - { - type: 'function', - function: 'palette', - arguments: { - color: [], - gradient: [false], - reverse: [false], - continuity: ['above'], - stop: [], - range: ['percent'], - rangeMax: [], - rangeMin: [], - }, - }, - ], - }); - }); }); }); diff --git a/src/plugins/charts/public/services/palettes/palettes.tsx b/src/plugins/charts/public/services/palettes/palettes.tsx index 65e3f9a84203dd3..b11d598c1c1cbc7 100644 --- a/src/plugins/charts/public/services/palettes/palettes.tsx +++ b/src/plugins/charts/public/services/palettes/palettes.tsx @@ -30,7 +30,6 @@ import { lightenColor } from './lighten_color'; import { ChartColorConfiguration, PaletteDefinition, SeriesLayer } from './types'; import { LegacyColorsService } from '../legacy_colors'; import { MappedColors } from '../mapped_colors'; -import { workoutColorForValue } from './helpers'; function buildRoundRobinCategoricalWithMappedColors(): Omit { const colors = euiPaletteColorBlind({ rotations: 2 }); @@ -65,8 +64,8 @@ function buildRoundRobinCategoricalWithMappedColors(): Omit euiPaletteColorBlind(), + getColor, + getColors: () => euiPaletteColorBlind(), toExpression: () => ({ type: 'expression', chain: [ @@ -103,9 +102,8 @@ function buildGradient( } return { id, - getCategoricalColor: getColor, - getCategoricalColors: colors, - canDynamicColoring: true, + getColor, + getColors: colors, toExpression: () => ({ type: 'expression', chain: [ @@ -143,8 +141,8 @@ function buildSyncedKibanaPalette( } return { id: 'kibana_palette', - getCategoricalColor: getColor, - getCategoricalColors: () => colors.seedColors.slice(0, 10), + getColor, + getColors: () => colors.seedColors.slice(0, 10), toExpression: () => ({ type: 'expression', chain: [ @@ -163,24 +161,7 @@ function buildSyncedKibanaPalette( function buildCustomPalette(): PaletteDefinition { return { id: 'custom', - getColorForValue: ( - value, - params: { - colors: string[]; - range: 'number' | 'percent'; - continuity: 'above' | 'below' | 'none' | 'all'; - gradient: boolean; - /** Stops values mark where colors end (non-inclusive value) */ - stops: number[]; - /** Important: specify rangeMin/rangeMax if custom stops are defined! */ - rangeMax: number; - rangeMin: number; - }, - dataBounds - ) => { - return workoutColorForValue(value, params, dataBounds); - }, - getCategoricalColor: ( + getColor: ( series: SeriesLayer[], chartConfiguration: ChartColorConfiguration = { behindText: false }, { colors, gradient }: { colors: string[]; gradient: boolean } @@ -198,48 +179,10 @@ function buildCustomPalette(): PaletteDefinition { }, internal: true, title: i18n.translate('charts.palettes.customLabel', { defaultMessage: 'Custom' }), - getCategoricalColors: ( - size: number, - { - colors, - gradient, - stepped, - stops, - }: { colors: string[]; gradient: boolean; stepped: boolean; stops: number[] } = { - colors: [], - gradient: false, - stepped: false, - stops: [], - } - ) => { - if (stepped) { - const range = stops[stops.length - 1] - stops[0]; - const offset = stops[0]; - const finalStops = [...stops.map((stop) => (stop - offset) / range)]; - return chroma.scale(colors).domain(finalStops).colors(size); - } + getColors: (size: number, { colors, gradient }: { colors: string[]; gradient: boolean }) => { return gradient ? chroma.scale(colors).colors(size) : colors; }, - canDynamicColoring: false, - toExpression: ({ - colors, - gradient, - stops = [], - rangeMax, - rangeMin, - rangeType = 'percent', - continuity = 'above', - reverse = false, - }: { - colors: string[]; - gradient: boolean; - stops: number[]; - rangeMax?: number; - rangeMin?: number; - rangeType: 'percent' | 'number'; - continuity?: 'all' | 'none' | 'above' | 'below'; - reverse?: boolean; - }) => ({ + toExpression: ({ colors, gradient }: { colors: string[]; gradient: boolean }) => ({ type: 'expression', chain: [ { @@ -248,12 +191,6 @@ function buildCustomPalette(): PaletteDefinition { arguments: { color: colors, gradient: [gradient], - reverse: [reverse], - continuity: [continuity], - stop: stops, - range: [rangeType], - rangeMax: rangeMax == null ? [] : [rangeMax], - rangeMin: rangeMin == null ? [] : [rangeMin], }, }, ], diff --git a/src/plugins/charts/public/services/palettes/types.ts b/src/plugins/charts/public/services/palettes/types.ts index 6f13f6217836402..3d2a6b032f63e97 100644 --- a/src/plugins/charts/public/services/palettes/types.ts +++ b/src/plugins/charts/public/services/palettes/types.ts @@ -79,12 +79,22 @@ export interface PaletteDefinition { * @param state The internal state of the palette */ toExpression: (state?: T) => Ast; + /** + * Renders the UI for editing the internal state of the palette. + * Not each palette has to feature an internal state, so this is an optional property. + * @param domElement The dom element to the render the editor UI into + * @param props Current state and state setter to issue updates + */ + renderEditor?: ( + domElement: Element, + props: { state?: T; setState: (updater: (oldState: T) => T) => void } + ) => void; /** * Color a series according to the internal rules of the palette. * @param series The current series along with its ancestors. * @param state The internal state of the palette */ - getCategoricalColor: ( + getColor: ( series: SeriesLayer[], chartConfiguration?: ChartColorConfiguration, state?: T @@ -93,20 +103,7 @@ export interface PaletteDefinition { * Get a spectrum of colors of the current palette. * This can be used if the chart wants to control color assignment locally. */ - getCategoricalColors: (size: number, state?: T) => string[]; - /** - * Define whether a palette supports dynamic coloring (i.e. gradient colors mapped to number values) - */ - canDynamicColoring?: boolean; - /** - * Get the assigned color for the given value based on its data domain and state settings. - * This can be used for dynamic coloring based on uniform color distribution or custom stops. - */ - getColorForValue?: ( - value: number | undefined, - state: T, - { min, max }: { min: number; max: number } - ) => string | undefined; + getColors: (size: number, state?: T) => string[]; } export interface PaletteRegistry { diff --git a/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx b/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx index 9249edef8af9211..b09a806e8fc2536 100644 --- a/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx +++ b/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx @@ -39,12 +39,12 @@ export function PalettePicker({ palettes={palettes .getAll() .filter(({ internal }) => !internal) - .map(({ id, title, getCategoricalColors }) => { + .map(({ id, title, getColors }) => { return { value: id, title, type: 'fixed', - palette: getCategoricalColors( + palette: getColors( 10, id === activePalette?.name ? activePalette?.params : undefined ), diff --git a/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts b/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts index a601da234e07829..7828ee33736eecd 100644 --- a/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts +++ b/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts @@ -90,7 +90,7 @@ describe('fetchIndexPattern', () => { ] as IndexPattern[]; const value = await fetchIndexPattern('indexTitle', indexPatternsService, { - fetchKibanaIndexForStringIndexes: true, + fetchKibabaIndexForStringIndexes: true, }); expect(value).toMatchInlineSnapshot(` @@ -104,9 +104,9 @@ describe('fetchIndexPattern', () => { `); }); - test('should return only indexPatternString if Kibana index does not exist (fetchKibanaIndexForStringIndexes is true)', async () => { + test('should return only indexPatternString if Kibana index does not exist (fetchKibabaIndexForStringIndexes is true)', async () => { const value = await fetchIndexPattern('indexTitle', indexPatternsService, { - fetchKibanaIndexForStringIndexes: true, + fetchKibabaIndexForStringIndexes: true, }); expect(value).toMatchInlineSnapshot(` diff --git a/src/plugins/vis_type_timeseries/common/index_patterns_utils.ts b/src/plugins/vis_type_timeseries/common/index_patterns_utils.ts index 1224fd33daee347..152fd5182225be0 100644 --- a/src/plugins/vis_type_timeseries/common/index_patterns_utils.ts +++ b/src/plugins/vis_type_timeseries/common/index_patterns_utils.ts @@ -51,9 +51,9 @@ export const fetchIndexPattern = async ( indexPatternValue: IndexPatternValue | undefined, indexPatternsService: Pick, options: { - fetchKibanaIndexForStringIndexes: boolean; + fetchKibabaIndexForStringIndexes: boolean; } = { - fetchKibanaIndexForStringIndexes: false, + fetchKibabaIndexForStringIndexes: false, } ): Promise => { let indexPattern: FetchedIndexPattern['indexPattern']; @@ -63,7 +63,7 @@ export const fetchIndexPattern = async ( indexPattern = await indexPatternsService.getDefault(); } else { if (isStringTypeIndexPattern(indexPatternValue)) { - if (options.fetchKibanaIndexForStringIndexes) { + if (options.fetchKibabaIndexForStringIndexes) { indexPattern = (await indexPatternsService.find(indexPatternValue)).find( (index) => index.title === indexPatternValue ); diff --git a/src/plugins/vis_type_timeseries/public/application/components/index_pattern.js b/src/plugins/vis_type_timeseries/public/application/components/index_pattern.js index 7d18af2bd0d59c9..bc2d9124e9c4a61 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/index_pattern.js +++ b/src/plugins/vis_type_timeseries/public/application/components/index_pattern.js @@ -8,7 +8,7 @@ import { get } from 'lodash'; import PropTypes from 'prop-types'; -import React, { useContext, useCallback, useEffect, useState } from 'react'; +import React, { useContext, useCallback, useEffect } from 'react'; import { htmlIdGenerator, EuiFieldText, @@ -29,17 +29,15 @@ import { LastValueModePopover } from './last_value_mode_popover'; import { KBN_FIELD_TYPES } from '../../../../data/public'; import { FormValidationContext } from '../contexts/form_validation_context'; import { DefaultIndexPatternContext } from '../contexts/default_index_context'; -import { PanelModelContext } from '../contexts/panel_model_context'; import { isGteInterval, validateReInterval, isAutoInterval } from './lib/get_interval'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { PANEL_TYPES, TIME_RANGE_DATA_MODES, TIME_RANGE_MODE_KEY } from '../../../common/enums'; -import { AUTO_INTERVAL, USE_KIBANA_INDEXES_KEY } from '../../../common/constants'; +import { AUTO_INTERVAL } from '../../../common/constants'; import { isTimerangeModeEnabled } from '../lib/check_ui_restrictions'; import { VisDataContext } from '../contexts/vis_data_context'; -import { getDataStart, getUISettings } from '../../services'; +import { getUISettings } from '../../services'; import { UI_SETTINGS } from '../../../../data/common'; -import { fetchIndexPattern } from '../../../common/index_patterns_utils'; const RESTRICT_FIELDS = [KBN_FIELD_TYPES.DATE]; const LEVEL_OF_DETAIL_STEPS = 10; @@ -79,13 +77,8 @@ export const IndexPattern = ({ const dropBucketName = `${prefix}drop_last_bucket`; const updateControlValidity = useContext(FormValidationContext); const defaultIndex = useContext(DefaultIndexPatternContext); - const panelModel = useContext(PanelModelContext); - const uiRestrictions = get(useContext(VisDataContext), 'uiRestrictions'); const maxBarsUiSettings = config.get(UI_SETTINGS.HISTOGRAM_MAX_BARS); - const useKibanaIndices = Boolean(panelModel?.[USE_KIBANA_INDEXES_KEY]); - - const [fetchedIndex, setFetchedIndex] = useState(); const handleMaxBarsChange = useCallback( ({ target }) => { @@ -125,7 +118,6 @@ export const IndexPattern = ({ }; const model = { ...defaults, ..._model }; - const index = model[indexPatternName]; const intervalValidation = validateIntervalValue(model[intervalName]); const selectedTimeRangeOption = timeRangeOptions.find( @@ -141,40 +133,11 @@ export const IndexPattern = ({ updateControlValidity(intervalName, intervalValidation.isValid); }, [intervalName, intervalValidation.isValid, updateControlValidity]); - useEffect(() => { - async function fetchIndex() { - const { indexPatterns } = getDataStart(); - - setFetchedIndex( - index - ? await fetchIndexPattern(index, indexPatterns, { - fetchKibanaIndexForStringIndexes: true, - }) - : { - indexPattern: undefined, - indexPatternString: undefined, - } - ); - } - - fetchIndex(); - }, [index]); - const toggleIndicatorDisplay = useCallback( () => onChange({ [HIDE_LAST_VALUE_INDICATOR]: !model.hide_last_value_indicator }), [model.hide_last_value_indicator, onChange] ); - const getTimefieldPlaceholder = () => { - if (!model[indexPatternName]) { - return defaultIndex?.timeFieldName; - } - - if (useKibanaIndices) { - return fetchedIndex?.indexPattern?.timeFieldName ?? undefined; - } - }; - return (

{!isTimeSeries && ( @@ -244,7 +207,6 @@ export const IndexPattern = ({ diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx b/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx index 07edfc2e6e0d706..ece90d479930933 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx +++ b/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx @@ -6,15 +6,18 @@ * Side Public License, v 1. */ -import React, { useContext, useCallback } from 'react'; +import React, { useState, useContext, useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFormRow, EuiText, EuiLink, htmlIdGenerator } from '@elastic/eui'; -import { getCoreStart } from '../../../../services'; +import { getCoreStart, getDataStart } from '../../../../services'; import { PanelModelContext } from '../../../contexts/panel_model_context'; -import { isStringTypeIndexPattern } from '../../../../../common/index_patterns_utils'; +import { + isStringTypeIndexPattern, + fetchIndexPattern, +} from '../../../../../common/index_patterns_utils'; import { FieldTextSelect } from './field_text_select'; import { ComboBoxSelect } from './combo_box_select'; @@ -29,7 +32,6 @@ interface IndexPatternSelectProps { onChange: Function; disabled?: boolean; allowIndexSwitchingMode?: boolean; - fetchedIndex: FetchedIndexPattern | null; } const defaultIndexPatternHelpText = i18n.translate( @@ -55,13 +57,13 @@ export const IndexPatternSelect = ({ indexPatternName, onChange, disabled, - fetchedIndex, allowIndexSwitchingMode, }: IndexPatternSelectProps) => { const htmlId = htmlIdGenerator(); const panelModel = useContext(PanelModelContext); const defaultIndex = useContext(DefaultIndexPatternContext); + const [fetchedIndex, setFetchedIndex] = useState(); const useKibanaIndices = Boolean(panelModel?.[USE_KIBANA_INDEXES_KEY]); const Component = useKibanaIndices ? ComboBoxSelect : FieldTextSelect; @@ -96,6 +98,25 @@ export const IndexPatternSelect = ({ }); }, [fetchedIndex]); + useEffect(() => { + async function fetchIndex() { + const { indexPatterns } = getDataStart(); + + setFetchedIndex( + value + ? await fetchIndexPattern(value, indexPatterns, { + fetchKibabaIndexForStringIndexes: true, + }) + : { + indexPattern: undefined, + indexPatternString: undefined, + } + ); + } + + fetchIndex(); + }, [value]); + if (!fetchedIndex) { return null; } diff --git a/src/plugins/vis_type_timeseries/public/application/components/palette_picker.tsx b/src/plugins/vis_type_timeseries/public/application/components/palette_picker.tsx index 749d6ca62bfa93b..20c0b40bb2e5427 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/palette_picker.tsx +++ b/src/plugins/vis_type_timeseries/public/application/components/palette_picker.tsx @@ -33,12 +33,12 @@ export function PalettePicker({ activePalette, palettes, setPalette, color }: Pa ...palettes .getAll() .filter(({ internal }) => !internal) - .map(({ id, title, getCategoricalColors }) => { + .map(({ id, title, getColors }) => { return { value: id, title, type: 'fixed' as const, - palette: getCategoricalColors(10), + palette: getColors(10), }; }), { @@ -49,7 +49,7 @@ export function PalettePicker({ activePalette, palettes, setPalette, color }: Pa type: 'fixed', palette: palettes .get('custom') - .getCategoricalColors(10, { colors: [color, finalGradientColor], gradient: true }), + .getColors(10, { colors: [color, finalGradientColor], gradient: true }), }, { value: PALETTES.RAINBOW, @@ -59,7 +59,7 @@ export function PalettePicker({ activePalette, palettes, setPalette, color }: Pa type: 'fixed', palette: palettes .get('custom') - .getCategoricalColors(10, { colors: rainbowColors.slice(0, 10), gradient: false }), + .getColors(10, { colors: rainbowColors.slice(0, 10), gradient: false }), }, ]} onChange={(newPalette) => { diff --git a/src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.ts b/src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.ts index 028ce3d028997c2..adcf1f3ad63cdb4 100644 --- a/src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.ts +++ b/src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.ts @@ -58,7 +58,7 @@ export const getSplitByTermsColor = ({ } : seriesPalette.params; - const outputColor = palettesRegistry?.get(paletteName || 'default').getCategoricalColor( + const outputColor = palettesRegistry?.get(paletteName || 'default').getColor( [ { name: seriesName || emptyLabel, diff --git a/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts b/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts index 5cdea62af95361b..cb105d7b439ccf0 100644 --- a/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts +++ b/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts @@ -31,22 +31,20 @@ export async function getVisData( const indexPatternsService = await framework.getIndexPatternsService(requestContext); const esQueryConfig = await getEsQueryConfig(uiSettings); - const promises = request.body.panels.map((panel) => { - const services: VisTypeTimeseriesRequestServices = { - esQueryConfig, - esShardTimeout, - indexPatternsService, - uiSettings, - searchStrategyRegistry: framework.searchStrategyRegistry, - cachedIndexPatternFetcher: getCachedIndexPatternFetcher( - indexPatternsService, - Boolean(panel.use_kibana_indexes) - ), - }; + const services: VisTypeTimeseriesRequestServices = { + esQueryConfig, + esShardTimeout, + indexPatternsService, + uiSettings, + searchStrategyRegistry: framework.searchStrategyRegistry, + cachedIndexPatternFetcher: getCachedIndexPatternFetcher(indexPatternsService), + }; - return panel.type === PANEL_TYPES.TABLE - ? getTableData(requestContext, request, panel, services) - : getSeriesData(requestContext, request, panel, services); + const promises = request.body.panels.map((panel) => { + if (panel.type === PANEL_TYPES.TABLE) { + return getTableData(requestContext, request, panel, services); + } + return getSeriesData(requestContext, request, panel, services); }); return Promise.all(promises).then((res) => { diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts b/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts index 26ea191ab921735..b03fa973e9da998 100644 --- a/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts +++ b/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts @@ -11,10 +11,7 @@ import { getIndexPatternKey, fetchIndexPattern } from '../../../../common/index_ import type { IndexPatternsService } from '../../../../../data/server'; import type { IndexPatternValue, FetchedIndexPattern } from '../../../../common/types'; -export const getCachedIndexPatternFetcher = ( - indexPatternsService: IndexPatternsService, - fetchKibanaIndexForStringIndexes: boolean = false -) => { +export const getCachedIndexPatternFetcher = (indexPatternsService: IndexPatternsService) => { const cache = new Map(); return async (indexPatternValue: IndexPatternValue): Promise => { @@ -24,9 +21,7 @@ export const getCachedIndexPatternFetcher = ( return cache.get(key); } - const fetchedIndex = fetchIndexPattern(indexPatternValue, indexPatternsService, { - fetchKibanaIndexForStringIndexes, - }); + const fetchedIndex = fetchIndexPattern(indexPatternValue, indexPatternsService); cache.set(key, fetchedIndex); diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js index 5abfc3e26ffcdd0..fd7f5a06cac5603 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js @@ -8,9 +8,9 @@ import { mathAgg } from '../series/math'; -export function math(bucket, panel, series, meta, extractFields) { +export function math(bucket, panel, series) { return (next) => (results) => { - const mathFn = mathAgg({ aggregations: bucket }, panel, series, meta, extractFields); + const mathFn = mathAgg({ aggregations: bucket }, panel, series); return mathFn(next)(results); }; } diff --git a/src/plugins/vis_type_xy/public/vis_component.tsx b/src/plugins/vis_type_xy/public/vis_component.tsx index dd88822f7f0f366..5da5ffcc637c6ce 100644 --- a/src/plugins/vis_type_xy/public/vis_component.tsx +++ b/src/plugins/vis_type_xy/public/vis_component.tsx @@ -245,7 +245,7 @@ const VisComponent = (props: VisComponentProps) => { if (Object.keys(overwriteColors).includes(seriesName)) { return overwriteColors[seriesName]; } - const outputColor = palettesRegistry?.get(visParams.palette.name).getCategoricalColor( + const outputColor = palettesRegistry?.get(visParams.palette.name).getColor( [ { name: seriesName, diff --git a/x-pack/plugins/alerting/server/config.test.ts b/x-pack/plugins/alerting/server/config.test.ts index a8befe5210752e8..069c41605ccfbc2 100644 --- a/x-pack/plugins/alerting/server/config.test.ts +++ b/x-pack/plugins/alerting/server/config.test.ts @@ -8,11 +8,10 @@ import { configSchema } from './config'; describe('config validation', () => { - test('alerting defaults', () => { + test('alerts defaults', () => { const config: Record = {}; expect(configSchema.validate(config)).toMatchInlineSnapshot(` Object { - "enableImportExport": false, "healthCheck": Object { "interval": "60m", }, diff --git a/x-pack/plugins/alerting/server/config.ts b/x-pack/plugins/alerting/server/config.ts index d50917fd135785a..e42955b385bf1eb 100644 --- a/x-pack/plugins/alerting/server/config.ts +++ b/x-pack/plugins/alerting/server/config.ts @@ -16,7 +16,6 @@ export const configSchema = schema.object({ interval: schema.string({ validate: validateDurationSchema, defaultValue: '5m' }), removalDelay: schema.string({ validate: validateDurationSchema, defaultValue: '1h' }), }), - enableImportExport: schema.boolean({ defaultValue: false }), }); export type AlertsConfig = TypeOf; diff --git a/x-pack/plugins/alerting/server/health/get_state.test.ts b/x-pack/plugins/alerting/server/health/get_state.test.ts index 96627e10fb3bdf8..643d966d1fad0bf 100644 --- a/x-pack/plugins/alerting/server/health/get_state.test.ts +++ b/x-pack/plugins/alerting/server/health/get_state.test.ts @@ -72,7 +72,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }), pollInterval ).subscribe(); @@ -108,7 +107,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }), pollInterval, retryDelay @@ -154,7 +152,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }) ).toPromise(); @@ -185,7 +182,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }) ).toPromise(); @@ -216,7 +212,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }) ).toPromise(); @@ -244,7 +239,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }), retryDelay ).subscribe((status) => { @@ -275,7 +269,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }), retryDelay ).subscribe((status) => { @@ -312,7 +305,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }) ).toPromise(); diff --git a/x-pack/plugins/alerting/server/plugin.test.ts b/x-pack/plugins/alerting/server/plugin.test.ts index 4e9249944a6bf9d..ec4b7095d67f7fc 100644 --- a/x-pack/plugins/alerting/server/plugin.test.ts +++ b/x-pack/plugins/alerting/server/plugin.test.ts @@ -18,7 +18,6 @@ import { AlertsConfig } from './config'; import { AlertType } from './types'; import { eventLogMock } from '../../event_log/server/mocks'; import { actionsMock } from '../../actions/server/mocks'; -import mappings from './saved_objects/mappings.json'; describe('Alerting Plugin', () => { describe('setup()', () => { @@ -26,8 +25,6 @@ describe('Alerting Plugin', () => { let coreSetup: ReturnType; let pluginsSetup: jest.Mocked; - beforeEach(() => jest.clearAllMocks()); - it('should log warning when Encrypted Saved Objects plugin is missing encryption key', async () => { const context = coreMock.createPluginInitializerContext({ healthCheck: { @@ -37,7 +34,6 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }); plugin = new AlertingPlugin(context); @@ -61,72 +57,6 @@ describe('Alerting Plugin', () => { ); }); - it('should register saved object with no management capability if enableImportExport is false', async () => { - const context = coreMock.createPluginInitializerContext({ - healthCheck: { - interval: '5m', - }, - invalidateApiKeysTask: { - interval: '5m', - removalDelay: '1h', - }, - enableImportExport: false, - }); - plugin = new AlertingPlugin(context); - - const setupMocks = coreMock.createSetup(); - await plugin.setup(setupMocks, { - licensing: licensingMock.createSetup(), - encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(), - taskManager: taskManagerMock.createSetup(), - eventLog: eventLogServiceMock.create(), - actions: actionsMock.createSetup(), - statusService: statusServiceMock.createSetupContract(), - }); - - expect(setupMocks.savedObjects.registerType).toHaveBeenCalledTimes(2); - const registerAlertingSavedObject = setupMocks.savedObjects.registerType.mock.calls[0][0]; - expect(registerAlertingSavedObject.name).toEqual('alert'); - expect(registerAlertingSavedObject.hidden).toBe(true); - expect(registerAlertingSavedObject.mappings).toEqual(mappings.alert); - expect(registerAlertingSavedObject.management).toBeUndefined(); - }); - - it('should register saved object with import/export capability if enableImportExport is true', async () => { - const context = coreMock.createPluginInitializerContext({ - healthCheck: { - interval: '5m', - }, - invalidateApiKeysTask: { - interval: '5m', - removalDelay: '1h', - }, - enableImportExport: true, - }); - plugin = new AlertingPlugin(context); - - const setupMocks = coreMock.createSetup(); - await plugin.setup(setupMocks, { - licensing: licensingMock.createSetup(), - encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(), - taskManager: taskManagerMock.createSetup(), - eventLog: eventLogServiceMock.create(), - actions: actionsMock.createSetup(), - statusService: statusServiceMock.createSetupContract(), - }); - - expect(setupMocks.savedObjects.registerType).toHaveBeenCalledTimes(2); - const registerAlertingSavedObject = setupMocks.savedObjects.registerType.mock.calls[0][0]; - expect(registerAlertingSavedObject.name).toEqual('alert'); - expect(registerAlertingSavedObject.hidden).toBe(true); - expect(registerAlertingSavedObject.mappings).toEqual(mappings.alert); - expect(registerAlertingSavedObject.management).not.toBeUndefined(); - expect(registerAlertingSavedObject.management?.importableAndExportable).toBe(true); - expect(registerAlertingSavedObject.management?.getTitle).not.toBeUndefined(); - expect(registerAlertingSavedObject.management?.onImport).not.toBeUndefined(); - expect(registerAlertingSavedObject.management?.onExport).not.toBeUndefined(); - }); - describe('registerType()', () => { let setup: PluginSetupContract; const sampleAlertType: AlertType = { @@ -189,7 +119,6 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }); const plugin = new AlertingPlugin(context); @@ -229,7 +158,6 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }); const plugin = new AlertingPlugin(context); @@ -283,7 +211,6 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, - enableImportExport: false, }); const plugin = new AlertingPlugin(context); diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 769243b8feaf6a4..990733c320dfe83 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -190,7 +190,7 @@ export class AlertingPlugin { event: { provider: EVENT_LOG_PROVIDER }, }); - setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects, this.config); + setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects); this.eventLogService = plugins.eventLog; plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS)); diff --git a/x-pack/plugins/alerting/server/saved_objects/index.ts b/x-pack/plugins/alerting/server/saved_objects/index.ts index c339183eeedcdbc..6b76fd97dc53b75 100644 --- a/x-pack/plugins/alerting/server/saved_objects/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/index.ts @@ -16,7 +16,6 @@ import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objec import { transformRulesForExport } from './transform_rule_for_export'; import { RawAlert } from '../types'; import { getImportWarnings } from './get_import_warnings'; -import { AlertsConfig } from '../config'; export { partiallyUpdateAlert } from './partially_update_alert'; export const AlertAttributesExcludedFromAAD = [ @@ -42,66 +41,59 @@ export type AlertAttributesExcludedFromAADType = export function setupSavedObjects( savedObjects: SavedObjectsServiceSetup, - encryptedSavedObjects: EncryptedSavedObjectsPluginSetup, - alertingConfig: Promise + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup ) { - alertingConfig.then((config: AlertsConfig) => { - savedObjects.registerType({ - name: 'alert', - hidden: true, - namespaceType: 'single', - migrations: getMigrations(encryptedSavedObjects), - mappings: mappings.alert, - ...(config.enableImportExport - ? { - management: { - importableAndExportable: true, - getTitle(ruleSavedObject: SavedObject) { - return `Rule: [${ruleSavedObject.attributes.name}]`; - }, - onImport(ruleSavedObjects) { - return { - warnings: getImportWarnings(ruleSavedObjects), - }; - }, - onExport( - context: SavedObjectsExportTransformContext, - objects: Array> - ) { - return transformRulesForExport(objects); - }, - }, - } - : {}), - }); + savedObjects.registerType({ + name: 'alert', + hidden: true, + namespaceType: 'single', + migrations: getMigrations(encryptedSavedObjects), + mappings: mappings.alert, + management: { + importableAndExportable: true, + getTitle(ruleSavedObject: SavedObject) { + return `Rule: [${ruleSavedObject.attributes.name}]`; + }, + onImport(ruleSavedObjects) { + return { + warnings: getImportWarnings(ruleSavedObjects), + }; + }, + onExport( + context: SavedObjectsExportTransformContext, + objects: Array> + ) { + return transformRulesForExport(objects); + }, + }, + }); - savedObjects.registerType({ - name: 'api_key_pending_invalidation', - hidden: true, - namespaceType: 'agnostic', - mappings: { - properties: { - apiKeyId: { - type: 'keyword', - }, - createdAt: { - type: 'date', - }, + savedObjects.registerType({ + name: 'api_key_pending_invalidation', + hidden: true, + namespaceType: 'agnostic', + mappings: { + properties: { + apiKeyId: { + type: 'keyword', + }, + createdAt: { + type: 'date', }, }, - }); + }, + }); - // Encrypted attributes - encryptedSavedObjects.registerType({ - type: 'alert', - attributesToEncrypt: new Set(['apiKey']), - attributesToExcludeFromAAD: new Set(AlertAttributesExcludedFromAAD), - }); + // Encrypted attributes + encryptedSavedObjects.registerType({ + type: 'alert', + attributesToEncrypt: new Set(['apiKey']), + attributesToExcludeFromAAD: new Set(AlertAttributesExcludedFromAAD), + }); - // Encrypted attributes - encryptedSavedObjects.registerType({ - type: 'api_key_pending_invalidation', - attributesToEncrypt: new Set(['apiKeyId']), - }); + // Encrypted attributes + encryptedSavedObjects.registerType({ + type: 'api_key_pending_invalidation', + attributesToEncrypt: new Set(['apiKeyId']), }); } diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts index 78d74b78c99ba65..120ab6de296dd83 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts @@ -180,8 +180,7 @@ test('enqueues execution per selected action', async () => { `); expect(jest.requireMock('./inject_action_params').injectActionParams).toHaveBeenCalledWith({ - ruleId: '1', - spaceId: 'default', + alertId: '1', actionTypeId: 'test', actionParams: { alertVal: 'My 1 name-of-alert default tag-A,tag-B 2 goes here', diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts index 93cced2043d5e13..2ecf5404856954b 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts @@ -138,8 +138,7 @@ export function createExecutionHandler< .map((action) => ({ ...action, params: injectActionParams({ - ruleId: alertId, - spaceId, + alertId, actionParams: action.params, actionTypeId: action.actionTypeId, }), diff --git a/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts b/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts index 0416a3c4d1214aa..62d834eb91da0de 100644 --- a/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts @@ -14,8 +14,7 @@ describe('injectActionParams', () => { }; const result = injectActionParams({ actionParams, - ruleId: '1', - spaceId: 'the-space', + alertId: '1', actionTypeId: '.server-log', }); expect(result).toMatchInlineSnapshot(` @@ -33,8 +32,7 @@ describe('injectActionParams', () => { }; const result = injectActionParams({ actionParams, - ruleId: '1', - spaceId: 'default', + alertId: '1', actionTypeId: '.email', }); expect(result).toMatchInlineSnapshot(` @@ -43,58 +41,8 @@ describe('injectActionParams', () => { "message": "State: \\"{{state.value}}\\", Context: \\"{{context.value}}\\"", }, "kibanaFooterLink": Object { - "path": "/app/management/insightsAndAlerting/triggersActions/rule/1", - "text": "View rule in Kibana", - }, - } - `); - }); - - test('injects viewInKibanaPath and viewInKibanaText when actionTypeId is .email and spaceId is undefined', () => { - const actionParams = { - body: { - message: 'State: "{{state.value}}", Context: "{{context.value}}"', - }, - }; - const result = injectActionParams({ - actionParams, - ruleId: '1', - spaceId: undefined, - actionTypeId: '.email', - }); - expect(result).toMatchInlineSnapshot(` - Object { - "body": Object { - "message": "State: \\"{{state.value}}\\", Context: \\"{{context.value}}\\"", - }, - "kibanaFooterLink": Object { - "path": "/app/management/insightsAndAlerting/triggersActions/rule/1", - "text": "View rule in Kibana", - }, - } - `); - }); - - test('injects viewInKibanaPath with space ID and viewInKibanaText when actionTypeId is .email', () => { - const actionParams = { - body: { - message: 'State: "{{state.value}}", Context: "{{context.value}}"', - }, - }; - const result = injectActionParams({ - actionParams, - ruleId: '1', - spaceId: 'not-the-default', - actionTypeId: '.email', - }); - expect(result).toMatchInlineSnapshot(` - Object { - "body": Object { - "message": "State: \\"{{state.value}}\\", Context: \\"{{context.value}}\\"", - }, - "kibanaFooterLink": Object { - "path": "/s/not-the-default/app/management/insightsAndAlerting/triggersActions/rule/1", - "text": "View rule in Kibana", + "path": "/app/management/insightsAndAlerting/triggersActions/alert/1", + "text": "View alert in Kibana", }, } `); diff --git a/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts b/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts index 11ac3f92d1071b8..177622867565cda 100644 --- a/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts +++ b/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts @@ -9,29 +9,25 @@ import { i18n } from '@kbn/i18n'; import { AlertActionParams } from '../types'; export interface InjectActionParamsOpts { - ruleId: string; - spaceId: string | undefined; + alertId: string; actionTypeId: string; actionParams: AlertActionParams; } export function injectActionParams({ - ruleId, - spaceId, + alertId, actionTypeId, actionParams, }: InjectActionParamsOpts) { // Inject kibanaFooterLink if action type is email. This is used by the email action type // to inject a "View alert in Kibana" with a URL in the email's footer. if (actionTypeId === '.email') { - const spacePrefix = - spaceId && spaceId.length > 0 && spaceId !== 'default' ? `/s/${spaceId}` : ''; return { ...actionParams, kibanaFooterLink: { - path: `${spacePrefix}/app/management/insightsAndAlerting/triggersActions/rule/${ruleId}`, + path: `/app/management/insightsAndAlerting/triggersActions/alert/${alertId}`, text: i18n.translate('xpack.alerting.injectActionParams.email.kibanaFooterLinkText', { - defaultMessage: 'View rule in Kibana', + defaultMessage: 'View alert in Kibana', }), }, }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts index c998964b8640032..8954adf2c18c710 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts @@ -22,7 +22,7 @@ import { SYMBOLIZE_AS_TYPES, } from '../../../../../../maps/common/constants'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../common/index_pattern_constants'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../../../../src/plugins/apm_oss/public'; import { useUrlParams } from '../../../../context/url_params_context/use_url_params'; import { SERVICE_NAME, diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useMapFilters.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useMapFilters.ts index e989577ac15aaa2..7a40880eb905366 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useMapFilters.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useMapFilters.ts @@ -17,7 +17,7 @@ import { USER_AGENT_OS, } from '../../../../../common/elasticsearch_fieldnames'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../common/index_pattern_constants'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../../../../src/plugins/apm_oss/public'; const getWildcardFilter = (field: string, value: string): Filter => { return { diff --git a/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx index 919d140c54c1ebf..4343d504c337392 100644 --- a/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { useLocation } from 'react-router-dom'; import rison, { RisonValue } from 'rison-node'; import url from 'url'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../common/index_pattern_constants'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../../../../src/plugins/apm_oss/public'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { getTimepickerRisonData } from '../rison_helpers'; diff --git a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts index 607a7e6227a9d6f..e627e9ed1d6cf6c 100644 --- a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts +++ b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts @@ -6,8 +6,10 @@ */ import { SavedObjectsErrorHelpers } from '../../../../../../src/core/server'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../../common/index_pattern_constants'; -import apmIndexPattern from '../../tutorial/index_pattern.json'; +import { + apmIndexPattern, + APM_STATIC_INDEX_PATTERN_ID, +} from '../../../../../../src/plugins/apm_oss/server'; import { hasHistoricalAgentData } from '../services/get_services/has_historical_agent_data'; import { Setup } from '../helpers/setup_request'; import { APMRouteHandlerResources } from '../../routes/typings'; diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index 824eba9bce0b08e..8d83f762e2023ec 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { i18n } from '@kbn/i18n'; import { combineLatest } from 'rxjs'; import { map, take } from 'rxjs/operators'; import { @@ -31,6 +32,7 @@ import { createApmAgentConfigurationIndex } from './lib/settings/agent_configura import { getApmIndices } from './lib/settings/apm_indices/get_apm_indices'; import { createApmCustomLinkIndex } from './lib/settings/custom_link/create_custom_link_index'; import { apmIndices, apmTelemetry } from './saved_objects'; +import { createElasticCloudInstructions } from './tutorial/elastic_cloud'; import { uiSettings } from './ui_settings'; import type { ApmPluginRequestHandlerContext, @@ -49,7 +51,6 @@ import { SERVICE_NAME, TRANSACTION_TYPE, } from '../common/elasticsearch_fieldnames'; -import { tutorialProvider } from './tutorial'; export class APMPlugin implements @@ -102,20 +103,28 @@ export class APMPlugin }); } - plugins.home?.tutorials.registerTutorial( - tutorialProvider({ - isEnabled: this.currentConfig['xpack.apm.ui.enabled'], - indexPatternTitle: this.currentConfig['apm_oss.indexPattern'], - cloud: plugins.cloud, - indices: { - errorIndices: this.currentConfig['apm_oss.errorIndices'], - metricsIndices: this.currentConfig['apm_oss.metricsIndices'], - onboardingIndices: this.currentConfig['apm_oss.onboardingIndices'], - sourcemapIndices: this.currentConfig['apm_oss.sourcemapIndices'], - transactionIndices: this.currentConfig['apm_oss.transactionIndices'], - }, - }) - ); + const ossTutorialProvider = plugins.apmOss.getRegisteredTutorialProvider(); + plugins.home?.tutorials.unregisterTutorial(ossTutorialProvider); + plugins.home?.tutorials.registerTutorial(() => { + const ossPart = ossTutorialProvider({}); + if (this.currentConfig!['xpack.apm.ui.enabled'] && ossPart.artifacts) { + // @ts-expect-error ossPart.artifacts.application is readonly + ossPart.artifacts.application = { + path: '/app/apm', + label: i18n.translate( + 'xpack.apm.tutorial.specProvider.artifacts.application.label', + { + defaultMessage: 'Launch APM', + } + ), + }; + } + + return { + ...ossPart, + elasticCloud: createElasticCloudInstructions(plugins.cloud), + }; + }); plugins.features.registerKibanaFeature(APM_FEATURE); diff --git a/x-pack/plugins/apm/server/tutorial/envs/elastic_cloud.ts b/x-pack/plugins/apm/server/tutorial/elastic_cloud.ts similarity index 94% rename from x-pack/plugins/apm/server/tutorial/envs/elastic_cloud.ts rename to x-pack/plugins/apm/server/tutorial/elastic_cloud.ts index c6afd6a592fff2b..08e1ff75d43242f 100644 --- a/x-pack/plugins/apm/server/tutorial/envs/elastic_cloud.ts +++ b/x-pack/plugins/apm/server/tutorial/elastic_cloud.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { INSTRUCTION_VARIANT } from '../../../../../../src/plugins/home/server'; +import { INSTRUCTION_VARIANT } from '../../../../../src/plugins/home/server'; import { createNodeAgentInstructions, @@ -19,8 +19,8 @@ import { createJavaAgentInstructions, createDotNetAgentInstructions, createPhpAgentInstructions, -} from '../instructions/apm_agent_instructions'; -import { CloudSetup } from '../../../../cloud/server'; +} from '../../../../../src/plugins/apm_oss/server'; +import { CloudSetup } from '../../../cloud/server'; export function createElasticCloudInstructions(cloudSetup?: CloudSetup) { const apmServerUrl = cloudSetup?.apm.url; diff --git a/x-pack/plugins/apm/server/tutorial/index.ts b/x-pack/plugins/apm/server/tutorial/index.ts deleted file mode 100644 index d678677a4b7514c..000000000000000 --- a/x-pack/plugins/apm/server/tutorial/index.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { onPremInstructions } from './envs/on_prem'; -import { createElasticCloudInstructions } from './envs/elastic_cloud'; -import apmIndexPattern from './index_pattern.json'; -import { CloudSetup } from '../../../cloud/server'; -import { - ArtifactsSchema, - TutorialsCategory, -} from '../../../../../src/plugins/home/server'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../common/index_pattern_constants'; - -const apmIntro = i18n.translate('xpack.apm.tutorial.introduction', { - defaultMessage: - 'Collect in-depth performance metrics and errors from inside your applications.', -}); -const moduleName = 'apm'; - -export const tutorialProvider = ({ - isEnabled, - indexPatternTitle, - indices, - cloud, -}: { - isEnabled: boolean; - indexPatternTitle: string; - cloud?: CloudSetup; - indices: { - errorIndices: string; - transactionIndices: string; - metricsIndices: string; - sourcemapIndices: string; - onboardingIndices: string; - }; -}) => () => { - const savedObjects = [ - { - ...apmIndexPattern, - id: APM_STATIC_INDEX_PATTERN_ID, - attributes: { - ...apmIndexPattern.attributes, - title: indexPatternTitle, - }, - }, - ]; - - const artifacts: ArtifactsSchema = { - dashboards: [ - { - id: '8d3ed660-7828-11e7-8c47-65b845b5cfb3', - linkLabel: i18n.translate( - 'xpack.apm.tutorial.specProvider.artifacts.dashboards.linkLabel', - { - defaultMessage: 'APM dashboard', - } - ), - isOverview: true, - }, - ], - }; - - if (isEnabled) { - // @ts-expect-error artifacts.application is readonly - artifacts.application = { - path: '/app/apm', - label: i18n.translate( - 'xpack.apm.tutorial.specProvider.artifacts.application.label', - { - defaultMessage: 'Launch APM', - } - ), - }; - } - - return { - id: 'apm', - name: i18n.translate('xpack.apm.tutorial.specProvider.name', { - defaultMessage: 'APM', - }), - moduleName, - category: TutorialsCategory.OTHER, - shortDescription: apmIntro, - longDescription: i18n.translate( - 'xpack.apm.tutorial.specProvider.longDescription', - { - defaultMessage: - 'Application Performance Monitoring (APM) collects in-depth \ -performance metrics and errors from inside your application. \ -It allows you to monitor the performance of thousands of applications in real time. \ -[Learn more]({learnMoreLink}).', - values: { - learnMoreLink: - '{config.docs.base_url}guide/en/apm/get-started/{config.docs.version}/index.html', - }, - } - ), - euiIconType: 'apmApp', - artifacts, - onPrem: onPremInstructions(indices), - elasticCloud: createElasticCloudInstructions(cloud), - previewImagePath: '/plugins/apm/assets/apm.png', - savedObjects, - savedObjectsInstallMsg: i18n.translate( - 'xpack.apm.tutorial.specProvider.savedObjectsInstallMsg', - { - defaultMessage: - 'An APM index pattern is required for some features in the APM UI.', - } - ), - }; -}; diff --git a/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts b/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts deleted file mode 100644 index a25021fac5d0065..000000000000000 --- a/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts +++ /dev/null @@ -1,931 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const createNodeAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.nodeClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('xpack.apm.tutorial.nodeClient.install.textPre', { - defaultMessage: - 'Install the APM agent for Node.js as a dependency to your application.', - }), - commands: ['npm install elastic-apm-node --save'], - }, - { - title: i18n.translate('xpack.apm.tutorial.nodeClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate('xpack.apm.tutorial.nodeClient.configure.textPre', { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the `serviceName`. \ -This agent supports a variety of frameworks but can also be used with your custom stack.', - }), - commands: `// ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.addThisToTheFileTopComment', - { - defaultMessage: - 'Add this to the VERY top of the first file loaded in your app', - } - )} -var apm = require('elastic-apm-node').start({curlyOpen} - - // ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Override the service name from package.json', - } - )} - // ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.allowedCharactersComment', - { - defaultMessage: 'Allowed characters: a-z, A-Z, 0-9, -, _, and space', - } - )} - serviceName: '', - - // ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.useIfApmRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a secret token', - } - )} - secretToken: '${secretToken}', - - // ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set the custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } - )} - serverUrl: '${apmServerUrl}', - - // ${i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.commands.setCustomServiceEnvironmentComment', - { - defaultMessage: 'Set the service environment', - } - )} - environment: 'production' -{curlyClose})`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.nodeClient.configure.textPost', - { - defaultMessage: - 'See [the documentation]({documentationLink}) for advanced usage, including how to use with \ -[Babel/ES Modules]({babelEsModulesLink}).', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/nodejs/current/index.html', - babelEsModulesLink: - '{config.docs.base_url}guide/en/apm/agent/nodejs/current/advanced-setup.html#es-modules', - }, - } - ), - }, -]; - -export const createDjangoAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.djangoClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('xpack.apm.tutorial.djangoClient.install.textPre', { - defaultMessage: 'Install the APM agent for Python as a dependency.', - }), - commands: ['$ pip install elastic-apm'], - }, - { - title: i18n.translate('xpack.apm.tutorial.djangoClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.textPre', - { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the `SERVICE_NAME`.', - } - ), - commands: `# ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.addAgentComment', - { - defaultMessage: 'Add the agent to the installed apps', - } - )} -INSTALLED_APPS = ( - 'elasticapm.contrib.django', - # ... -) - -ELASTIC_APM = {curlyOpen} - # ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Set the required service name. Allowed characters:', - } - )} - # ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.allowedCharactersComment', - { - defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', - } - )} - 'SERVICE_NAME': '', - - # ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.useIfApmServerRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a secret token', - } - )} - 'SECRET_TOKEN': '${secretToken}', - - # ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set the custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } - )} - 'SERVER_URL': '${apmServerUrl}', - - # ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.setServiceEnvironmentComment', - { - defaultMessage: 'Set the service environment', - } - )} - 'ENVIRONMENT': 'production', -{curlyClose} - -# ${i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.commands.addTracingMiddlewareComment', - { - defaultMessage: - 'To send performance metrics, add our tracing middleware:', - } - )} -MIDDLEWARE = ( - 'elasticapm.contrib.django.middleware.TracingMiddleware', - #... -)`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.djangoClient.configure.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for advanced usage.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/python/current/django-support.html', - }, - } - ), - }, -]; - -export const createFlaskAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.flaskClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('xpack.apm.tutorial.flaskClient.install.textPre', { - defaultMessage: 'Install the APM agent for Python as a dependency.', - }), - commands: ['$ pip install elastic-apm[flask]'], - }, - { - title: i18n.translate('xpack.apm.tutorial.flaskClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.textPre', - { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the `SERVICE_NAME`.', - } - ), - commands: `# ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.initializeUsingEnvironmentVariablesComment', - { - defaultMessage: 'initialize using environment variables', - } - )} -from elasticapm.contrib.flask import ElasticAPM -app = Flask(__name__) -apm = ElasticAPM(app) - -# ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.configureElasticApmComment', - { - defaultMessage: - "or configure to use ELASTIC_APM in your application's settings", - } - )} -from elasticapm.contrib.flask import ElasticAPM -app.config['ELASTIC_APM'] = {curlyOpen} - # ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.setRequiredServiceNameComment', - { - defaultMessage: 'Set the required service name. Allowed characters:', - } - )} - # ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.allowedCharactersComment', - { - defaultMessage: 'a-z, A-Z, 0-9, -, _, and space', - } - )} - 'SERVICE_NAME': '', - - # ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.useIfApmServerRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a secret token', - } - )} - 'SECRET_TOKEN': '${secretToken}', - - # ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set the custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } - )} - 'SERVER_URL': '${apmServerUrl}', - - # ${i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.commands.setServiceEnvironmentComment', - { - defaultMessage: 'Set the service environment', - } - )} - 'ENVIRONMENT': 'production', -{curlyClose} - -apm = ElasticAPM(app)`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.flaskClient.configure.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for advanced usage.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/python/current/flask-support.html', - }, - } - ), - }, -]; - -export const createRailsAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.railsClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('xpack.apm.tutorial.railsClient.install.textPre', { - defaultMessage: 'Add the agent to your Gemfile.', - }), - commands: [`gem 'elastic-apm'`], - }, - { - title: i18n.translate('xpack.apm.tutorial.railsClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.railsClient.configure.textPre', - { - defaultMessage: - 'APM is automatically started when your app boots. Configure the agent, by creating the config file {configFile}', - values: { configFile: '`config/elastic_apm.yml`' }, - } - ), - commands: `# config/elastic_apm.yml: - -# Set the service name - allowed characters: a-z, A-Z, 0-9, -, _ and space -# Defaults to the name of your Rails app -service_name: 'my-service' - -# Use if APM Server requires a secret token -secret_token: '${secretToken}' - -# Set the custom APM Server URL (default: http://localhost:8200) -server_url: '${apmServerUrl || 'http://localhost:8200'}' - -# Set the service environment -environment: 'production'`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.railsClient.configure.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html', - }, - } - ), - }, -]; - -export const createRackAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.rackClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('xpack.apm.tutorial.rackClient.install.textPre', { - defaultMessage: 'Add the agent to your Gemfile.', - }), - commands: [`gem 'elastic-apm'`], - }, - { - title: i18n.translate('xpack.apm.tutorial.rackClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate('xpack.apm.tutorial.rackClient.configure.textPre', { - defaultMessage: - 'For Rack or a compatible framework (e.g. Sinatra), include the middleware in your app and start the agent.', - }), - commands: `# config.ru - require 'sinatra/base' - - class MySinatraApp < Sinatra::Base - use ElasticAPM::Middleware - - # ... - end - - ElasticAPM.start( - app: MySinatraApp, # ${i18n.translate( - 'xpack.apm.tutorial.rackClient.configure.commands.requiredComment', - { - defaultMessage: 'required', - } - )} - config_file: '' # ${i18n.translate( - 'xpack.apm.tutorial.rackClient.configure.commands.optionalComment', - { - defaultMessage: 'optional, defaults to config/elastic_apm.yml', - } - )} - ) - - run MySinatraApp - - at_exit {curlyOpen} ElasticAPM.stop {curlyClose}`.split('\n'), - }, - { - title: i18n.translate('xpack.apm.tutorial.rackClient.createConfig.title', { - defaultMessage: 'Create config file', - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.textPre', - { - defaultMessage: 'Create a config file {configFile}:', - values: { configFile: '`config/elastic_apm.yml`' }, - } - ), - commands: `# config/elastic_apm.yml: - -# ${i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.commands.setServiceNameComment', - { - defaultMessage: - 'Set the service name - allowed characters: a-z, A-Z, 0-9, -, _ and space', - } - )} -# ${i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.commands.defaultsToTheNameOfRackAppClassComment', - { - defaultMessage: "Defaults to the name of your Rack app's class.", - } - )} -service_name: 'my-service' - -# ${i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.commands.useIfApmServerRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a token', - } - )} -secret_token: '${secretToken}' - -# ${i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.commands.setCustomApmServerComment', - { - defaultMessage: - 'Set custom APM Server URL (default: {defaultServerUrl})', - values: { defaultServerUrl: 'http://localhost:8200' }, - } - )} -server_url: '${apmServerUrl || 'http://localhost:8200'}', - -# ${i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.commands.setServiceEnvironment', - { - defaultMessage: 'Set the service environment', - } - )} -environment: 'production'`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.rackClient.createConfig.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/ruby/current/index.html', - }, - } - ), - }, -]; - -export const createJsAgentInstructions = (apmServerUrl = '') => [ - { - title: i18n.translate( - 'xpack.apm.tutorial.jsClient.enableRealUserMonitoring.title', - { - defaultMessage: 'Enable Real User Monitoring support in APM Server', - } - ), - textPre: i18n.translate( - 'xpack.apm.tutorial.jsClient.enableRealUserMonitoring.textPre', - { - defaultMessage: - 'APM Server disables RUM support by default. See the [documentation]({documentationLink}) \ -for details on how to enable RUM support.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/server/{config.docs.version}/configuration-rum.html', - }, - } - ), - }, - { - title: i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.title', - { - defaultMessage: 'Set up the Agent as a dependency', - } - ), - textPre: i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.textPre', - { - defaultMessage: - 'You can install the Agent as a dependency to your application with \ -`npm install @elastic/apm-rum --save`.\n\n\ -The Agent can then be initialized and configured in your application like this:', - } - ), - commands: `import {curlyOpen} init as initApm {curlyClose} from '@elastic/apm-rum' -var apm = initApm({curlyOpen} - - // ${i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.commands.setRequiredServiceNameComment', - { - defaultMessage: - 'Set required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)', - } - )} - serviceName: 'your-app-name', - - // ${i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } - )} - serverUrl: '${apmServerUrl}', - - // ${i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.commands.setServiceVersionComment', - { - defaultMessage: - 'Set the service version (required for source map feature)', - } - )} - serviceVersion: '', - - // ${i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.commands.setServiceEnvironmentComment', - { - defaultMessage: 'Set the service environment', - } - )} - environment: 'production' -{curlyClose})`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.jsClient.installDependency.textPost', - { - defaultMessage: - 'Framework integrations, like React or Angular, have custom dependencies. \ -See the [integration documentation]({docLink}) for more information.', - values: { - docLink: - '{config.docs.base_url}guide/en/apm/agent/rum-js/current/framework-integrations.html', - }, - } - ), - }, - { - title: i18n.translate('xpack.apm.tutorial.jsClient.scriptTags.title', { - defaultMessage: 'Set up the Agent with Script Tags', - }), - textPre: i18n.translate('xpack.apm.tutorial.jsClient.scriptTags.textPre', { - defaultMessage: - "Alternatively, you can use Script tags to set up and configure the Agent. \ -Add a ` - -`.split('\n'), - }, -]; - -export const createGoAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.goClient.install.title', { - defaultMessage: 'Install the APM agent', - }), - textPre: i18n.translate('xpack.apm.tutorial.goClient.install.textPre', { - defaultMessage: 'Install the APM agent packages for Go.', - }), - commands: ['go get go.elastic.co/apm'], - }, - { - title: i18n.translate('xpack.apm.tutorial.goClient.configure.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate('xpack.apm.tutorial.goClient.configure.textPre', { - defaultMessage: - 'Agents are libraries that run inside of your application process. \ -APM services are created programmatically based on the executable \ -file name, or the `ELASTIC_APM_SERVICE_NAME` environment variable.', - }), - commands: `# ${i18n.translate( - 'xpack.apm.tutorial.goClient.configure.commands.initializeUsingEnvironmentVariablesComment', - { - defaultMessage: 'Initialize using environment variables:', - } - )} - -# ${i18n.translate( - 'xpack.apm.tutorial.goClient.configure.commands.setServiceNameComment', - { - defaultMessage: - 'Set the service name. Allowed characters: # a-z, A-Z, 0-9, -, _, and space.', - } - )} -# ${i18n.translate( - 'xpack.apm.tutorial.goClient.configure.commands.usedExecutableNameComment', - { - defaultMessage: - 'If ELASTIC_APM_SERVICE_NAME is not specified, the executable name will be used.', - } - )} -export ELASTIC_APM_SERVICE_NAME= - -# ${i18n.translate( - 'xpack.apm.tutorial.goClient.configure.commands.setCustomApmServerUrlComment', - { - defaultMessage: - 'Set custom APM Server URL (default: {defaultApmServerUrl})', - values: { defaultApmServerUrl: 'http://localhost:8200' }, - } - )} -export ELASTIC_APM_SERVER_URL=${apmServerUrl} - -# ${i18n.translate( - 'xpack.apm.tutorial.goClient.configure.commands.useIfApmRequiresTokenComment', - { - defaultMessage: 'Use if APM Server requires a secret token', - } - )} -export ELASTIC_APM_SECRET_TOKEN=${secretToken} - -# ${i18n.translate( - 'xpack.apm.tutorial.goClient.configure.commands.setServiceEnvironment', - { - defaultMessage: 'Set the service environment', - } - )} -export ELASTIC_APM_ENVIRONMENT= -`.split('\n'), - textPost: i18n.translate('xpack.apm.tutorial.goClient.configure.textPost', { - defaultMessage: - 'See the [documentation]({documentationLink}) for advanced configuration.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/go/current/configuration.html', - }, - }), - }, - { - title: i18n.translate('xpack.apm.tutorial.goClient.instrument.title', { - defaultMessage: 'Instrument your application', - }), - textPre: i18n.translate('xpack.apm.tutorial.goClient.instrument.textPre', { - defaultMessage: - 'Instrument your Go application by using one of the provided instrumentation modules or \ -by using the tracer API directly.', - }), - commands: `\ -import ( - "net/http" - - "go.elastic.co/apm/module/apmhttp" -) - -func main() {curlyOpen} - mux := http.NewServeMux() - ... - http.ListenAndServe(":8080", apmhttp.Wrap(mux)) -{curlyClose} -`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.goClient.instrument.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for a detailed \ -guide to instrumenting Go source code.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/go/current/instrumenting-source.html', - }, - } - ), - }, -]; - -export const createJavaAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.javaClient.download.title', { - defaultMessage: 'Download the APM agent', - }), - textPre: i18n.translate('xpack.apm.tutorial.javaClient.download.textPre', { - defaultMessage: - 'Download the agent jar from [Maven Central]({mavenCentralLink}). \ -Do **not** add the agent as a dependency to your application.', - values: { - mavenCentralLink: - 'http://search.maven.org/#search%7Cga%7C1%7Ca%3Aelastic-apm-agent', - }, - }), - }, - { - title: i18n.translate( - 'xpack.apm.tutorial.javaClient.startApplication.title', - { - defaultMessage: 'Start your application with the javaagent flag', - } - ), - textPre: i18n.translate( - 'xpack.apm.tutorial.javaClient.startApplication.textPre', - { - defaultMessage: - 'Add the `-javaagent` flag and configure the agent with system properties.\n\n \ -* Set the required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)\n \ -* Set the custom APM Server URL (default: {customApmServerUrl})\n \ -* Set the APM Server secret token\n \ -* Set the service environment\n \ -* Set the base package of your application', - values: { customApmServerUrl: 'http://localhost:8200' }, - } - ), - commands: `java -javaagent:/path/to/elastic-apm-agent-.jar \\ - -Delastic.apm.service_name=my-application \\ - -Delastic.apm.server_urls=${apmServerUrl || 'http://localhost:8200'} \\ - -Delastic.apm.secret_token=${secretToken} \\ - -Delastic.apm.environment=production \\ - -Delastic.apm.application_packages=org.example \\ - -jar my-application.jar`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.javaClient.startApplication.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for configuration options and advanced \ -usage.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/java/current/index.html', - }, - } - ), - }, -]; - -export const createDotNetAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.dotNetClient.download.title', { - defaultMessage: 'Download the APM agent', - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.download.textPre', - { - defaultMessage: - 'Add the the agent package(s) from [NuGet]({allNuGetPackagesLink}) to your .NET application. There are multiple \ - NuGet packages available for different use cases. \n\nFor an ASP.NET Core application with Entity Framework \ - Core download the [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}) package. This package will automatically add every \ - agent component to your application. \n\n In case you would like to minimize the dependencies, you can use the \ - [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) package for just \ - ASP.NET Core monitoring or the [Elastic.Apm.EfCore]({efCorePackageLink}) package for just Entity Framework Core monitoring. \n\n \ - In case you only want to use the public Agent API for manual instrumentation use the [Elastic.Apm]({elasticApmPackageLink}) package.', - values: { - allNuGetPackagesLink: 'https://www.nuget.org/packages?q=Elastic.apm', - netCoreAllApmPackageLink: - 'https://www.nuget.org/packages/Elastic.Apm.NetCoreAll', - aspNetCorePackageLink: - 'https://www.nuget.org/packages/Elastic.Apm.AspNetCore', - efCorePackageLink: - 'https://www.nuget.org/packages/Elastic.Apm.EntityFrameworkCore', - elasticApmPackageLink: 'https://www.nuget.org/packages/Elastic.Apm', - }, - } - ), - }, - { - title: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.configureApplication.title', - { - defaultMessage: 'Add the agent to the application', - } - ), - textPre: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.configureApplication.textPre', - { - defaultMessage: - 'In case of ASP.NET Core with the `Elastic.Apm.NetCoreAll` package, call the `UseAllElasticApm` \ - method in the `Configure` method within the `Startup.cs` file.', - } - ), - commands: `public class Startup -{curlyOpen} - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - {curlyOpen} - app.UseAllElasticApm(Configuration); - //…rest of the method - {curlyClose} - //…rest of the class -{curlyClose}`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.configureApplication.textPost', - { - defaultMessage: - 'Passing an `IConfiguration` instance is optional and by doing so, the agent will read config settings through this \ - `IConfiguration` instance (e.g. from the `appsettings.json` file).', - } - ), - }, - { - title: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.configureAgent.title', - { - defaultMessage: 'Sample appsettings.json file:', - } - ), - commands: `{curlyOpen} - "ElasticApm": {curlyOpen} - "SecretToken": "${secretToken}", - "ServerUrls": "${ - apmServerUrl || 'http://localhost:8200' - }", //Set custom APM Server URL (default: http://localhost:8200) - "ServiceName": "MyApp", //allowed characters: a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application - "Environment": "production", // Set the service environment - {curlyClose} -{curlyClose}`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.dotNetClient.configureAgent.textPost', - { - defaultMessage: - 'In case you don’t pass an `IConfiguration` instance to the agent (e.g. in case of non ASP.NET Core applications) \ - you can also configure the agent through environment variables. \n \ - See [the documentation]({documentationLink}) for advanced usage.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/dotnet/current/configuration.html', - }, - } - ), - }, -]; - -export const createPhpAgentInstructions = ( - apmServerUrl = '', - secretToken = '' -) => [ - { - title: i18n.translate('xpack.apm.tutorial.phpClient.download.title', { - defaultMessage: 'Download the APM agent', - }), - textPre: i18n.translate('xpack.apm.tutorial.phpClient.download.textPre', { - defaultMessage: - 'Download the package corresponding to your platform from [GitHub releases]({githubReleasesLink}).', - values: { - githubReleasesLink: 'https://github.com/elastic/apm-agent-php/releases', - }, - }), - }, - { - title: i18n.translate('xpack.apm.tutorial.phpClient.installPackage.title', { - defaultMessage: 'Install the downloaded package', - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.phpClient.installPackage.textPre', - { - defaultMessage: 'For example on Alpine Linux using APK package:', - } - ), - commands: ['apk add --allow-untrusted .apk'], - textPost: i18n.translate( - 'xpack.apm.tutorial.phpClient.installPackage.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for installation commands on other supported platforms and advanced installation.', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/php/current/setup.html', - }, - } - ), - }, - { - title: i18n.translate('xpack.apm.tutorial.phpClient.configureAgent.title', { - defaultMessage: 'Configure the agent', - }), - textPre: i18n.translate( - 'xpack.apm.tutorial.phpClient.configureAgent.textPre', - { - defaultMessage: - 'APM is automatically started when your app boots. Configure the agent either via `php.ini` file:', - } - ), - commands: `elastic_apm.server_url=http://localhost:8200 -elastic_apm.service_name="My service" -`.split('\n'), - textPost: i18n.translate( - 'xpack.apm.tutorial.phpClient.configure.textPost', - { - defaultMessage: - 'See the [documentation]({documentationLink}) for configuration options and advanced usage.\n\n', - values: { - documentationLink: - '{config.docs.base_url}guide/en/apm/agent/php/current/configuration.html', - }, - } - ), - }, -]; diff --git a/x-pack/plugins/canvas/public/functions/pie.test.js b/x-pack/plugins/canvas/public/functions/pie.test.js index b1c174634089287..915d8525079dbf8 100644 --- a/x-pack/plugins/canvas/public/functions/pie.test.js +++ b/x-pack/plugins/canvas/public/functions/pie.test.js @@ -18,7 +18,7 @@ describe('pie', () => { const fn = functionWrapper( pieFunctionFactory({ get: () => ({ - getCategoricalColors: () => ['red', 'black'], + getColors: () => ['red', 'black'], }), }) ); @@ -59,7 +59,7 @@ describe('pie', () => { const mockedFn = functionWrapper( pieFunctionFactory({ get: () => ({ - getCategoricalColors: mockedColors, + getColors: mockedColors, }), }) ); diff --git a/x-pack/plugins/canvas/public/functions/pie.ts b/x-pack/plugins/canvas/public/functions/pie.ts index a91dc16b770c9f8..0840667302ebefe 100644 --- a/x-pack/plugins/canvas/public/functions/pie.ts +++ b/x-pack/plugins/canvas/public/functions/pie.ts @@ -173,7 +173,7 @@ export function pieFunctionFactory( canvas: false, colors: paletteService .get(palette.name || 'custom') - .getCategoricalColors(data.length, palette.params), + .getColors(data.length, palette.params), legend: getLegendConfig(legend, data.length), grid: { show: false, diff --git a/x-pack/plugins/canvas/public/functions/plot.test.js b/x-pack/plugins/canvas/public/functions/plot.test.js index 5ed858961d7980a..849752d2c984ba0 100644 --- a/x-pack/plugins/canvas/public/functions/plot.test.js +++ b/x-pack/plugins/canvas/public/functions/plot.test.js @@ -21,7 +21,7 @@ describe('plot', () => { const fn = functionWrapper( plotFunctionFactory({ get: () => ({ - getCategoricalColors: () => ['red', 'black'], + getColors: () => ['red', 'black'], }), }) ); @@ -121,7 +121,7 @@ describe('plot', () => { const mockedFn = functionWrapper( plotFunctionFactory({ get: () => ({ - getCategoricalColors: mockedColors, + getColors: mockedColors, }), }) ); diff --git a/x-pack/plugins/canvas/public/functions/plot/index.ts b/x-pack/plugins/canvas/public/functions/plot/index.ts index 477c7041901461a..c0c73c3a21bc6c1 100644 --- a/x-pack/plugins/canvas/public/functions/plot/index.ts +++ b/x-pack/plugins/canvas/public/functions/plot/index.ts @@ -144,7 +144,7 @@ export function plotFunctionFactory( canvas: false, colors: paletteService .get(args.palette.name || 'custom') - .getCategoricalColors(data.length, args.palette.params), + .getColors(data.length, args.palette.params), legend: getLegendConfig(args.legend, data.length), grid: gridConfig, xaxis: getFlotAxisConfig('x', args.xaxis, { diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts index 66f2bf78e0c9c3b..de13077cd1b0999 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts @@ -12,16 +12,9 @@ import fetch from 'node-fetch'; const { Response } = jest.requireActual('node-fetch'); -jest.mock('@kbn/utils', () => ({ - kibanaPackageJson: { version: '1.0.0' }, -})); - import { loggingSystemMock } from 'src/core/server/mocks'; -import { - callEnterpriseSearchConfigAPI, - warnMismatchedVersions, -} from './enterprise_search_config_api'; +import { callEnterpriseSearchConfigAPI } from './enterprise_search_config_api'; describe('callEnterpriseSearchConfigAPI', () => { const mockConfig = { @@ -225,22 +218,4 @@ describe('callEnterpriseSearchConfigAPI', () => { "Exceeded 200ms timeout while checking http://localhost:3002. Please consider increasing your enterpriseSearch.accessCheckTimeout value so that users aren't prevented from accessing Enterprise Search plugins due to slow responses." ); }); - - describe('warnMismatchedVersions', () => { - it("logs a warning when Enterprise Search and Kibana's versions are not the same", () => { - warnMismatchedVersions('1.1.0', mockDependencies.log); - - expect(mockDependencies.log.warn).toHaveBeenCalledWith( - expect.stringContaining( - 'Your Kibana instance (v1.0.0) is not the same version as your Enterprise Search instance (v1.1.0)' - ) - ); - }); - - it("does not log a warning when Enterprise Search and Kibana's versions are the same", () => { - warnMismatchedVersions('1.0.0', mockDependencies.log); - - expect(mockDependencies.log.warn).not.toHaveBeenCalled(); - }); - }); }); diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts index 0f2faf1fd8a3abb..ebe718dfebd3090 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts @@ -8,8 +8,6 @@ import AbortController from 'abort-controller'; import fetch from 'node-fetch'; -import { kibanaPackageJson } from '@kbn/utils'; - import { KibanaRequest, Logger } from 'src/core/server'; import { stripTrailingSlash } from '../../common/strip_slashes'; @@ -60,8 +58,6 @@ export const callEnterpriseSearchConfigAPI = async ({ }); const data = await response.json(); - warnMismatchedVersions(data?.version?.number, log); - return { access: { hasAppSearchAccess: !!data?.current_user?.access?.app_search, @@ -139,13 +135,3 @@ export const callEnterpriseSearchConfigAPI = async ({ clearTimeout(timeout); } }; - -export const warnMismatchedVersions = (enterpriseSearchVersion: string, log: Logger) => { - const kibanaVersion = kibanaPackageJson.version; - - if (enterpriseSearchVersion !== kibanaVersion) { - log.warn( - `Your Kibana instance (v${kibanaVersion}) is not the same version as your Enterprise Search instance (v${enterpriseSearchVersion}), which may cause unexpected behavior. Use matching versions for the best experience.` - ); - } -}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.test.tsx deleted file mode 100644 index 27bf5af72fb61d4..000000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.test.tsx +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { fireEvent, act } from '@testing-library/react'; - -import { createTestRendererMock } from '../../mock'; - -import { HostsInput } from './hosts_input'; - -function renderInput(value = ['http://host1.com']) { - const renderer = createTestRendererMock(); - const mockOnChange = jest.fn(); - - const utils = renderer.render( - - ); - - return { utils, mockOnChange }; -} - -test('it should allow to add a new host', async () => { - const { utils, mockOnChange } = renderInput(); - - const addRowEl = await utils.findByText('Add row'); - fireEvent.click(addRowEl); - expect(mockOnChange).toHaveBeenCalledWith(['http://host1.com', '']); -}); - -test('it should allow to remove an host', async () => { - const { utils, mockOnChange } = renderInput(['http://host1.com', 'http://host2.com']); - - await act(async () => { - const deleteRowEl = await utils.container.querySelector('[aria-label="Delete host"]'); - if (!deleteRowEl) { - throw new Error('Delete host button not found'); - } - fireEvent.click(deleteRowEl); - }); - - expect(mockOnChange).toHaveBeenCalledWith(['http://host2.com']); -}); - -test('it should allow to update existing host with single host', async () => { - const { utils, mockOnChange } = renderInput(['http://host1.com']); - - const inputEl = await utils.findByDisplayValue('http://host1.com'); - fireEvent.change(inputEl, { target: { value: 'http://newhost.com' } }); - expect(mockOnChange).toHaveBeenCalledWith(['http://newhost.com']); -}); - -test('it should allow to update existing host with multiple hosts', async () => { - const { utils, mockOnChange } = renderInput(['http://host1.com', 'http://host2.com']); - - const inputEl = await utils.findByDisplayValue('http://host1.com'); - fireEvent.change(inputEl, { target: { value: 'http://newhost.com' } }); - expect(mockOnChange).toHaveBeenCalledWith(['http://newhost.com', 'http://host2.com']); -}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.tsx deleted file mode 100644 index 0e5f9a5e028b5e4..000000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.tsx +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React, { useMemo, useCallback, useState } from 'react'; -import type { ReactNode, FunctionComponent, ChangeEvent } from 'react'; -import sytled, { useTheme } from 'styled-components'; - -import { - EuiFlexGroup, - EuiFlexItem, - EuiButtonEmpty, - EuiFormRow, - EuiFieldText, - EuiDragDropContext, - EuiDroppable, - EuiDraggable, - EuiIcon, - EuiButtonIcon, - EuiSpacer, - EuiFormHelpText, - euiDragDropReorder, - EuiFormErrorText, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; - -import type { EuiTheme } from '../../../../../../../../src/plugins/kibana_react/common'; - -interface Props { - id: string; - value: string[]; - onChange: (newValue: string[]) => void; - label: string; - helpText: ReactNode; - errors?: Array<{ message: string; index?: number }>; - isInvalid?: boolean; -} - -interface SortableTextFieldProps { - id: string; - index: number; - value: string; - onChange: (e: ChangeEvent) => void; - onDelete: (index: number) => void; - errors?: string[]; - autoFocus?: boolean; -} - -const DraggableDiv = sytled.div` - margin: ${(props) => props.theme.eui.euiSizeS}; -`; - -function displayErrors(errors?: string[]) { - return errors?.length - ? errors.map((error, errorIndex) => ( - {error} - )) - : null; -} - -const SortableTextField: FunctionComponent = React.memo( - ({ id, index, value, onChange, onDelete, autoFocus, errors }) => { - const onDeleteHandler = useCallback(() => { - onDelete(index); - }, [onDelete, index]); - - const isInvalid = (errors?.length ?? 0) > 0; - const theme = useTheme() as EuiTheme; - - return ( - - {(provided, state) => ( - - - - - - - - - {displayErrors(errors)} - - - - - - )} - - ); - } -); - -export const HostsInput: FunctionComponent = ({ - id, - value, - onChange, - helpText, - label, - isInvalid, - errors, -}) => { - const [autoFocus, setAutoFocus] = useState(false); - const rows = useMemo( - () => - value.map((host, idx) => ({ - value: host, - onChange: (e: ChangeEvent) => { - const newValue = [...value]; - newValue[idx] = e.target.value; - - onChange(newValue); - }, - })), - [value, onChange] - ); - - const onDelete = useCallback( - (idx: number) => { - onChange([...value.slice(0, idx), ...value.slice(idx + 1)]); - }, - [value, onChange] - ); - - const addRowHandler = useCallback(() => { - setAutoFocus(true); - onChange([...value, '']); - }, [value, onChange]); - - const onDragEndHandler = useCallback( - ({ source, destination }) => { - if (source && destination) { - const items = euiDragDropReorder(value, source.index, destination.index); - - onChange(items); - } - }, - [value, onChange] - ); - - const globalErrors = useMemo(() => { - return errors && errors.filter((err) => err.index === undefined).map(({ message }) => message); - }, [errors]); - - const indexedErrors = useMemo(() => { - if (!errors) { - return []; - } - return errors.reduce((acc, err) => { - if (err.index === undefined) { - return acc; - } - - if (!acc[err.index]) { - acc[err.index] = []; - } - - acc[err.index].push(err.message); - - return acc; - }, [] as string[][]); - }, [errors]); - - const isSortable = rows.length > 1; - return ( - - <> - {helpText} - - - - {rows.map((row, idx) => ( - - {isSortable ? ( - - ) : ( - <> - - {displayErrors(indexedErrors[idx])} - - )} - - ))} - - - {displayErrors(globalErrors)} - - - - - - - ); -}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx index ea2e795d5fabbbe..b8028547910097a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx @@ -20,10 +20,10 @@ import { EuiFlyoutFooter, EuiForm, EuiFormRow, + EuiComboBox, EuiCode, EuiCodeEditor, EuiLink, - EuiPanel, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiText } from '@elastic/eui'; @@ -41,7 +41,6 @@ import { isDiffPathProtocol } from '../../../../../common/'; import { SettingsConfirmModal } from './confirm_modal'; import type { SettingsConfirmModalProps } from './confirm_modal'; -import { HostsInput } from './hosts_input'; import 'brace/mode/yaml'; import 'brace/theme/textmate'; @@ -60,60 +59,37 @@ function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { const [isLoading, setIsloading] = React.useState(false); const { notifications } = useStartServices(); - const fleetServerHostsInput = useComboInput('fleetServerHostsComboBox', [], (value) => { + const fleetServerHostsInput = useComboInput([], (value) => { if (value.length === 0) { return [ - { - message: i18n.translate('xpack.fleet.settings.fleetServerHostsEmptyError', { - defaultMessage: 'At least one URL is required', - }), - }, + i18n.translate('xpack.fleet.settings.fleetServerHostsEmptyError', { + defaultMessage: 'At least one URL is required', + }), ]; } - - const res: Array<{ message: string; index: number }> = []; - value.forEach((val, idx) => { - if (!val.match(URL_REGEX)) { - res.push({ - message: i18n.translate('xpack.fleet.settings.fleetServerHostsError', { - defaultMessage: 'Invalid URL', - }), - index: idx, - }); - } - }); - if (res.length) { - return res; + if (value.some((v) => !v.match(URL_REGEX))) { + return [ + i18n.translate('xpack.fleet.settings.fleetServerHostsError', { + defaultMessage: 'Invalid URL', + }), + ]; } - if (value.length && isDiffPathProtocol(value)) { return [ - { - message: i18n.translate( - 'xpack.fleet.settings.fleetServerHostsDifferentPathOrProtocolError', - { - defaultMessage: 'Protocol and path must be the same for each URL', - } - ), - }, + i18n.translate('xpack.fleet.settings.fleetServerHostsDifferentPathOrProtocolError', { + defaultMessage: 'Protocol and path must be the same for each URL', + }), ]; } }); - const elasticsearchUrlInput = useComboInput('esHostsComboxBox', [], (value) => { - const res: Array<{ message: string; index: number }> = []; - value.forEach((val, idx) => { - if (!val.match(URL_REGEX)) { - res.push({ - message: i18n.translate('xpack.fleet.settings.elasticHostError', { - defaultMessage: 'Invalid URL', - }), - index: idx, - }); - } - }); - if (res.length) { - return res; + const elasticsearchUrlInput = useComboInput([], (value) => { + if (value.some((v) => !v.match(URL_REGEX))) { + return [ + i18n.translate('xpack.fleet.settings.elasticHostError', { + defaultMessage: 'Invalid URL', + }), + ]; } }); @@ -288,72 +264,91 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => { /> - - - - - ), - }} - /> - } - /> - - - - - + + + + + ), + }} + /> + } + {...inputs.fleetServerHosts.formRowProps} + > + + + - - - + + + ), }} - {...inputs.additionalYamlConfig.props} - onChange={inputs.additionalYamlConfig.setValue} /> - - + } + {...inputs.elasticsearchUrl.formRowProps} + > + + + + + + ); diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_input.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_input.ts index e4a517dbae9c8fd..6314fbeb0c72ebd 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_input.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_input.ts @@ -5,12 +5,11 @@ * 2.0. */ -import { useState, useCallback } from 'react'; -import type React from 'react'; +import React from 'react'; export function useInput(defaultValue = '', validate?: (value: string) => string[] | undefined) { - const [value, setValue] = useState(defaultValue); - const [errors, setErrors] = useState(); + const [value, setValue] = React.useState(defaultValue); + const [errors, setErrors] = React.useState(); const onChange = (e: React.ChangeEvent) => { const newValue = e.target.value; @@ -51,31 +50,31 @@ export function useInput(defaultValue = '', validate?: (value: string) => string } export function useComboInput( - id: string, defaultValue = [], - validate?: (value: string[]) => Array<{ message: string; index?: number }> | undefined + validate?: (value: string[]) => string[] | undefined ) { - const [value, setValue] = useState(defaultValue); - const [errors, setErrors] = useState | undefined>(); + const [value, setValue] = React.useState(defaultValue); + const [errors, setErrors] = React.useState(); const isInvalid = errors !== undefined; - const onChange = useCallback( - (newValues: string[]) => { - setValue(newValues); - if (errors && validate && validate(newValues) === undefined) { - setErrors(undefined); - } - }, - [validate, errors] - ); - return { props: { - id, - value, - onChange, - errors, + selectedOptions: value.map((val: string) => ({ label: val })), + onCreateOption: (newVal: any) => { + setValue([...value, newVal]); + }, + onChange: (newSelectedOptions: any[]) => { + const newValues = newSelectedOptions.map((option) => option.label); + setValue(newValues); + if (errors && validate && validate(newValues) === undefined) { + setErrors(undefined); + } + }, + isInvalid, + }, + formRowProps: { + error: errors, isInvalid, }, value, diff --git a/x-pack/plugins/index_management/kibana.json b/x-pack/plugins/index_management/kibana.json index cd29e7b9ee1cdcd..5dcff0ba942e124 100644 --- a/x-pack/plugins/index_management/kibana.json +++ b/x-pack/plugins/index_management/kibana.json @@ -3,7 +3,7 @@ "version": "kibana", "server": true, "ui": true, - "requiredPlugins": ["home", "management", "features", "share"], + "requiredPlugins": ["home", "licensing", "management", "features", "share"], "optionalPlugins": ["security", "usageCollection", "fleet"], "configPath": ["xpack", "index_management"], "requiredBundles": [ diff --git a/x-pack/plugins/index_management/server/plugin.ts b/x-pack/plugins/index_management/server/plugin.ts index 35d25eb452b84da..d2ef5a7eed6e7a9 100644 --- a/x-pack/plugins/index_management/server/plugin.ts +++ b/x-pack/plugins/index_management/server/plugin.ts @@ -5,9 +5,11 @@ * 2.0. */ +import { i18n } from '@kbn/i18n'; import { CoreSetup, Plugin, + Logger, PluginInitializerContext, ILegacyCustomClusterClient, } from 'src/core/server'; @@ -15,7 +17,7 @@ import { import { PLUGIN } from '../common/constants/plugin'; import { Dependencies } from './types'; import { ApiRoutes } from './routes'; -import { IndexDataEnricher } from './services'; +import { License, IndexDataEnricher } from './services'; import { isEsError, handleEsError, parseEsError } from './shared_imports'; import { elasticsearchJsPlugin } from './client/elasticsearch'; import type { IndexManagementRequestHandlerContext } from './types'; @@ -34,20 +36,38 @@ async function getCustomEsClient(getStartServices: CoreSetup['getStartServices'] export class IndexMgmtServerPlugin implements Plugin { private readonly apiRoutes: ApiRoutes; + private readonly license: License; + private readonly logger: Logger; private readonly indexDataEnricher: IndexDataEnricher; private dataManagementESClient?: ILegacyCustomClusterClient; constructor(initContext: PluginInitializerContext) { + this.logger = initContext.logger.get(); this.apiRoutes = new ApiRoutes(); + this.license = new License(); this.indexDataEnricher = new IndexDataEnricher(); } setup( { http, getStartServices }: CoreSetup, - { features, security }: Dependencies + { features, licensing, security }: Dependencies ): IndexManagementPluginSetup { const router = http.createRouter(); + this.license.setup( + { + pluginId: PLUGIN.id, + minimumLicenseType: PLUGIN.minimumLicenseType, + defaultErrorMessage: i18n.translate('xpack.idxMgmt.licenseCheckErrorMessage', { + defaultMessage: 'License check failed', + }), + }, + { + licensing, + logger: this.logger, + } + ); + features.registerElasticsearchFeature({ id: PLUGIN.id, management: { @@ -77,6 +97,7 @@ export class IndexMgmtServerPlugin implements Plugin security !== undefined && security.license.isEnabled(), }, diff --git a/x-pack/plugins/index_management/server/routes/api/component_templates/create.ts b/x-pack/plugins/index_management/server/routes/api/component_templates/create.ts index 4bf05b44c43a701..a6c0592e035e79c 100644 --- a/x-pack/plugins/index_management/server/routes/api/component_templates/create.ts +++ b/x-pack/plugins/index_management/server/routes/api/component_templates/create.ts @@ -12,7 +12,11 @@ import { RouteDependencies } from '../../../types'; import { addBasePath } from '../index'; import { componentTemplateSchema } from './schema_validation'; -export const registerCreateRoute = ({ router, lib: { isEsError } }: RouteDependencies): void => { +export const registerCreateRoute = ({ + router, + license, + lib: { isEsError }, +}: RouteDependencies): void => { router.post( { path: addBasePath('/component_templates'), @@ -20,7 +24,7 @@ export const registerCreateRoute = ({ router, lib: { isEsError } }: RouteDepende body: componentTemplateSchema, }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { callAsCurrentUser } = ctx.dataManagement!.client; const serializedComponentTemplate = serializeComponentTemplate(req.body); @@ -69,6 +73,6 @@ export const registerCreateRoute = ({ router, lib: { isEsError } }: RouteDepende throw error; } - } + }) ); }; diff --git a/x-pack/plugins/index_management/server/routes/api/component_templates/delete.ts b/x-pack/plugins/index_management/server/routes/api/component_templates/delete.ts index d30f54f6e44adf0..abf04da638cafcb 100644 --- a/x-pack/plugins/index_management/server/routes/api/component_templates/delete.ts +++ b/x-pack/plugins/index_management/server/routes/api/component_templates/delete.ts @@ -14,7 +14,7 @@ const paramsSchema = schema.object({ names: schema.string(), }); -export const registerDeleteRoute = ({ router }: RouteDependencies): void => { +export const registerDeleteRoute = ({ router, license }: RouteDependencies): void => { router.delete( { path: addBasePath('/component_templates/{names}'), @@ -22,7 +22,7 @@ export const registerDeleteRoute = ({ router }: RouteDependencies): void => { params: paramsSchema, }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { callAsCurrentUser } = ctx.dataManagement!.client; const { names } = req.params; const componentNames = names.split(','); @@ -48,6 +48,6 @@ export const registerDeleteRoute = ({ router }: RouteDependencies): void => { ); return res.ok({ body: response }); - } + }) ); }; diff --git a/x-pack/plugins/index_management/server/routes/api/component_templates/get.ts b/x-pack/plugins/index_management/server/routes/api/component_templates/get.ts index a5d70e65f870a99..552aa5a9a2888c6 100644 --- a/x-pack/plugins/index_management/server/routes/api/component_templates/get.ts +++ b/x-pack/plugins/index_management/server/routes/api/component_templates/get.ts @@ -19,11 +19,11 @@ const paramsSchema = schema.object({ name: schema.string(), }); -export function registerGetAllRoute({ router, lib: { isEsError } }: RouteDependencies) { +export function registerGetAllRoute({ router, license, lib: { isEsError } }: RouteDependencies) { // Get all component templates router.get( { path: addBasePath('/component_templates'), validate: false }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { callAsCurrentUser } = ctx.dataManagement!.client; try { @@ -56,7 +56,7 @@ export function registerGetAllRoute({ router, lib: { isEsError } }: RouteDepende throw error; } - } + }) ); // Get single component template @@ -67,7 +67,7 @@ export function registerGetAllRoute({ router, lib: { isEsError } }: RouteDepende params: paramsSchema, }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { callAsCurrentUser } = ctx.dataManagement!.client; const { name } = req.params; @@ -96,6 +96,6 @@ export function registerGetAllRoute({ router, lib: { isEsError } }: RouteDepende throw error; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/component_templates/privileges.test.ts b/x-pack/plugins/index_management/server/routes/api/component_templates/privileges.test.ts index eccf2d945785f2d..62fb228a34cedfb 100644 --- a/x-pack/plugins/index_management/server/routes/api/component_templates/privileges.test.ts +++ b/x-pack/plugins/index_management/server/routes/api/component_templates/privileges.test.ts @@ -8,6 +8,7 @@ import { httpServerMock, httpServiceMock } from 'src/core/server/mocks'; import { kibanaResponseFactory, RequestHandlerContext, RequestHandler } from 'src/core/server'; +import { License } from '../../../services/license'; import { IndexDataEnricher } from '../../../services/index_data_enricher'; import { registerPrivilegesRoute } from './privileges'; @@ -46,6 +47,9 @@ describe('GET privileges', () => { registerPrivilegesRoute({ router, + license: { + guardApiRoute: (route: any) => route, + } as License, config: { isSecurityEnabled: () => true, }, @@ -114,6 +118,9 @@ describe('GET privileges', () => { registerPrivilegesRoute({ router, + license: { + guardApiRoute: (route: any) => route, + } as License, config: { isSecurityEnabled: () => false, }, diff --git a/x-pack/plugins/index_management/server/routes/api/component_templates/privileges.ts b/x-pack/plugins/index_management/server/routes/api/component_templates/privileges.ts index 62ad93453091ec8..1ed6555eb380676 100644 --- a/x-pack/plugins/index_management/server/routes/api/component_templates/privileges.ts +++ b/x-pack/plugins/index_management/server/routes/api/component_templates/privileges.ts @@ -17,13 +17,13 @@ const extractMissingPrivileges = (privilegesObject: { [key: string]: boolean } = return privileges; }, []); -export const registerPrivilegesRoute = ({ router, config }: RouteDependencies) => { +export const registerPrivilegesRoute = ({ license, router, config }: RouteDependencies) => { router.get( { path: addBasePath('/component_templates/privileges'), validate: false, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const privilegesResult: Privileges = { hasAllPrivileges: true, missingPrivileges: { @@ -66,6 +66,6 @@ export const registerPrivilegesRoute = ({ router, config }: RouteDependencies) = } catch (e) { throw e; } - } + }) ); }; diff --git a/x-pack/plugins/index_management/server/routes/api/component_templates/update.ts b/x-pack/plugins/index_management/server/routes/api/component_templates/update.ts index ee94b8f2b0082d8..42b53ab6ee25b32 100644 --- a/x-pack/plugins/index_management/server/routes/api/component_templates/update.ts +++ b/x-pack/plugins/index_management/server/routes/api/component_templates/update.ts @@ -15,7 +15,11 @@ const paramsSchema = schema.object({ name: schema.string(), }); -export const registerUpdateRoute = ({ router, lib: { isEsError } }: RouteDependencies): void => { +export const registerUpdateRoute = ({ + router, + license, + lib: { isEsError }, +}: RouteDependencies): void => { router.put( { path: addBasePath('/component_templates/{name}'), @@ -24,7 +28,7 @@ export const registerUpdateRoute = ({ router, lib: { isEsError } }: RouteDepende params: paramsSchema, }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { callAsCurrentUser } = ctx.dataManagement!.client; const { name } = req.params; const { template, version, _meta } = req.body; @@ -53,6 +57,6 @@ export const registerUpdateRoute = ({ router, lib: { isEsError } }: RouteDepende throw error; } - } + }) ); }; diff --git a/x-pack/plugins/index_management/server/routes/api/data_streams/register_delete_route.ts b/x-pack/plugins/index_management/server/routes/api/data_streams/register_delete_route.ts index 49166f4823a026c..476228cfce2fcf9 100644 --- a/x-pack/plugins/index_management/server/routes/api/data_streams/register_delete_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/data_streams/register_delete_route.ts @@ -15,13 +15,13 @@ const bodySchema = schema.object({ dataStreams: schema.arrayOf(schema.string()), }); -export function registerDeleteRoute({ router }: RouteDependencies) { +export function registerDeleteRoute({ router, license }: RouteDependencies) { router.post( { path: addBasePath('/delete_data_streams'), validate: { body: bodySchema }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { callAsCurrentUser } = ctx.dataManagement!.client; const { dataStreams } = req.body as TypeOf; @@ -48,6 +48,6 @@ export function registerDeleteRoute({ router }: RouteDependencies) { ); return res.ok({ body: response }); - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/data_streams/register_get_route.ts b/x-pack/plugins/index_management/server/routes/api/data_streams/register_get_route.ts index 1ce7c14f0a20936..9573b9cc6436f24 100644 --- a/x-pack/plugins/index_management/server/routes/api/data_streams/register_get_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/data_streams/register_get_route.ts @@ -103,13 +103,18 @@ const getDataStreamsPrivileges = (client: ElasticsearchClient, names: string[]) }); }; -export function registerGetAllRoute({ router, lib: { handleEsError }, config }: RouteDependencies) { +export function registerGetAllRoute({ + router, + license, + lib: { handleEsError }, + config, +}: RouteDependencies) { const querySchema = schema.object({ includeStats: schema.maybe(schema.oneOf([schema.literal('true'), schema.literal('false')])), }); router.get( { path: addBasePath('/data_streams'), validate: { query: querySchema } }, - async (ctx, req, response) => { + license.guardApiRoute(async (ctx, req, response) => { const { asCurrentUser } = ctx.core.elasticsearch.client; const includeStats = (req.query as TypeOf).includeStats === 'true'; @@ -146,11 +151,16 @@ export function registerGetAllRoute({ router, lib: { handleEsError }, config }: } catch (error) { return handleEsError({ error, response }); } - } + }) ); } -export function registerGetOneRoute({ router, lib: { handleEsError }, config }: RouteDependencies) { +export function registerGetOneRoute({ + router, + license, + lib: { handleEsError }, + config, +}: RouteDependencies) { const paramsSchema = schema.object({ name: schema.string(), }); @@ -159,7 +169,7 @@ export function registerGetOneRoute({ router, lib: { handleEsError }, config }: path: addBasePath('/data_streams/{name}'), validate: { params: paramsSchema }, }, - async (ctx, req, response) => { + license.guardApiRoute(async (ctx, req, response) => { const { name } = req.params as TypeOf; const { asCurrentUser } = ctx.core.elasticsearch.client; try { @@ -197,6 +207,6 @@ export function registerGetOneRoute({ router, lib: { handleEsError }, config }: } catch (error) { return handleEsError({ error, response }); } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts index 593f0cda6886e31..2f5da4b1d8957a1 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts @@ -14,10 +14,10 @@ const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), }); -export function registerClearCacheRoute({ router, lib }: RouteDependencies) { +export function registerClearCacheRoute({ router, license, lib }: RouteDependencies) { router.post( { path: addBasePath('/indices/clear_cache'), validate: { body: bodySchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const payload = req.body as typeof bodySchema.type; const { indices = [] } = payload; @@ -40,6 +40,6 @@ export function registerClearCacheRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_close_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_close_route.ts index 777adcd05570955..1a0babfc3a5b1fa 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_close_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_close_route.ts @@ -14,10 +14,10 @@ const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), }); -export function registerCloseRoute({ router, lib }: RouteDependencies) { +export function registerCloseRoute({ router, license, lib }: RouteDependencies) { router.post( { path: addBasePath('/indices/close'), validate: { body: bodySchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const payload = req.body as typeof bodySchema.type; const { indices = [] } = payload; @@ -40,6 +40,6 @@ export function registerCloseRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_delete_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_delete_route.ts index 914835089a43819..9a022d4595d1c0b 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_delete_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_delete_route.ts @@ -14,10 +14,10 @@ const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), }); -export function registerDeleteRoute({ router, lib }: RouteDependencies) { +export function registerDeleteRoute({ router, license, lib }: RouteDependencies) { router.post( { path: addBasePath('/indices/delete'), validate: { body: bodySchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const body = req.body as typeof bodySchema.type; const { indices = [] } = body; @@ -40,6 +40,6 @@ export function registerDeleteRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.ts index bb1759a034cc7e4..b064f3520004a0f 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.ts @@ -14,10 +14,10 @@ const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), }); -export function registerFlushRoute({ router, lib }: RouteDependencies) { +export function registerFlushRoute({ router, license, lib }: RouteDependencies) { router.post( { path: addBasePath('/indices/flush'), validate: { body: bodySchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const body = req.body as typeof bodySchema.type; const { indices = [] } = body; @@ -40,6 +40,6 @@ export function registerFlushRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts index 6f0e8f0fec5673a..1c14f660b98c679 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts @@ -15,7 +15,7 @@ const bodySchema = schema.object({ maxNumSegments: schema.maybe(schema.number()), }); -export function registerForcemergeRoute({ router, lib }: RouteDependencies) { +export function registerForcemergeRoute({ router, license, lib }: RouteDependencies) { router.post( { path: addBasePath('/indices/forcemerge'), @@ -23,7 +23,7 @@ export function registerForcemergeRoute({ router, lib }: RouteDependencies) { body: bodySchema, }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { maxNumSegments, indices = [] } = req.body as typeof bodySchema.type; const params = { expandWildcards: 'none', @@ -47,6 +47,6 @@ export function registerForcemergeRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_freeze_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_freeze_route.ts index 4b1281e0f21219e..b669d78f2ba5972 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_freeze_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_freeze_route.ts @@ -14,10 +14,10 @@ const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), }); -export function registerFreezeRoute({ router, lib }: RouteDependencies) { +export function registerFreezeRoute({ router, license, lib }: RouteDependencies) { router.post( { path: addBasePath('/indices/freeze'), validate: { body: bodySchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const body = req.body as typeof bodySchema.type; const { indices = [] } = body; @@ -42,6 +42,6 @@ export function registerFreezeRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.ts index 47c454e96c8e2ae..0b253b9fe66c97c 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.ts @@ -9,23 +9,26 @@ import { fetchIndices } from '../../../lib/fetch_indices'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '../index'; -export function registerListRoute({ router, indexDataEnricher, lib }: RouteDependencies) { - router.get({ path: addBasePath('/indices'), validate: false }, async (ctx, req, res) => { - try { - const indices = await fetchIndices( - ctx.core.elasticsearch.legacy.client.callAsCurrentUser, - indexDataEnricher - ); - return res.ok({ body: indices }); - } catch (e) { - if (lib.isEsError(e)) { - return res.customError({ - statusCode: e.statusCode, - body: e, - }); +export function registerListRoute({ router, license, indexDataEnricher, lib }: RouteDependencies) { + router.get( + { path: addBasePath('/indices'), validate: false }, + license.guardApiRoute(async (ctx, req, res) => { + try { + const indices = await fetchIndices( + ctx.core.elasticsearch.legacy.client.callAsCurrentUser, + indexDataEnricher + ); + return res.ok({ body: indices }); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + throw e; } - // Case: default - throw e; - } - }); + }) + ); } diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_open_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_open_route.ts index cad57ce60de654f..a35ddfcf4d91b2a 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_open_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_open_route.ts @@ -14,10 +14,10 @@ const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), }); -export function registerOpenRoute({ router, lib }: RouteDependencies) { +export function registerOpenRoute({ router, license, lib }: RouteDependencies) { router.post( { path: addBasePath('/indices/open'), validate: { body: bodySchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const body = req.body as typeof bodySchema.type; const { indices = [] } = body; @@ -40,6 +40,6 @@ export function registerOpenRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.ts index e2c0155e2808650..f69d2d90a5b8fc6 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.ts @@ -14,10 +14,10 @@ const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), }); -export function registerRefreshRoute({ router, lib }: RouteDependencies) { +export function registerRefreshRoute({ router, license, lib }: RouteDependencies) { router.post( { path: addBasePath('/indices/refresh'), validate: { body: bodySchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const body = req.body as typeof bodySchema.type; const { indices = [] } = body; @@ -40,6 +40,6 @@ export function registerRefreshRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_reload_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_reload_route.ts index 8d83cd21f427dd3..04b7d760fc1d623 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_reload_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_reload_route.ts @@ -17,10 +17,15 @@ const bodySchema = schema.maybe( }) ); -export function registerReloadRoute({ router, indexDataEnricher, lib }: RouteDependencies) { +export function registerReloadRoute({ + router, + license, + indexDataEnricher, + lib, +}: RouteDependencies) { router.post( { path: addBasePath('/indices/reload'), validate: { body: bodySchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { indexNames = [] } = (req.body as typeof bodySchema.type) ?? {}; try { @@ -40,6 +45,6 @@ export function registerReloadRoute({ router, indexDataEnricher, lib }: RouteDep // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_unfreeze_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_unfreeze_route.ts index 45102f4874129ad..3cda4d6b5f1682f 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_unfreeze_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_unfreeze_route.ts @@ -14,10 +14,10 @@ const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), }); -export function registerUnfreezeRoute({ router, lib }: RouteDependencies) { +export function registerUnfreezeRoute({ router, license, lib }: RouteDependencies) { router.post( { path: addBasePath('/indices/unfreeze'), validate: { body: bodySchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { indices = [] } = req.body as typeof bodySchema.type; const params = { path: `/${encodeURIComponent(indices.join(','))}/_unfreeze`, @@ -37,6 +37,6 @@ export function registerUnfreezeRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/mapping/register_mapping_route.ts b/x-pack/plugins/index_management/server/routes/api/mapping/register_mapping_route.ts index 406ceba16c8bdae..f0b62bacdee426c 100644 --- a/x-pack/plugins/index_management/server/routes/api/mapping/register_mapping_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/mapping/register_mapping_route.ts @@ -21,10 +21,10 @@ function formatHit(hit: { [key: string]: { mappings: any } }, indexName: string) }; } -export function registerMappingRoute({ router, lib }: RouteDependencies) { +export function registerMappingRoute({ router, license, lib }: RouteDependencies) { router.get( { path: addBasePath('/mapping/{indexName}'), validate: { params: paramsSchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { indexName } = req.params as typeof paramsSchema.type; const params = { expand_wildcards: 'none', @@ -48,6 +48,6 @@ export function registerMappingRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/settings/register_load_route.ts b/x-pack/plugins/index_management/server/routes/api/settings/register_load_route.ts index 276b326929e8f92..7a661a9e9e4f494 100644 --- a/x-pack/plugins/index_management/server/routes/api/settings/register_load_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/settings/register_load_route.ts @@ -21,10 +21,10 @@ function formatHit(hit: { [key: string]: {} }) { return hit[key]; } -export function registerLoadRoute({ router, lib }: RouteDependencies) { +export function registerLoadRoute({ router, license, lib }: RouteDependencies) { router.get( { path: addBasePath('/settings/{indexName}'), validate: { params: paramsSchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { indexName } = req.params as typeof paramsSchema.type; const params = { expandWildcards: 'none', @@ -50,6 +50,6 @@ export function registerLoadRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/settings/register_update_route.ts b/x-pack/plugins/index_management/server/routes/api/settings/register_update_route.ts index b4f12b91083df9e..4c153d6293a79f2 100644 --- a/x-pack/plugins/index_management/server/routes/api/settings/register_update_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/settings/register_update_route.ts @@ -16,13 +16,13 @@ const paramsSchema = schema.object({ indexName: schema.string(), }); -export function registerUpdateRoute({ router, lib }: RouteDependencies) { +export function registerUpdateRoute({ router, license, lib }: RouteDependencies) { router.put( { path: addBasePath('/settings/{indexName}'), validate: { body: bodySchema, params: paramsSchema }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { indexName } = req.params as typeof paramsSchema.type; const params = { ignoreUnavailable: true, @@ -48,6 +48,6 @@ export function registerUpdateRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.ts b/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.ts index 42a3012ea8e174e..f8385711b55fe2a 100644 --- a/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/stats/register_stats_route.ts @@ -23,10 +23,10 @@ function formatHit(hit: { _shards: any; indices: { [key: string]: any } }, index }; } -export function registerStatsRoute({ router, lib }: RouteDependencies) { +export function registerStatsRoute({ router, license, lib }: RouteDependencies) { router.get( { path: addBasePath('/stats/{indexName}'), validate: { params: paramsSchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { indexName } = req.params as typeof paramsSchema.type; const params = { expand_wildcards: 'none', @@ -49,6 +49,6 @@ export function registerStatsRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/templates/register_create_route.ts b/x-pack/plugins/index_management/server/routes/api/templates/register_create_route.ts index d8a236bdebd1558..97e3c380e13ecd3 100644 --- a/x-pack/plugins/index_management/server/routes/api/templates/register_create_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/templates/register_create_route.ts @@ -15,10 +15,10 @@ import { saveTemplate, doesTemplateExist } from './lib'; const bodySchema = templateSchema; -export function registerCreateRoute({ router, lib }: RouteDependencies) { +export function registerCreateRoute({ router, license, lib }: RouteDependencies) { router.post( { path: addBasePath('/index_templates'), validate: { body: bodySchema } }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { callAsCurrentUser } = ctx.dataManagement!.client; const template = req.body as TemplateDeserialized; const { @@ -64,6 +64,6 @@ export function registerCreateRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/templates/register_delete_route.ts b/x-pack/plugins/index_management/server/routes/api/templates/register_delete_route.ts index 083964dec9edcc1..e258fafa534e31c 100644 --- a/x-pack/plugins/index_management/server/routes/api/templates/register_delete_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/templates/register_delete_route.ts @@ -22,13 +22,13 @@ const bodySchema = schema.object({ ), }); -export function registerDeleteRoute({ router }: RouteDependencies) { +export function registerDeleteRoute({ router, license }: RouteDependencies) { router.post( { path: addBasePath('/delete_index_templates'), validate: { body: bodySchema }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { callAsCurrentUser } = ctx.dataManagement!.client; const { templates } = req.body as TypeOf; const response: { templatesDeleted: Array; errors: any[] } = { @@ -60,6 +60,6 @@ export function registerDeleteRoute({ router }: RouteDependencies) { ); return res.ok({ body: response }); - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/templates/register_get_routes.ts b/x-pack/plugins/index_management/server/routes/api/templates/register_get_routes.ts index bd000186d91c402..006532cfd4dbe1c 100644 --- a/x-pack/plugins/index_management/server/routes/api/templates/register_get_routes.ts +++ b/x-pack/plugins/index_management/server/routes/api/templates/register_get_routes.ts @@ -17,29 +17,32 @@ import { getCloudManagedTemplatePrefix } from '../../../lib/get_managed_template import { RouteDependencies } from '../../../types'; import { addBasePath } from '../index'; -export function registerGetAllRoute({ router }: RouteDependencies) { - router.get({ path: addBasePath('/index_templates'), validate: false }, async (ctx, req, res) => { - const { callAsCurrentUser } = ctx.dataManagement!.client; - const cloudManagedTemplatePrefix = await getCloudManagedTemplatePrefix(callAsCurrentUser); - - const legacyTemplatesEs = await callAsCurrentUser('indices.getTemplate'); - const { index_templates: templatesEs } = await callAsCurrentUser( - 'dataManagement.getComposableIndexTemplates' - ); - - const legacyTemplates = deserializeLegacyTemplateList( - legacyTemplatesEs, - cloudManagedTemplatePrefix - ); - const templates = deserializeTemplateList(templatesEs, cloudManagedTemplatePrefix); - - const body = { - templates, - legacyTemplates, - }; - - return res.ok({ body }); - }); +export function registerGetAllRoute({ router, license }: RouteDependencies) { + router.get( + { path: addBasePath('/index_templates'), validate: false }, + license.guardApiRoute(async (ctx, req, res) => { + const { callAsCurrentUser } = ctx.dataManagement!.client; + const cloudManagedTemplatePrefix = await getCloudManagedTemplatePrefix(callAsCurrentUser); + + const legacyTemplatesEs = await callAsCurrentUser('indices.getTemplate'); + const { index_templates: templatesEs } = await callAsCurrentUser( + 'dataManagement.getComposableIndexTemplates' + ); + + const legacyTemplates = deserializeLegacyTemplateList( + legacyTemplatesEs, + cloudManagedTemplatePrefix + ); + const templates = deserializeTemplateList(templatesEs, cloudManagedTemplatePrefix); + + const body = { + templates, + legacyTemplates, + }; + + return res.ok({ body }); + }) + ); } const paramsSchema = schema.object({ @@ -51,13 +54,13 @@ const querySchema = schema.object({ legacy: schema.maybe(schema.oneOf([schema.literal('true'), schema.literal('false')])), }); -export function registerGetOneRoute({ router, lib }: RouteDependencies) { +export function registerGetOneRoute({ router, license, lib }: RouteDependencies) { router.get( { path: addBasePath('/index_templates/{name}'), validate: { params: paramsSchema, query: querySchema }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { name } = req.params as TypeOf; const { callAsCurrentUser } = ctx.dataManagement!.client; @@ -103,6 +106,6 @@ export function registerGetOneRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts b/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts index 0c3d8faea628cf1..f4554bd2fb1fa6e 100644 --- a/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/templates/register_simulate_route.ts @@ -12,13 +12,13 @@ import { addBasePath } from '../index'; const bodySchema = schema.object({}, { unknowns: 'allow' }); -export function registerSimulateRoute({ router, lib }: RouteDependencies) { +export function registerSimulateRoute({ router, license, lib }: RouteDependencies) { router.post( { path: addBasePath('/index_templates/simulate'), validate: { body: bodySchema }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { callAsCurrentUser } = ctx.dataManagement!.client; const template = req.body as TypeOf; @@ -42,6 +42,6 @@ export function registerSimulateRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/routes/api/templates/register_update_route.ts b/x-pack/plugins/index_management/server/routes/api/templates/register_update_route.ts index 07a7d457f047376..f0070408768cbf5 100644 --- a/x-pack/plugins/index_management/server/routes/api/templates/register_update_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/templates/register_update_route.ts @@ -18,13 +18,13 @@ const paramsSchema = schema.object({ name: schema.string(), }); -export function registerUpdateRoute({ router, lib }: RouteDependencies) { +export function registerUpdateRoute({ router, license, lib }: RouteDependencies) { router.put( { path: addBasePath('/index_templates/{name}'), validate: { body: bodySchema, params: paramsSchema }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { callAsCurrentUser } = ctx.dataManagement!.client; const { name } = req.params as typeof paramsSchema.type; const template = req.body as TemplateDeserialized; @@ -58,6 +58,6 @@ export function registerUpdateRoute({ router, lib }: RouteDependencies) { // Case: default throw e; } - } + }) ); } diff --git a/x-pack/plugins/index_management/server/services/index.ts b/x-pack/plugins/index_management/server/services/index.ts index 576d7c46fa086ac..3af5117e2b7aaaa 100644 --- a/x-pack/plugins/index_management/server/services/index.ts +++ b/x-pack/plugins/index_management/server/services/index.ts @@ -5,4 +5,6 @@ * 2.0. */ +export { License } from './license'; + export { IndexDataEnricher, Enricher } from './index_data_enricher'; diff --git a/x-pack/plugins/index_management/server/services/license.ts b/x-pack/plugins/index_management/server/services/license.ts new file mode 100644 index 000000000000000..0898c01a1e46698 --- /dev/null +++ b/x-pack/plugins/index_management/server/services/license.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Logger } from 'src/core/server'; +import type { KibanaRequest, KibanaResponseFactory, RequestHandler } from 'kibana/server'; + +import { LicensingPluginSetup } from '../../../licensing/server'; +import { LicenseType } from '../../../licensing/common/types'; +import type { IndexManagementRequestHandlerContext } from '../types'; + +export interface LicenseStatus { + isValid: boolean; + message?: string; +} + +interface SetupSettings { + pluginId: string; + minimumLicenseType: LicenseType; + defaultErrorMessage: string; +} + +export class License { + private licenseStatus: LicenseStatus = { + isValid: false, + message: 'Invalid License', + }; + + setup( + { pluginId, minimumLicenseType, defaultErrorMessage }: SetupSettings, + { licensing, logger }: { licensing: LicensingPluginSetup; logger: Logger } + ) { + licensing.license$.subscribe((license) => { + const { state, message } = license.check(pluginId, minimumLicenseType); + const hasRequiredLicense = state === 'valid'; + + if (hasRequiredLicense) { + this.licenseStatus = { isValid: true }; + } else { + this.licenseStatus = { + isValid: false, + message: message || defaultErrorMessage, + }; + if (message) { + logger.info(message); + } + } + }); + } + + guardApiRoute( + handler: RequestHandler + ) { + const license = this; + + return function licenseCheck( + ctx: Context, + request: KibanaRequest, + response: KibanaResponseFactory + ) { + const licenseStatus = license.getStatus(); + + if (!licenseStatus.isValid) { + return response.customError({ + body: { + message: licenseStatus.message || '', + }, + statusCode: 403, + }); + } + + return handler(ctx, request, response); + }; + } + + getStatus() { + return this.licenseStatus; + } +} diff --git a/x-pack/plugins/index_management/server/types.ts b/x-pack/plugins/index_management/server/types.ts index c980279d5bf3061..0854733d5db5958 100644 --- a/x-pack/plugins/index_management/server/types.ts +++ b/x-pack/plugins/index_management/server/types.ts @@ -14,7 +14,7 @@ import type { import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; import { LicensingPluginSetup } from '../../licensing/server'; import { SecurityPluginSetup } from '../../security/server'; -import { IndexDataEnricher } from './services'; +import { License, IndexDataEnricher } from './services'; import { isEsError, parseEsError, handleEsError } from './shared_imports'; export interface Dependencies { @@ -25,6 +25,7 @@ export interface Dependencies { export interface RouteDependencies { router: IndexManagementRouter; + license: License; config: { isSecurityEnabled: () => boolean; }; diff --git a/x-pack/plugins/infra/public/components/log_stream/log_stream.stories.mdx b/x-pack/plugins/infra/public/components/log_stream/log_stream.stories.mdx index 7f1636b00d24e35..901a4b6a8383e34 100644 --- a/x-pack/plugins/infra/public/components/log_stream/log_stream.stories.mdx +++ b/x-pack/plugins/infra/public/components/log_stream/log_stream.stories.mdx @@ -113,7 +113,7 @@ export const Template = (args) => ; The purpose of this component is to allow you, the developer, to have your very own Log Stream in your plugin. -The component is exposed through `infra/public`. Since Kibana uses relative paths, it is up to you to find how to import it (sorry). +The component is exposed through `infra/public`. Since Kibana uses relative paths is up to you to find how to import it (sorry). ```tsx import { LogStream } from '../../../../../../infra/public'; @@ -124,9 +124,8 @@ import { LogStream } from '../../../../../../infra/public'; To use the component your plugin needs to follow certain criteria: -- Ensure `"infra"` and `"data"` are specified as a `requiredPlugins` in your plugin's `kibana.json`. -- Ensure the `` component is mounted inside the hierachy of a [`kibana-react` provider](https://github.com/elastic/kibana/blob/b2d0aa7b7fae1c89c8f9e8854ae73e71be64e765/src/plugins/kibana_react/README.md#L45). At a minimum, the kibana-react provider must pass `http` (from core start services) and `data` (from core plugin start dependencies). -- Ensure the `` component is mounted inside the hierachy of a [`EuiThemeProvider`](https://github.com/elastic/kibana/blob/master/src/plugins/kibana_react/common/eui_styled_components.tsx). +- Ensure `"infra"` is specified as a `requiredPlugins` in your plugin's `kibana.json`. +- Ensure the `` component is mounted inside the hiearchy of a [`kibana-react` provider](https://github.com/elastic/kibana/blob/b2d0aa7b7fae1c89c8f9e8854ae73e71be64e765/src/plugins/kibana_react/README.md#L45). ## Usage @@ -355,30 +354,25 @@ The infra plugin has the concept of a "source configuration", a collection of se The `` component will use the `"default"` source configuration. If you want to use your own configuration, you need to first create it when you initialize your plugin, and then specify it in the `` component with the `sourceId` prop. ```tsx -// Your `server/plugin.ts` +// Your `plugin/init.ts` class MyPlugin { // ... setup(core, plugins) { plugins.infra.defineInternalSourceConfiguration( 'my_source', // ID for your source configuration { - name: 'some-name', - description: 'some description', - logIndices: { // Also accepts an `index_pattern` type with `indexPatternId` - type: 'index_name', - indexName: 'some-index', - }, + logAlias: 'some-index-*', // Optional. what ES index to query. logColumns: [ - { timestampColumn: { id: '...uuid4' }, // The `@timestamp` column. `id` is an arbitrary string identifier. - { fieldColumn: { id: '...uuid4', field: 'some_field' }}, // Any column(s) you want. `id` is an arbitrary string identifier. - { messageColumn: { id: '...uuid' }} // The `message` column. `id` is an arbitrary string identifier. + { timestampColumn: { id: '...uuid4' }, // The `@timestamp` column. + { fieldColumn: { id: '...uuid4', field: 'some_field' }}, // Any column(s) you want. + { messageColumn: { id: '...uuid' }} // The `message` column. ] } ); } } -// Somewhere else in your client-side code +// Somewhere else on your code { + private readonly logger: Logger; + private readonly license: License; private readonly apiRoutes: ApiRoutes; - constructor() { + constructor({ logger }: PluginInitializerContext) { + this.logger = logger.get(); + this.license = new License(); this.apiRoutes = new ApiRoutes(); } - public setup({ http }: CoreSetup, { security, features }: Dependencies) { + public setup({ http }: CoreSetup, { licensing, security, features }: Dependencies) { + this.logger.debug('ingest_pipelines: setup'); + const router = http.createRouter(); + this.license.setup( + { + pluginId: PLUGIN_ID, + minimumLicenseType: PLUGIN_MIN_LICENSE_TYPE, + defaultErrorMessage: i18n.translate('xpack.ingestPipelines.licenseCheckErrorMessage', { + defaultMessage: 'License check failed', + }), + }, + { + licensing, + logger: this.logger, + } + ); + features.registerElasticsearchFeature({ id: 'ingest_pipelines', management: { @@ -36,6 +61,7 @@ export class IngestPipelinesPlugin implements Plugin { this.apiRoutes.setup({ router, + license: this.license, config: { isSecurityEnabled: () => security !== undefined && security.license.isEnabled(), }, diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/create.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/create.ts index b078ca051a27240..388c82aa34b3d12 100644 --- a/x-pack/plugins/ingest_pipelines/server/routes/api/create.ts +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/create.ts @@ -20,6 +20,7 @@ const bodySchema = schema.object({ export const registerCreateRoute = ({ router, + license, lib: { handleEsError }, }: RouteDependencies): void => { router.post( @@ -29,7 +30,7 @@ export const registerCreateRoute = ({ body: bodySchema, }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { client: clusterClient } = ctx.core.elasticsearch; const pipeline = req.body as Pipeline; @@ -73,6 +74,6 @@ export const registerCreateRoute = ({ } catch (error) { return handleEsError({ error, response: res }); } - } + }) ); }; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/delete.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/delete.ts index 1ffa5adabd83b35..8cc7d7044ad08e4 100644 --- a/x-pack/plugins/ingest_pipelines/server/routes/api/delete.ts +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/delete.ts @@ -14,7 +14,7 @@ const paramsSchema = schema.object({ names: schema.string(), }); -export const registerDeleteRoute = ({ router }: RouteDependencies): void => { +export const registerDeleteRoute = ({ router, license }: RouteDependencies): void => { router.delete( { path: `${API_BASE_PATH}/{names}`, @@ -22,7 +22,7 @@ export const registerDeleteRoute = ({ router }: RouteDependencies): void => { params: paramsSchema, }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { client: clusterClient } = ctx.core.elasticsearch; const { names } = req.params; const pipelineNames = names.split(','); @@ -48,6 +48,6 @@ export const registerDeleteRoute = ({ router }: RouteDependencies): void => { ); return res.ok({ body: response }); - } + }) ); }; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/documents.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/documents.ts index 6f7233c70dbfe8b..324bcdd3edb4622 100644 --- a/x-pack/plugins/ingest_pipelines/server/routes/api/documents.ts +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/documents.ts @@ -17,6 +17,7 @@ const paramsSchema = schema.object({ export const registerDocumentsRoute = ({ router, + license, lib: { handleEsError }, }: RouteDependencies): void => { router.get( @@ -26,7 +27,7 @@ export const registerDocumentsRoute = ({ params: paramsSchema, }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { client: clusterClient } = ctx.core.elasticsearch; const { index, id } = req.params; @@ -45,6 +46,6 @@ export const registerDocumentsRoute = ({ } catch (error) { return handleEsError({ error, response: res }); } - } + }) ); }; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/get.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/get.ts index b512ebda5ecdb2d..853bd1c7dde2382 100644 --- a/x-pack/plugins/ingest_pipelines/server/routes/api/get.ts +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/get.ts @@ -15,25 +15,32 @@ const paramsSchema = schema.object({ name: schema.string(), }); -export const registerGetRoutes = ({ router, lib: { handleEsError } }: RouteDependencies): void => { +export const registerGetRoutes = ({ + router, + license, + lib: { handleEsError }, +}: RouteDependencies): void => { // Get all pipelines - router.get({ path: API_BASE_PATH, validate: false }, async (ctx, req, res) => { - const { client: clusterClient } = ctx.core.elasticsearch; + router.get( + { path: API_BASE_PATH, validate: false }, + license.guardApiRoute(async (ctx, req, res) => { + const { client: clusterClient } = ctx.core.elasticsearch; - try { - const { body: pipelines } = await clusterClient.asCurrentUser.ingest.getPipeline(); + try { + const { body: pipelines } = await clusterClient.asCurrentUser.ingest.getPipeline(); - return res.ok({ body: deserializePipelines(pipelines) }); - } catch (error) { - const esErrorResponse = handleEsError({ error, response: res }); - if (esErrorResponse.status === 404) { - // ES returns 404 when there are no pipelines - // Instead, we return an empty array and 200 status back to the client - return res.ok({ body: [] }); + return res.ok({ body: deserializePipelines(pipelines) }); + } catch (error) { + const esErrorResponse = handleEsError({ error, response: res }); + if (esErrorResponse.status === 404) { + // ES returns 404 when there are no pipelines + // Instead, we return an empty array and 200 status back to the client + return res.ok({ body: [] }); + } + return esErrorResponse; } - return esErrorResponse; - } - }); + }) + ); // Get single pipeline router.get( @@ -43,7 +50,7 @@ export const registerGetRoutes = ({ router, lib: { handleEsError } }: RouteDepen params: paramsSchema, }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { client: clusterClient } = ctx.core.elasticsearch; const { name } = req.params; @@ -61,6 +68,6 @@ export const registerGetRoutes = ({ router, lib: { handleEsError } }: RouteDepen } catch (error) { return handleEsError({ error, response: res }); } - } + }) ); }; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts index 5368b59b35a41ac..e1e4b2d3d288663 100644 --- a/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts @@ -17,13 +17,13 @@ const extractMissingPrivileges = (privilegesObject: { [key: string]: boolean } = return privileges; }, []); -export const registerPrivilegesRoute = ({ router, config }: RouteDependencies) => { +export const registerPrivilegesRoute = ({ license, router, config }: RouteDependencies) => { router.get( { path: `${API_BASE_PATH}/privileges`, validate: false, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const privilegesResult: Privileges = { hasAllPrivileges: true, missingPrivileges: { @@ -51,6 +51,6 @@ export const registerPrivilegesRoute = ({ router, config }: RouteDependencies) = privilegesResult.hasAllPrivileges = hasAllPrivileges; return res.ok({ body: privilegesResult }); - } + }) ); }; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts index f697a38e21561e8..a1d0a4ec2e3d32d 100644 --- a/x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts @@ -19,6 +19,7 @@ const bodySchema = schema.object({ export const registerSimulateRoute = ({ router, + license, lib: { handleEsError }, }: RouteDependencies): void => { router.post( @@ -28,7 +29,7 @@ export const registerSimulateRoute = ({ body: bodySchema, }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { client: clusterClient } = ctx.core.elasticsearch; const { pipeline, documents, verbose } = req.body; @@ -46,6 +47,6 @@ export const registerSimulateRoute = ({ } catch (error) { return handleEsError({ error, response: res }); } - } + }) ); }; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/update.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/update.ts index 35af1395f5e37b4..0d3e2a37795273b 100644 --- a/x-pack/plugins/ingest_pipelines/server/routes/api/update.ts +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/update.ts @@ -19,6 +19,7 @@ const paramsSchema = schema.object({ export const registerUpdateRoute = ({ router, + license, lib: { handleEsError }, }: RouteDependencies): void => { router.put( @@ -29,7 +30,7 @@ export const registerUpdateRoute = ({ params: paramsSchema, }, }, - async (ctx, req, res) => { + license.guardApiRoute(async (ctx, req, res) => { const { client: clusterClient } = ctx.core.elasticsearch; const { name } = req.params; // eslint-disable-next-line @typescript-eslint/naming-convention @@ -53,6 +54,6 @@ export const registerUpdateRoute = ({ } catch (error) { return handleEsError({ error, response: res }); } - } + }) ); }; diff --git a/x-pack/plugins/apm/common/index_pattern_constants.ts b/x-pack/plugins/ingest_pipelines/server/services/index.ts similarity index 77% rename from x-pack/plugins/apm/common/index_pattern_constants.ts rename to x-pack/plugins/ingest_pipelines/server/services/index.ts index 4b67bba1fef910c..b006d7280525748 100644 --- a/x-pack/plugins/apm/common/index_pattern_constants.ts +++ b/x-pack/plugins/ingest_pipelines/server/services/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export const APM_STATIC_INDEX_PATTERN_ID = 'apm_static_index_pattern_id'; +export { License } from './license'; diff --git a/x-pack/plugins/ingest_pipelines/server/services/license.ts b/x-pack/plugins/ingest_pipelines/server/services/license.ts new file mode 100644 index 000000000000000..05878b170ff1d0f --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/services/license.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Logger } from 'src/core/server'; +import { + KibanaRequest, + KibanaResponseFactory, + RequestHandler, + RequestHandlerContext, +} from 'kibana/server'; + +import { LicensingPluginSetup } from '../../../licensing/server'; +import { LicenseType } from '../../../licensing/common/types'; + +export interface LicenseStatus { + isValid: boolean; + message?: string; +} + +interface SetupSettings { + pluginId: string; + minimumLicenseType: LicenseType; + defaultErrorMessage: string; +} + +export class License { + private licenseStatus: LicenseStatus = { + isValid: false, + message: 'Invalid License', + }; + + setup( + { pluginId, minimumLicenseType, defaultErrorMessage }: SetupSettings, + { licensing, logger }: { licensing: LicensingPluginSetup; logger: Logger } + ) { + licensing.license$.subscribe((license) => { + const { state, message } = license.check(pluginId, minimumLicenseType); + const hasRequiredLicense = state === 'valid'; + + if (hasRequiredLicense) { + this.licenseStatus = { isValid: true }; + } else { + this.licenseStatus = { + isValid: false, + message: message || defaultErrorMessage, + }; + if (message) { + logger.info(message); + } + } + }); + } + + guardApiRoute(handler: RequestHandler) { + const license = this; + + return function licenseCheck( + ctx: RequestHandlerContext, + request: KibanaRequest, + response: KibanaResponseFactory + ) { + const licenseStatus = license.getStatus(); + + if (!licenseStatus.isValid) { + return response.customError({ + body: { + message: licenseStatus.message || '', + }, + statusCode: 403, + }); + } + + return handler(ctx, request, response); + }; + } + + getStatus() { + return this.licenseStatus; + } +} diff --git a/x-pack/plugins/ingest_pipelines/server/types.ts b/x-pack/plugins/ingest_pipelines/server/types.ts index efc0679708a5d95..912a0c88eef62ad 100644 --- a/x-pack/plugins/ingest_pipelines/server/types.ts +++ b/x-pack/plugins/ingest_pipelines/server/types.ts @@ -6,17 +6,21 @@ */ import { IRouter } from 'src/core/server'; +import { LicensingPluginSetup } from '../../licensing/server'; import { SecurityPluginSetup } from '../../security/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; +import { License } from './services'; import { handleEsError } from './shared_imports'; export interface Dependencies { security: SecurityPluginSetup; features: FeaturesPluginSetup; + licensing: LicensingPluginSetup; } export interface RouteDependencies { router: IRouter; + license: License; config: { isSecurityEnabled: () => boolean; }; diff --git a/x-pack/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/plugins/lens/public/app_plugin/app.test.tsx index 30b4e2d954d2b8e..72b8bfa38491ac8 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.test.tsx @@ -6,14 +6,15 @@ */ import React from 'react'; -import { Subject } from 'rxjs'; +import { Observable, Subject } from 'rxjs'; import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { App } from './app'; import { LensAppProps, LensAppServices } from './types'; import { EditorFrameInstance, EditorFrameProps } from '../types'; import { Document } from '../persistence'; -import { makeDefaultServices, mountWithProvider } from '../mocks'; +import { DOC_TYPE } from '../../common'; +import { mount } from 'enzyme'; import { I18nProvider } from '@kbn/i18n/react'; import { SavedObjectSaveModal, @@ -21,20 +22,31 @@ import { } from '../../../../../src/plugins/saved_objects/public'; import { createMemoryHistory } from 'history'; import { + DataPublicPluginStart, esFilters, FilterManager, IFieldType, IIndexPattern, - IndexPattern, - Query, + UI_SETTINGS, } from '../../../../../src/plugins/data/public'; +import { navigationPluginMock } from '../../../../../src/plugins/navigation/public/mocks'; import { TopNavMenuData } from '../../../../../src/plugins/navigation/public'; -import { LensByValueInput } from '../editor_frame_service/embeddable/embeddable'; +import { coreMock } from 'src/core/public/mocks'; +import { + LensByValueInput, + LensSavedObjectAttributes, + LensByReferenceInput, +} from '../editor_frame_service/embeddable/embeddable'; import { SavedObjectReference } from '../../../../../src/core/types'; +import { + mockAttributeService, + createEmbeddableStateTransferMock, +} from '../../../../../src/plugins/embeddable/public/mocks'; +import { LensAttributeService } from '../lens_attribute_service'; import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; +import { EmbeddableStateTransfer } from '../../../../../src/plugins/embeddable/public'; import moment from 'moment'; -import { setState, LensAppState } from '../state_management/index'; jest.mock('../editor_frame_service/editor_frame/expression_helpers'); jest.mock('src/core/public'); jest.mock('../../../../../src/plugins/saved_objects/public', () => { @@ -49,16 +61,13 @@ jest.mock('../../../../../src/plugins/saved_objects/public', () => { }; }); -jest.mock('lodash', () => { - const original = jest.requireActual('lodash'); +const navigationStartMock = navigationPluginMock.createStartContract(); - return { - ...original, - debounce: (fn: unknown) => fn, - }; +jest.spyOn(navigationStartMock.ui.TopNavMenu.prototype, 'constructor').mockImplementation(() => { + return
; }); -// const navigationStartMock = navigationPluginMock.createStartContract(); +const { TopNavMenu } = navigationStartMock.ui; function createMockFrame(): jest.Mocked { return { @@ -68,7 +77,91 @@ function createMockFrame(): jest.Mocked { const sessionIdSubject = new Subject(); +function createMockSearchService() { + let sessionIdCounter = 1; + return { + session: { + start: jest.fn(() => `sessionId-${sessionIdCounter++}`), + clear: jest.fn(), + getSessionId: jest.fn(() => `sessionId-${sessionIdCounter}`), + getSession$: jest.fn(() => sessionIdSubject.asObservable()), + }, + }; +} + +function createMockFilterManager() { + const unsubscribe = jest.fn(); + + let subscriber: () => void; + let filters: unknown = []; + + return { + getUpdates$: () => ({ + subscribe: ({ next }: { next: () => void }) => { + subscriber = next; + return unsubscribe; + }, + }), + setFilters: jest.fn((newFilters: unknown[]) => { + filters = newFilters; + if (subscriber) subscriber(); + }), + setAppFilters: jest.fn((newFilters: unknown[]) => { + filters = newFilters; + if (subscriber) subscriber(); + }), + getFilters: () => filters, + getGlobalFilters: () => { + // @ts-ignore + return filters.filter(esFilters.isFilterPinned); + }, + removeAll: () => { + filters = []; + subscriber(); + }, + }; +} + +function createMockQueryString() { + return { + getQuery: jest.fn(() => ({ query: '', language: 'kuery' })), + setQuery: jest.fn(), + getDefaultQuery: jest.fn(() => ({ query: '', language: 'kuery' })), + }; +} + +function createMockTimefilter() { + const unsubscribe = jest.fn(); + + let timeFilter = { from: 'now-7d', to: 'now' }; + let subscriber: () => void; + return { + getTime: jest.fn(() => timeFilter), + setTime: jest.fn((newTimeFilter) => { + timeFilter = newTimeFilter; + if (subscriber) { + subscriber(); + } + }), + getTimeUpdate$: () => ({ + subscribe: ({ next }: { next: () => void }) => { + subscriber = next; + return unsubscribe; + }, + }), + calculateBounds: jest.fn(() => ({ + min: moment('2021-01-10T04:00:00.000Z'), + max: moment('2021-01-10T08:00:00.000Z'), + })), + getBounds: jest.fn(() => timeFilter), + getRefreshInterval: () => {}, + getRefreshIntervalDefaults: () => {}, + getAutoRefreshFetch$: () => new Observable(), + }; +} + describe('Lens App', () => { + let core: ReturnType; let defaultDoc: Document; let defaultSavedObjectId: string; @@ -78,6 +171,27 @@ describe('Lens App', () => { expectedSaveAndReturnButton: { emphasize: true, testId: 'lnsApp_saveAndReturnButton' }, }; + function makeAttributeService(): LensAttributeService { + const attributeServiceMock = mockAttributeService< + LensSavedObjectAttributes, + LensByValueInput, + LensByReferenceInput + >( + DOC_TYPE, + { + saveMethod: jest.fn(), + unwrapMethod: jest.fn(), + checkForDuplicateTitle: jest.fn(), + }, + core + ); + attributeServiceMock.unwrapAttributes = jest.fn().mockResolvedValue(defaultDoc); + attributeServiceMock.wrapAttributes = jest + .fn() + .mockResolvedValue({ savedObjectId: defaultSavedObjectId }); + return attributeServiceMock; + } + function makeDefaultProps(): jest.Mocked { return { editorFrame: createMockFrame(), @@ -89,15 +203,64 @@ describe('Lens App', () => { }; } - async function mountWith({ - props = makeDefaultProps(), - services = makeDefaultServices(sessionIdSubject), - storePreloadedState, + function makeDefaultServices(): jest.Mocked { + return { + http: core.http, + chrome: core.chrome, + overlays: core.overlays, + uiSettings: core.uiSettings, + navigation: navigationStartMock, + notifications: core.notifications, + attributeService: makeAttributeService(), + savedObjectsClient: core.savedObjects.client, + dashboardFeatureFlag: { allowByValueEmbeddables: false }, + stateTransfer: createEmbeddableStateTransferMock() as EmbeddableStateTransfer, + getOriginatingAppName: jest.fn(() => 'defaultOriginatingApp'), + application: { + ...core.application, + capabilities: { + ...core.application.capabilities, + visualize: { save: true, saveQuery: true, show: true }, + }, + getUrlForApp: jest.fn((appId: string) => `/testbasepath/app/${appId}#/`), + }, + data: ({ + query: { + filterManager: createMockFilterManager(), + timefilter: { + timefilter: createMockTimefilter(), + }, + queryString: createMockQueryString(), + state$: new Observable(), + }, + indexPatterns: { + get: jest.fn((id) => { + return new Promise((resolve) => resolve({ id })); + }), + }, + search: createMockSearchService(), + nowProvider: { + get: jest.fn(), + }, + } as unknown) as DataPublicPluginStart, + storage: { + get: jest.fn(), + set: jest.fn(), + remove: jest.fn(), + clear: jest.fn(), + }, + }; + } + + function mountWith({ + props: incomingProps, + services: incomingServices, }: { props?: jest.Mocked; services?: jest.Mocked; - storePreloadedState?: Partial; }) { + const props = incomingProps ?? makeDefaultProps(); + const services = incomingServices ?? makeDefaultServices(); const wrappingComponent: React.FC<{ children: React.ReactNode; }> = ({ children }) => { @@ -107,40 +270,61 @@ describe('Lens App', () => { ); }; - - const { instance, lensStore } = await mountWithProvider( - , - services.data, - storePreloadedState, - wrappingComponent - ); - const frame = props.editorFrame as ReturnType; - return { instance, frame, props, services, lensStore }; + const component = mount(, { wrappingComponent }); + return { component, frame, props, services }; } beforeEach(() => { + core = coreMock.createStart({ basePath: '/testbasepath' }); defaultSavedObjectId = '1234'; defaultDoc = ({ savedObjectId: defaultSavedObjectId, title: 'An extremely cool default document!', expression: 'definitely a valid expression', state: { - query: 'lucene', + query: 'kuery', filters: [{ query: { match_phrase: { src: 'test' } } }], }, references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], } as unknown) as Document; + + core.uiSettings.get.mockImplementation( + jest.fn((type) => { + if (type === UI_SETTINGS.TIMEPICKER_TIME_DEFAULTS) { + return { from: 'now-7d', to: 'now' }; + } else if (type === UI_SETTINGS.SEARCH_QUERY_LANGUAGE) { + return 'kuery'; + } else if (type === 'state:storeInSessionStorage') { + return false; + } else { + return []; + } + }) + ); }); - it('renders the editor frame', async () => { - const { frame } = await mountWith({}); + it('renders the editor frame', () => { + const { frame } = mountWith({}); expect(frame.EditorFrameContainer.mock.calls).toMatchInlineSnapshot(` Array [ Array [ Object { + "dateRange": Object { + "fromDate": "2021-01-10T04:00:00.000Z", + "toDate": "2021-01-10T08:00:00.000Z", + }, + "doc": undefined, + "filters": Array [], "initialContext": undefined, + "onChange": [Function], "onError": [Function], + "query": Object { + "language": "kuery", + "query": "", + }, + "savedQuery": undefined, + "searchSessionId": "sessionId-1", "showNoDataPopover": [Function], }, Object {}, @@ -149,8 +333,13 @@ describe('Lens App', () => { `); }); - it('updates global filters with store state', async () => { - const services = makeDefaultServices(sessionIdSubject); + it('clears app filters on load', () => { + const { services } = mountWith({}); + expect(services.data.query.filterManager.setAppFilters).toHaveBeenCalledWith([]); + }); + + it('passes global filters to frame', async () => { + const services = makeDefaultServices(); const indexPattern = ({ id: 'index1' } as unknown) as IIndexPattern; const pinnedField = ({ name: 'pinnedField' } as unknown) as IFieldType; const pinnedFilter = esFilters.buildExistsFilter(pinnedField, indexPattern); @@ -160,28 +349,25 @@ describe('Lens App', () => { services.data.query.filterManager.getGlobalFilters = jest.fn().mockImplementation(() => { return [pinnedFilter]; }); - const { instance, lensStore } = await mountWith({ services }); + const { component, frame } = mountWith({ services }); - instance.update(); - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ - query: { query: '', language: 'lucene' }, + component.update(); + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ + dateRange: { fromDate: '2021-01-10T04:00:00.000Z', toDate: '2021-01-10T08:00:00.000Z' }, + query: { query: '', language: 'kuery' }, filters: [pinnedFilter], - resolvedDateRange: { - fromDate: '2021-01-10T04:00:00.000Z', - toDate: '2021-01-10T08:00:00.000Z', - }, }), - }); - + {} + ); expect(services.data.query.filterManager.getFilters).not.toHaveBeenCalled(); }); - it('displays errors from the frame in a toast', async () => { - const { instance, frame, services } = await mountWith({}); + it('displays errors from the frame in a toast', () => { + const { component, frame, services } = mountWith({}); const onError = frame.EditorFrameContainer.mock.calls[0][0].onError; onError({ message: 'error' }); - instance.update(); + component.update(); expect(services.notifications.toasts.addDanger).toHaveBeenCalled(); }); @@ -198,7 +384,7 @@ describe('Lens App', () => { } as unknown) as Document; it('sets breadcrumbs when the document title changes', async () => { - const { instance, services, lensStore } = await mountWith({}); + const { component, services } = mountWith({}); expect(services.chrome.setBreadcrumbs).toHaveBeenCalledWith([ { @@ -209,13 +395,9 @@ describe('Lens App', () => { { text: 'Create' }, ]); + services.attributeService.unwrapAttributes = jest.fn().mockResolvedValue(breadcrumbDoc); await act(async () => { - instance.setProps({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); - lensStore.dispatch( - setState({ - persistedDoc: breadcrumbDoc, - }) - ); + component.setProps({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); }); expect(services.chrome.setBreadcrumbs).toHaveBeenCalledWith([ @@ -230,17 +412,10 @@ describe('Lens App', () => { it('sets originatingApp breadcrumb when the document title changes', async () => { const props = makeDefaultProps(); - const services = makeDefaultServices(sessionIdSubject); + const services = makeDefaultServices(); props.incomingState = { originatingApp: 'coolContainer' }; services.getOriginatingAppName = jest.fn(() => 'The Coolest Container Ever Made'); - - const { instance, lensStore } = await mountWith({ - props, - services, - storePreloadedState: { - isLinkedToOriginatingApp: true, - }, - }); + const { component } = mountWith({ props, services }); expect(services.chrome.setBreadcrumbs).toHaveBeenCalledWith([ { text: 'The Coolest Container Ever Made', onClick: expect.anything() }, @@ -252,14 +427,9 @@ describe('Lens App', () => { { text: 'Create' }, ]); + services.attributeService.unwrapAttributes = jest.fn().mockResolvedValue(breadcrumbDoc); await act(async () => { - instance.setProps({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); - - lensStore.dispatch( - setState({ - persistedDoc: breadcrumbDoc, - }) - ); + component.setProps({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); }); expect(services.chrome.setBreadcrumbs).toHaveBeenCalledWith([ @@ -275,36 +445,99 @@ describe('Lens App', () => { }); describe('persistence', () => { + it('does not load a document if there is no initial input', () => { + const { services } = mountWith({}); + expect(services.attributeService.unwrapAttributes).not.toHaveBeenCalled(); + }); + it('loads a document and uses query and filters if initial input is provided', async () => { - const { instance, lensStore, services } = await mountWith({}); - const document = ({ + const { component, frame, services } = mountWith({}); + services.attributeService.unwrapAttributes = jest.fn().mockResolvedValue({ savedObjectId: defaultSavedObjectId, state: { query: 'fake query', filters: [{ query: { match_phrase: { src: 'test' } } }], }, references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], - } as unknown) as Document; + }); - act(() => { - lensStore.dispatch( - setState({ - query: ('fake query' as unknown) as Query, - indexPatternsForTopNav: ([{ id: '1' }] as unknown) as IndexPattern[], - lastKnownDoc: document, - persistedDoc: document, - }) - ); + await act(async () => { + component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); }); - instance.update(); - expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( + expect(services.attributeService.unwrapAttributes).toHaveBeenCalledWith({ + savedObjectId: defaultSavedObjectId, + }); + expect(services.data.indexPatterns.get).toHaveBeenCalledWith('1'); + expect(services.data.query.filterManager.setAppFilters).toHaveBeenCalledWith([ + { query: { match_phrase: { src: 'test' } } }, + ]); + expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: 'fake query', indexPatterns: [{ id: '1' }], }), {} ); + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ + doc: expect.objectContaining({ + savedObjectId: defaultSavedObjectId, + state: expect.objectContaining({ + query: 'fake query', + filters: [{ query: { match_phrase: { src: 'test' } } }], + }), + }), + }), + {} + ); + }); + + it('does not load documents on sequential renders unless the id changes', async () => { + const { services, component } = mountWith({}); + + await act(async () => { + component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + }); + await act(async () => { + component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + }); + expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(1); + + await act(async () => { + component.setProps({ initialInput: { savedObjectId: '5678' } }); + }); + + expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(2); + }); + + it('handles document load errors', async () => { + const services = makeDefaultServices(); + services.attributeService.unwrapAttributes = jest.fn().mockRejectedValue('failed to load'); + const { component, props } = mountWith({ services }); + + await act(async () => { + component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + }); + + expect(services.attributeService.unwrapAttributes).toHaveBeenCalledWith({ + savedObjectId: defaultSavedObjectId, + }); + expect(services.notifications.toasts.addDanger).toHaveBeenCalled(); + expect(props.redirectTo).toHaveBeenCalled(); + }); + + it('adds to the recently accessed list on load', async () => { + const { component, services } = mountWith({}); + + await act(async () => { + component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + }); + expect(services.chrome.recentlyAccessed.add).toHaveBeenCalledWith( + '/app/lens#/edit/1234', + 'An extremely cool default document!', + '1234' + ); }); describe('save buttons', () => { @@ -351,7 +584,7 @@ describe('Lens App', () => { : undefined, }; - const services = makeDefaultServices(sessionIdSubject); + const services = makeDefaultServices(); services.attributeService.wrapAttributes = jest .fn() .mockImplementation(async ({ savedObjectId }) => ({ @@ -366,27 +599,39 @@ describe('Lens App', () => { }, } as jest.ResolvedValue); - const { frame, instance, lensStore } = await mountWith({ services, props }); - - act(() => { - lensStore.dispatch( - setState({ - isSaveable: true, - lastKnownDoc: { savedObjectId: initialSavedObjectId, ...lastKnownDoc } as Document, - }) - ); + let frame: jest.Mocked = {} as jest.Mocked; + let component: ReactWrapper = {} as ReactWrapper; + await act(async () => { + const { frame: newFrame, component: newComponent } = mountWith({ services, props }); + frame = newFrame; + component = newComponent; }); - instance.update(); - expect(getButton(instance).disableButton).toEqual(false); + if (initialSavedObjectId) { + expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(1); + } else { + expect(services.attributeService.unwrapAttributes).not.toHaveBeenCalled(); + } + + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + + act(() => + onChange({ + filterableIndexPatterns: [], + doc: { savedObjectId: initialSavedObjectId, ...lastKnownDoc } as Document, + isSaveable: true, + }) + ); + component.update(); + expect(getButton(component).disableButton).toEqual(false); await act(async () => { - testSave(instance, { ...saveProps }); + testSave(component, { ...saveProps }); }); - return { props, services, instance, frame, lensStore }; + return { props, services, component, frame }; } it('shows a disabled save button when the user does not have permissions', async () => { - const services = makeDefaultServices(sessionIdSubject); + const services = makeDefaultServices(); services.application = { ...services.application, capabilities: { @@ -394,36 +639,36 @@ describe('Lens App', () => { visualize: { save: false, saveQuery: false, show: true }, }, }; - const { instance, lensStore } = await mountWith({ services }); - expect(getButton(instance).disableButton).toEqual(true); - act(() => { - lensStore.dispatch( - setState({ - lastKnownDoc: ({ savedObjectId: 'will save this' } as unknown) as Document, - isSaveable: true, - }) - ); - }); - instance.update(); - expect(getButton(instance).disableButton).toEqual(true); + const { component, frame } = mountWith({ services }); + expect(getButton(component).disableButton).toEqual(true); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + act(() => + onChange({ + filterableIndexPatterns: [], + doc: ({ savedObjectId: 'will save this' } as unknown) as Document, + isSaveable: true, + }) + ); + component.update(); + expect(getButton(component).disableButton).toEqual(true); }); it('shows a save button that is enabled when the frame has provided its state and does not show save and return or save as', async () => { - const { instance, lensStore, services } = await mountWith({}); - expect(getButton(instance).disableButton).toEqual(true); - act(() => { - lensStore.dispatch( - setState({ - isSaveable: true, - lastKnownDoc: ({ savedObjectId: 'will save this' } as unknown) as Document, - }) - ); - }); - instance.update(); - expect(getButton(instance).disableButton).toEqual(false); + const { component, frame } = mountWith({}); + expect(getButton(component).disableButton).toEqual(true); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + act(() => + onChange({ + filterableIndexPatterns: [], + doc: ({ savedObjectId: 'will save this' } as unknown) as Document, + isSaveable: true, + }) + ); + component.update(); + expect(getButton(component).disableButton).toEqual(false); await act(async () => { - const topNavMenuConfig = instance.find(services.navigation.ui.TopNavMenu).prop('config'); + const topNavMenuConfig = component.find(TopNavMenu).prop('config'); expect(topNavMenuConfig).not.toContainEqual( expect.objectContaining(navMenuItems.expectedSaveAndReturnButton) ); @@ -438,7 +683,7 @@ describe('Lens App', () => { it('Shows Save and Return and Save As buttons in create by value mode with originating app', async () => { const props = makeDefaultProps(); - const services = makeDefaultServices(sessionIdSubject); + const services = makeDefaultServices(); services.dashboardFeatureFlag = { allowByValueEmbeddables: true }; props.incomingState = { originatingApp: 'ultraDashboard', @@ -452,16 +697,10 @@ describe('Lens App', () => { } as LensByValueInput, }; - const { instance } = await mountWith({ - props, - services, - storePreloadedState: { - isLinkedToOriginatingApp: true, - }, - }); + const { component } = mountWith({ props, services }); await act(async () => { - const topNavMenuConfig = instance.find(services.navigation.ui.TopNavMenu).prop('config'); + const topNavMenuConfig = component.find(TopNavMenu).prop('config'); expect(topNavMenuConfig).toContainEqual( expect.objectContaining(navMenuItems.expectedSaveAndReturnButton) ); @@ -481,15 +720,10 @@ describe('Lens App', () => { originatingApp: 'ultraDashboard', }; - const { instance, services } = await mountWith({ - props, - storePreloadedState: { - isLinkedToOriginatingApp: true, - }, - }); + const { component } = mountWith({ props }); await act(async () => { - const topNavMenuConfig = instance.find(services.navigation.ui.TopNavMenu).prop('config'); + const topNavMenuConfig = component.find(TopNavMenu).prop('config'); expect(topNavMenuConfig).toContainEqual( expect.objectContaining(navMenuItems.expectedSaveAndReturnButton) ); @@ -536,7 +770,7 @@ describe('Lens App', () => { }); it('saves the latest doc as a copy', async () => { - const { props, services, instance } = await save({ + const { props, services, component } = await save({ initialSavedObjectId: defaultSavedObjectId, newCopyOnSave: true, newTitle: 'hello there', @@ -550,7 +784,7 @@ describe('Lens App', () => { ); expect(props.redirectTo).toHaveBeenCalledWith(defaultSavedObjectId); await act(async () => { - instance.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); }); expect(services.attributeService.wrapAttributes).toHaveBeenCalledTimes(1); expect(services.notifications.toasts.addSuccess).toHaveBeenCalledWith( @@ -559,7 +793,7 @@ describe('Lens App', () => { }); it('saves existing docs', async () => { - const { props, services, instance, lensStore } = await save({ + const { props, services, component } = await save({ initialSavedObjectId: defaultSavedObjectId, newCopyOnSave: false, newTitle: 'hello there', @@ -574,51 +808,35 @@ describe('Lens App', () => { ); expect(props.redirectTo).not.toHaveBeenCalled(); await act(async () => { - instance.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); }); - - expect(lensStore.dispatch).toHaveBeenCalledWith({ - payload: { - lastKnownDoc: expect.objectContaining({ - savedObjectId: defaultSavedObjectId, - title: 'hello there', - }), - persistedDoc: expect.objectContaining({ - savedObjectId: defaultSavedObjectId, - title: 'hello there', - }), - isLinkedToOriginatingApp: false, - }, - type: 'app/setState', - }); - + expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(1); expect(services.notifications.toasts.addSuccess).toHaveBeenCalledWith( "Saved 'hello there'" ); }); it('handles save failure by showing a warning, but still allows another save', async () => { - const services = makeDefaultServices(sessionIdSubject); + const services = makeDefaultServices(); services.attributeService.wrapAttributes = jest .fn() .mockRejectedValue({ message: 'failed' }); - const { instance, props, lensStore } = await mountWith({ services }); - act(() => { - lensStore.dispatch( - setState({ - isSaveable: true, - lastKnownDoc: ({ id: undefined } as unknown) as Document, - }) - ); - }); - - instance.update(); + const { component, props, frame } = mountWith({ services }); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + act(() => + onChange({ + filterableIndexPatterns: [], + doc: ({ id: undefined } as unknown) as Document, + isSaveable: true, + }) + ); + component.update(); await act(async () => { - testSave(instance, { newCopyOnSave: false, newTitle: 'hello there' }); + testSave(component, { newCopyOnSave: false, newTitle: 'hello there' }); }); expect(props.redirectTo).not.toHaveBeenCalled(); - expect(getButton(instance).disableButton).toEqual(false); + expect(getButton(component).disableButton).toEqual(false); }); it('saves new doc and redirects to originating app', async () => { @@ -677,29 +895,28 @@ describe('Lens App', () => { }); it('checks for duplicate title before saving', async () => { - const services = makeDefaultServices(sessionIdSubject); + const services = makeDefaultServices(); services.attributeService.wrapAttributes = jest .fn() .mockReturnValue(Promise.resolve({ savedObjectId: '123' })); - const { instance, lensStore } = await mountWith({ services }); - await act(async () => { - lensStore.dispatch( - setState({ - isSaveable: true, - lastKnownDoc: ({ savedObjectId: '123' } as unknown) as Document, - }) - ); - }); - - instance.update(); + const { component, frame } = mountWith({ services }); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + await act(async () => + onChange({ + filterableIndexPatterns: [], + doc: ({ savedObjectId: '123' } as unknown) as Document, + isSaveable: true, + }) + ); + component.update(); await act(async () => { - instance.setProps({ initialInput: { savedObjectId: '123' } }); - getButton(instance).run(instance.getDOMNode()); + component.setProps({ initialInput: { savedObjectId: '123' } }); + getButton(component).run(component.getDOMNode()); }); - instance.update(); + component.update(); const onTitleDuplicate = jest.fn(); await act(async () => { - instance.find(SavedObjectSaveModal).prop('onSave')({ + component.find(SavedObjectSaveModal).prop('onSave')({ onTitleDuplicate, isTitleDuplicateConfirmed: false, newCopyOnSave: false, @@ -716,20 +933,19 @@ describe('Lens App', () => { }); it('does not show the copy button on first save', async () => { - const { instance, lensStore } = await mountWith({}); - await act(async () => { - lensStore.dispatch( - setState({ - isSaveable: true, - lastKnownDoc: ({} as unknown) as Document, - }) - ); - }); - - instance.update(); - await act(async () => getButton(instance).run(instance.getDOMNode())); - instance.update(); - expect(instance.find(SavedObjectSaveModal).prop('showCopyOnSave')).toEqual(false); + const { component, frame } = mountWith({}); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + await act(async () => + onChange({ + filterableIndexPatterns: [], + doc: ({} as unknown) as Document, + isSaveable: true, + }) + ); + component.update(); + await act(async () => getButton(component).run(component.getDOMNode())); + component.update(); + expect(component.find(SavedObjectSaveModal).prop('showCopyOnSave')).toEqual(false); }); }); }); @@ -744,38 +960,38 @@ describe('Lens App', () => { } it('should be disabled when no data is available', async () => { - const { instance, lensStore } = await mountWith({}); - await act(async () => { - lensStore.dispatch( - setState({ - isSaveable: true, - lastKnownDoc: ({} as unknown) as Document, - }) - ); - }); - instance.update(); - expect(getButton(instance).disableButton).toEqual(true); + const { component, frame } = mountWith({}); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + await act(async () => + onChange({ + filterableIndexPatterns: [], + doc: ({} as unknown) as Document, + isSaveable: true, + }) + ); + component.update(); + expect(getButton(component).disableButton).toEqual(true); }); it('should disable download when not saveable', async () => { - const { instance, lensStore } = await mountWith({}); - - await act(async () => { - lensStore.dispatch( - setState({ - lastKnownDoc: ({} as unknown) as Document, - isSaveable: false, - activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, - }) - ); - }); + const { component, frame } = mountWith({}); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + + await act(async () => + onChange({ + filterableIndexPatterns: [], + doc: ({} as unknown) as Document, + isSaveable: false, + activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, + }) + ); - instance.update(); - expect(getButton(instance).disableButton).toEqual(true); + component.update(); + expect(getButton(component).disableButton).toEqual(true); }); it('should still be enabled even if the user is missing save permissions', async () => { - const services = makeDefaultServices(sessionIdSubject); + const services = makeDefaultServices(); services.application = { ...services.application, capabilities: { @@ -784,63 +1000,59 @@ describe('Lens App', () => { }, }; - const { instance, lensStore } = await mountWith({ services }); - await act(async () => { - lensStore.dispatch( - setState({ - lastKnownDoc: ({} as unknown) as Document, - isSaveable: true, - activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, - }) - ); - }); - instance.update(); - expect(getButton(instance).disableButton).toEqual(false); + const { component, frame } = mountWith({ services }); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + await act(async () => + onChange({ + filterableIndexPatterns: [], + doc: ({} as unknown) as Document, + isSaveable: true, + activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, + }) + ); + component.update(); + expect(getButton(component).disableButton).toEqual(false); }); }); describe('query bar state management', () => { - it('uses the default time and query language settings', async () => { - const { lensStore, services } = await mountWith({}); - expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( + it('uses the default time and query language settings', () => { + const { frame } = mountWith({}); + expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ - query: { query: '', language: 'lucene' }, + query: { query: '', language: 'kuery' }, dateRangeFrom: 'now-7d', dateRangeTo: 'now', }), {} ); - - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ - query: { query: '', language: 'lucene' }, - resolvedDateRange: { - fromDate: '2021-01-10T04:00:00.000Z', - toDate: '2021-01-10T08:00:00.000Z', - }, + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ + dateRange: { fromDate: '2021-01-10T04:00:00.000Z', toDate: '2021-01-10T08:00:00.000Z' }, + query: { query: '', language: 'kuery' }, }), - }); + {} + ); }); it('updates the index patterns when the editor frame is changed', async () => { - const { instance, lensStore, services } = await mountWith({}); - expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( + const { component, frame } = mountWith({}); + expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ indexPatterns: [], }), {} ); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; await act(async () => { - lensStore.dispatch( - setState({ - indexPatternsForTopNav: [{ id: '1' }] as IndexPattern[], - lastKnownDoc: ({} as unknown) as Document, - isSaveable: true, - }) - ); + onChange({ + filterableIndexPatterns: ['1'], + doc: ({ id: undefined } as unknown) as Document, + isSaveable: true, + }); }); - instance.update(); - expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( + component.update(); + expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ indexPatterns: [{ id: '1' }], }), @@ -848,16 +1060,14 @@ describe('Lens App', () => { ); // Do it again to verify that the dirty checking is done right await act(async () => { - lensStore.dispatch( - setState({ - indexPatternsForTopNav: [{ id: '2' }] as IndexPattern[], - lastKnownDoc: ({} as unknown) as Document, - isSaveable: true, - }) - ); + onChange({ + filterableIndexPatterns: ['2'], + doc: ({ id: undefined } as unknown) as Document, + isSaveable: true, + }); }); - instance.update(); - expect(services.navigation.ui.TopNavMenu).toHaveBeenLastCalledWith( + component.update(); + expect(TopNavMenu).toHaveBeenLastCalledWith( expect.objectContaining({ indexPatterns: [{ id: '2' }], }), @@ -865,20 +1075,20 @@ describe('Lens App', () => { ); }); - it('updates the editor frame when the user changes query or time in the search bar', async () => { - const { instance, services, lensStore } = await mountWith({}); + it('updates the editor frame when the user changes query or time in the search bar', () => { + const { component, frame, services } = mountWith({}); (services.data.query.timefilter.timefilter.calculateBounds as jest.Mock).mockReturnValue({ min: moment('2021-01-09T04:00:00.000Z'), max: moment('2021-01-09T08:00:00.000Z'), }); act(() => - instance.find(services.navigation.ui.TopNavMenu).prop('onQuerySubmit')!({ + component.find(TopNavMenu).prop('onQuerySubmit')!({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) ); - instance.update(); - expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( + component.update(); + expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: { query: 'new', language: 'lucene' }, dateRangeFrom: 'now-14d', @@ -890,75 +1100,64 @@ describe('Lens App', () => { from: 'now-14d', to: 'now-7d', }); - - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ + dateRange: { fromDate: '2021-01-09T04:00:00.000Z', toDate: '2021-01-09T08:00:00.000Z' }, query: { query: 'new', language: 'lucene' }, - resolvedDateRange: { - fromDate: '2021-01-09T04:00:00.000Z', - toDate: '2021-01-09T08:00:00.000Z', - }, }), - }); + {} + ); }); - it('updates the filters when the user changes them', async () => { - const { instance, services, lensStore } = await mountWith({}); + it('updates the filters when the user changes them', () => { + const { component, frame, services } = mountWith({}); const indexPattern = ({ id: 'index1' } as unknown) as IIndexPattern; const field = ({ name: 'myfield' } as unknown) as IFieldType; - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ - filters: [], - }), - }); act(() => services.data.query.filterManager.setFilters([ esFilters.buildExistsFilter(field, indexPattern), ]) ); - instance.update(); - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ + component.update(); + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ filters: [esFilters.buildExistsFilter(field, indexPattern)], }), - }); + {} + ); }); - it('updates the searchSessionId when the user changes query or time in the search bar', async () => { - const { instance, services, lensStore } = await mountWith({}); - - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ - searchSessionId: `sessionId-1`, - }), - }); - + it('updates the searchSessionId when the user changes query or time in the search bar', () => { + const { component, frame, services } = mountWith({}); act(() => - instance.find(services.navigation.ui.TopNavMenu).prop('onQuerySubmit')!({ + component.find(TopNavMenu).prop('onQuerySubmit')!({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: '', language: 'lucene' }, }) ); - instance.update(); - - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ - searchSessionId: `sessionId-2`, + component.update(); + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ + searchSessionId: `sessionId-1`, }), - }); + {} + ); + // trigger again, this time changing just the query act(() => - instance.find(services.navigation.ui.TopNavMenu).prop('onQuerySubmit')!({ + component.find(TopNavMenu).prop('onQuerySubmit')!({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) ); - instance.update(); - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ - searchSessionId: `sessionId-3`, + component.update(); + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ + searchSessionId: `sessionId-2`, }), - }); + {} + ); + const indexPattern = ({ id: 'index1' } as unknown) as IIndexPattern; const field = ({ name: 'myfield' } as unknown) as IFieldType; act(() => @@ -966,18 +1165,19 @@ describe('Lens App', () => { esFilters.buildExistsFilter(field, indexPattern), ]) ); - instance.update(); - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ - searchSessionId: `sessionId-4`, + component.update(); + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ + searchSessionId: `sessionId-3`, }), - }); + {} + ); }); }); describe('saved query handling', () => { - it('does not allow saving when the user is missing the saveQuery permission', async () => { - const services = makeDefaultServices(sessionIdSubject); + it('does not allow saving when the user is missing the saveQuery permission', () => { + const services = makeDefaultServices(); services.application = { ...services.application, capabilities: { @@ -985,16 +1185,16 @@ describe('Lens App', () => { visualize: { save: false, saveQuery: false, show: true }, }, }; - await mountWith({ services }); - expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( + mountWith({ services }); + expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ showSaveQuery: false }), {} ); }); - it('persists the saved query ID when the query is saved', async () => { - const { instance, services } = await mountWith({}); - expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( + it('persists the saved query ID when the query is saved', () => { + const { component } = mountWith({}); + expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ showSaveQuery: true, savedQuery: undefined, @@ -1005,7 +1205,7 @@ describe('Lens App', () => { {} ); act(() => { - instance.find(services.navigation.ui.TopNavMenu).prop('onSaved')!({ + component.find(TopNavMenu).prop('onSaved')!({ id: '1', attributes: { title: '', @@ -1014,7 +1214,7 @@ describe('Lens App', () => { }, }); }); - expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( + expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ savedQuery: { id: '1', @@ -1029,10 +1229,10 @@ describe('Lens App', () => { ); }); - it('changes the saved query ID when the query is updated', async () => { - const { instance, services } = await mountWith({}); + it('changes the saved query ID when the query is updated', () => { + const { component } = mountWith({}); act(() => { - instance.find(services.navigation.ui.TopNavMenu).prop('onSaved')!({ + component.find(TopNavMenu).prop('onSaved')!({ id: '1', attributes: { title: '', @@ -1042,7 +1242,7 @@ describe('Lens App', () => { }); }); act(() => { - instance.find(services.navigation.ui.TopNavMenu).prop('onSavedQueryUpdated')!({ + component.find(TopNavMenu).prop('onSavedQueryUpdated')!({ id: '2', attributes: { title: 'new title', @@ -1051,7 +1251,7 @@ describe('Lens App', () => { }, }); }); - expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( + expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ savedQuery: { id: '2', @@ -1066,10 +1266,10 @@ describe('Lens App', () => { ); }); - it('updates the query if saved query is selected', async () => { - const { instance, services } = await mountWith({}); + it('updates the query if saved query is selected', () => { + const { component } = mountWith({}); act(() => { - instance.find(services.navigation.ui.TopNavMenu).prop('onSavedQueryUpdated')!({ + component.find(TopNavMenu).prop('onSavedQueryUpdated')!({ id: '2', attributes: { title: 'new title', @@ -1078,7 +1278,7 @@ describe('Lens App', () => { }, }); }); - expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( + expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: { query: 'abc:def', language: 'lucene' }, }), @@ -1086,10 +1286,10 @@ describe('Lens App', () => { ); }); - it('clears all existing unpinned filters when the active saved query is cleared', async () => { - const { instance, services, lensStore } = await mountWith({}); + it('clears all existing unpinned filters when the active saved query is cleared', () => { + const { component, frame, services } = mountWith({}); act(() => - instance.find(services.navigation.ui.TopNavMenu).prop('onQuerySubmit')!({ + component.find(TopNavMenu).prop('onQuerySubmit')!({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) @@ -1101,22 +1301,23 @@ describe('Lens App', () => { const pinned = esFilters.buildExistsFilter(pinnedField, indexPattern); FilterManager.setFiltersStore([pinned], esFilters.FilterStateStore.GLOBAL_STATE); act(() => services.data.query.filterManager.setFilters([pinned, unpinned])); - instance.update(); - act(() => instance.find(services.navigation.ui.TopNavMenu).prop('onClearSavedQuery')!()); - instance.update(); - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ + component.update(); + act(() => component.find(TopNavMenu).prop('onClearSavedQuery')!()); + component.update(); + expect(frame.EditorFrameContainer).toHaveBeenLastCalledWith( + expect.objectContaining({ filters: [pinned], }), - }); + {} + ); }); }); describe('search session id management', () => { - it('updates the searchSessionId when the query is updated', async () => { - const { instance, lensStore, services } = await mountWith({}); + it('updates the searchSessionId when the query is updated', () => { + const { component, frame } = mountWith({}); act(() => { - instance.find(services.navigation.ui.TopNavMenu).prop('onSaved')!({ + component.find(TopNavMenu).prop('onSaved')!({ id: '1', attributes: { title: '', @@ -1126,7 +1327,7 @@ describe('Lens App', () => { }); }); act(() => { - instance.find(services.navigation.ui.TopNavMenu).prop('onSavedQueryUpdated')!({ + component.find(TopNavMenu).prop('onSavedQueryUpdated')!({ id: '2', attributes: { title: 'new title', @@ -1135,18 +1336,37 @@ describe('Lens App', () => { }, }); }); - instance.update(); - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ + component.update(); + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ searchSessionId: `sessionId-2`, }), + {} + ); + }); + + it('re-renders the frame if session id changes from the outside', async () => { + const services = makeDefaultServices(); + const { frame } = mountWith({ props: undefined, services }); + + act(() => { + sessionIdSubject.next('new-session-id'); + }); + await act(async () => { + await new Promise((r) => setTimeout(r, 0)); }); + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ + searchSessionId: `new-session-id`, + }), + {} + ); }); - it('updates the searchSessionId when the active saved query is cleared', async () => { - const { instance, services, lensStore } = await mountWith({}); + it('updates the searchSessionId when the active saved query is cleared', () => { + const { component, frame, services } = mountWith({}); act(() => - instance.find(services.navigation.ui.TopNavMenu).prop('onQuerySubmit')!({ + component.find(TopNavMenu).prop('onQuerySubmit')!({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) @@ -1158,14 +1378,15 @@ describe('Lens App', () => { const pinned = esFilters.buildExistsFilter(pinnedField, indexPattern); FilterManager.setFiltersStore([pinned], esFilters.FilterStateStore.GLOBAL_STATE); act(() => services.data.query.filterManager.setFilters([pinned, unpinned])); - instance.update(); - act(() => instance.find(services.navigation.ui.TopNavMenu).prop('onClearSavedQuery')!()); - instance.update(); - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ - searchSessionId: `sessionId-4`, + component.update(); + act(() => component.find(TopNavMenu).prop('onClearSavedQuery')!()); + component.update(); + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ + searchSessionId: `sessionId-2`, }), - }); + {} + ); }); const mockUpdate = { @@ -1186,39 +1407,70 @@ describe('Lens App', () => { activeData: undefined, }; - it('updates the state if session id changes from the outside', async () => { - const services = makeDefaultServices(sessionIdSubject); - const { lensStore } = await mountWith({ props: undefined, services }); - + it('does not update the searchSessionId when the state changes', () => { + const { component, frame } = mountWith({}); act(() => { - sessionIdSubject.next('new-session-id'); + component.find(frame.EditorFrameContainer).prop('onChange')(mockUpdate); }); - await act(async () => { - await new Promise((r) => setTimeout(r, 0)); - }); - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ - searchSessionId: `new-session-id`, + component.update(); + expect(frame.EditorFrameContainer).not.toHaveBeenCalledWith( + expect.objectContaining({ + searchSessionId: `sessionId-2`, }), - }); + {} + ); }); - it('does not update the searchSessionId when the state changes', async () => { - const { lensStore } = await mountWith({}); + it('does update the searchSessionId when the state changes and too much time passed', () => { + const { component, frame, services } = mountWith({}); + + // time range is 100,000ms ago to 30,000ms ago (that's a lag of 30 percent) + (services.data.nowProvider.get as jest.Mock).mockReturnValue(new Date(Date.now() - 30000)); + (services.data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({ + from: 'now-2m', + to: 'now', + }); + (services.data.query.timefilter.timefilter.getBounds as jest.Mock).mockReturnValue({ + min: moment(Date.now() - 100000), + max: moment(Date.now() - 30000), + }); + act(() => { - lensStore.dispatch( - setState({ - indexPatternsForTopNav: [], - lastKnownDoc: mockUpdate.doc, - isSaveable: true, - }) - ); + component.find(frame.EditorFrameContainer).prop('onChange')(mockUpdate); }); - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ - searchSessionId: `sessionId-1`, + component.update(); + expect(frame.EditorFrameContainer).toHaveBeenCalledWith( + expect.objectContaining({ + searchSessionId: `sessionId-2`, }), + {} + ); + }); + + it('does not update the searchSessionId when the state changes and too little time has passed', () => { + const { component, frame, services } = mountWith({}); + + // time range is 100,000ms ago to 300ms ago (that's a lag of .3 percent, not enough to trigger a session update) + (services.data.nowProvider.get as jest.Mock).mockReturnValue(new Date(Date.now() - 300)); + (services.data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({ + from: 'now-2m', + to: 'now', }); + (services.data.query.timefilter.timefilter.getBounds as jest.Mock).mockReturnValue({ + min: moment(Date.now() - 100000), + max: moment(Date.now() - 300), + }); + + act(() => { + component.find(frame.EditorFrameContainer).prop('onChange')(mockUpdate); + }); + component.update(); + expect(frame.EditorFrameContainer).not.toHaveBeenCalledWith( + expect.objectContaining({ + searchSessionId: `sessionId-2`, + }), + {} + ); }); }); @@ -1231,16 +1483,16 @@ describe('Lens App', () => { confirmLeave = jest.fn(); }); - it('should not show a confirm message if there is no expression to save', async () => { - const { props } = await mountWith({}); + it('should not show a confirm message if there is no expression to save', () => { + const { props } = mountWith({}); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(defaultLeave).toHaveBeenCalled(); expect(confirmLeave).not.toHaveBeenCalled(); }); - it('does not confirm if the user is missing save permissions', async () => { - const services = makeDefaultServices(sessionIdSubject); + it('does not confirm if the user is missing save permissions', () => { + const services = makeDefaultServices(); services.application = { ...services.application, capabilities: { @@ -1248,36 +1500,36 @@ describe('Lens App', () => { visualize: { save: false, saveQuery: false, show: true }, }, }; - const { instance, props, lensStore } = await mountWith({ services }); - act(() => { - lensStore.dispatch( - setState({ - indexPatternsForTopNav: [] as IndexPattern[], - lastKnownDoc: ({ - savedObjectId: undefined, - references: [], - } as unknown) as Document, - isSaveable: true, - }) - ); - }); - instance.update(); + const { component, frame, props } = mountWith({ services }); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + act(() => + onChange({ + filterableIndexPatterns: [], + doc: ({ + savedObjectId: undefined, + references: [], + } as unknown) as Document, + isSaveable: true, + }) + ); + component.update(); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(defaultLeave).toHaveBeenCalled(); expect(confirmLeave).not.toHaveBeenCalled(); }); - it('should confirm when leaving with an unsaved doc', async () => { - const { lensStore, props } = await mountWith({}); - act(() => { - lensStore.dispatch( - setState({ - lastKnownDoc: ({ savedObjectId: undefined, state: {} } as unknown) as Document, - isSaveable: true, - }) - ); - }); + it('should confirm when leaving with an unsaved doc', () => { + const { component, frame, props } = mountWith({}); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + act(() => + onChange({ + filterableIndexPatterns: [], + doc: ({ savedObjectId: undefined, state: {} } as unknown) as Document, + isSaveable: true, + }) + ); + component.update(); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(confirmLeave).toHaveBeenCalled(); @@ -1285,19 +1537,22 @@ describe('Lens App', () => { }); it('should confirm when leaving with unsaved changes to an existing doc', async () => { - const { lensStore, props } = await mountWith({}); - act(() => { - lensStore.dispatch( - setState({ - persistedDoc: defaultDoc, - lastKnownDoc: ({ - savedObjectId: defaultSavedObjectId, - references: [], - } as unknown) as Document, - isSaveable: true, - }) - ); + const { component, frame, props } = mountWith({}); + await act(async () => { + component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); }); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + act(() => + onChange({ + filterableIndexPatterns: [], + doc: ({ + savedObjectId: defaultSavedObjectId, + references: [], + } as unknown) as Document, + isSaveable: true, + }) + ); + component.update(); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(confirmLeave).toHaveBeenCalled(); @@ -1305,16 +1560,19 @@ describe('Lens App', () => { }); it('should not confirm when changes are saved', async () => { - const { lensStore, props } = await mountWith({}); - act(() => { - lensStore.dispatch( - setState({ - lastKnownDoc: defaultDoc, - persistedDoc: defaultDoc, - isSaveable: true, - }) - ); + const { component, frame, props } = mountWith({}); + await act(async () => { + component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); }); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + act(() => + onChange({ + filterableIndexPatterns: [], + doc: defaultDoc, + isSaveable: true, + }) + ); + component.update(); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(defaultLeave).toHaveBeenCalled(); @@ -1322,19 +1580,19 @@ describe('Lens App', () => { }); it('should confirm when the latest doc is invalid', async () => { - const { lensStore, props } = await mountWith({}); - act(() => { - lensStore.dispatch( - setState({ - persistedDoc: defaultDoc, - lastKnownDoc: ({ - savedObjectId: defaultSavedObjectId, - references: [], - } as unknown) as Document, - isSaveable: true, - }) - ); + const { component, frame, props } = mountWith({}); + await act(async () => { + component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); }); + const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + act(() => + onChange({ + filterableIndexPatterns: [], + doc: ({ savedObjectId: defaultSavedObjectId, references: [] } as unknown) as Document, + isSaveable: true, + }) + ); + component.update(); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(confirmLeave).toHaveBeenCalled(); diff --git a/x-pack/plugins/lens/public/app_plugin/app.tsx b/x-pack/plugins/lens/public/app_plugin/app.tsx index 61ed2934a40011e..c172f36913c2178 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.tsx @@ -7,38 +7,49 @@ import './app.scss'; -import { isEqual, partition } from 'lodash'; -import React, { useState, useEffect, useCallback } from 'react'; +import _ from 'lodash'; +import React, { useState, useEffect, useCallback, useRef } from 'react'; import { i18n } from '@kbn/i18n'; import { Toast } from 'kibana/public'; import { VisualizeFieldContext } from 'src/plugins/ui_actions/public'; +import { Datatable } from 'src/plugins/expressions/public'; import { EuiBreadcrumb } from '@elastic/eui'; +import { delay, finalize, switchMap, tap } from 'rxjs/operators'; +import { downloadMultipleAs } from '../../../../../src/plugins/share/public'; import { createKbnUrlStateStorage, withNotifyOnErrors, } from '../../../../../src/plugins/kibana_utils/public'; import { useKibana } from '../../../../../src/plugins/kibana_react/public'; -import { checkForDuplicateTitle } from '../../../../../src/plugins/saved_objects/public'; +import { + OnSaveProps, + checkForDuplicateTitle, +} from '../../../../../src/plugins/saved_objects/public'; import { injectFilterReferences } from '../persistence'; import { trackUiEvent } from '../lens_ui_telemetry'; -import { esFilters, syncQueryStateWithUrl } from '../../../../../src/plugins/data/public'; -import { getFullPath, APP_ID } from '../../common'; -import { LensAppProps, LensAppServices, RunSave } from './types'; -import { LensTopNavMenu } from './lens_top_nav'; +import { + DataPublicPluginStart, + esFilters, + exporters, + Filter, + IndexPattern as IndexPatternInstance, + IndexPatternsContract, + Query, + SavedQuery, + syncQueryStateWithUrl, + waitUntilNextSessionCompletes$, +} from '../../../../../src/plugins/data/public'; +import { LENS_EMBEDDABLE_TYPE, getFullPath, APP_ID } from '../../common'; +import { LensAppProps, LensAppServices, LensAppState } from './types'; +import { getLensTopNavConfig } from './lens_top_nav'; import { Document } from '../persistence'; import { SaveModal } from './save_modal'; import { LensByReferenceInput, LensEmbeddableInput, } from '../editor_frame_service/embeddable/embeddable'; +import { useTimeRange } from './time_range'; import { EditorFrameInstance } from '../types'; -import { - setState as setAppState, - useLensSelector, - useLensDispatch, - LensAppState, - DispatchSetState, -} from '../state_management'; export function App({ history, @@ -56,6 +67,7 @@ export function App({ data, chrome, overlays, + navigation, uiSettings, application, stateTransfer, @@ -69,18 +81,29 @@ export function App({ dashboardFeatureFlag, } = useKibana().services; - const dispatch = useLensDispatch(); - const dispatchSetState: DispatchSetState = useCallback( - (state: Partial) => dispatch(setAppState(state)), - [dispatch] - ); - - const appState = useLensSelector((state) => state.app); + const startSession = useCallback(() => data.search.session.start(), [data.search.session]); + + const [state, setState] = useState(() => { + return { + query: data.query.queryString.getQuery(), + // Do not use app-specific filters from previous app, + // only if Lens was opened with the intention to visualize a field (e.g. coming from Discover) + filters: !initialContext + ? data.query.filterManager.getGlobalFilters() + : data.query.filterManager.getFilters(), + isLoading: Boolean(initialInput), + indexPatternsForTopNav: [], + isLinkedToOriginatingApp: Boolean(incomingState?.originatingApp), + isSaveable: false, + searchSessionId: startSession(), + }; + }); // Used to show a popover that guides the user towards changing the date range when no data is available. const [indicateNoData, setIndicateNoData] = useState(false); const [isSaveModalVisible, setIsSaveModalVisible] = useState(false); - const { lastKnownDoc } = appState; + + const { lastKnownDoc } = state; const showNoDataPopover = useCallback(() => { setIndicateNoData(true); @@ -93,10 +116,19 @@ export function App({ }, [ setIndicateNoData, indicateNoData, - appState.indexPatternsForTopNav, - appState.searchSessionId, + state.query, + state.filters, + state.indexPatternsForTopNav, + state.searchSessionId, ]); + const { resolvedDateRange, from: fromDate, to: toDate } = useTimeRange( + data, + state.lastKnownDoc, + setState, + state.searchSessionId + ); + const onError = useCallback( (e: { message: string }) => notifications.toasts.addDanger({ @@ -110,13 +142,56 @@ export function App({ Boolean( // Temporarily required until the 'by value' paradigm is default. dashboardFeatureFlag.allowByValueEmbeddables && - appState.isLinkedToOriginatingApp && + state.isLinkedToOriginatingApp && !(initialInput as LensByReferenceInput)?.savedObjectId ), - [dashboardFeatureFlag.allowByValueEmbeddables, appState.isLinkedToOriginatingApp, initialInput] + [dashboardFeatureFlag.allowByValueEmbeddables, state.isLinkedToOriginatingApp, initialInput] ); useEffect(() => { + // Clear app-specific filters when navigating to Lens. Necessary because Lens + // can be loaded without a full page refresh. If the user navigates to Lens from Discover + // we keep the filters + if (!initialContext) { + data.query.filterManager.setAppFilters([]); + } + + const filterSubscription = data.query.filterManager.getUpdates$().subscribe({ + next: () => { + setState((s) => ({ + ...s, + filters: data.query.filterManager.getFilters(), + searchSessionId: startSession(), + })); + trackUiEvent('app_filters_updated'); + }, + }); + + const timeSubscription = data.query.timefilter.timefilter.getTimeUpdate$().subscribe({ + next: () => { + setState((s) => ({ + ...s, + searchSessionId: startSession(), + })); + }, + }); + + const autoRefreshSubscription = data.query.timefilter.timefilter + .getAutoRefreshFetch$() + .pipe( + tap(() => { + setState((s) => ({ + ...s, + searchSessionId: startSession(), + })); + }), + switchMap((done) => + // best way in lens to estimate that all panels are updated is to rely on search session service state + waitUntilNextSessionCompletes$(data.search.session).pipe(finalize(done)) + ) + ) + .subscribe(); + const kbnUrlStateStorage = createKbnUrlStateStorage({ history, useHash: uiSettings.get('state:storeInSessionStorage'), @@ -127,10 +202,41 @@ export function App({ kbnUrlStateStorage ); + const sessionSubscription = data.search.session + .getSession$() + // wait for a tick to filter/timerange subscribers the chance to update the session id in the state + .pipe(delay(0)) + // then update if it didn't get updated yet + .subscribe((newSessionId) => { + if (newSessionId) { + setState((prevState) => { + if (prevState.searchSessionId !== newSessionId) { + return { ...prevState, searchSessionId: newSessionId }; + } else { + return prevState; + } + }); + } + }); + return () => { stopSyncingQueryServiceStateWithUrl(); + filterSubscription.unsubscribe(); + timeSubscription.unsubscribe(); + autoRefreshSubscription.unsubscribe(); + sessionSubscription.unsubscribe(); }; - }, [data.search.session, notifications.toasts, uiSettings, data.query, history]); + }, [ + data.query.filterManager, + data.query.timefilter.timefilter, + data.search.session, + notifications.toasts, + uiSettings, + data.query, + history, + initialContext, + startSession, + ]); useEffect(() => { onAppLeave((actions) => { @@ -138,11 +244,11 @@ export function App({ // or when the user has configured something without saving if ( application.capabilities.visualize.save && - !isEqual( - appState.persistedDoc?.state, + !_.isEqual( + state.persistedDoc?.state, getLastKnownDocWithoutPinnedFilters(lastKnownDoc)?.state ) && - (appState.isSaveable || appState.persistedDoc) + (state.isSaveable || state.persistedDoc) ) { return actions.confirm( i18n.translate('xpack.lens.app.unsavedWorkMessage', { @@ -159,8 +265,8 @@ export function App({ }, [ onAppLeave, lastKnownDoc, - appState.isSaveable, - appState.persistedDoc, + state.isSaveable, + state.persistedDoc, application.capabilities.visualize.save, ]); @@ -168,7 +274,7 @@ export function App({ useEffect(() => { const isByValueMode = getIsByValueMode(); const breadcrumbs: EuiBreadcrumb[] = []; - if (appState.isLinkedToOriginatingApp && getOriginatingAppName() && redirectToOrigin) { + if (state.isLinkedToOriginatingApp && getOriginatingAppName() && redirectToOrigin) { breadcrumbs.push({ onClick: () => { redirectToOrigin(); @@ -191,31 +297,113 @@ export function App({ let currentDocTitle = i18n.translate('xpack.lens.breadcrumbsCreate', { defaultMessage: 'Create', }); - if (appState.persistedDoc) { + if (state.persistedDoc) { currentDocTitle = isByValueMode ? i18n.translate('xpack.lens.breadcrumbsByValue', { defaultMessage: 'Edit visualization' }) - : appState.persistedDoc.title; + : state.persistedDoc.title; } breadcrumbs.push({ text: currentDocTitle }); chrome.setBreadcrumbs(breadcrumbs); }, [ dashboardFeatureFlag.allowByValueEmbeddables, + state.isLinkedToOriginatingApp, getOriginatingAppName, + state.persistedDoc, redirectToOrigin, getIsByValueMode, + initialInput, application, chrome, + ]); + + useEffect(() => { + if ( + !initialInput || + (attributeService.inputIsRefType(initialInput) && + initialInput.savedObjectId === state.persistedDoc?.savedObjectId) + ) { + return; + } + + setState((s) => ({ ...s, isLoading: true })); + attributeService + .unwrapAttributes(initialInput) + .then((attributes) => { + if (!initialInput) { + return; + } + const doc = { + ...initialInput, + ...attributes, + type: LENS_EMBEDDABLE_TYPE, + }; + + if (attributeService.inputIsRefType(initialInput)) { + chrome.recentlyAccessed.add( + getFullPath(initialInput.savedObjectId), + attributes.title, + initialInput.savedObjectId + ); + } + const indexPatternIds = _.uniq( + doc.references.filter(({ type }) => type === 'index-pattern').map(({ id }) => id) + ); + getAllIndexPatterns(indexPatternIds, data.indexPatterns) + .then(({ indexPatterns }) => { + // Don't overwrite any pinned filters + data.query.filterManager.setAppFilters( + injectFilterReferences(doc.state.filters, doc.references) + ); + setState((s) => ({ + ...s, + isLoading: false, + ...(!_.isEqual(state.persistedDoc, doc) ? { persistedDoc: doc } : null), + lastKnownDoc: doc, + query: doc.state.query, + indexPatternsForTopNav: indexPatterns, + })); + }) + .catch((e) => { + setState((s) => ({ ...s, isLoading: false })); + redirectTo(); + }); + }) + .catch((e) => { + setState((s) => ({ ...s, isLoading: false })); + notifications.toasts.addDanger( + i18n.translate('xpack.lens.app.docLoadingError', { + defaultMessage: 'Error loading saved document', + }) + ); + + redirectTo(); + }); + }, [ + notifications, + data.indexPatterns, + data.query.filterManager, initialInput, - appState.isLinkedToOriginatingApp, - appState.persistedDoc, + attributeService, + redirectTo, + chrome.recentlyAccessed, + state.persistedDoc, ]); const tagsIds = - appState.persistedDoc && savedObjectsTagging - ? savedObjectsTagging.ui.getTagIdsFromReferences(appState.persistedDoc.references) + state.persistedDoc && savedObjectsTagging + ? savedObjectsTagging.ui.getTagIdsFromReferences(state.persistedDoc.references) : []; - const runSave: RunSave = async (saveProps, options) => { + const runSave = async ( + saveProps: Omit & { + returnToOrigin: boolean; + dashboardId?: string | null; + onTitleDuplicate?: OnSaveProps['onTitleDuplicate']; + newDescription?: string; + newTags?: string[]; + }, + options: { saveToLibrary: boolean } + ) => { if (!lastKnownDoc) { return; } @@ -314,8 +502,10 @@ export function App({ docToSave.title, newInput.savedObjectId ); - - dispatchSetState({ isLinkedToOriginatingApp: false }); + setState((s) => ({ + ...s, + isLinkedToOriginatingApp: false, + })); setIsSaveModalVisible(false); // remove editor state so the connection is still broken after reload @@ -329,12 +519,12 @@ export function App({ ...docToSave, ...newInput, }; - - dispatchSetState({ - isLinkedToOriginatingApp: false, + setState((s) => ({ + ...s, persistedDoc: newDoc, lastKnownDoc: newDoc, - }); + isLinkedToOriginatingApp: false, + })); setIsSaveModalVisible(false); } catch (e) { @@ -345,37 +535,187 @@ export function App({ } }; + const lastKnownDocRef = useRef(state.lastKnownDoc); + lastKnownDocRef.current = state.lastKnownDoc; + + const activeDataRef = useRef(state.activeData); + activeDataRef.current = state.activeData; + + const { TopNavMenu } = navigation.ui; + const savingToLibraryPermitted = Boolean( - appState.isSaveable && application.capabilities.visualize.save + state.isSaveable && application.capabilities.visualize.save + ); + const savingToDashboardPermitted = Boolean( + state.isSaveable && application.capabilities.dashboard?.showWriteControls ); + const unsavedTitle = i18n.translate('xpack.lens.app.unsavedFilename', { + defaultMessage: 'unsaved', + }); + const topNavConfig = getLensTopNavConfig({ + showSaveAndReturn: Boolean( + state.isLinkedToOriginatingApp && + // Temporarily required until the 'by value' paradigm is default. + (dashboardFeatureFlag.allowByValueEmbeddables || Boolean(initialInput)) + ), + enableExportToCSV: Boolean( + state.isSaveable && state.activeData && Object.keys(state.activeData).length + ), + isByValueMode: getIsByValueMode(), + allowByValue: dashboardFeatureFlag.allowByValueEmbeddables, + showCancel: Boolean(state.isLinkedToOriginatingApp), + savingToLibraryPermitted, + savingToDashboardPermitted, + actions: { + exportToCSV: () => { + if (!state.activeData) { + return; + } + const datatables = Object.values(state.activeData); + const content = datatables.reduce>( + (memo, datatable, i) => { + // skip empty datatables + if (datatable) { + const postFix = datatables.length > 1 ? `-${i + 1}` : ''; + + memo[`${lastKnownDoc?.title || unsavedTitle}${postFix}.csv`] = { + content: exporters.datatableToCSV(datatable, { + csvSeparator: uiSettings.get('csv:separator', ','), + quoteValues: uiSettings.get('csv:quoteValues', true), + formatFactory: data.fieldFormats.deserialize, + }), + type: exporters.CSV_MIME_TYPE, + }; + } + return memo; + }, + {} + ); + if (content) { + downloadMultipleAs(content); + } + }, + saveAndReturn: () => { + if (savingToDashboardPermitted && lastKnownDoc) { + // disabling the validation on app leave because the document has been saved. + onAppLeave((actions) => { + return actions.default(); + }); + runSave( + { + newTitle: lastKnownDoc.title, + newCopyOnSave: false, + isTitleDuplicateConfirmed: false, + returnToOrigin: true, + }, + { + saveToLibrary: + (initialInput && attributeService.inputIsRefType(initialInput)) ?? false, + } + ); + } + }, + showSaveModal: () => { + if (savingToDashboardPermitted || savingToLibraryPermitted) { + setIsSaveModalVisible(true); + } + }, + cancel: () => { + if (redirectToOrigin) { + redirectToOrigin(); + } + }, + }, + }); + return ( <>
- { + const { dateRange, query } = payload; + const currentRange = data.query.timefilter.timefilter.getTime(); + if (dateRange.from !== currentRange.from || dateRange.to !== currentRange.to) { + data.query.timefilter.timefilter.setTime(dateRange); + trackUiEvent('app_date_change'); + } else { + // Query has changed, renew the session id. + // Time change will be picked up by the time subscription + setState((s) => ({ + ...s, + searchSessionId: startSession(), + })); + trackUiEvent('app_query_change'); + } + setState((s) => ({ + ...s, + query: query || s.query, + })); + }} + onSaved={(savedQuery) => { + setState((s) => ({ ...s, savedQuery })); + }} + onSavedQueryUpdated={(savedQuery) => { + const savedQueryFilters = savedQuery.attributes.filters || []; + const globalFilters = data.query.filterManager.getGlobalFilters(); + data.query.filterManager.setFilters([...globalFilters, ...savedQueryFilters]); + setState((s) => ({ + ...s, + savedQuery: { ...savedQuery }, // Shallow query for reference issues + query: savedQuery.attributes.query, + })); + }} + onClearSavedQuery={() => { + data.query.filterManager.setFilters(data.query.filterManager.getGlobalFilters()); + setState((s) => ({ + ...s, + savedQuery: undefined, + filters: data.query.filterManager.getGlobalFilters(), + query: data.query.queryString.getDefaultQuery(), + })); + }} + query={state.query} + dateRangeFrom={fromDate} + dateRangeTo={toDate} indicateNoData={indicateNoData} /> - {(!appState.isAppLoading || appState.persistedDoc) && ( + {(!state.isLoading || state.persistedDoc) && ( )}
Toast; showNoDataPopover: () => void; initialContext: VisualizeFieldContext | undefined; + setState: React.Dispatch>; + data: DataPublicPluginStart; + lastKnownDoc: React.MutableRefObject; + activeData: React.MutableRefObject | undefined>; }) { const { EditorFrameContainer } = editorFrame; return ( { + if (isSaveable !== oldIsSaveable) { + setState((s) => ({ ...s, isSaveable })); + } + if (!_.isEqual(persistedDoc, doc) && !_.isEqual(lastKnownDoc.current, doc)) { + setState((s) => ({ ...s, lastKnownDoc: doc })); + } + if (!_.isEqual(activeDataRef.current, activeData)) { + setState((s) => ({ ...s, activeData })); + } + + // Update the cached index patterns if the user made a change to any of them + if ( + indexPatternsForTopNav.length !== filterableIndexPatterns.length || + filterableIndexPatterns.some( + (id) => !indexPatternsForTopNav.find((indexPattern) => indexPattern.id === id) + ) + ) { + getAllIndexPatterns(filterableIndexPatterns, data.indexPatterns).then( + ({ indexPatterns }) => { + if (indexPatterns) { + setState((s) => ({ ...s, indexPatternsForTopNav: indexPatterns })); + } + } + ); + } + }} /> ); }); +export async function getAllIndexPatterns( + ids: string[], + indexPatternsService: IndexPatternsContract +): Promise<{ indexPatterns: IndexPatternInstance[]; rejectedIds: string[] }> { + const responses = await Promise.allSettled(ids.map((id) => indexPatternsService.get(id))); + const fullfilled = responses.filter( + (response): response is PromiseFulfilledResult => + response.status === 'fulfilled' + ); + const rejectedIds = responses + .map((_response, i) => ids[i]) + .filter((id, i) => responses[i].status === 'rejected'); + // return also the rejected ids in case we want to show something later on + return { indexPatterns: fullfilled.map((response) => response.value), rejectedIds }; +} + function getLastKnownDocWithoutPinnedFilters(doc?: Document) { if (!doc) return undefined; - const [pinnedFilters, appFilters] = partition( + const [pinnedFilters, appFilters] = _.partition( injectFilterReferences(doc.state?.filters || [], doc.references), esFilters.isFilterPinned ); diff --git a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx index 245e964bbd2e671..f90a21b2818d476 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx +++ b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx @@ -5,25 +5,11 @@ * 2.0. */ -import { isEqual } from 'lodash'; import { i18n } from '@kbn/i18n'; -import React from 'react'; import { TopNavMenuData } from '../../../../../src/plugins/navigation/public'; -import { LensAppServices, LensTopNavActions, LensTopNavMenuProps } from './types'; -import { downloadMultipleAs } from '../../../../../src/plugins/share/public'; -import { trackUiEvent } from '../lens_ui_telemetry'; -import { exporters } from '../../../../../src/plugins/data/public'; +import { LensTopNavActions } from './types'; -import { useKibana } from '../../../../../src/plugins/kibana_react/public'; -import { - setState as setAppState, - useLensSelector, - useLensDispatch, - LensAppState, - DispatchSetState, -} from '../state_management'; - -function getLensTopNavConfig(options: { +export function getLensTopNavConfig(options: { showSaveAndReturn: boolean; enableExportToCSV: boolean; showCancel: boolean; @@ -115,185 +101,6 @@ function getLensTopNavConfig(options: { }), }); } + return topNavMenu; } - -export const LensTopNavMenu = ({ - setHeaderActionMenu, - initialInput, - indicateNoData, - setIsSaveModalVisible, - getIsByValueMode, - runSave, - onAppLeave, - redirectToOrigin, -}: LensTopNavMenuProps) => { - const { - data, - navigation, - uiSettings, - application, - attributeService, - dashboardFeatureFlag, - } = useKibana().services; - - const dispatch = useLensDispatch(); - const dispatchSetState: DispatchSetState = React.useCallback( - (state: Partial) => dispatch(setAppState(state)), - [dispatch] - ); - - const { - isSaveable, - isLinkedToOriginatingApp, - indexPatternsForTopNav, - query, - lastKnownDoc, - activeData, - savedQuery, - } = useLensSelector((state) => state.app); - - const { TopNavMenu } = navigation.ui; - const { from, to } = data.query.timefilter.timefilter.getTime(); - - const savingToLibraryPermitted = Boolean(isSaveable && application.capabilities.visualize.save); - const savingToDashboardPermitted = Boolean( - isSaveable && application.capabilities.dashboard?.showWriteControls - ); - - const unsavedTitle = i18n.translate('xpack.lens.app.unsavedFilename', { - defaultMessage: 'unsaved', - }); - const topNavConfig = getLensTopNavConfig({ - showSaveAndReturn: Boolean( - isLinkedToOriginatingApp && - // Temporarily required until the 'by value' paradigm is default. - (dashboardFeatureFlag.allowByValueEmbeddables || Boolean(initialInput)) - ), - enableExportToCSV: Boolean(isSaveable && activeData && Object.keys(activeData).length), - isByValueMode: getIsByValueMode(), - allowByValue: dashboardFeatureFlag.allowByValueEmbeddables, - showCancel: Boolean(isLinkedToOriginatingApp), - savingToLibraryPermitted, - savingToDashboardPermitted, - actions: { - exportToCSV: () => { - if (!activeData) { - return; - } - const datatables = Object.values(activeData); - const content = datatables.reduce>( - (memo, datatable, i) => { - // skip empty datatables - if (datatable) { - const postFix = datatables.length > 1 ? `-${i + 1}` : ''; - - memo[`${lastKnownDoc?.title || unsavedTitle}${postFix}.csv`] = { - content: exporters.datatableToCSV(datatable, { - csvSeparator: uiSettings.get('csv:separator', ','), - quoteValues: uiSettings.get('csv:quoteValues', true), - formatFactory: data.fieldFormats.deserialize, - }), - type: exporters.CSV_MIME_TYPE, - }; - } - return memo; - }, - {} - ); - if (content) { - downloadMultipleAs(content); - } - }, - saveAndReturn: () => { - if (savingToDashboardPermitted && lastKnownDoc) { - // disabling the validation on app leave because the document has been saved. - onAppLeave((actions) => { - return actions.default(); - }); - runSave( - { - newTitle: lastKnownDoc.title, - newCopyOnSave: false, - isTitleDuplicateConfirmed: false, - returnToOrigin: true, - }, - { - saveToLibrary: - (initialInput && attributeService.inputIsRefType(initialInput)) ?? false, - } - ); - } - }, - showSaveModal: () => { - if (savingToDashboardPermitted || savingToLibraryPermitted) { - setIsSaveModalVisible(true); - } - }, - cancel: () => { - if (redirectToOrigin) { - redirectToOrigin(); - } - }, - }, - }); - - return ( - { - const { dateRange, query: newQuery } = payload; - const currentRange = data.query.timefilter.timefilter.getTime(); - if (dateRange.from !== currentRange.from || dateRange.to !== currentRange.to) { - data.query.timefilter.timefilter.setTime(dateRange); - trackUiEvent('app_date_change'); - } else { - // Query has changed, renew the session id. - // Time change will be picked up by the time subscription - dispatchSetState({ searchSessionId: data.search.session.start() }); - trackUiEvent('app_query_change'); - } - if (newQuery) { - if (!isEqual(newQuery, query)) { - dispatchSetState({ query: newQuery }); - } - } - }} - onSaved={(newSavedQuery) => { - dispatchSetState({ savedQuery: newSavedQuery }); - }} - onSavedQueryUpdated={(newSavedQuery) => { - const savedQueryFilters = newSavedQuery.attributes.filters || []; - const globalFilters = data.query.filterManager.getGlobalFilters(); - data.query.filterManager.setFilters([...globalFilters, ...savedQueryFilters]); - dispatchSetState({ - query: newSavedQuery.attributes.query, - savedQuery: { ...newSavedQuery }, - }); // Shallow query for reference issues - }} - onClearSavedQuery={() => { - data.query.filterManager.setFilters(data.query.filterManager.getGlobalFilters()); - dispatchSetState({ - filters: data.query.filterManager.getGlobalFilters(), - query: data.query.queryString.getDefaultQuery(), - savedQuery: undefined, - }); - }} - indexPatterns={indexPatternsForTopNav} - query={query} - dateRangeFrom={from} - dateRangeTo={to} - indicateNoData={indicateNoData} - showSearchBar={true} - showDatePicker={true} - showQueryBar={true} - showFilterBar={true} - data-test-subj="lnsApp_topNav" - screenTitle={'lens'} - appName={'lens'} - /> - ); -}; diff --git a/x-pack/plugins/lens/public/app_plugin/mounter.test.tsx b/x-pack/plugins/lens/public/app_plugin/mounter.test.tsx deleted file mode 100644 index f2640c5c32acf99..000000000000000 --- a/x-pack/plugins/lens/public/app_plugin/mounter.test.tsx +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { makeDefaultServices, mockLensStore } from '../mocks'; -import { act } from 'react-dom/test-utils'; -import { loadDocument } from './mounter'; -import { LensEmbeddableInput } from '../editor_frame_service/embeddable/embeddable'; - -const defaultSavedObjectId = '1234'; - -describe('Mounter', () => { - describe('loadDocument', () => { - it('does not load a document if there is no initial input', async () => { - const services = makeDefaultServices(); - const redirectCallback = jest.fn(); - const lensStore = mockLensStore({ data: services.data }); - await loadDocument(redirectCallback, undefined, services, lensStore); - expect(services.attributeService.unwrapAttributes).not.toHaveBeenCalled(); - }); - - it('loads a document and uses query and filters if initial input is provided', async () => { - const services = makeDefaultServices(); - const redirectCallback = jest.fn(); - services.attributeService.unwrapAttributes = jest.fn().mockResolvedValue({ - savedObjectId: defaultSavedObjectId, - state: { - query: 'fake query', - filters: [{ query: { match_phrase: { src: 'test' } } }], - }, - references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], - }); - - const lensStore = await mockLensStore({ data: services.data }); - await act(async () => { - await loadDocument( - redirectCallback, - { savedObjectId: defaultSavedObjectId } as LensEmbeddableInput, - services, - lensStore - ); - }); - - expect(services.attributeService.unwrapAttributes).toHaveBeenCalledWith({ - savedObjectId: defaultSavedObjectId, - }); - - expect(services.data.indexPatterns.get).toHaveBeenCalledWith('1'); - - expect(services.data.query.filterManager.setAppFilters).toHaveBeenCalledWith([ - { query: { match_phrase: { src: 'test' } } }, - ]); - - expect(lensStore.getState()).toEqual({ - app: expect.objectContaining({ - persistedDoc: expect.objectContaining({ - savedObjectId: defaultSavedObjectId, - state: expect.objectContaining({ - query: 'fake query', - filters: [{ query: { match_phrase: { src: 'test' } } }], - }), - }), - }), - }); - }); - - it('does not load documents on sequential renders unless the id changes', async () => { - const redirectCallback = jest.fn(); - const services = makeDefaultServices(); - const lensStore = mockLensStore({ data: services.data }); - - await act(async () => { - await loadDocument( - redirectCallback, - { savedObjectId: defaultSavedObjectId } as LensEmbeddableInput, - services, - lensStore - ); - }); - - await act(async () => { - await loadDocument( - redirectCallback, - { savedObjectId: defaultSavedObjectId } as LensEmbeddableInput, - services, - lensStore - ); - }); - - expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(1); - - await act(async () => { - await loadDocument( - redirectCallback, - { savedObjectId: '5678' } as LensEmbeddableInput, - services, - lensStore - ); - }); - - expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(2); - }); - - it('handles document load errors', async () => { - const services = makeDefaultServices(); - const redirectCallback = jest.fn(); - - const lensStore = mockLensStore({ data: services.data }); - - services.attributeService.unwrapAttributes = jest.fn().mockRejectedValue('failed to load'); - - await act(async () => { - await loadDocument( - redirectCallback, - { savedObjectId: defaultSavedObjectId } as LensEmbeddableInput, - services, - lensStore - ); - }); - expect(services.attributeService.unwrapAttributes).toHaveBeenCalledWith({ - savedObjectId: defaultSavedObjectId, - }); - expect(services.notifications.toasts.addDanger).toHaveBeenCalled(); - expect(redirectCallback).toHaveBeenCalled(); - }); - - it('adds to the recently accessed list on load', async () => { - const redirectCallback = jest.fn(); - - const services = makeDefaultServices(); - const lensStore = mockLensStore({ data: services.data }); - await act(async () => { - await loadDocument( - redirectCallback, - ({ savedObjectId: defaultSavedObjectId } as unknown) as LensEmbeddableInput, - services, - lensStore - ); - }); - - expect(services.chrome.recentlyAccessed.add).toHaveBeenCalledWith( - '/app/lens#/edit/1234', - 'An extremely cool default document!', - '1234' - ); - }); - }); -}); diff --git a/x-pack/plugins/lens/public/app_plugin/mounter.tsx b/x-pack/plugins/lens/public/app_plugin/mounter.tsx index 708573e843fcf4a..e6eb115562d378d 100644 --- a/x-pack/plugins/lens/public/app_plugin/mounter.tsx +++ b/x-pack/plugins/lens/public/app_plugin/mounter.tsx @@ -15,8 +15,6 @@ import { render, unmountComponentAtNode } from 'react-dom'; import { i18n } from '@kbn/i18n'; import { DashboardFeatureFlagConfig } from 'src/plugins/dashboard/public'; -import { Provider } from 'react-redux'; -import { uniq, isEqual } from 'lodash'; import { Storage } from '../../../../../src/plugins/kibana_utils/public'; import { LensReportManager, setReportManager, trackUiEvent } from '../lens_ui_telemetry'; @@ -25,7 +23,7 @@ import { App } from './app'; import { EditorFrameStart } from '../types'; import { addHelpMenuToAppChrome } from '../help_menu_util'; import { LensPluginStartDependencies } from '../plugin'; -import { LENS_EMBEDDABLE_TYPE, LENS_EDIT_BY_VALUE, APP_ID, getFullPath } from '../../common'; +import { LENS_EMBEDDABLE_TYPE, LENS_EDIT_BY_VALUE, APP_ID } from '../../common'; import { LensEmbeddableInput, LensByReferenceInput, @@ -36,16 +34,6 @@ import { LensAttributeService } from '../lens_attribute_service'; import { LensAppServices, RedirectToOriginProps, HistoryLocationState } from './types'; import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; -import { - makeConfigureStore, - navigateAway, - getPreloadedState, - LensRootStore, - setState, -} from '../state_management'; -import { getAllIndexPatterns, getResolvedDateRange } from '../utils'; -import { injectFilterReferences } from '../persistence'; - export async function mountApp( core: CoreSetup, params: AppMountParameters, @@ -161,32 +149,8 @@ export async function mountApp( coreStart.application.navigateToApp(embeddableEditorIncomingState?.originatingApp); } }; - const initialContext = - historyLocationState && historyLocationState.type === ACTION_VISUALIZE_LENS_FIELD - ? historyLocationState.payload - : undefined; - - // Clear app-specific filters when navigating to Lens. Necessary because Lens - // can be loaded without a full page refresh. If the user navigates to Lens from Discover - // we keep the filters - if (!initialContext) { - data.query.filterManager.setAppFilters([]); - } - - const preloadedState = getPreloadedState({ - query: data.query.queryString.getQuery(), - // Do not use app-specific filters from previous app, - // only if Lens was opened with the intention to visualize a field (e.g. coming from Discover) - filters: !initialContext - ? data.query.filterManager.getGlobalFilters() - : data.query.filterManager.getFilters(), - searchSessionId: data.search.session.start(), - resolvedDateRange: getResolvedDateRange(data.query.timefilter.timefilter), - isLinkedToOriginatingApp: Boolean(embeddableEditorIncomingState?.originatingApp), - }); - - const lensStore: LensRootStore = makeConfigureStore(preloadedState, { data }); + // const featureFlagConfig = await getByValueFeatureFlag(); const EditorRenderer = React.memo( (props: { id?: string; history: History; editByValue?: boolean }) => { const redirectCallback = useCallback( @@ -196,23 +160,23 @@ export async function mountApp( [props.history] ); trackUiEvent('loaded'); - const initialInput = getInitialInput(props.id, props.editByValue); - loadDocument(redirectCallback, initialInput, lensServices, lensStore); return ( - - - + ); } ); @@ -268,86 +232,5 @@ export async function mountApp( data.search.session.clear(); unmountComponentAtNode(params.element); unlistenParentHistory(); - lensStore.dispatch(navigateAway()); }; } - -export function loadDocument( - redirectCallback: (savedObjectId?: string) => void, - initialInput: LensEmbeddableInput | undefined, - lensServices: LensAppServices, - lensStore: LensRootStore -) { - const { attributeService, chrome, notifications, data } = lensServices; - const { persistedDoc } = lensStore.getState().app; - if ( - !initialInput || - (attributeService.inputIsRefType(initialInput) && - initialInput.savedObjectId === persistedDoc?.savedObjectId) - ) { - return; - } - lensStore.dispatch(setState({ isAppLoading: true })); - - attributeService - .unwrapAttributes(initialInput) - .then((attributes) => { - if (!initialInput) { - return; - } - const doc = { - ...initialInput, - ...attributes, - type: LENS_EMBEDDABLE_TYPE, - }; - - if (attributeService.inputIsRefType(initialInput)) { - chrome.recentlyAccessed.add( - getFullPath(initialInput.savedObjectId), - attributes.title, - initialInput.savedObjectId - ); - } - const indexPatternIds = uniq( - doc.references.filter(({ type }) => type === 'index-pattern').map(({ id }) => id) - ); - getAllIndexPatterns(indexPatternIds, data.indexPatterns) - .then(({ indexPatterns }) => { - // Don't overwrite any pinned filters - data.query.filterManager.setAppFilters( - injectFilterReferences(doc.state.filters, doc.references) - ); - lensStore.dispatch( - setState({ - query: doc.state.query, - isAppLoading: false, - indexPatternsForTopNav: indexPatterns, - lastKnownDoc: doc, - ...(!isEqual(persistedDoc, doc) ? { persistedDoc: doc } : null), - }) - ); - }) - .catch((e) => { - lensStore.dispatch( - setState({ - isAppLoading: false, - }) - ); - redirectCallback(); - }); - }) - .catch((e) => { - lensStore.dispatch( - setState({ - isAppLoading: false, - }) - ); - notifications.toasts.addDanger( - i18n.translate('xpack.lens.app.docLoadingError', { - defaultMessage: 'Error loading saved document', - }) - ); - - redirectCallback(); - }); -} diff --git a/x-pack/plugins/lens/public/app_plugin/time_range.ts b/x-pack/plugins/lens/public/app_plugin/time_range.ts new file mode 100644 index 000000000000000..c9e507f3e6f1321 --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/time_range.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import './app.scss'; + +import _ from 'lodash'; +import moment from 'moment'; +import { useEffect, useMemo } from 'react'; +import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; +import { LensAppState } from './types'; +import { Document } from '../persistence'; + +function containsDynamicMath(dateMathString: string) { + return dateMathString.includes('now'); +} + +const TIME_LAG_PERCENTAGE_LIMIT = 0.02; + +/** + * Fetches the current global time range from data plugin and restarts session + * if the fixed "now" parameter is diverging too much from the actual current time. + * @param data data plugin contract to manage current now value, time range and session + * @param lastKnownDoc Current state of the editor + * @param setState state setter for Lens app state + * @param searchSessionId current session id + */ +export function useTimeRange( + data: DataPublicPluginStart, + lastKnownDoc: Document | undefined, + setState: React.Dispatch>, + searchSessionId: string +) { + const timefilter = data.query.timefilter.timefilter; + const { from, to } = data.query.timefilter.timefilter.getTime(); + + // Need a stable reference for the frame component of the dateRange + const resolvedDateRange = useMemo(() => { + const { min, max } = timefilter.calculateBounds({ + from, + to, + }); + return { fromDate: min?.toISOString() || from, toDate: max?.toISOString() || to }; + // recalculate current date range if the session gets updated because it + // might change "now" and calculateBounds depends on it internally + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [timefilter, searchSessionId, from, to]); + + useEffect(() => { + const unresolvedTimeRange = timefilter.getTime(); + if ( + !containsDynamicMath(unresolvedTimeRange.from) && + !containsDynamicMath(unresolvedTimeRange.to) + ) { + return; + } + + const { min, max } = timefilter.getBounds(); + + if (!min || !max) { + // bounds not fully specified, bailing out + return; + } + + // calculate length of currently configured range in ms + const timeRangeLength = moment.duration(max.diff(min)).asMilliseconds(); + + // calculate lag of managed "now" for date math + const nowDiff = Date.now() - data.nowProvider.get().valueOf(); + + // if the lag is signifcant, start a new session to clear the cache + if (nowDiff > timeRangeLength * TIME_LAG_PERCENTAGE_LIMIT) { + setState((s) => ({ + ...s, + searchSessionId: data.search.session.start(), + })); + } + }, [data.nowProvider, data.search.session, timefilter, lastKnownDoc, setState]); + + return { resolvedDateRange, from, to }; +} diff --git a/x-pack/plugins/lens/public/app_plugin/types.ts b/x-pack/plugins/lens/public/app_plugin/types.ts index 72850552723f33a..c9143542e67bfba 100644 --- a/x-pack/plugins/lens/public/app_plugin/types.ts +++ b/x-pack/plugins/lens/public/app_plugin/types.ts @@ -6,7 +6,6 @@ */ import { History } from 'history'; -import { OnSaveProps } from 'src/plugins/saved_objects/public'; import { ApplicationStart, AppMountParameters, @@ -17,7 +16,14 @@ import { OverlayStart, SavedObjectsStart, } from '../../../../../src/core/public'; -import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; +import { + DataPublicPluginStart, + Filter, + IndexPattern, + Query, + SavedQuery, +} from '../../../../../src/plugins/data/public'; +import { Document } from '../persistence'; import { LensEmbeddableInput } from '../editor_frame_service/embeddable/embeddable'; import { NavigationPublicPluginStart } from '../../../../../src/plugins/navigation/public'; import { LensAttributeService } from '../lens_attribute_service'; @@ -32,7 +38,28 @@ import { EmbeddableEditorState, EmbeddableStateTransfer, } from '../../../../../src/plugins/embeddable/public'; +import { TableInspectorAdapter } from '../editor_frame_service/types'; import { EditorFrameInstance } from '../types'; + +export interface LensAppState { + isLoading: boolean; + persistedDoc?: Document; + lastKnownDoc?: Document; + + // index patterns used to determine which filters are available in the top nav. + indexPatternsForTopNav: IndexPattern[]; + + // Determines whether the lens editor shows the 'save and return' button, and the originating app breadcrumb. + isLinkedToOriginatingApp?: boolean; + + query: Query; + filters: Filter[]; + savedQuery?: SavedQuery; + isSaveable: boolean; + activeData?: TableInspectorAdapter; + searchSessionId: string; +} + export interface RedirectToOriginProps { input?: LensEmbeddableInput; isCopied?: boolean; @@ -55,32 +82,6 @@ export interface LensAppProps { initialContext?: VisualizeFieldContext; } -export type RunSave = ( - saveProps: Omit & { - returnToOrigin: boolean; - dashboardId?: string | null; - onTitleDuplicate?: OnSaveProps['onTitleDuplicate']; - newDescription?: string; - newTags?: string[]; - }, - options: { - saveToLibrary: boolean; - } -) => Promise; - -export interface LensTopNavMenuProps { - onAppLeave: AppMountParameters['onAppLeave']; - setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; - - redirectToOrigin?: (props?: RedirectToOriginProps) => void; - // The initial input passed in by the container when editing. Can be either by reference or by value. - initialInput?: LensEmbeddableInput; - getIsByValueMode: () => boolean; - indicateNoData: boolean; - setIsSaveModalVisible: React.Dispatch>; - runSave: RunSave; -} - export interface HistoryLocationState { type: typeof ACTION_VISUALIZE_LENS_FIELD; payload: VisualizeFieldContext; diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/__snapshots__/table_basic.test.tsx.snap b/x-pack/plugins/lens/public/datatable_visualization/components/__snapshots__/table_basic.test.tsx.snap index a4be46f61990b6b..afc69c2e8861f93 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/__snapshots__/table_basic.test.tsx.snap +++ b/x-pack/plugins/lens/public/datatable_visualization/components/__snapshots__/table_basic.test.tsx.snap @@ -13,13 +13,6 @@ exports[`DatatableComponent it renders actions column when there are row actions "b": "left", "c": "right", }, - "getColorForValue": [MockFunction], - "minMaxByColumnId": Object { - "c": Object { - "max": 3, - "min": 3, - }, - }, "rowHasRowClickTriggerActions": Array [ true, true, @@ -251,13 +244,6 @@ exports[`DatatableComponent it renders the title and value 1`] = ` "b": "left", "c": "right", }, - "getColorForValue": [MockFunction], - "minMaxByColumnId": Object { - "c": Object { - "max": 3, - "min": 3, - }, - }, "rowHasRowClickTriggerActions": undefined, "table": Object { "columns": Array [ @@ -476,13 +462,6 @@ exports[`DatatableComponent it should not render actions on header when it is in "b": "left", "c": "right", }, - "getColorForValue": [MockFunction], - "minMaxByColumnId": Object { - "c": Object { - "max": 3, - "min": 3, - }, - }, "rowHasRowClickTriggerActions": Array [ false, false, diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.test.tsx index 67255dc8a953eac..9bc982ebd9944b0 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.test.tsx @@ -11,12 +11,6 @@ import { DataContext } from './table_basic'; import { createGridCell } from './cell_value'; import { FieldFormat } from 'src/plugins/data/public'; import { Datatable } from 'src/plugins/expressions/public'; -import { IUiSettingsClient } from 'kibana/public'; -import { act } from 'react-dom/test-utils'; -import { ReactWrapper } from 'enzyme'; -import { Args, ColumnConfigArg } from '../expression'; -import { DataContextType } from './types'; -import { chartPluginMock } from 'src/plugins/charts/public/mocks'; describe('datatable cell renderer', () => { const table: Datatable = { @@ -36,9 +30,7 @@ describe('datatable cell renderer', () => { { a: { convert: (x) => `formatted ${x}` } as FieldFormat, }, - { columns: [], sortingColumnId: '', sortingDirection: 'none' }, - DataContext, - ({ get: jest.fn() } as unknown) as IUiSettingsClient + DataContext ); it('renders formatted value', () => { @@ -86,111 +78,4 @@ describe('datatable cell renderer', () => { ); expect(cell.find('.lnsTableCell').prop('className')).toContain('--right'); }); - - describe('dynamic coloring', () => { - const paletteRegistry = chartPluginMock.createPaletteRegistry(); - const customPalette = paletteRegistry.get('custom'); - - function getCellRenderer(columnConfig: Args) { - return createGridCell( - { - a: { convert: (x) => `formatted ${x}` } as FieldFormat, - }, - columnConfig, - DataContext, - ({ get: jest.fn() } as unknown) as IUiSettingsClient - ); - } - function getColumnConfiguration(): Args { - return { - title: 'myData', - columns: [ - { - columnId: 'a', - colorMode: 'none', - palette: { - type: 'palette', - name: 'custom', - params: { - colors: ['#aaa', '#bbb', '#ccc', '#ddd', '#eee'], - gradient: false, - stops: [20, 40, 60, 80, 100], - range: 'percent', - rangeMin: 0, - rangeMax: 100, - }, - }, - type: 'lens_datatable_column', - } as ColumnConfigArg, - ], - sortingColumnId: '', - sortingDirection: 'none', - }; - } - - function flushEffect(component: ReactWrapper) { - return act(async () => { - await component; - await new Promise((r) => setImmediate(r)); - component.update(); - }); - } - - async function renderCellComponent(columnConfig: Args, context: Partial = {}) { - const CellRendererWithPalette = getCellRenderer(columnConfig); - const setCellProps = jest.fn(); - - const cell = mountWithIntl( - 123 */ } }, - getColorForValue: customPalette.getColorForValue, - ...context, - }} - > - - - ); - - await flushEffect(cell); - - return { setCellProps, cell }; - } - - it('ignores coloring when colorMode is set to "none"', async () => { - const { setCellProps } = await renderCellComponent(getColumnConfiguration()); - - expect(setCellProps).not.toHaveBeenCalled(); - }); - - it('should set the coloring of the cell when enabled', async () => { - const columnConfig = getColumnConfiguration(); - columnConfig.columns[0].colorMode = 'cell'; - - const { setCellProps } = await renderCellComponent(columnConfig, {}); - - expect(setCellProps).toHaveBeenCalledWith({ - style: expect.objectContaining({ backgroundColor: 'blue' }), - }); - }); - - it('should set the coloring of the text when enabled', async () => { - const columnConfig = getColumnConfiguration(); - columnConfig.columns[0].colorMode = 'text'; - - const { setCellProps } = await renderCellComponent(columnConfig, {}); - - expect(setCellProps).toHaveBeenCalledWith({ - style: expect.objectContaining({ color: 'blue' }), - }); - }); - }); }); diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.tsx index a6c50f00cb77fdd..2261dd06b532ba5 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.tsx @@ -5,74 +5,30 @@ * 2.0. */ -import React, { useContext, useEffect } from 'react'; +import React, { useContext } from 'react'; import { EuiDataGridCellValueElementProps } from '@elastic/eui'; -import { IUiSettingsClient } from 'kibana/public'; import type { FormatFactory } from '../../types'; import type { DataContextType } from './types'; -import { ColumnConfig } from './table_basic'; -import { getContrastColor } from '../../shared_components/coloring/utils'; -import { getOriginalId } from '../transpose_helpers'; export const createGridCell = ( formatters: Record>, - columnConfig: ColumnConfig, - DataContext: React.Context, - uiSettings: IUiSettingsClient -) => { - // Changing theme requires a full reload of the page, so we can cache here - const IS_DARK_THEME = uiSettings.get('theme:darkMode'); - return ({ rowIndex, columnId, setCellProps }: EuiDataGridCellValueElementProps) => { - const { table, alignments, minMaxByColumnId, getColorForValue } = useContext(DataContext); - const rowValue = table?.rows[rowIndex][columnId]; - const content = formatters[columnId]?.convert(rowValue, 'html'); - const currentAlignment = alignments && alignments[columnId]; - const alignmentClassName = `lnsTableCell--${currentAlignment}`; + DataContext: React.Context +) => ({ rowIndex, columnId }: EuiDataGridCellValueElementProps) => { + const { table, alignments } = useContext(DataContext); + const rowValue = table?.rows[rowIndex][columnId]; + const content = formatters[columnId]?.convert(rowValue, 'html'); + const currentAlignment = alignments && alignments[columnId]; + const alignmentClassName = `lnsTableCell--${currentAlignment}`; - const { colorMode, palette } = - columnConfig.columns.find(({ columnId: id }) => id === columnId) || {}; - - useEffect(() => { - const originalId = getOriginalId(columnId); - if (minMaxByColumnId?.[originalId]) { - if (colorMode !== 'none' && palette?.params && getColorForValue) { - // workout the bucket the value belongs to - const color = getColorForValue(rowValue, palette.params, minMaxByColumnId[originalId]); - if (color) { - const style = { [colorMode === 'cell' ? 'backgroundColor' : 'color']: color }; - if (colorMode === 'cell' && color) { - style.color = getContrastColor(color, IS_DARK_THEME); - } - setCellProps({ - style, - }); - } - } - } - // make sure to clean it up when something change - // this avoids cell's styling to stick forever - return () => { - if (minMaxByColumnId?.[originalId]) { - setCellProps({ - style: { - backgroundColor: undefined, - color: undefined, - }, - }); - } - }; - }, [rowValue, columnId, setCellProps, colorMode, palette, minMaxByColumnId, getColorForValue]); - - return ( -
- ); - }; + return ( +
+ ); }; diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.scss b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.scss deleted file mode 100644 index 504adb05e57d7b2..000000000000000 --- a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.scss +++ /dev/null @@ -1,7 +0,0 @@ -.lnsDynamicColoringRow { - align-items: center; -} - -.lnsDynamicColoringClickable { - cursor: pointer; -} \ No newline at end of file diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.test.tsx index 88948e9a7615b86..e0d31a3ed020129 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.test.tsx @@ -12,18 +12,12 @@ import { DatatableVisualizationState } from '../visualization'; import { createMockDatasource, createMockFramePublicAPI } from '../../editor_frame_service/mocks'; import { mountWithIntl } from '@kbn/test/jest'; import { TableDimensionEditor } from './dimension_editor'; -import { chartPluginMock } from 'src/plugins/charts/public/mocks'; -import { PaletteRegistry } from 'src/plugins/charts/public'; -import { PalettePanelContainer } from './palette_panel_container'; -import { act } from 'react-dom/test-utils'; describe('data table dimension editor', () => { let frame: FramePublicAPI; let state: DatatableVisualizationState; let setState: (newState: DatatableVisualizationState) => void; - let props: VisualizationDimensionEditorProps & { - paletteService: PaletteRegistry; - }; + let props: VisualizationDimensionEditorProps; function testState(): DatatableVisualizationState { return { @@ -65,8 +59,6 @@ describe('data table dimension editor', () => { layerId: 'first', state, setState, - paletteService: chartPluginMock.createPaletteRegistry(), - panelRef: React.createRef(), }; }); @@ -80,23 +72,17 @@ describe('data table dimension editor', () => { it('should render default alignment for number', () => { frame.activeData!.first.columns[0].meta.type = 'number'; const instance = mountWithIntl(); - expect( - instance - .find('[data-test-subj="lnsDatatable_alignment_groups"]') - .find(EuiButtonGroup) - .prop('idSelected') - ).toEqual(expect.stringContaining('right')); + expect(instance.find(EuiButtonGroup).prop('idSelected')).toEqual( + expect.stringContaining('right') + ); }); it('should render specific alignment', () => { state.columns[0].alignment = 'center'; const instance = mountWithIntl(); - expect( - instance - .find('[data-test-subj="lnsDatatable_alignment_groups"]') - .find(EuiButtonGroup) - .prop('idSelected') - ).toEqual(expect.stringContaining('center')); + expect(instance.find(EuiButtonGroup).prop('idSelected')).toEqual( + expect.stringContaining('center') + ); }); it('should set state for the right column', () => { @@ -109,10 +95,7 @@ describe('data table dimension editor', () => { }, ]; const instance = mountWithIntl(); - instance - .find('[data-test-subj="lnsDatatable_alignment_groups"]') - .find(EuiButtonGroup) - .prop('onChange')('center'); + instance.find(EuiButtonGroup).prop('onChange')('center'); expect(setState).toHaveBeenCalledWith({ ...state, columns: [ @@ -126,90 +109,4 @@ describe('data table dimension editor', () => { ], }); }); - - it('should not show the dynamic coloring option for non numeric columns', () => { - const instance = mountWithIntl(); - expect(instance.find('[data-test-subj="lnsDatatable_dynamicColoring_groups"]').exists()).toBe( - false - ); - expect(instance.find('[data-test-subj="lnsDatatable_dynamicColoring_palette"]').exists()).toBe( - false - ); - }); - - it('should set the dynamic coloring default to "none"', () => { - frame.activeData!.first.columns[0].meta.type = 'number'; - const instance = mountWithIntl(); - expect( - instance - .find('[data-test-subj="lnsDatatable_dynamicColoring_groups"]') - .find(EuiButtonGroup) - .prop('idSelected') - ).toEqual(expect.stringContaining('none')); - - expect(instance.find('[data-test-subj="lnsDatatable_dynamicColoring_palette"]').exists()).toBe( - false - ); - }); - - it('should show the dynamic palette display ony when colorMode is different from "none"', () => { - frame.activeData!.first.columns[0].meta.type = 'number'; - state.columns[0].colorMode = 'text'; - const instance = mountWithIntl(); - expect( - instance - .find('[data-test-subj="lnsDatatable_dynamicColoring_groups"]') - .find(EuiButtonGroup) - .prop('idSelected') - ).toEqual(expect.stringContaining('text')); - - expect(instance.find('[data-test-subj="lnsDatatable_dynamicColoring_palette"]').exists()).toBe( - true - ); - }); - - it('should set the coloring mode to the right column', () => { - frame.activeData!.first.columns[0].meta.type = 'number'; - state.columns = [ - { - columnId: 'foo', - }, - { - columnId: 'bar', - }, - ]; - const instance = mountWithIntl(); - instance - .find('[data-test-subj="lnsDatatable_dynamicColoring_groups"]') - .find(EuiButtonGroup) - .prop('onChange')('cell'); - expect(setState).toHaveBeenCalledWith({ - ...state, - columns: [ - { - columnId: 'foo', - colorMode: 'cell', - palette: expect.objectContaining({ type: 'palette' }), - }, - { - columnId: 'bar', - }, - ], - }); - }); - - it('should open the palette panel when "Settings" link is clicked in the palette input', () => { - frame.activeData!.first.columns[0].meta.type = 'number'; - state.columns[0].colorMode = 'cell'; - const instance = mountWithIntl(); - - act(() => - (instance - .find('[data-test-subj="lnsDatatable_dynamicColoring_trigger"]') - .first() - .prop('onClick') as () => void)?.() - ); - - expect(instance.find(PalettePanelContainer).exists()).toBe(true); - }); }); diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx index 76c47a9c743c519..a750744811790fc 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx @@ -5,91 +5,36 @@ * 2.0. */ -import React, { useState } from 'react'; +import React from 'react'; import { i18n } from '@kbn/i18n'; -import { - EuiFormRow, - EuiSwitch, - EuiButtonGroup, - htmlIdGenerator, - EuiColorPaletteDisplay, - EuiFlexItem, - EuiFlexGroup, - EuiButtonEmpty, -} from '@elastic/eui'; -import { PaletteRegistry } from 'src/plugins/charts/public'; +import { EuiFormRow, EuiSwitch, EuiButtonGroup, htmlIdGenerator } from '@elastic/eui'; import { VisualizationDimensionEditorProps } from '../../types'; import { DatatableVisualizationState } from '../visualization'; import { getOriginalId } from '../transpose_helpers'; -import { - CustomizablePalette, - applyPaletteParams, - defaultPaletteParams, - FIXED_PROGRESSION, - getStopsForFixedMode, -} from '../../shared_components/'; -import { PalettePanelContainer } from './palette_panel_container'; -import { findMinMaxByColumnId } from './shared_utils'; -import './dimension_editor.scss'; const idPrefix = htmlIdGenerator()(); -type ColumnType = DatatableVisualizationState['columns'][number]; - -function updateColumnWith( - state: DatatableVisualizationState, - columnId: string, - newColumnProps: Partial -) { - return state.columns.map((currentColumn) => { - if (currentColumn.columnId === columnId) { - return { ...currentColumn, ...newColumnProps }; - } else { - return currentColumn; - } - }); -} - export function TableDimensionEditor( - props: VisualizationDimensionEditorProps & { - paletteService: PaletteRegistry; - } + props: VisualizationDimensionEditorProps ) { const { state, setState, frame, accessor } = props; const column = state.columns.find(({ columnId }) => accessor === columnId); - const [isPaletteOpen, setIsPaletteOpen] = useState(false); if (!column) return null; if (column.isTransposed) return null; - const currentData = frame.activeData?.[state.layerId]; - // either read config state or use same logic as chart itself - const isNumericField = - currentData?.columns.find((col) => col.id === accessor || getOriginalId(col.id) === accessor) - ?.meta.type === 'number'; - - const currentAlignment = column?.alignment || (isNumericField ? 'right' : 'left'); - const currentColorMode = column?.colorMode || 'none'; - const hasDynamicColoring = currentColorMode !== 'none'; + const currentAlignment = + column?.alignment || + (frame.activeData && + frame.activeData[state.layerId]?.columns.find( + (col) => col.id === accessor || getOriginalId(col.id) === accessor + )?.meta.type === 'number' + ? 'right' + : 'left'); const visibleColumnsCount = state.columns.filter((c) => !c.hidden).length; - const hasTransposedColumn = state.columns.some(({ isTransposed }) => isTransposed); - const columnsToCheck = hasTransposedColumn - ? currentData?.columns.filter(({ id }) => getOriginalId(id) === accessor).map(({ id }) => id) || - [] - : [accessor]; - const minMaxByColumnId = findMinMaxByColumnId(columnsToCheck, currentData); - const currentMinMax = minMaxByColumnId[accessor]; - - const activePalette = column?.palette || { - type: 'palette', - name: defaultPaletteParams.name, - }; - // need to tell the helper that the colorStops are required to display - const displayStops = applyPaletteParams(props.paletteService, activePalette, currentMinMax); - return ( <> { - const newMode = id.replace(idPrefix, '') as ColumnType['alignment']; - setState({ - ...state, - columns: updateColumnWith(state, accessor, { alignment: newMode }), + const newMode = id.replace(idPrefix, '') as 'left' | 'right' | 'center'; + const newColumns = state.columns.map((currentColumn) => { + if (currentColumn.columnId === accessor) { + return { + ...currentColumn, + alignment: newMode, + }; + } else { + return currentColumn; + } }); + setState({ ...state, columns: newColumns }); }} /> @@ -175,135 +127,6 @@ export function TableDimensionEditor( /> )} - {isNumericField && ( - <> - - { - const newMode = id.replace(idPrefix, '') as ColumnType['colorMode']; - const params: Partial = { - colorMode: newMode, - }; - if (!column?.palette && newMode !== 'none') { - params.palette = { - ...activePalette, - params: { - ...activePalette.params, - // that's ok, at first open we're going to throw them away and recompute - stops: displayStops, - }, - }; - } - // clear up when switching to no coloring - if (column?.palette && newMode === 'none') { - params.palette = undefined; - } - setState({ - ...state, - columns: updateColumnWith(state, accessor, params), - }); - }} - /> - - {hasDynamicColoring && ( - - - - { - setIsPaletteOpen(!isPaletteOpen); - }} - /> - - - { - setIsPaletteOpen(!isPaletteOpen); - }} - size="xs" - flush="both" - > - {i18n.translate('xpack.lens.paletteTableGradient.customize', { - defaultMessage: 'Edit', - })} - - setIsPaletteOpen(!isPaletteOpen)} - > - { - setState({ - ...state, - columns: updateColumnWith(state, accessor, { palette: newPalette }), - }); - }} - /> - - - - - )} - - )} ); } diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.scss b/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.scss deleted file mode 100644 index db14d064d1881e9..000000000000000 --- a/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.scss +++ /dev/null @@ -1,53 +0,0 @@ -@import '@elastic/eui/src/components/flyout/variables'; -@import '@elastic/eui/src/components/flyout/mixins'; - -.lnsPalettePanelContainer { - // Use the EuiFlyout style - @include euiFlyout; - // But with custom positioning to keep it within the sidebar contents - position: absolute; - right: 0; - left: 0; - top: 0; - bottom: 0; - animation: euiFlyout $euiAnimSpeedNormal $euiAnimSlightResistance; - // making just a bit higher than the dimension flyout to stack on top of it - z-index: $euiZLevel3 + 1 -} - -.lnsPalettePanelContainer__footer { - padding: $euiSizeS; -} - -.lnsPalettePanelContainer__header { - padding: $euiSizeS $euiSizeXS; -} - -.lnsPalettePanelContainer__headerTitle { - padding: $euiSizeS $euiSizeXS; - cursor: pointer; - - &:hover { - text-decoration: underline; - } -} - -.lnsPalettePanelContainer__headerLink { - &:focus-within { - background-color: transparentize($euiColorVis1, .9); - - .lnsPalettePanelContainer__headerTitle { - text-decoration: underline; - } - } -} - -.lnsPalettePanelContainer__backIcon { - &:hover { - transform: none !important; // sass-lint:disable-line no-important - } - - &:focus { - background-color: transparent; - } -} diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.tsx deleted file mode 100644 index 1371fbe73ef8454..000000000000000 --- a/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.tsx +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import './palette_panel_container.scss'; - -import React, { useState, useEffect, MutableRefObject } from 'react'; -import { - EuiFlyoutHeader, - EuiFlyoutFooter, - EuiTitle, - EuiButtonIcon, - EuiButtonEmpty, - EuiFlexGroup, - EuiFlexItem, - EuiFocusTrap, - EuiOutsideClickDetector, - EuiPortal, -} from '@elastic/eui'; - -import { i18n } from '@kbn/i18n'; - -export function PalettePanelContainer({ - isOpen, - handleClose, - children, - siblingRef, -}: { - isOpen: boolean; - handleClose: () => void; - children: React.ReactElement | React.ReactElement[]; - siblingRef: MutableRefObject; -}) { - const [focusTrapIsEnabled, setFocusTrapIsEnabled] = useState(false); - - const closeFlyout = () => { - handleClose(); - setFocusTrapIsEnabled(false); - }; - - useEffect(() => { - if (isOpen) { - // without setTimeout here the flyout pushes content when animating - setTimeout(() => { - setFocusTrapIsEnabled(true); - }, 255); - } - }, [isOpen]); - - return isOpen && siblingRef.current ? ( - - - -
- - - - - - - -

- - {i18n.translate('xpack.lens.table.palettePanelTitle', { - defaultMessage: 'Edit color', - })} - -

-
-
-
-
- - {children} - - - - {i18n.translate('xpack.lens.table.palettePanelContainer.back', { - defaultMessage: 'Back', - })} - - -
-
-
-
- ) : null; -} diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/shared_utils.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/shared_utils.tsx deleted file mode 100644 index 92a949e65c67eac..000000000000000 --- a/x-pack/plugins/lens/public/datatable_visualization/components/shared_utils.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Datatable } from 'src/plugins/expressions'; -import { getOriginalId } from '../transpose_helpers'; - -export const findMinMaxByColumnId = (columnIds: string[], table: Datatable | undefined) => { - const minMax: Record = {}; - - if (table != null) { - for (const columnId of columnIds) { - const originalId = getOriginalId(columnId); - minMax[originalId] = minMax[originalId] || { max: -Infinity, min: Infinity }; - table.rows.forEach((row) => { - const rowValue = row[columnId]; - if (rowValue != null) { - if (minMax[originalId].min > rowValue) { - minMax[originalId].min = rowValue; - } - if (minMax[originalId].max < rowValue) { - minMax[originalId].max = rowValue; - } - } - }); - // what happens when there's no data in the table? Fallback to a percent range - if (minMax[originalId].max === -Infinity) { - minMax[originalId] = { max: 100, min: 0, fallback: true }; - } - } - } - return minMax; -}; diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx index 509969c2b71ec0a..22577e8ef5fd31e 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx @@ -15,8 +15,6 @@ import { LensIconChartDatatable } from '../../assets/chart_datatable'; import { DataContext, DatatableComponent } from './table_basic'; import { LensMultiTable } from '../../types'; import { DatatableProps } from '../expression'; -import { chartPluginMock } from 'src/plugins/charts/public/mocks'; -import { IUiSettingsClient } from 'kibana/public'; function sampleArgs() { const indexPatternId = 'indexPatternId'; @@ -101,8 +99,6 @@ describe('DatatableComponent', () => { formatFactory={(x) => x as IFieldFormat} dispatchEvent={onDispatchEvent} getType={jest.fn()} - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} renderMode="edit" /> ) @@ -122,8 +118,6 @@ describe('DatatableComponent', () => { getType={jest.fn()} rowHasRowClickTriggerActions={[true, true, true]} renderMode="edit" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ) ).toMatchSnapshot(); @@ -142,8 +136,6 @@ describe('DatatableComponent', () => { getType={jest.fn()} rowHasRowClickTriggerActions={[false, false, false]} renderMode="display" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ) ).toMatchSnapshot(); @@ -166,8 +158,6 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn(() => ({ type: 'buckets' } as IAggType))} renderMode="edit" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -209,8 +199,6 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn(() => ({ type: 'buckets' } as IAggType))} renderMode="edit" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -291,8 +279,6 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn(() => ({ type: 'buckets' } as IAggType))} renderMode="edit" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -339,8 +325,6 @@ describe('DatatableComponent', () => { type === 'count' ? ({ type: 'metrics' } as IAggType) : ({ type: 'buckets' } as IAggType) )} renderMode="edit" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); expect(component.find(EmptyPlaceholder).prop('icon')).toEqual(LensIconChartDatatable); @@ -361,8 +345,6 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn()} renderMode="edit" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -411,8 +393,6 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn()} renderMode="display" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -441,8 +421,6 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn()} renderMode="display" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -469,8 +447,6 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn()} renderMode="display" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -495,8 +471,6 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn()} renderMode="edit" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); // mnake a copy of the data, changing only the name of the first column @@ -509,34 +483,4 @@ describe('DatatableComponent', () => { 'new a' ); }); - - test('it does compute minMax for each numeric column', () => { - const { data, args } = sampleArgs(); - - const wrapper = shallow( - ({ convert: (x) => x } as IFieldFormat)} - dispatchEvent={onDispatchEvent} - getType={jest.fn()} - renderMode="display" - paletteService={chartPluginMock.createPaletteRegistry()} - uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} - /> - ); - - expect(wrapper.find(DataContext.Provider).prop('value').minMaxByColumnId).toEqual({ - c: { min: 3, max: 3 }, - }); - }); }); diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx index e6fcf3f321f7f30..24cde07cebaa0e4 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx @@ -18,7 +18,6 @@ import { EuiDataGridSorting, EuiDataGridStyle, } from '@elastic/eui'; -import { CustomPaletteState, PaletteOutput } from 'src/plugins/charts/common'; import { FormatFactory, LensFilterEvent, LensTableRowContextMenuEvent } from '../../types'; import { VisualizationContainer } from '../../visualization_container'; import { EmptyPlaceholder } from '../../shared_components'; @@ -41,8 +40,6 @@ import { createGridSortingConfig, createTransposeColumnFilterHandler, } from './table_actions'; -import { findMinMaxByColumnId } from './shared_utils'; -import { CUSTOM_PALETTE } from '../../shared_components/coloring/constants'; export const DataContext = React.createContext({}); @@ -53,9 +50,8 @@ const gridStyle: EuiDataGridStyle = { export interface ColumnConfig { columns: Array< - Omit & { + ColumnState & { type: 'lens_datatable_column'; - palette?: PaletteOutput; } >; sortingColumnId: string | undefined; @@ -207,34 +203,20 @@ export const DatatableComponent = (props: DatatableRenderProps) => { ] ); - const isNumericMap: Record = useMemo(() => { - const numericMap: Record = {}; - for (const column of firstLocalTable.columns) { - numericMap[column.id] = column.meta.type === 'number'; - } - return numericMap; - }, [firstLocalTable]); - const alignments: Record = useMemo(() => { const alignmentMap: Record = {}; columnConfig.columns.forEach((column) => { if (column.alignment) { alignmentMap[column.columnId] = column.alignment; } else { - alignmentMap[column.columnId] = isNumericMap[column.columnId] ? 'right' : 'left'; + const isNumeric = + firstLocalTable.columns.find((dataColumn) => dataColumn.id === column.columnId)?.meta + .type === 'number'; + alignmentMap[column.columnId] = isNumeric ? 'right' : 'left'; } }); return alignmentMap; - }, [columnConfig, isNumericMap]); - - const minMaxByColumnId: Record = useMemo(() => { - return findMinMaxByColumnId( - columnConfig.columns - .filter(({ columnId }) => isNumericMap[columnId]) - .map(({ columnId }) => columnId), - firstTable - ); - }, [firstTable, isNumericMap, columnConfig]); + }, [firstLocalTable, columnConfig]); const trailingControlColumns: EuiDataGridControlColumn[] = useMemo(() => { if (!hasAtLeastOneRowClickAction || !onRowContextMenuClick) { @@ -272,10 +254,7 @@ export const DatatableComponent = (props: DatatableRenderProps) => { ]; }, [firstTableRef, onRowContextMenuClick, columnConfig, hasAtLeastOneRowClickAction]); - const renderCellValue = useMemo( - () => createGridCell(formatters, columnConfig, DataContext, props.uiSettings), - [formatters, columnConfig, props.uiSettings] - ); + const renderCellValue = useMemo(() => createGridCell(formatters, DataContext), [formatters]); const columnVisibility = useMemo(() => ({ visibleColumns, setVisibleColumns: () => {} }), [ visibleColumns, @@ -307,8 +286,6 @@ export const DatatableComponent = (props: DatatableRenderProps) => { table: firstLocalTable, rowHasRowClickTriggerActions: props.rowHasRowClickTriggerActions, alignments, - minMaxByColumnId, - getColorForValue: props.paletteService.get(CUSTOM_PALETTE).getColorForValue!, }} > IAggType; renderMode: RenderMode; - paletteService: PaletteRegistry; - uiSettings: IUiSettingsClient; /** * A boolean for each table row, which is true if the row active @@ -59,10 +55,4 @@ export interface DataContextType { table?: Datatable; rowHasRowClickTriggerActions?: boolean[]; alignments?: Record; - minMaxByColumnId?: Record; - getColorForValue?: ( - value: number | undefined, - state: CustomPaletteState, - minMax: { min: number; max: number } - ) => string | undefined; } diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 2d5f4aea9885623..7d879217abf8b2c 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -17,9 +17,6 @@ import { ExpressionFunctionDefinition, ExpressionRenderDefinition, } from 'src/plugins/expressions'; -import { CustomPaletteState, PaletteOutput } from 'src/plugins/charts/common'; -import { PaletteRegistry } from 'src/plugins/charts/public'; -import { IUiSettingsClient } from 'kibana/public'; import { getSortingCriteria } from './sorting'; import { DatatableComponent } from './components/table_basic'; @@ -29,15 +26,10 @@ import type { FormatFactory, ILensInterpreterRenderHandlers, LensMultiTable } fr import type { DatatableRender } from './components/types'; import { transposeTable } from './transpose_helpers'; -export type ColumnConfigArg = Omit & { - type: 'lens_datatable_column'; - palette?: PaletteOutput; -}; - export interface Args { title: string; description?: string; - columns: ColumnConfigArg[]; + columns: Array; sortingColumnId: string | undefined; sortingDirection: 'asc' | 'desc' | 'none'; } @@ -168,11 +160,6 @@ export const datatableColumn: ExpressionFunctionDefinition< width: { types: ['number'], help: '' }, isTransposed: { types: ['boolean'], help: '' }, transposable: { types: ['boolean'], help: '' }, - colorMode: { types: ['string'], help: '' }, - palette: { - types: ['palette'], - help: '', - }, }, fn: function fn(input: unknown, args: ColumnState) { return { @@ -185,8 +172,6 @@ export const datatableColumn: ExpressionFunctionDefinition< export const getDatatableRenderer = (dependencies: { formatFactory: FormatFactory; getType: Promise<(name: string) => IAggType>; - paletteService: PaletteRegistry; - uiSettings: IUiSettingsClient; }): ExpressionRenderDefinition => ({ name: 'lens_datatable_renderer', displayName: i18n.translate('xpack.lens.datatable.visualizationName', { @@ -237,10 +222,8 @@ export const getDatatableRenderer = (dependencies: { formatFactory={dependencies.formatFactory} dispatchEvent={handlers.event} renderMode={handlers.getRenderMode()} - paletteService={dependencies.paletteService} getType={resolvedGetType} rowHasRowClickTriggerActions={rowHasRowClickTriggerActions} - uiSettings={dependencies.uiSettings} /> , domNode, diff --git a/x-pack/plugins/lens/public/datatable_visualization/index.ts b/x-pack/plugins/lens/public/datatable_visualization/index.ts index 7f48d00d00f7f79..f0939f619522942 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/index.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/index.ts @@ -6,7 +6,6 @@ */ import { CoreSetup } from 'kibana/public'; -import { ChartsPluginSetup } from 'src/plugins/charts/public'; import { ExpressionsSetup } from '../../../../../src/plugins/expressions/public'; import { EditorFrameSetup, FormatFactory } from '../types'; import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; @@ -18,7 +17,6 @@ export interface DatatableVisualizationPluginSetupPlugins { expressions: ExpressionsSetup; formatFactory: Promise; editorFrame: EditorFrameSetup; - charts: ChartsPluginSetup; } export class DatatableVisualization { @@ -26,16 +24,15 @@ export class DatatableVisualization { setup( core: CoreSetup, - { expressions, formatFactory, editorFrame, charts }: DatatableVisualizationPluginSetupPlugins + { expressions, formatFactory, editorFrame }: DatatableVisualizationPluginSetupPlugins ) { editorFrame.registerVisualization(async () => { const { getDatatable, datatableColumn, getDatatableRenderer, - getDatatableVisualization, + datatableVisualization, } = await import('../async_services'); - const palettes = await charts.palettes.getPalettes(); const resolvedFormatFactory = await formatFactory; expressions.registerFunction(() => datatableColumn); @@ -46,11 +43,9 @@ export class DatatableVisualization { getType: core .getStartServices() .then(([_, { data: dataStart }]) => dataStart.search.aggs.types.get), - paletteService: palettes, - uiSettings: core.uiSettings, }) ); - return getDatatableVisualization({ paletteService: palettes }); + return datatableVisualization; }); } } diff --git a/x-pack/plugins/lens/public/datatable_visualization/transpose_helpers.ts b/x-pack/plugins/lens/public/datatable_visualization/transpose_helpers.ts index a35edf7499073a8..6e29e018b481e2e 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/transpose_helpers.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/transpose_helpers.ts @@ -7,9 +7,9 @@ import type { FieldFormat } from 'src/plugins/data/public'; import type { Datatable, DatatableColumn, DatatableRow } from 'src/plugins/expressions'; -import { ColumnConfig } from './components/table_basic'; -import { Args, ColumnConfigArg } from './expression'; +import { Args } from './expression'; +import { ColumnState } from './visualization'; const TRANSPOSE_SEPARATOR = '---'; @@ -87,11 +87,11 @@ export function transposeTable( function transposeRows( firstTable: Datatable, - bucketsColumnArgs: ColumnConfigArg[], + bucketsColumnArgs: Array, formatters: Record, transposedColumnFormatter: FieldFormat, transposedColumnId: string, - metricsColumnArgs: ColumnConfigArg[] + metricsColumnArgs: Array ) { const rowsByBucketColumns: Record = groupRowsByBucketColumns( firstTable, @@ -113,8 +113,8 @@ function transposeRows( */ function updateColumnArgs( args: Args, - bucketsColumnArgs: ColumnConfig['columns'], - transposedColumnGroups: Array + bucketsColumnArgs: Array, + transposedColumnGroups: Array> ) { args.columns = [...bucketsColumnArgs]; // add first column from each group, then add second column for each group, ... @@ -151,8 +151,8 @@ function getUniqueValues(table: Datatable, formatter: FieldFormat, columnId: str */ function transposeColumns( args: Args, - bucketsColumnArgs: ColumnConfig['columns'], - metricColumns: ColumnConfig['columns'], + bucketsColumnArgs: Array, + metricColumns: Array, firstTable: Datatable, uniqueValues: string[], uniqueRawValues: unknown[], @@ -196,10 +196,10 @@ function transposeColumns( */ function mergeRowGroups( rowsByBucketColumns: Record, - bucketColumns: ColumnConfigArg[], + bucketColumns: ColumnState[], formatter: FieldFormat, transposedColumnId: string, - metricColumns: ColumnConfigArg[] + metricColumns: ColumnState[] ) { return Object.values(rowsByBucketColumns).map((rows) => { const mergedRow: DatatableRow = {}; @@ -222,7 +222,7 @@ function mergeRowGroups( */ function groupRowsByBucketColumns( firstTable: Datatable, - bucketColumns: ColumnConfigArg[], + bucketColumns: ColumnState[], formatters: Record ) { const rowsByBucketColumns: Record = {}; diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx index ea8237defc29118..1848565114dea5d 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx @@ -8,7 +8,7 @@ import { Ast } from '@kbn/interpreter/common'; import { buildExpression } from '../../../../../src/plugins/expressions/public'; import { createMockDatasource, createMockFramePublicAPI } from '../editor_frame_service/mocks'; -import { DatatableVisualizationState, getDatatableVisualization } from './visualization'; +import { DatatableVisualizationState, datatableVisualization } from './visualization'; import { Operation, DataType, @@ -16,7 +16,6 @@ import { TableSuggestionColumn, VisualizationDimensionGroupConfig, } from '../types'; -import { chartPluginMock } from 'src/plugins/charts/public/mocks'; function mockFrame(): FramePublicAPI { return { @@ -33,10 +32,6 @@ function mockFrame(): FramePublicAPI { }; } -const datatableVisualization = getDatatableVisualization({ - paletteService: chartPluginMock.createPaletteRegistry(), -}); - describe('Datatable Visualization', () => { describe('#initialize', () => { it('should initialize from the empty state', () => { @@ -432,28 +427,22 @@ describe('Datatable Visualization', () => { ); const columnArgs = buildExpression(expression).findFunction('lens_datatable_column'); expect(columnArgs).toHaveLength(2); - expect(columnArgs[0].arguments).toEqual( - expect.objectContaining({ - columnId: ['c'], - hidden: [], - width: [], - isTransposed: [], - transposable: [true], - alignment: [], - colorMode: ['none'], - }) - ); - expect(columnArgs[1].arguments).toEqual( - expect.objectContaining({ - columnId: ['b'], - hidden: [], - width: [], - isTransposed: [], - transposable: [true], - alignment: [], - colorMode: ['none'], - }) - ); + expect(columnArgs[0].arguments).toEqual({ + columnId: ['c'], + hidden: [], + width: [], + isTransposed: [], + transposable: [true], + alignment: [], + }); + expect(columnArgs[1].arguments).toEqual({ + columnId: ['b'], + hidden: [], + width: [], + isTransposed: [], + transposable: [true], + alignment: [], + }); }); it('returns no expression if the metric dimension is not defined', () => { diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx index efde4160019e73a..9bd482c73bff58e 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx @@ -11,7 +11,6 @@ import { Ast } from '@kbn/interpreter/common'; import { I18nProvider } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { DatatableColumn } from 'src/plugins/expressions/public'; -import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; import { SuggestionRequest, Visualization, @@ -20,9 +19,6 @@ import { } from '../types'; import { LensIconChartDatatable } from '../assets/chart_datatable'; import { TableDimensionEditor } from './components/dimension_editor'; -import { CUSTOM_PALETTE } from '../shared_components/coloring/constants'; -import { CustomPaletteParams } from '../shared_components/coloring/types'; -import { getStopsForFixedMode } from '../shared_components'; export interface ColumnState { columnId: string; @@ -36,8 +32,6 @@ export interface ColumnState { originalName?: string; bucketValues?: Array<{ originalBucketColumn: DatatableColumn; value: unknown }>; alignment?: 'left' | 'right' | 'center'; - palette?: PaletteOutput; - colorMode?: 'none' | 'cell' | 'text'; } export interface SortingState { @@ -55,11 +49,7 @@ const visualizationLabel = i18n.translate('xpack.lens.datatable.label', { defaultMessage: 'Table', }); -export const getDatatableVisualization = ({ - paletteService, -}: { - paletteService: PaletteRegistry; -}): Visualization => ({ +export const datatableVisualization: Visualization = { id: 'lnsDatatable', visualizationTypes: [ @@ -249,26 +239,10 @@ export const getDatatableVisualization = ({ layerId: state.layerId, accessors: sortedColumns .filter((c) => !datasource!.getOperationForColumnId(c)?.isBucketed) - .map((accessor) => { - const columnConfig = columnMap[accessor]; - const hasColoring = Boolean( - columnConfig.colorMode !== 'none' && columnConfig.palette?.params?.stops - ); - return { - columnId: accessor, - triggerIcon: columnConfig.hidden - ? 'invisible' - : hasColoring - ? 'colorBy' - : undefined, - palette: hasColoring - ? getStopsForFixedMode( - columnConfig.palette?.params?.stops || [], - columnConfig.palette?.params?.colorStops - ) - : undefined, - }; - }), + .map((accessor) => ({ + columnId: accessor, + triggerIcon: columnMap[accessor].hidden ? 'invisible' : undefined, + })), supportsMoreColumns: true, filterOperations: (op) => !op.isBucketed, required: true, @@ -311,7 +285,7 @@ export const getDatatableVisualization = ({ renderDimensionEditor(domElement, props) { render( - + , domElement ); @@ -346,41 +320,26 @@ export const getDatatableVisualization = ({ arguments: { title: [title || ''], description: [description || ''], - columns: columns.map((column) => { - const paletteParams = { - ...column.palette?.params, - // rewrite colors and stops as two distinct arguments - colors: (column.palette?.params?.stops || []).map(({ color }) => color), - stops: - column.palette?.params?.name === 'custom' - ? (column.palette?.params?.stops || []).map(({ stop }) => stop) - : [], - reverse: false, // managed at UI level - }; - - return { - type: 'expression', - chain: [ - { - type: 'function', - function: 'lens_datatable_column', - arguments: { - columnId: [column.columnId], - hidden: typeof column.hidden === 'undefined' ? [] : [column.hidden], - width: typeof column.width === 'undefined' ? [] : [column.width], - isTransposed: - typeof column.isTransposed === 'undefined' ? [] : [column.isTransposed], - transposable: [ - !datasource!.getOperationForColumnId(column.columnId)?.isBucketed, - ], - alignment: typeof column.alignment === 'undefined' ? [] : [column.alignment], - colorMode: [column.colorMode ?? 'none'], - palette: [paletteService.get(CUSTOM_PALETTE).toExpression(paletteParams)], - }, + columns: columns.map((column) => ({ + type: 'expression', + chain: [ + { + type: 'function', + function: 'lens_datatable_column', + arguments: { + columnId: [column.columnId], + hidden: typeof column.hidden === 'undefined' ? [] : [column.hidden], + width: typeof column.width === 'undefined' ? [] : [column.width], + isTransposed: + typeof column.isTransposed === 'undefined' ? [] : [column.isTransposed], + transposable: [ + !datasource!.getOperationForColumnId(column.columnId)?.isBucketed, + ], + alignment: typeof column.alignment === 'undefined' ? [] : [column.alignment], }, - ], - }; - }), + }, + ], + })), sortingColumnId: [state.sorting?.columnId || ''], sortingDirection: [state.sorting?.direction || 'none'], }, @@ -436,7 +395,7 @@ export const getDatatableVisualization = ({ return state; } }, -}); +}; function getDataSourceAndSortedColumns( state: DatatableVisualizationState, diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.tsx index a8d610f2740de51..b8d3170b3e16509 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.tsx @@ -29,13 +29,11 @@ export function DimensionContainer({ groupLabel, handleClose, panel, - panelRef, }: { isOpen: boolean; handleClose: () => void; panel: React.ReactElement; groupLabel: string; - panelRef: (el: HTMLDivElement) => void; }) { const [focusTrapIsEnabled, setFocusTrapIsEnabled] = useState(false); @@ -75,67 +73,65 @@ export function DimensionContainer({ }); return isOpen ? ( -
- - - -
- - - - -

- - {i18n.translate('xpack.lens.configure.configurePanelTitle', { - defaultMessage: '{groupLabel} configuration', - values: { - groupLabel, - }, - })} - -

-
-
- - - -
-
- - {panel} - - - - {i18n.translate('xpack.lens.dimensionContainer.close', { - defaultMessage: 'Close', - })} - - -
-
-
-
+ + + +
+ + + + + + + +

+ + {i18n.translate('xpack.lens.configure.configurePanelTitle', { + defaultMessage: '{groupLabel} configuration', + values: { + groupLabel, + }, + })} + +

+
+
+
+
+ + {panel} + + + + {i18n.translate('xpack.lens.dimensionContainer.close', { + defaultMessage: 'Close', + })} + + +
+
+
) : null; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx index a605a94a3464682..cf3c9099d4b0dda 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx @@ -7,7 +7,7 @@ import './layer_panel.scss'; -import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react'; +import React, { useState, useEffect, useMemo, useCallback } from 'react'; import { EuiPanel, EuiSpacer, @@ -72,7 +72,6 @@ export function LayerPanel( setActiveDimension(initialActiveDimensionState); }, [activeVisualization.id]); - const panelRef = useRef(null); const registerLayerRef = useCallback((el) => registerNewLayerRef(layerId, el), [ layerId, registerNewLayerRef, @@ -406,7 +405,6 @@ export function LayerPanel( (panelRef.current = el)} isOpen={!!activeId} groupLabel={activeGroup?.groupLabel || ''} handleClose={() => { @@ -486,7 +484,6 @@ export function LayerPanel( groupId: activeGroup.groupId, accessor: activeId, setState: props.updateVisualization, - panelRef, }} />
diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx index 351b4009240ebbd..f23e4c74e1a8be2 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx @@ -7,7 +7,6 @@ import React, { ReactElement } from 'react'; import { ReactWrapper } from 'enzyme'; -import { setState, LensRootStore } from '../../state_management/index'; // Tests are executed in a jsdom environment who does not have sizing methods, // thus the AutoSizer will always compute a 0x0 size space @@ -29,7 +28,8 @@ jest.mock('react-virtualized-auto-sizer', () => { }); import { EuiPanel, EuiToolTip } from '@elastic/eui'; -import { EditorFrame, EditorFrameProps } from './editor_frame'; +import { mountWithIntl as mount } from '@kbn/test/jest'; +import { EditorFrame } from './editor_frame'; import { DatasourcePublicAPI, DatasourceSuggestion, Visualization } from '../../types'; import { act } from 'react-dom/test-utils'; import { coreMock } from 'src/core/public/mocks'; @@ -44,9 +44,9 @@ import { ReactExpressionRendererType } from 'src/plugins/expressions/public'; import { DragDrop } from '../../drag_drop'; import { FrameLayout } from './frame_layout'; import { uiActionsPluginMock } from '../../../../../../src/plugins/ui_actions/public/mocks'; +import { dataPluginMock } from '../../../../../../src/plugins/data/public/mocks'; import { chartPluginMock } from '../../../../../../src/plugins/charts/public/mocks'; import { expressionsPluginMock } from '../../../../../../src/plugins/expressions/public/mocks'; -import { mockDataPlugin, mountWithProvider } from '../../mocks'; function generateSuggestion(state = {}): DatasourceSuggestion { return { @@ -62,7 +62,7 @@ function generateSuggestion(state = {}): DatasourceSuggestion { } function getDefaultProps() { - const defaultProps = { + return { store: { save: jest.fn(), load: jest.fn(), @@ -72,17 +72,18 @@ function getDefaultProps() { onChange: jest.fn(), dateRange: { fromDate: '', toDate: '' }, query: { query: '', language: 'lucene' }, + filters: [], core: coreMock.createStart(), plugins: { uiActions: uiActionsPluginMock.createStartContract(), - data: mockDataPlugin(), + data: dataPluginMock.createStartContract(), expressions: expressionsPluginMock.createStartContract(), charts: chartPluginMock.createStartContract(), }, palettes: chartPluginMock.createPaletteRegistry(), showNoDataPopover: jest.fn(), + searchSessionId: 'sessionId', }; - return defaultProps; } describe('editor_frame', () => { @@ -132,57 +133,85 @@ describe('editor_frame', () => { describe('initialization', () => { it('should initialize initial datasource', async () => { mockVisualization.getLayerIds.mockReturnValue([]); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - }, - - ExpressionRenderer: expressionRendererMock, - }; + await act(async () => { + mount( + + ); + }); - await mountWithProvider(, props.plugins.data); expect(mockDatasource.initialize).toHaveBeenCalled(); }); + it('should not initialize datasource and visualization if no initial one is specificed', () => { + act(() => { + mount( + + ); + }); + + expect(mockVisualization.initialize).not.toHaveBeenCalled(); + expect(mockDatasource.initialize).not.toHaveBeenCalled(); + }); + it('should initialize all datasources with state from doc', async () => { const mockDatasource3 = createMockDatasource('testDatasource3'); const datasource1State = { datasource1: '' }; const datasource2State = { datasource2: '' }; - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - testDatasource2: mockDatasource2, - testDatasource3: mockDatasource3, - }, - ExpressionRenderer: expressionRendererMock, - }; - - await mountWithProvider(, props.plugins.data, { - persistedDoc: { - visualizationType: 'testVis', - title: '', - state: { - datasourceStates: { - testDatasource: datasource1State, - testDatasource2: datasource2State, - }, - visualization: {}, - query: { query: '', language: 'lucene' }, - filters: [], - }, - references: [], - }, + await act(async () => { + mount( + + ); }); - expect(mockDatasource.initialize).toHaveBeenCalledWith(datasource1State, [], undefined, { isFullEditor: true, }); @@ -193,40 +222,42 @@ describe('editor_frame', () => { }); it('should not render something before all datasources are initialized', async () => { - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - }, - - ExpressionRenderer: expressionRendererMock, - }; - await act(async () => { - mountWithProvider(, props.plugins.data); + mount( + + ); expect(mockDatasource.renderDataPanel).not.toHaveBeenCalled(); }); expect(mockDatasource.renderDataPanel).toHaveBeenCalled(); }); it('should not initialize visualization before datasource is initialized', async () => { - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - }, - - ExpressionRenderer: expressionRendererMock, - }; - await act(async () => { - mountWithProvider(, props.plugins.data); + mount( + + ); expect(mockVisualization.initialize).not.toHaveBeenCalled(); }); @@ -234,19 +265,23 @@ describe('editor_frame', () => { }); it('should pass the public frame api into visualization initialize', async () => { - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - }, - - ExpressionRenderer: expressionRendererMock, - }; + const defaultProps = getDefaultProps(); await act(async () => { - mountWithProvider(, props.plugins.data); + mount( + + ); expect(mockVisualization.initialize).not.toHaveBeenCalled(); }); @@ -256,43 +291,33 @@ describe('editor_frame', () => { removeLayers: expect.any(Function), query: { query: '', language: 'lucene' }, filters: [], - dateRange: { fromDate: '2021-01-10T04:00:00.000Z', toDate: '2021-01-10T08:00:00.000Z' }, - availablePalettes: props.palettes, - searchSessionId: 'sessionId-1', + dateRange: { fromDate: 'now-7d', toDate: 'now' }, + availablePalettes: defaultProps.palettes, + searchSessionId: 'sessionId', }); }); it('should add new layer on active datasource on frame api call', async () => { const initialState = { datasource2: '' }; mockDatasource2.initialize.mockReturnValue(Promise.resolve(initialState)); - - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - testDatasource2: mockDatasource2, - }, - - ExpressionRenderer: expressionRendererMock, - }; - await mountWithProvider(, props.plugins.data, { - persistedDoc: { - visualizationType: 'testVis', - title: '', - state: { - datasourceStates: { + await act(async () => { + mount( + + ); }); + act(() => { mockVisualization.initialize.mock.calls[0][0].addNewLayer(); }); @@ -307,33 +332,22 @@ describe('editor_frame', () => { mockDatasource2.getLayers.mockReturnValue(['abc', 'def']); mockDatasource2.removeLayer.mockReturnValue({ removed: true }); mockVisualization.getLayerIds.mockReturnValue(['first', 'abc', 'def']); - - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - testDatasource2: mockDatasource2, - }, - ExpressionRenderer: expressionRendererMock, - }; - - await mountWithProvider(, props.plugins.data, { - persistedDoc: { - visualizationType: 'testVis', - title: '', - state: { - datasourceStates: { + await act(async () => { + mount( + + ); }); act(() => { @@ -348,26 +362,28 @@ describe('editor_frame', () => { const initialState = {}; let databaseInitialized: ({}) => void; - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: { - ...mockDatasource, - initialize: () => - new Promise((resolve) => { - databaseInitialized = resolve; - }), - }, - }, - - ExpressionRenderer: expressionRendererMock, - }; - - await mountWithProvider(, props.plugins.data); - + await act(async () => { + mount( + + new Promise((resolve) => { + databaseInitialized = resolve; + }), + }, + }} + initialDatasourceId="testDatasource" + initialVisualizationId="testVis" + ExpressionRenderer={expressionRendererMock} + /> + ); + }); await act(async () => { databaseInitialized!(initialState); }); @@ -381,22 +397,25 @@ describe('editor_frame', () => { const initialState = {}; mockDatasource.getLayers.mockReturnValue(['first']); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: { ...mockVisualization, initialize: () => initialState }, - }, - datasourceMap: { - testDatasource: { - ...mockDatasource, - initialize: () => Promise.resolve(), - }, - }, - - ExpressionRenderer: expressionRendererMock, - }; - - await mountWithProvider(, props.plugins.data); + await act(async () => { + mount( + initialState }, + }} + datasourceMap={{ + testDatasource: { + ...mockDatasource, + initialize: () => Promise.resolve(), + }, + }} + initialDatasourceId="testDatasource" + initialVisualizationId="testVis" + ExpressionRenderer={expressionRendererMock} + /> + ); + }); expect(mockVisualization.getConfiguration).toHaveBeenCalledWith( expect.objectContaining({ state: initialState }) @@ -408,21 +427,25 @@ describe('editor_frame', () => { it('should render the resulting expression using the expression renderer', async () => { mockDatasource.getLayers.mockReturnValue(['first']); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: { ...mockVisualization, toExpression: () => 'vis' }, - }, - datasourceMap: { - testDatasource: { - ...mockDatasource, - toExpression: () => 'datasource', - }, - }, - - ExpressionRenderer: expressionRendererMock, - }; - instance = (await mountWithProvider(, props.plugins.data)).instance; + await act(async () => { + instance = mount( + 'vis' }, + }} + datasourceMap={{ + testDatasource: { + ...mockDatasource, + toExpression: () => 'datasource', + }, + }} + initialDatasourceId="testDatasource" + initialVisualizationId="testVis" + ExpressionRenderer={expressionRendererMock} + /> + ); + }); instance.update(); @@ -443,34 +466,37 @@ describe('editor_frame', () => { ); mockDatasource2.getLayers.mockReturnValue(['second', 'third']); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: { ...mockVisualization, toExpression: () => 'vis' }, - }, - datasourceMap: { testDatasource: mockDatasource, testDatasource2: mockDatasource2 }, - - ExpressionRenderer: expressionRendererMock, - }; - - instance = ( - await mountWithProvider(, props.plugins.data, { - persistedDoc: { - visualizationType: 'testVis', - title: '', - state: { - datasourceStates: { - testDatasource: {}, - testDatasource2: {}, + await act(async () => { + instance = mount( + 'vis' }, + }} + datasourceMap={{ + testDatasource: mockDatasource, + testDatasource2: mockDatasource2, + }} + initialDatasourceId="testDatasource" + initialVisualizationId="testVis" + ExpressionRenderer={expressionRendererMock} + doc={{ + visualizationType: 'testVis', + title: '', + state: { + datasourceStates: { + testDatasource: {}, + testDatasource2: {}, + }, + visualization: {}, + query: { query: '', language: 'lucene' }, + filters: [], }, - visualization: {}, - query: { query: '', language: 'lucene' }, - filters: [], - }, - references: [], - }, - }) - ).instance; + references: [], + }} + /> + ); + }); instance.update(); @@ -551,18 +577,23 @@ describe('editor_frame', () => { describe('state update', () => { it('should re-render config panel after state update', async () => { mockDatasource.getLayers.mockReturnValue(['first']); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - }, - ExpressionRenderer: expressionRendererMock, - }; - await mountWithProvider(, props.plugins.data); + await act(async () => { + mount( + + ); + }); const updatedState = {}; const setDatasourceState = (mockDatasource.renderDataPanel as jest.Mock).mock.calls[0][1] .setState; @@ -570,9 +601,8 @@ describe('editor_frame', () => { setDatasourceState(updatedState); }); - // TODO: temporary regression // validation requires to calls this getConfiguration API - expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(9); + expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(7); expect(mockVisualization.getConfiguration).toHaveBeenLastCalledWith( expect.objectContaining({ state: updatedState, @@ -583,18 +613,22 @@ describe('editor_frame', () => { it('should re-render data panel after state update', async () => { mockDatasource.getLayers.mockReturnValue(['first']); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - }, - - ExpressionRenderer: expressionRendererMock, - }; - await mountWithProvider(, props.plugins.data); + await act(async () => { + mount( + + ); + }); const setDatasourceState = (mockDatasource.renderDataPanel as jest.Mock).mock.calls[0][1] .setState; @@ -619,18 +653,23 @@ describe('editor_frame', () => { it('should re-render config panel with updated datasource api after datasource state update', async () => { mockDatasource.getLayers.mockReturnValue(['first']); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - }, - ExpressionRenderer: expressionRendererMock, - }; - await mountWithProvider(, props.plugins.data); + await act(async () => { + mount( + + ); + }); const updatedPublicAPI: DatasourcePublicAPI = { datasourceId: 'testDatasource', @@ -645,9 +684,8 @@ describe('editor_frame', () => { setDatasourceState({}); }); - // TODO: temporary regression, selectors will help // validation requires to calls this getConfiguration API - expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(9); + expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(7); expect(mockVisualization.getConfiguration).toHaveBeenLastCalledWith( expect.objectContaining({ frame: expect.objectContaining({ @@ -665,33 +703,37 @@ describe('editor_frame', () => { mockDatasource.getLayers.mockReturnValue(['first']); mockDatasource2.getLayers.mockReturnValue(['second', 'third']); mockVisualization.getLayerIds.mockReturnValue(['first', 'second', 'third']); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - testDatasource2: mockDatasource2, - }, - ExpressionRenderer: expressionRendererMock, - }; - await mountWithProvider(, props.plugins.data, { - persistedDoc: { - visualizationType: 'testVis', - title: '', - state: { - datasourceStates: { - testDatasource: {}, - testDatasource2: {}, - }, - visualization: {}, - query: { query: '', language: 'lucene' }, - filters: [], - }, - references: [], - }, + await act(async () => { + mount( + + ); }); expect(mockVisualization.getConfiguration).toHaveBeenCalled(); @@ -714,33 +756,36 @@ describe('editor_frame', () => { const datasource1State = { datasource1: '' }; const datasource2State = { datasource2: '' }; - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - testDatasource2: mockDatasource2, - }, - - ExpressionRenderer: expressionRendererMock, - }; - await mountWithProvider(, props.plugins.data, { - persistedDoc: { - visualizationType: 'testVis', - title: '', - state: { - datasourceStates: { - testDatasource: datasource1State, - testDatasource2: datasource2State, - }, - visualization: {}, - query: { query: '', language: 'lucene' }, - filters: [], - }, - references: [], - }, + await act(async () => { + mount( + + ); }); expect(mockDatasource.getPublicAPI).toHaveBeenCalledWith( @@ -768,18 +813,22 @@ describe('editor_frame', () => { mockDatasource.initialize.mockResolvedValue(datasourceState); mockDatasource.getLayers.mockReturnValue(['first']); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - }, - - ExpressionRenderer: expressionRendererMock, - }; - await mountWithProvider(, props.plugins.data); + await act(async () => { + mount( + + ); + }); expect(mockDatasource.getPublicAPI).toHaveBeenCalledWith({ state: datasourceState, @@ -821,20 +870,24 @@ describe('editor_frame', () => { }, ]); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - testVis2: mockVisualization2, - }, - datasourceMap: { - testDatasource: mockDatasource, - testDatasource2: mockDatasource2, - }, - - ExpressionRenderer: expressionRendererMock, - }; - instance = (await mountWithProvider(, props.plugins.data)).instance; + await act(async () => { + instance = mount( + + ); + }); // necessary to flush elements to dom synchronously instance.update(); @@ -931,41 +984,49 @@ describe('editor_frame', () => { describe('suggestions', () => { it('should fetch suggestions of currently active datasource when initializes from visualization trigger', async () => { - const props = { - ...getDefaultProps(), - initialContext: { - indexPatternId: '1', - fieldName: 'test', - }, - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - testDatasource2: mockDatasource2, - }, - - ExpressionRenderer: expressionRendererMock, - }; - await mountWithProvider(, props.plugins.data); + await act(async () => { + mount( + + ); + }); expect(mockDatasource.getDatasourceSuggestionsForVisualizeField).toHaveBeenCalled(); }); it('should fetch suggestions of currently active datasource', async () => { - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - testDatasource2: mockDatasource2, - }, - - ExpressionRenderer: expressionRendererMock, - }; - await mountWithProvider(, props.plugins.data); + await act(async () => { + mount( + + ); + }); expect(mockDatasource.getDatasourceSuggestionsFromCurrentState).toHaveBeenCalled(); expect(mockDatasource2.getDatasourceSuggestionsFromCurrentState).not.toHaveBeenCalled(); @@ -985,20 +1046,24 @@ describe('editor_frame', () => { }, ]); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - testVis2: mockVisualization2, - }, - datasourceMap: { - testDatasource: mockDatasource, - testDatasource2: mockDatasource2, - }, - - ExpressionRenderer: expressionRendererMock, - }; - await mountWithProvider(, props.plugins.data); + await act(async () => { + mount( + + ); + }); expect(mockVisualization.getSuggestions).toHaveBeenCalled(); expect(mockVisualization2.getSuggestions).toHaveBeenCalled(); @@ -1007,66 +1072,71 @@ describe('editor_frame', () => { let instance: ReactWrapper; it('should display top 5 suggestions in descending order', async () => { mockDatasource.getLayers.mockReturnValue(['first']); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: { - ...mockVisualization, - getSuggestions: () => [ - { - score: 0.1, - state: {}, - title: 'Suggestion6', - previewIcon: 'empty', - }, - { - score: 0.5, - state: {}, - title: 'Suggestion3', - previewIcon: 'empty', - }, - { - score: 0.7, - state: {}, - title: 'Suggestion2', - previewIcon: 'empty', - }, - { - score: 0.8, - state: {}, - title: 'Suggestion1', - previewIcon: 'empty', + + await act(async () => { + instance = mount( + [ + { + score: 0.1, + state: {}, + title: 'Suggestion6', + previewIcon: 'empty', + }, + { + score: 0.5, + state: {}, + title: 'Suggestion3', + previewIcon: 'empty', + }, + { + score: 0.7, + state: {}, + title: 'Suggestion2', + previewIcon: 'empty', + }, + { + score: 0.8, + state: {}, + title: 'Suggestion1', + previewIcon: 'empty', + }, + ], }, - ], - }, - testVis2: { - ...mockVisualization, - getSuggestions: () => [ - { - score: 0.4, - state: {}, - title: 'Suggestion5', - previewIcon: 'empty', + testVis2: { + ...mockVisualization, + getSuggestions: () => [ + { + score: 0.4, + state: {}, + title: 'Suggestion5', + previewIcon: 'empty', + }, + { + score: 0.45, + state: {}, + title: 'Suggestion4', + previewIcon: 'empty', + }, + ], }, - { - score: 0.45, - state: {}, - title: 'Suggestion4', - previewIcon: 'empty', + }} + datasourceMap={{ + testDatasource: { + ...mockDatasource, + getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], }, - ], - }, - }, - datasourceMap: { - testDatasource: { - ...mockDatasource, - getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], - }, - }, - - ExpressionRenderer: expressionRendererMock, - }; - instance = (await mountWithProvider(, props.plugins.data)).instance; + }} + initialDatasourceId="testDatasource" + initialVisualizationId="testVis" + ExpressionRenderer={expressionRendererMock} + /> + ); + }); // TODO why is this necessary? instance.update(); @@ -1089,32 +1159,37 @@ describe('editor_frame', () => { mockDatasource.getLayers.mockReturnValue(['first', 'second', 'third']); const newDatasourceState = {}; const suggestionVisState = {}; - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: { - ...mockVisualization, - getSuggestions: () => [ - { - score: 0.8, - state: suggestionVisState, - title: 'Suggestion1', - previewIcon: 'empty', - }, - ], - }, - testVis2: mockVisualization2, - }, - datasourceMap: { - testDatasource: { - ...mockDatasource, - getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], - }, - }, - ExpressionRenderer: expressionRendererMock, - }; - instance = (await mountWithProvider(, props.plugins.data)).instance; + await act(async () => { + instance = mount( + [ + { + score: 0.8, + state: suggestionVisState, + title: 'Suggestion1', + previewIcon: 'empty', + }, + ], + }, + testVis2: mockVisualization2, + }} + datasourceMap={{ + testDatasource: { + ...mockDatasource, + getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], + }, + }} + initialDatasourceId="testDatasource" + initialVisualizationId="testVis2" + ExpressionRenderer={expressionRendererMock} + /> + ); + }); // TODO why is this necessary? instance.update(); @@ -1124,8 +1199,7 @@ describe('editor_frame', () => { }); // validation requires to calls this getConfiguration API - // TODO: why so many times? - expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(10); + expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(5); expect(mockVisualization.getConfiguration).toHaveBeenCalledWith( expect.objectContaining({ state: suggestionVisState, @@ -1142,40 +1216,45 @@ describe('editor_frame', () => { it('should switch to best suggested visualization on field drop', async () => { mockDatasource.getLayers.mockReturnValue(['first']); const suggestionVisState = {}; - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: { - ...mockVisualization, - getSuggestions: () => [ - { - score: 0.2, - state: {}, - title: 'Suggestion1', - previewIcon: 'empty', + + await act(async () => { + instance = mount( + [ + { + score: 0.2, + state: {}, + title: 'Suggestion1', + previewIcon: 'empty', + }, + { + score: 0.8, + state: suggestionVisState, + title: 'Suggestion2', + previewIcon: 'empty', + }, + ], }, - { - score: 0.8, - state: suggestionVisState, - title: 'Suggestion2', - previewIcon: 'empty', + testVis2: mockVisualization2, + }} + datasourceMap={{ + testDatasource: { + ...mockDatasource, + getDatasourceSuggestionsForField: () => [generateSuggestion()], + getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], + getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], }, - ], - }, - testVis2: mockVisualization2, - }, - datasourceMap: { - testDatasource: { - ...mockDatasource, - getDatasourceSuggestionsForField: () => [generateSuggestion()], - getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], - getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], - }, - }, - - ExpressionRenderer: expressionRendererMock, - }; - instance = (await mountWithProvider(, props.plugins.data)).instance; + }} + initialDatasourceId="testDatasource" + initialVisualizationId="testVis" + ExpressionRenderer={expressionRendererMock} + /> + ); + }); // TODO why is this necessary? instance.update(); @@ -1195,58 +1274,63 @@ describe('editor_frame', () => { mockDatasource.getLayers.mockReturnValue(['first', 'second', 'third']); const suggestionVisState = {}; - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: { - ...mockVisualization, - getSuggestions: () => [ - { - score: 0.2, - state: {}, - title: 'Suggestion1', - previewIcon: 'empty', + await act(async () => { + instance = mount( + [ + { + score: 0.2, + state: {}, + title: 'Suggestion1', + previewIcon: 'empty', + }, + { + score: 0.6, + state: {}, + title: 'Suggestion2', + previewIcon: 'empty', + }, + ], }, - { - score: 0.6, - state: {}, - title: 'Suggestion2', - previewIcon: 'empty', + testVis2: { + ...mockVisualization2, + getSuggestions: () => [ + { + score: 0.8, + state: suggestionVisState, + title: 'Suggestion3', + previewIcon: 'empty', + }, + ], }, - ], - }, - testVis2: { - ...mockVisualization2, - getSuggestions: () => [ - { - score: 0.8, - state: suggestionVisState, - title: 'Suggestion3', - previewIcon: 'empty', + }} + datasourceMap={{ + testDatasource: { + ...mockDatasource, + getDatasourceSuggestionsForField: () => [generateSuggestion()], + getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], + getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], + renderDataPanel: (_element, { dragDropContext: { setDragging, dragging } }) => { + if (!dragging || dragging.id !== 'draggedField') { + setDragging({ + id: 'draggedField', + humanData: { label: 'draggedField' }, + }); + } + }, }, - ], - }, - }, - datasourceMap: { - testDatasource: { - ...mockDatasource, - getDatasourceSuggestionsForField: () => [generateSuggestion()], - getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], - getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], - renderDataPanel: (_element, { dragDropContext: { setDragging, dragging } }) => { - if (!dragging || dragging.id !== 'draggedField') { - setDragging({ - id: 'draggedField', - humanData: { label: 'draggedField' }, - }); - } - }, - }, - }, + }} + initialDatasourceId="testDatasource" + initialVisualizationId="testVis2" + ExpressionRenderer={expressionRendererMock} + /> + ); + }); - ExpressionRenderer: expressionRendererMock, - } as EditorFrameProps; - instance = (await mountWithProvider(, props.plugins.data)).instance; // TODO why is this necessary? instance.update(); @@ -1300,55 +1384,58 @@ describe('editor_frame', () => { ], }; - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: { - ...mockVisualization, - getSuggestions: () => [ - { - score: 0.2, - state: {}, - title: 'Suggestion1', - previewIcon: 'empty', + await act(async () => { + instance = mount( + [ + { + score: 0.2, + state: {}, + title: 'Suggestion1', + previewIcon: 'empty', + }, + { + score: 0.6, + state: {}, + title: 'Suggestion2', + previewIcon: 'empty', + }, + ], }, - { - score: 0.6, - state: {}, - title: 'Suggestion2', - previewIcon: 'empty', + testVis2: { + ...mockVisualization2, + getSuggestions: () => [], }, - ], - }, - testVis2: { - ...mockVisualization2, - getSuggestions: () => [], - }, - testVis3: { - ...mockVisualization3, - }, - }, - datasourceMap: { - testDatasource: { - ...mockDatasource, - getDatasourceSuggestionsForField: () => [generateSuggestion()], - getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], - getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], - renderDataPanel: (_element, { dragDropContext: { setDragging, dragging } }) => { - if (!dragging || dragging.id !== 'draggedField') { - setDragging({ - id: 'draggedField', - humanData: { label: '1' }, - }); - } - }, - }, - }, - - ExpressionRenderer: expressionRendererMock, - } as EditorFrameProps; - - instance = (await mountWithProvider(, props.plugins.data)).instance; + testVis3: { + ...mockVisualization3, + }, + }} + datasourceMap={{ + testDatasource: { + ...mockDatasource, + getDatasourceSuggestionsForField: () => [generateSuggestion()], + getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], + getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], + renderDataPanel: (_element, { dragDropContext: { setDragging, dragging } }) => { + if (!dragging || dragging.id !== 'draggedField') { + setDragging({ + id: 'draggedField', + humanData: { label: '1' }, + }); + } + }, + }, + }} + initialDatasourceId="testDatasource" + initialVisualizationId="testVis2" + ExpressionRenderer={expressionRendererMock} + /> + ); + }); // TODO why is this necessary? instance.update(); @@ -1394,79 +1481,74 @@ describe('editor_frame', () => { })); mockVisualization.initialize.mockReturnValue({ initialState: true }); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - }, - - ExpressionRenderer: expressionRendererMock, - onChange, - }; - - let lensStore: LensRootStore = {} as LensRootStore; await act(async () => { - const mounted = await mountWithProvider(, props.plugins.data); - lensStore = mounted.lensStore; - expect(lensStore.dispatch).toHaveBeenCalledTimes(0); + mount( + + ); + expect(onChange).toHaveBeenCalledTimes(0); resolver({}); }); - expect(lensStore.dispatch).toHaveBeenCalledTimes(2); - expect(lensStore.dispatch).toHaveBeenNthCalledWith(1, { - payload: { - indexPatternsForTopNav: [{ id: '1' }], - lastKnownDoc: { - savedObjectId: undefined, - description: undefined, - references: [ - { - id: '1', - name: 'index-pattern-0', - type: 'index-pattern', - }, - ], - state: { - visualization: null, // Not yet loaded - datasourceStates: { testDatasource: {} }, - query: { query: '', language: 'lucene' }, - filters: [], + expect(onChange).toHaveBeenCalledTimes(2); + expect(onChange).toHaveBeenNthCalledWith(1, { + filterableIndexPatterns: ['1'], + doc: { + id: undefined, + description: undefined, + references: [ + { + id: '1', + name: 'index-pattern-0', + type: 'index-pattern', }, - title: '', - type: 'lens', - visualizationType: 'testVis', + ], + state: { + visualization: null, // Not yet loaded + datasourceStates: { testDatasource: {} }, + query: { query: '', language: 'lucene' }, + filters: [], }, + title: '', + type: 'lens', + visualizationType: 'testVis', }, - type: 'app/onChangeFromEditorFrame', + isSaveable: false, }); - expect(lensStore.dispatch).toHaveBeenLastCalledWith({ - payload: { - indexPatternsForTopNav: [{ id: '1' }], - lastKnownDoc: { - references: [ - { - id: '1', - name: 'index-pattern-0', - type: 'index-pattern', - }, - ], - description: undefined, - savedObjectId: undefined, - state: { - visualization: { initialState: true }, // Now loaded - datasourceStates: { testDatasource: {} }, - query: { query: '', language: 'lucene' }, - filters: [], + expect(onChange).toHaveBeenLastCalledWith({ + filterableIndexPatterns: ['1'], + doc: { + references: [ + { + id: '1', + name: 'index-pattern-0', + type: 'index-pattern', }, - title: '', - type: 'lens', - visualizationType: 'testVis', + ], + description: undefined, + id: undefined, + state: { + visualization: { initialState: true }, // Now loaded + datasourceStates: { testDatasource: {} }, + query: { query: '', language: 'lucene' }, + filters: [], }, + title: '', + type: 'lens', + visualizationType: 'testVis', }, - type: 'app/onChangeFromEditorFrame', + isSaveable: false, }); }); @@ -1479,63 +1561,48 @@ describe('editor_frame', () => { mockDatasource.getLayers.mockReturnValue(['first']); mockVisualization.initialize.mockReturnValue({ initialState: true }); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - }, - - ExpressionRenderer: expressionRendererMock, - onChange, - }; - - const { instance: el, lensStore } = await mountWithProvider( - , - props.plugins.data - ); - instance = el; + await act(async () => { + instance = mount( + + ); + }); - expect(lensStore.dispatch).toHaveBeenCalledTimes(2); + expect(onChange).toHaveBeenCalledTimes(2); mockDatasource.toExpression.mockReturnValue('data expression'); mockVisualization.toExpression.mockReturnValue('vis expression'); - await act(async () => { - lensStore.dispatch(setState({ query: { query: 'new query', language: 'lucene' } })); - }); - + instance.setProps({ query: { query: 'new query', language: 'lucene' } }); instance.update(); - expect(lensStore.dispatch).toHaveBeenCalledTimes(4); - expect(lensStore.dispatch).toHaveBeenNthCalledWith(3, { - payload: { - query: { - language: 'lucene', - query: 'new query', - }, - }, - type: 'app/setState', - }); - expect(lensStore.dispatch).toHaveBeenNthCalledWith(4, { - payload: { - lastKnownDoc: { - savedObjectId: undefined, - references: [], - state: { - datasourceStates: { testDatasource: { datasource: '' } }, - visualization: { initialState: true }, - query: { query: 'new query', language: 'lucene' }, - filters: [], - }, - title: '', - type: 'lens', - visualizationType: 'testVis', + expect(onChange).toHaveBeenCalledTimes(3); + expect(onChange).toHaveBeenNthCalledWith(3, { + filterableIndexPatterns: [], + doc: { + id: undefined, + references: [], + state: { + datasourceStates: { testDatasource: { datasource: '' } }, + visualization: { initialState: true }, + query: { query: 'new query', language: 'lucene' }, + filters: [], }, - isSaveable: true, + title: '', + type: 'lens', + visualizationType: 'testVis', }, - type: 'app/onChangeFromEditorFrame', + isSaveable: true, }); }); @@ -1550,23 +1617,21 @@ describe('editor_frame', () => { })); mockVisualization.initialize.mockReturnValue({ initialState: true }); - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: mockVisualization, - }, - datasourceMap: { - testDatasource: mockDatasource, - }, - - ExpressionRenderer: expressionRendererMock, - onChange, - }; - const mounted = await mountWithProvider(, props.plugins.data); - instance = mounted.instance; - const { lensStore } = mounted; + await act(async () => { + instance = mount( + + ); + }); - expect(lensStore.dispatch).toHaveBeenCalledTimes(2); + expect(onChange).toHaveBeenCalledTimes(2); await act(async () => { (instance.find(FrameLayout).prop('dataPanel') as ReactElement)!.props.dispatch({ @@ -1578,7 +1643,7 @@ describe('editor_frame', () => { }); }); - expect(lensStore.dispatch).toHaveBeenCalledTimes(3); + expect(onChange).toHaveBeenCalledTimes(3); }); }); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx index 4710e03d336bcfa..91b59664ada838c 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx @@ -7,10 +7,7 @@ import React, { useEffect, useReducer, useState, useCallback } from 'react'; import { CoreStart } from 'kibana/public'; -import { isEqual } from 'lodash'; import { PaletteRegistry } from 'src/plugins/charts/public'; -import { IndexPattern } from '../../../../../../src/plugins/data/public'; -import { getAllIndexPatterns } from '../../utils'; import { ReactExpressionRendererType } from '../../../../../../src/plugins/expressions/public'; import { Datasource, FramePublicAPI, Visualization } from '../../types'; import { reducer, getInitialState } from './state_management'; @@ -23,6 +20,7 @@ import { Document } from '../../persistence/saved_object_store'; import { DragDropIdentifier, RootDragDropProvider } from '../../drag_drop'; import { getSavedObjectFormat } from './save'; import { generateId } from '../../id_generator'; +import { Filter, Query, SavedQuery } from '../../../../../../src/plugins/data/public'; import { VisualizeFieldContext } from '../../../../../../src/plugins/ui_actions/public'; import { EditorFrameStartPlugins } from '../service'; import { initializeDatasources, createDatasourceLayers } from './state_helpers'; @@ -32,45 +30,37 @@ import { switchToSuggestion, } from './suggestion_helpers'; import { trackUiEvent } from '../../lens_ui_telemetry'; -import { - useLensSelector, - useLensDispatch, - LensAppState, - DispatchSetState, - onChangeFromEditorFrame, -} from '../../state_management'; export interface EditorFrameProps { + doc?: Document; datasourceMap: Record; visualizationMap: Record; + initialDatasourceId: string | null; + initialVisualizationId: string | null; ExpressionRenderer: ReactExpressionRendererType; palettes: PaletteRegistry; onError: (e: { message: string }) => void; core: CoreStart; plugins: EditorFrameStartPlugins; + dateRange: { + fromDate: string; + toDate: string; + }; + query: Query; + filters: Filter[]; + savedQuery?: SavedQuery; + searchSessionId: string; + onChange: (arg: { + filterableIndexPatterns: string[]; + doc: Document; + isSaveable: boolean; + }) => void; showNoDataPopover: () => void; initialContext?: VisualizeFieldContext; } export function EditorFrame(props: EditorFrameProps) { - const { - filters, - searchSessionId, - savedQuery, - query, - persistedDoc, - indexPatternsForTopNav, - lastKnownDoc, - activeData, - isSaveable, - resolvedDateRange: dateRange, - } = useLensSelector((state) => state.app); - const [state, dispatch] = useReducer(reducer, { ...props, doc: persistedDoc }, getInitialState); - const dispatchLens = useLensDispatch(); - const dispatchChange: DispatchSetState = useCallback( - (s: Partial) => dispatchLens(onChangeFromEditorFrame(s)), - [dispatchLens] - ); + const [state, dispatch] = useReducer(reducer, props, getInitialState); const [visualizeTriggerFieldContext, setVisualizeTriggerFieldContext] = useState( props.initialContext ); @@ -91,7 +81,7 @@ export function EditorFrame(props: EditorFrameProps) { initializeDatasources( props.datasourceMap, state.datasourceStates, - persistedDoc?.references, + props.doc?.references, visualizeTriggerFieldContext, { isFullEditor: true } ) @@ -119,11 +109,11 @@ export function EditorFrame(props: EditorFrameProps) { const framePublicAPI: FramePublicAPI = { datasourceLayers, - activeData, - dateRange, - query, - filters, - searchSessionId, + activeData: state.activeData, + dateRange: props.dateRange, + query: props.query, + filters: props.filters, + searchSessionId: props.searchSessionId, availablePalettes: props.palettes, addNewLayer() { @@ -170,19 +160,19 @@ export function EditorFrame(props: EditorFrameProps) { useEffect( () => { - if (persistedDoc) { + if (props.doc) { dispatch({ type: 'VISUALIZATION_LOADED', doc: { - ...persistedDoc, + ...props.doc, state: { - ...persistedDoc.state, - visualization: persistedDoc.visualizationType - ? props.visualizationMap[persistedDoc.visualizationType].initialize( + ...props.doc.state, + visualization: props.doc.visualizationType + ? props.visualizationMap[props.doc.visualizationType].initialize( framePublicAPI, - persistedDoc.state.visualization + props.doc.state.visualization ) - : persistedDoc.state.visualization, + : props.doc.state.visualization, }, }, }); @@ -194,7 +184,7 @@ export function EditorFrame(props: EditorFrameProps) { } }, // eslint-disable-next-line react-hooks/exhaustive-deps - [persistedDoc] + [props.doc] ); // Initialize visualization as soon as all datasources are ready @@ -215,7 +205,7 @@ export function EditorFrame(props: EditorFrameProps) { // Get suggestions for visualize field when all datasources are ready useEffect(() => { - if (allLoaded && visualizeTriggerFieldContext && !persistedDoc) { + if (allLoaded && visualizeTriggerFieldContext && !props.doc) { applyVisualizeFieldSuggestions({ datasourceMap: props.datasourceMap, datasourceStates: state.datasourceStates, @@ -230,51 +220,6 @@ export function EditorFrame(props: EditorFrameProps) { // eslint-disable-next-line react-hooks/exhaustive-deps }, [allLoaded]); - const getStateToUpdate: ( - arg: { - filterableIndexPatterns: string[]; - doc: Document; - isSaveable: boolean; - }, - oldState: { - isSaveable: boolean; - indexPatternsForTopNav: IndexPattern[]; - persistedDoc?: Document; - lastKnownDoc?: Document; - } - ) => Promise | undefined> = async ( - { filterableIndexPatterns, doc, isSaveable: incomingIsSaveable }, - prevState - ) => { - const batchedStateToUpdate: Partial = {}; - - if (incomingIsSaveable !== prevState.isSaveable) { - batchedStateToUpdate.isSaveable = incomingIsSaveable; - } - - if (!isEqual(prevState.persistedDoc, doc) && !isEqual(prevState.lastKnownDoc, doc)) { - batchedStateToUpdate.lastKnownDoc = doc; - } - const hasIndexPatternsChanged = - prevState.indexPatternsForTopNav.length !== filterableIndexPatterns.length || - filterableIndexPatterns.some( - (id) => !prevState.indexPatternsForTopNav.find((indexPattern) => indexPattern.id === id) - ); - // Update the cached index patterns if the user made a change to any of them - if (hasIndexPatternsChanged) { - const { indexPatterns } = await getAllIndexPatterns( - filterableIndexPatterns, - props.plugins.data.indexPatterns - ); - if (indexPatterns) { - batchedStateToUpdate.indexPatternsForTopNav = indexPatterns; - } - } - if (Object.keys(batchedStateToUpdate).length) { - return batchedStateToUpdate; - } - }; - // The frame needs to call onChange every time its internal state changes useEffect( () => { @@ -287,43 +232,31 @@ export function EditorFrame(props: EditorFrameProps) { return; } - const savedObjectFormat = getSavedObjectFormat({ - activeDatasources: Object.keys(state.datasourceStates).reduce( - (datasourceMap, datasourceId) => ({ - ...datasourceMap, - [datasourceId]: props.datasourceMap[datasourceId], - }), - {} - ), - visualization: activeVisualization, - state, - framePublicAPI, - }); - - // Frame loader (app or embeddable) is expected to call this when it loads and updates - // This should be replaced with a top-down state - getStateToUpdate(savedObjectFormat, { - isSaveable, - persistedDoc, - indexPatternsForTopNav, - lastKnownDoc, - }).then((batchedStateToUpdate) => { - if (batchedStateToUpdate) { - dispatchChange(batchedStateToUpdate); - } - }); + props.onChange( + getSavedObjectFormat({ + activeDatasources: Object.keys(state.datasourceStates).reduce( + (datasourceMap, datasourceId) => ({ + ...datasourceMap, + [datasourceId]: props.datasourceMap[datasourceId], + }), + {} + ), + visualization: activeVisualization, + state, + framePublicAPI, + }) + ); }, // eslint-disable-next-line react-hooks/exhaustive-deps [ activeVisualization, state.datasourceStates, state.visualization, - activeData, - query, - filters, - savedQuery, + state.activeData, + props.query, + props.filters, + props.savedQuery, state.title, - dispatchChange, ] ); @@ -393,9 +326,9 @@ export function EditorFrame(props: EditorFrameProps) { } dispatch={dispatch} core={props.core} - query={query} - dateRange={dateRange} - filters={filters} + query={props.query} + dateRange={props.dateRange} + filters={props.filters} showNoDataPopover={props.showNoDataPopover} dropOntoWorkspace={dropOntoWorkspace} hasSuggestionForField={hasSuggestionForField} diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/save.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/save.ts index 86a28be65d2b9f8..6eec13dd9d7ce08 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/save.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/save.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { uniq } from 'lodash'; +import _ from 'lodash'; import { SavedObjectReference } from 'kibana/public'; +import { Datatable } from 'src/plugins/expressions'; import { EditorFrameState } from './state_management'; import { Document } from '../../persistence/saved_object_store'; import { Datasource, Visualization, FramePublicAPI } from '../../types'; @@ -29,6 +30,7 @@ export function getSavedObjectFormat({ doc: Document; filterableIndexPatterns: string[]; isSaveable: boolean; + activeData: Record | undefined; } { const datasourceStates: Record = {}; const references: SavedObjectReference[] = []; @@ -40,7 +42,7 @@ export function getSavedObjectFormat({ references.push(...savedObjectReferences); }); - const uniqueFilterableIndexPatternIds = uniq( + const uniqueFilterableIndexPatternIds = _.uniq( references.filter(({ type }) => type === 'index-pattern').map(({ id }) => id) ); @@ -75,5 +77,6 @@ export function getSavedObjectFormat({ }, filterableIndexPatterns: uniqueFilterableIndexPatternIds, isSaveable: expression !== null, + activeData: state.activeData, }; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.test.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.test.ts index af8a9c0a8555880..5d6dae557dbb8ef 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.test.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.test.ts @@ -24,7 +24,10 @@ describe('editor_frame state management', () => { onError: jest.fn(), datasourceMap: { testDatasource: ({} as unknown) as Datasource }, visualizationMap: { testVis: ({ initialize: jest.fn() } as unknown) as Visualization }, + initialDatasourceId: 'testDatasource', + initialVisualizationId: 'testVis', ExpressionRenderer: createExpressionRendererMock(), + onChange: jest.fn(), core: coreMock.createStart(), plugins: { uiActions: uiActionsPluginMock.createStartContract(), @@ -33,7 +36,11 @@ describe('editor_frame state management', () => { charts: chartPluginMock.createStartContract(), }, palettes: chartPluginMock.createPaletteRegistry(), + dateRange: { fromDate: 'now-7d', toDate: 'now' }, + query: { query: '', language: 'lucene' }, + filters: [], showNoDataPopover: jest.fn(), + searchSessionId: 'sessionId', }; }); @@ -94,8 +101,8 @@ describe('editor_frame state management', () => { `); }); - it('should not set active id if initiated with empty document and visualizationMap is empty', () => { - const initialState = getInitialState({ ...props, visualizationMap: {} }); + it('should not set active id if no initial visualization is passed in', () => { + const initialState = getInitialState({ ...props, initialVisualizationId: null }); expect(initialState.visualization.state).toEqual(null); expect(initialState.visualization.activeId).toEqual(null); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.ts index aa365d1e66d6c5c..53aba0d6f3f6c17 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.ts @@ -7,6 +7,7 @@ import { EditorFrameProps } from './index'; import { Document } from '../../persistence/saved_object_store'; +import { TableInspectorAdapter } from '../types'; export interface PreviewState { visualization: { @@ -22,6 +23,7 @@ export interface EditorFrameState extends PreviewState { description?: string; stagedPreview?: PreviewState; activeDatasourceId: string | null; + activeData?: TableInspectorAdapter; } export type Action = @@ -33,6 +35,10 @@ export type Action = type: 'UPDATE_TITLE'; title: string; } + | { + type: 'UPDATE_ACTIVE_DATA'; + tables: TableInspectorAdapter; + } | { type: 'UPDATE_STATE'; // Just for diagnostics, so we can determine what action @@ -97,27 +103,25 @@ export function getActiveDatasourceIdFromDoc(doc?: Document) { return null; } - const [firstDatasourceFromDoc] = Object.keys(doc.state.datasourceStates); - return firstDatasourceFromDoc || null; + const [initialDatasourceId] = Object.keys(doc.state.datasourceStates); + return initialDatasourceId || null; } -export const getInitialState = ( - params: EditorFrameProps & { doc?: Document } -): EditorFrameState => { - const datasourceStates: EditorFrameState['datasourceStates'] = {}; - - const initialDatasourceId = - getActiveDatasourceIdFromDoc(params.doc) || Object.keys(params.datasourceMap)[0] || null; +function getInitialDatasourceId(props: EditorFrameProps) { + return props.initialDatasourceId + ? props.initialDatasourceId + : getActiveDatasourceIdFromDoc(props.doc); +} - const initialVisualizationId = - (params.doc && params.doc.visualizationType) || Object.keys(params.visualizationMap)[0] || null; +export const getInitialState = (props: EditorFrameProps): EditorFrameState => { + const datasourceStates: EditorFrameState['datasourceStates'] = {}; - if (params.doc) { - Object.entries(params.doc.state.datasourceStates).forEach(([datasourceId, state]) => { + if (props.doc) { + Object.entries(props.doc.state.datasourceStates).forEach(([datasourceId, state]) => { datasourceStates[datasourceId] = { isLoading: true, state }; }); - } else if (initialDatasourceId) { - datasourceStates[initialDatasourceId] = { + } else if (props.initialDatasourceId) { + datasourceStates[props.initialDatasourceId] = { state: null, isLoading: true, }; @@ -126,10 +130,10 @@ export const getInitialState = ( return { title: '', datasourceStates, - activeDatasourceId: initialDatasourceId, + activeDatasourceId: getInitialDatasourceId(props), visualization: { state: null, - activeId: initialVisualizationId, + activeId: props.initialVisualizationId, }, }; }; @@ -142,6 +146,11 @@ export const reducer = (state: EditorFrameState, action: Action): EditorFrameSta return { ...state, title: action.title }; case 'UPDATE_STATE': return action.updater(state); + case 'UPDATE_ACTIVE_DATA': + return { + ...state, + activeData: { ...action.tables }, + }; case 'UPDATE_LAYER': return { ...state, diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts index bd8f134f59fbb70..83b09226265423f 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { flatten } from 'lodash'; +import _ from 'lodash'; import { Ast } from '@kbn/interpreter/common'; import { IconType } from '@elastic/eui/src/components/icon/icon'; import { Datatable } from 'src/plugins/expressions'; @@ -79,7 +79,7 @@ export function getSuggestions({ ); // Collect all table suggestions from available datasources - const datasourceTableSuggestions = flatten( + const datasourceTableSuggestions = _.flatten( datasources.map(([datasourceId, datasource]) => { const datasourceState = datasourceStates[datasourceId].state; let dataSourceSuggestions; @@ -103,9 +103,9 @@ export function getSuggestions({ // Pass all table suggestions to all visualization extensions to get visualization suggestions // and rank them by score - return flatten( + return _.flatten( Object.entries(visualizationMap).map(([visualizationId, visualization]) => - flatten( + _.flatten( datasourceTableSuggestions.map((datasourceSuggestion) => { const table = datasourceSuggestion.table; const currentVisualizationState = diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx index 1d248c4411023c2..baa9d45a431eaf9 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx @@ -16,14 +16,14 @@ import { DatasourceMock, createMockFramePublicAPI, } from '../../mocks'; -import { mockDataPlugin, mountWithProvider } from '../../../mocks'; + jest.mock('../../../debounced_component', () => { return { debouncedComponent: (fn: unknown) => fn, }; }); -import { WorkspacePanel } from './workspace_panel'; +import { WorkspacePanel, WorkspacePanelProps } from './workspace_panel'; import { mountWithIntl as mount } from '@kbn/test/jest'; import { ReactWrapper } from 'enzyme'; import { DragDrop, ChildDragDropProvider } from '../../../drag_drop'; @@ -34,6 +34,7 @@ import { UiActionsStart } from '../../../../../../../src/plugins/ui_actions/publ import { uiActionsPluginMock } from '../../../../../../../src/plugins/ui_actions/public/mocks'; import { TriggerContract } from '../../../../../../../src/plugins/ui_actions/public/triggers'; import { VIS_EVENT_TO_TRIGGER } from '../../../../../../../src/plugins/visualizations/public/embeddable'; +import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; const defaultPermissions: Record>> = { navLinks: { management: true }, @@ -49,22 +50,24 @@ function createCoreStartWithPermissions(newCapabilities = defaultPermissions) { return core; } -const defaultProps = { - activeDatasourceId: 'mock', - datasourceStates: {}, - datasourceMap: {}, - framePublicAPI: createMockFramePublicAPI(), - activeVisualizationId: 'vis', - visualizationState: {}, - dispatch: () => {}, - ExpressionRenderer: createExpressionRendererMock(), - core: createCoreStartWithPermissions(), - plugins: { - uiActions: uiActionsPluginMock.createStartContract(), - data: mockDataPlugin(), - }, - getSuggestionForField: () => undefined, -}; +function getDefaultProps() { + return { + activeDatasourceId: 'mock', + datasourceStates: {}, + datasourceMap: {}, + framePublicAPI: createMockFramePublicAPI(), + activeVisualizationId: 'vis', + visualizationState: {}, + dispatch: () => {}, + ExpressionRenderer: createExpressionRendererMock(), + core: createCoreStartWithPermissions(), + plugins: { + uiActions: uiActionsPluginMock.createStartContract(), + data: dataPluginMock.createStartContract(), + }, + getSuggestionForField: () => undefined, + }; +} describe('workspace_panel', () => { let mockVisualization: jest.Mocked; @@ -75,7 +78,7 @@ describe('workspace_panel', () => { let uiActionsMock: jest.Mocked; let trigger: jest.Mocked; - let instance: ReactWrapper; + let instance: ReactWrapper; beforeEach(() => { // These are used in specific tests to assert function calls @@ -92,56 +95,50 @@ describe('workspace_panel', () => { instance.unmount(); }); - it('should render an explanatory text if no visualization is active', async () => { - const mounted = await mountWithProvider( + it('should render an explanatory text if no visualization is active', () => { + instance = mount( , - defaultProps.plugins.data + /> ); - instance = mounted.instance; expect(instance.find('[data-test-subj="empty-workspace"]')).toHaveLength(2); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should render an explanatory text if the visualization does not produce an expression', async () => { - const mounted = await mountWithProvider( + it('should render an explanatory text if the visualization does not produce an expression', () => { + instance = mount( null }, }} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; expect(instance.find('[data-test-subj="empty-workspace"]')).toHaveLength(2); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should render an explanatory text if the datasource does not produce an expression', async () => { - const mounted = await mountWithProvider( + it('should render an explanatory text if the datasource does not produce an expression', () => { + instance = mount( 'vis' }, }} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; expect(instance.find('[data-test-subj="empty-workspace"]')).toHaveLength(2); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should render the resulting expression using the expression renderer', async () => { + it('should render the resulting expression using the expression renderer', () => { const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, @@ -149,9 +146,9 @@ describe('workspace_panel', () => { mockDatasource.toExpression.mockReturnValue('datasource'); mockDatasource.getLayers.mockReturnValue(['first']); - const mounted = await mountWithProvider( + instance = mount( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; - expect(instance.find(expressionRendererMock).prop('expression')).toMatchInlineSnapshot(` "kibana | lens_merge_tables layerIds=\\"first\\" tables={datasource} @@ -179,16 +173,16 @@ describe('workspace_panel', () => { `); }); - it('should execute a trigger on expression event', async () => { + it('should execute a trigger on expression event', () => { const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, }; mockDatasource.toExpression.mockReturnValue('datasource'); mockDatasource.getLayers.mockReturnValue(['first']); - const props = defaultProps; + const props = getDefaultProps(); - const mounted = await mountWithProvider( + instance = mount( { }} ExpressionRenderer={expressionRendererMock} plugins={{ ...props.plugins, uiActions: uiActionsMock }} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; const onEvent = expressionRendererMock.mock.calls[0][0].onEvent!; @@ -220,7 +212,7 @@ describe('workspace_panel', () => { expect(trigger.exec).toHaveBeenCalledWith({ data: eventData }); }); - it('should push add current data table to state on data$ emitting value', async () => { + it('should push add current data table to state on data$ emitting value', () => { const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, @@ -229,9 +221,9 @@ describe('workspace_panel', () => { mockDatasource.getLayers.mockReturnValue(['first']); const dispatch = jest.fn(); - const mounted = await mountWithProvider( + instance = mount( { }} dispatch={dispatch} ExpressionRenderer={expressionRendererMock} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; - const onData = expressionRendererMock.mock.calls[0][0].onData$!; const tableData = { table1: { columns: [], rows: [] } }; onData(undefined, { tables: { tables: tableData } }); - expect(mounted.lensStore.dispatch).toHaveBeenCalledWith({ - type: 'app/onActiveDataChange', - payload: { activeData: tableData }, - }); + expect(dispatch).toHaveBeenCalledWith({ type: 'UPDATE_ACTIVE_DATA', tables: tableData }); }); - it('should include data fetching for each layer in the expression', async () => { + it('should include data fetching for each layer in the expression', () => { const mockDatasource2 = createMockDatasource('a'); const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { @@ -277,9 +263,9 @@ describe('workspace_panel', () => { mockDatasource2.toExpression.mockReturnValue('datasource2'); mockDatasource2.getLayers.mockReturnValue(['second', 'third']); - const mounted = await mountWithProvider( + instance = mount( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; const ast = fromExpression(instance.find(expressionRendererMock).prop('expression') as string); @@ -357,9 +341,9 @@ describe('workspace_panel', () => { expressionRendererMock = jest.fn((_arg) => ); await act(async () => { - const mounted = await mountWithProvider( + instance = mount( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; }); instance.update(); @@ -410,9 +392,9 @@ describe('workspace_panel', () => { expressionRendererMock = jest.fn((_arg) => ); await act(async () => { - const mounted = await mountWithProvider( + instance = mount( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; }); instance.update(); @@ -454,16 +434,16 @@ describe('workspace_panel', () => { expect(expressionRendererMock).toHaveBeenCalledTimes(2); }); - it('should show an error message if there are missing indexpatterns in the visualization', async () => { + it('should show an error message if there are missing indexpatterns in the visualization', () => { mockDatasource.getLayers.mockReturnValue(['first']); mockDatasource.checkIntegrity.mockReturnValue(['a']); const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, }; - const mounted = await mountWithProvider( + instance = mount( { visualizationMap={{ vis: { ...mockVisualization, toExpression: () => 'vis' }, }} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; expect(instance.find('[data-test-subj="missing-refs-failure"]').exists()).toBeTruthy(); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should not show the management action in case of missing indexpattern and no navigation permissions', async () => { + it('should not show the management action in case of missing indexpattern and no navigation permissions', () => { mockDatasource.getLayers.mockReturnValue(['first']); const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, }; - const mounted = await mountWithProvider( + instance = mount( { navLinks: { management: false }, management: { kibana: { indexPatterns: true } }, })} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; expect( instance.find('[data-test-subj="configuration-failure-reconfigure-indexpatterns"]').exists() ).toBeFalsy(); }); - it('should not show the management action in case of missing indexpattern and no indexPattern specific permissions', async () => { + it('should not show the management action in case of missing indexpattern and no indexPattern specific permissions', () => { mockDatasource.getLayers.mockReturnValue(['first']); const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, }; - const mounted = await mountWithProvider( + instance = mount( { navLinks: { management: true }, management: { kibana: { indexPatterns: false } }, })} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; expect( instance.find('[data-test-subj="configuration-failure-reconfigure-indexpatterns"]').exists() ).toBeFalsy(); }); - it('should show an error message if validation on datasource does not pass', async () => { + it('should show an error message if validation on datasource does not pass', () => { mockDatasource.getErrorMessages.mockReturnValue([ { shortMessage: 'An error occurred', longMessage: 'An long description here' }, ]); @@ -576,9 +550,9 @@ describe('workspace_panel', () => { first: mockDatasource.publicAPIMock, }; - const mounted = await mountWithProvider( + instance = mount( { visualizationMap={{ vis: { ...mockVisualization, toExpression: () => 'vis' }, }} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; expect(instance.find('[data-test-subj="configuration-failure"]').exists()).toBeTruthy(); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should show an error message if validation on visualization does not pass', async () => { + it('should show an error message if validation on visualization does not pass', () => { mockDatasource.getErrorMessages.mockReturnValue(undefined); mockDatasource.getLayers.mockReturnValue(['first']); mockVisualization.getErrorMessages.mockReturnValue([ @@ -613,9 +585,9 @@ describe('workspace_panel', () => { first: mockDatasource.publicAPIMock, }; - const mounted = await mountWithProvider( + instance = mount( { visualizationMap={{ vis: mockVisualization, }} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; expect(instance.find('[data-test-subj="configuration-failure"]').exists()).toBeTruthy(); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should show an error message if validation on both datasource and visualization do not pass', async () => { + it('should show an error message if validation on both datasource and visualization do not pass', () => { mockDatasource.getErrorMessages.mockReturnValue([ { shortMessage: 'An error occurred', longMessage: 'An long description here' }, ]); @@ -652,9 +622,9 @@ describe('workspace_panel', () => { first: mockDatasource.publicAPIMock, }; - const mounted = await mountWithProvider( + instance = mount( { visualizationMap={{ vis: mockVisualization, }} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; // EuiFlexItem duplicates internally the attribute, so we need to filter only the most inner one here expect( @@ -680,7 +648,7 @@ describe('workspace_panel', () => { expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should show an error message if the expression fails to parse', async () => { + it('should show an error message if the expression fails to parse', () => { mockDatasource.toExpression.mockReturnValue('|||'); mockDatasource.getLayers.mockReturnValue(['first']); const framePublicAPI = createMockFramePublicAPI(); @@ -688,9 +656,9 @@ describe('workspace_panel', () => { first: mockDatasource.publicAPIMock, }; - const mounted = await mountWithProvider( + instance = mount( { visualizationMap={{ vis: { ...mockVisualization, toExpression: () => 'vis' }, }} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; expect(instance.find('[data-test-subj="expression-failure"]').exists()).toBeTruthy(); expect(instance.find(expressionRendererMock)).toHaveLength(0); @@ -722,9 +688,9 @@ describe('workspace_panel', () => { }; await act(async () => { - const mounted = await mountWithProvider( + instance = mount( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; }); instance.update(); @@ -763,9 +727,9 @@ describe('workspace_panel', () => { }; await act(async () => { - const mounted = await mountWithProvider( + instance = mount( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - />, - defaultProps.plugins.data + /> ); - instance = mounted.instance; }); instance.update(); @@ -829,7 +791,7 @@ describe('workspace_panel', () => { dropTargetsByOrder={undefined} > { ); } - it('should immediately transition if exactly one suggestion is returned', async () => { + it('should immediately transition if exactly one suggestion is returned', () => { mockGetSuggestionForField.mockReturnValue({ visualizationId: 'vis', datasourceState: {}, diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index 94065f316340cbf..3d5d9a6d84d8112 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -54,7 +54,6 @@ import { DropIllustration } from '../../../assets/drop_illustration'; import { getOriginalRequestErrorMessages } from '../../error_helper'; import { getMissingIndexPattern, validateDatasourceAndVisualization } from '../state_helpers'; import { DefaultInspectorAdapters } from '../../../../../../../src/plugins/expressions/common'; -import { onActiveDataChange, useLensDispatch } from '../../../state_management'; export interface WorkspacePanelProps { activeVisualizationId: string | null; @@ -429,15 +428,16 @@ export const VisualizationWrapper = ({ ] ); - const dispatchLens = useLensDispatch(); - const onData$ = useCallback( (data: unknown, inspectorAdapters?: Partial) => { if (inspectorAdapters && inspectorAdapters.tables) { - dispatchLens(onActiveDataChange({ activeData: { ...inspectorAdapters.tables.tables } })); + dispatch({ + type: 'UPDATE_ACTIVE_DATA', + tables: inspectorAdapters.tables.tables, + }); } }, - [dispatchLens] + [dispatch] ); if (localState.configurationValidationError?.length) { diff --git a/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx b/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx index 38669d72474df14..a56b3ccaa5bde7f 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx @@ -105,9 +105,10 @@ export type FrameMock = jest.Mocked; export function createMockPaletteDefinition(): jest.Mocked { return { - getCategoricalColors: jest.fn((_) => ['#ff0000', '#00ff00']), + getColors: jest.fn((_) => ['#ff0000', '#00ff00']), title: 'Mock Palette', id: 'default', + renderEditor: jest.fn(), toExpression: jest.fn(() => ({ type: 'expression', chain: [ @@ -118,7 +119,7 @@ export function createMockPaletteDefinition(): jest.Mocked { }, ], })), - getCategoricalColor: jest.fn().mockReturnValue('#ff0000'), + getColor: jest.fn().mockReturnValue('#ff0000'), }; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/service.tsx b/x-pack/plugins/lens/public/editor_frame_service/service.tsx index 62274df23e837bd..f6500596ce5a0ea 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/service.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/service.tsx @@ -126,11 +126,26 @@ export class EditorFrameService { collectAsyncDefinitions(this.visualizations), ]); - const { EditorFrame } = await import('../async_services'); + const firstDatasourceId = Object.keys(resolvedDatasources)[0]; + const firstVisualizationId = Object.keys(resolvedVisualizations)[0]; + + const { EditorFrame, getActiveDatasourceIdFromDoc } = await import('../async_services'); + const palettes = await plugins.charts.palettes.getPalettes(); return { - EditorFrameContainer: ({ onError, showNoDataPopover, initialContext }) => { + EditorFrameContainer: ({ + doc, + onError, + dateRange, + query, + filters, + savedQuery, + onChange, + showNoDataPopover, + initialContext, + searchSessionId, + }) => { return (
); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx index 0e74ef6b85c804d..8d18a2752fd7e33 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx @@ -9,7 +9,6 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useState } from 'react'; import { EuiFieldNumber, EuiFormRow } from '@elastic/eui'; -import { useDebounceWithOptions } from '../../../../shared_components'; import { FormattedIndexPatternColumn, ReferenceBasedIndexPatternColumn } from '../column_types'; import { IndexPatternLayer } from '../../../types'; import { @@ -20,7 +19,12 @@ import { hasDateField, } from './utils'; import { updateColumnParam } from '../../layer_helpers'; -import { getFormatFromPreviousColumn, isValidNumber, getFilter } from '../helpers'; +import { + getFormatFromPreviousColumn, + isValidNumber, + useDebounceWithOptions, + getFilter, +} from '../helpers'; import { adjustTimeScaleOnOtherColumnChange } from '../../time_scale_utils'; import { HelpPopover, HelpPopoverButton } from '../../../help_popover'; import type { OperationDefinition, ParamEditorProps } from '..'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx index 45abbcd3d9cf96d..f719ac4250912ec 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx @@ -5,11 +5,35 @@ * 2.0. */ +import { useRef } from 'react'; +import useDebounce from 'react-use/lib/useDebounce'; import { i18n } from '@kbn/i18n'; import { IndexPatternColumn, operationDefinitionMap } from '.'; import { FieldBasedIndexPatternColumn } from './column_types'; import { IndexPattern } from '../../types'; +export const useDebounceWithOptions = ( + fn: Function, + { skipFirstRender }: { skipFirstRender: boolean } = { skipFirstRender: false }, + ms?: number | undefined, + deps?: React.DependencyList | undefined +) => { + const isFirstRender = useRef(true); + const newDeps = [...(deps || []), isFirstRender]; + + return useDebounce( + () => { + if (skipFirstRender && isFirstRender.current) { + isFirstRender.current = false; + return; + } + return fn(); + }, + ms, + newDeps + ); +}; + export function getInvalidFieldMessage( column: FieldBasedIndexPatternColumn, indexPattern?: IndexPattern diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx index 4c09ae4ed8c47ba..705a1f7172fff8d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx @@ -16,10 +16,10 @@ import { getInvalidFieldMessage, getSafeName, isValidNumber, + useDebounceWithOptions, getFilter, } from './helpers'; import { FieldBasedIndexPatternColumn } from './column_types'; -import { useDebounceWithOptions } from '../../../shared_components'; export interface PercentileIndexPatternColumn extends FieldBasedIndexPatternColumn { operationType: 'percentile'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx index 43f5527e42d4bf2..b3ffb58df00d395 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx @@ -22,7 +22,6 @@ import { htmlIdGenerator, keys, } from '@elastic/eui'; -import { useDebounceWithOptions } from '../../../../shared_components'; import { IFieldFormat } from '../../../../../../../../src/plugins/data/common'; import { RangeTypeLens, isValidRange } from './ranges'; import { FROM_PLACEHOLDER, TO_PLACEHOLDER, TYPING_DEBOUNCE_TIME } from './constants'; @@ -32,7 +31,7 @@ import { DraggableBucketContainer, LabelInput, } from '../shared_components'; -import { isValidNumber } from '../helpers'; +import { isValidNumber, useDebounceWithOptions } from '../helpers'; const generateId = htmlIdGenerator(); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/range_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/range_editor.tsx index 3389c723b4daf6e..4851b6ff3ec9758 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/range_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/range_editor.tsx @@ -23,7 +23,7 @@ import { UI_SETTINGS } from '../../../../../../../../src/plugins/data/public'; import { RangeColumnParams, UpdateParamsFnType, MODES_TYPES } from './ranges'; import { AdvancedRangeEditor } from './advanced_editor'; import { TYPING_DEBOUNCE_TIME, MODES, MIN_HISTOGRAM_BARS } from './constants'; -import { useDebounceWithOptions } from '../../../../shared_components'; +import { useDebounceWithOptions } from '../helpers'; import { HelpPopover, HelpPopoverButton } from '../../../help_popover'; const GranularityHelpPopover = () => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx index a4c0f8f1c50e05f..915e67c4eba0bd1 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx @@ -8,7 +8,7 @@ import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiFieldNumber } from '@elastic/eui'; -import { useDebounceWithOptions } from '../../../../shared_components'; +import { useDebounceWithOptions } from '../helpers'; export const ValuesInput = ({ value, diff --git a/x-pack/plugins/lens/public/mocks.tsx b/x-pack/plugins/lens/public/mocks.tsx index 473c170aef29487..c1f885d167659de 100644 --- a/x-pack/plugins/lens/public/mocks.tsx +++ b/x-pack/plugins/lens/public/mocks.tsx @@ -6,35 +6,8 @@ */ import React from 'react'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { ReactWrapper } from 'enzyme'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { mountWithIntl as mount } from '@kbn/test/jest'; -import { Observable, Subject } from 'rxjs'; -import { coreMock } from 'src/core/public/mocks'; -import moment from 'moment'; -import { Provider } from 'react-redux'; -import { act } from 'react-dom/test-utils'; import { LensPublicStart } from '.'; import { visualizationTypes } from './xy_visualization/types'; -import { navigationPluginMock } from '../../../../src/plugins/navigation/public/mocks'; -import { LensAppServices } from './app_plugin/types'; -import { DOC_TYPE } from '../common'; -import { DataPublicPluginStart, esFilters, UI_SETTINGS } from '../../../../src/plugins/data/public'; -import { - LensByValueInput, - LensSavedObjectAttributes, - LensByReferenceInput, -} from './editor_frame_service/embeddable/embeddable'; -import { - mockAttributeService, - createEmbeddableStateTransferMock, -} from '../../../../src/plugins/embeddable/public/mocks'; -import { LensAttributeService } from './lens_attribute_service'; -import { EmbeddableStateTransfer } from '../../../../src/plugins/embeddable/public'; - -import { makeConfigureStore, getPreloadedState, LensAppState } from './state_management/index'; -import { getResolvedDateRange } from './utils'; export type Start = jest.Mocked; @@ -53,252 +26,3 @@ const createStartContract = (): Start => { export const lensPluginMock = { createStartContract, }; - -export const defaultDoc = ({ - savedObjectId: '1234', - title: 'An extremely cool default document!', - expression: 'definitely a valid expression', - state: { - query: 'kuery', - filters: [{ query: { match_phrase: { src: 'test' } } }], - }, - references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], -} as unknown) as Document; - -export function createMockTimefilter() { - const unsubscribe = jest.fn(); - - let timeFilter = { from: 'now-7d', to: 'now' }; - let subscriber: () => void; - return { - getTime: jest.fn(() => timeFilter), - setTime: jest.fn((newTimeFilter) => { - timeFilter = newTimeFilter; - if (subscriber) { - subscriber(); - } - }), - getTimeUpdate$: () => ({ - subscribe: ({ next }: { next: () => void }) => { - subscriber = next; - return unsubscribe; - }, - }), - calculateBounds: jest.fn(() => ({ - min: moment('2021-01-10T04:00:00.000Z'), - max: moment('2021-01-10T08:00:00.000Z'), - })), - getBounds: jest.fn(() => timeFilter), - getRefreshInterval: () => {}, - getRefreshIntervalDefaults: () => {}, - getAutoRefreshFetch$: () => new Observable(), - }; -} - -export function mockDataPlugin(sessionIdSubject = new Subject()) { - function createMockSearchService() { - let sessionIdCounter = 1; - return { - session: { - start: jest.fn(() => `sessionId-${sessionIdCounter++}`), - clear: jest.fn(), - getSessionId: jest.fn(() => `sessionId-${sessionIdCounter}`), - getSession$: jest.fn(() => sessionIdSubject.asObservable()), - }, - }; - } - - function createMockFilterManager() { - const unsubscribe = jest.fn(); - - let subscriber: () => void; - let filters: unknown = []; - - return { - getUpdates$: () => ({ - subscribe: ({ next }: { next: () => void }) => { - subscriber = next; - return unsubscribe; - }, - }), - setFilters: jest.fn((newFilters: unknown[]) => { - filters = newFilters; - if (subscriber) subscriber(); - }), - setAppFilters: jest.fn((newFilters: unknown[]) => { - filters = newFilters; - if (subscriber) subscriber(); - }), - getFilters: () => filters, - getGlobalFilters: () => { - // @ts-ignore - return filters.filter(esFilters.isFilterPinned); - }, - removeAll: () => { - filters = []; - subscriber(); - }, - }; - } - - function createMockQueryString() { - return { - getQuery: jest.fn(() => ({ query: '', language: 'lucene' })), - setQuery: jest.fn(), - getDefaultQuery: jest.fn(() => ({ query: '', language: 'lucene' })), - }; - } - return ({ - query: { - filterManager: createMockFilterManager(), - timefilter: { - timefilter: createMockTimefilter(), - }, - queryString: createMockQueryString(), - state$: new Observable(), - }, - indexPatterns: { - get: jest.fn((id) => { - return new Promise((resolve) => resolve({ id })); - }), - }, - search: createMockSearchService(), - nowProvider: { - get: jest.fn(), - }, - } as unknown) as DataPublicPluginStart; -} - -export function makeDefaultServices( - sessionIdSubject = new Subject(), - doc = defaultDoc -): jest.Mocked { - const core = coreMock.createStart({ basePath: '/testbasepath' }); - core.uiSettings.get.mockImplementation( - jest.fn((type) => { - if (type === UI_SETTINGS.TIMEPICKER_TIME_DEFAULTS) { - return { from: 'now-7d', to: 'now' }; - } else if (type === UI_SETTINGS.SEARCH_QUERY_LANGUAGE) { - return 'kuery'; - } else if (type === 'state:storeInSessionStorage') { - return false; - } else { - return []; - } - }) - ); - - const navigationStartMock = navigationPluginMock.createStartContract(); - - jest.spyOn(navigationStartMock.ui.TopNavMenu.prototype, 'constructor').mockImplementation(() => { - return
; - }); - - function makeAttributeService(): LensAttributeService { - const attributeServiceMock = mockAttributeService< - LensSavedObjectAttributes, - LensByValueInput, - LensByReferenceInput - >( - DOC_TYPE, - { - saveMethod: jest.fn(), - unwrapMethod: jest.fn(), - checkForDuplicateTitle: jest.fn(), - }, - core - ); - - attributeServiceMock.unwrapAttributes = jest.fn().mockResolvedValue(doc); - attributeServiceMock.wrapAttributes = jest.fn().mockResolvedValue({ - savedObjectId: ((doc as unknown) as LensByReferenceInput).savedObjectId, - }); - - return attributeServiceMock; - } - - return { - http: core.http, - chrome: core.chrome, - overlays: core.overlays, - uiSettings: core.uiSettings, - navigation: navigationStartMock, - notifications: core.notifications, - attributeService: makeAttributeService(), - savedObjectsClient: core.savedObjects.client, - dashboardFeatureFlag: { allowByValueEmbeddables: false }, - stateTransfer: createEmbeddableStateTransferMock() as EmbeddableStateTransfer, - getOriginatingAppName: jest.fn(() => 'defaultOriginatingApp'), - application: { - ...core.application, - capabilities: { - ...core.application.capabilities, - visualize: { save: true, saveQuery: true, show: true }, - }, - getUrlForApp: jest.fn((appId: string) => `/testbasepath/app/${appId}#/`), - }, - data: mockDataPlugin(sessionIdSubject), - storage: { - get: jest.fn(), - set: jest.fn(), - remove: jest.fn(), - clear: jest.fn(), - }, - }; -} - -export function mockLensStore({ - data, - storePreloadedState, -}: { - data: DataPublicPluginStart; - storePreloadedState?: Partial; -}) { - const lensStore = makeConfigureStore( - getPreloadedState({ - query: data.query.queryString.getQuery(), - filters: data.query.filterManager.getGlobalFilters(), - searchSessionId: data.search.session.start(), - resolvedDateRange: getResolvedDateRange(data.query.timefilter.timefilter), - ...storePreloadedState, - }), - { - data, - } - ); - - const origDispatch = lensStore.dispatch; - lensStore.dispatch = jest.fn(origDispatch); - return lensStore; -} - -export const mountWithProvider = async ( - component: React.ReactElement, - data: DataPublicPluginStart, - storePreloadedState?: Partial, - extraWrappingComponent?: React.FC<{ - children: React.ReactNode; - }> -) => { - const lensStore = mockLensStore({ data, storePreloadedState }); - - const wrappingComponent: React.FC<{ - children: React.ReactNode; - }> = ({ children }) => { - if (extraWrappingComponent) { - return extraWrappingComponent({ - children: {children}, - }); - } - return {children}; - }; - - let instance: ReactWrapper = {} as ReactWrapper; - - await act(async () => { - instance = mount(component, ({ - wrappingComponent, - } as unknown) as ReactWrapper); - }); - return { instance, lensStore }; -}; diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.test.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.test.tsx index a9e7e4adb9ca786..7191da0af6bfe79 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.test.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.test.tsx @@ -161,7 +161,7 @@ describe('PieVisualization component', () => { [] as HierarchyOfArrays ); - expect(defaultArgs.paletteService.get('mock').getCategoricalColor).toHaveBeenCalledWith( + expect(defaultArgs.paletteService.get('mock').getColor).toHaveBeenCalledWith( [ { name: 'css', diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index 6c1cbe63a5a3e32..cc31222f6b9ab07 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -150,7 +150,7 @@ export function PieComponent( } } - const outputColor = paletteService.get(palette.name).getCategoricalColor( + const outputColor = paletteService.get(palette.name).getColor( seriesLayers, { behindText: categoryDisplay !== 'hide', diff --git a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx index f413b122d913ccd..ad8d87292b1d803 100644 --- a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx @@ -126,7 +126,7 @@ export const getPieVisualization = ({ triggerIcon: 'colorBy', palette: paletteService .get(state.palette?.name || 'default') - .getCategoricalColors(10, state.palette?.params), + .getColors(10, state.palette?.params), }; } diff --git a/x-pack/plugins/lens/public/shared_components/coloring/color_stops.test.tsx b/x-pack/plugins/lens/public/shared_components/coloring/color_stops.test.tsx deleted file mode 100644 index 54c7f3cef90fe35..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/coloring/color_stops.test.tsx +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiColorPicker } from '@elastic/eui'; -import { mount } from 'enzyme'; -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { CustomStops, CustomStopsProps } from './color_stops'; - -describe('Color Stops component', () => { - let props: CustomStopsProps; - beforeEach(() => { - props = { - colorStops: [ - { color: '#aaa', stop: 20 }, - { color: '#bbb', stop: 40 }, - { color: '#ccc', stop: 60 }, - ], - paletteConfiguration: {}, - dataBounds: { min: 0, max: 200 }, - onChange: jest.fn(), - 'data-test-prefix': 'my-test', - }; - }); - it('should display all the color stops passed', () => { - const component = mount(); - expect( - component.find('input[data-test-subj^="my-test_dynamicColoring_stop_value_"]') - ).toHaveLength(3); - }); - - it('should disable the delete buttons when there are 2 stops or less', () => { - // reduce to 2 stops - props.colorStops = props.colorStops.slice(0, 2); - const component = mount(); - expect( - component - .find('[data-test-subj="my-test_dynamicColoring_removeStop_0"]') - .first() - .prop('isDisabled') - ).toBe(true); - }); - - it('should add a new stop with default color and reasonable distance from last one', () => { - let component = mount(); - const addStopButton = component - .find('[data-test-subj="my-test_dynamicColoring_addStop"]') - .first(); - act(() => { - addStopButton.prop('onClick')!({} as React.MouseEvent); - }); - component = component.update(); - - expect( - component.find('input[data-test-subj^="my-test_dynamicColoring_stop_value_"]') - ).toHaveLength(4); - expect( - component.find('input[data-test-subj="my-test_dynamicColoring_stop_value_3"]').prop('value') - ).toBe('80'); // 60-40 + 60 - expect( - component - // workaround for https://github.com/elastic/eui/issues/4792 - .find('[data-test-subj="my-test_dynamicColoring_stop_color_3"]') - .last() // pick the inner element - .childAt(0) - .prop('color') - ).toBe('#ccc'); // pick previous color - }); - - it('should restore previous color when abandoning the field with an empty color', () => { - let component = mount(); - expect( - component - .find('[data-test-subj="my-test_dynamicColoring_stop_row_0"]') - .first() - .find(EuiColorPicker) - .first() - .prop('color') - ).toBe('#aaa'); - act(() => { - component - .find('[data-test-subj="my-test_dynamicColoring_stop_row_0"]') - .first() - .find(EuiColorPicker) - .first() - .prop('onChange')!('', { - rgba: [NaN, NaN, NaN, NaN], - hex: '', - isValid: false, - }); - }); - component = component.update(); - expect( - component - .find('[data-test-subj="my-test_dynamicColoring_stop_row_0"]') - .first() - .find(EuiColorPicker) - .first() - .prop('color') - ).toBe(''); - act(() => { - component - .find('[data-test-subj="my-test_dynamicColoring_stop_color_0"]') - .first() - .prop('onBlur')!({} as React.FocusEvent); - }); - component = component.update(); - expect( - component - .find('[data-test-subj="my-test_dynamicColoring_stop_row_0"]') - .first() - .find(EuiColorPicker) - .first() - .prop('color') - ).toBe('#aaa'); - }); - - it('should sort stops value on whole component blur', () => { - let component = mount(); - let firstStopValueInput = component - .find('[data-test-subj="my-test_dynamicColoring_stop_value_0"]') - .first(); - act(() => { - firstStopValueInput.prop('onChange')!(({ - target: { value: ' 90' }, - } as unknown) as React.ChangeEvent); - }); - - component = component.update(); - - act(() => { - component - .find('[data-test-subj="my-test_dynamicColoring_stop_row_0"]') - .first() - .prop('onBlur')!({} as React.FocusEvent); - }); - component = component.update(); - - // retrieve again the input - firstStopValueInput = component - .find('[data-test-subj="my-test_dynamicColoring_stop_value_0"]') - .first(); - expect(firstStopValueInput.prop('value')).toBe('40'); - // the previous one move at the bottom - expect( - component - .find('[data-test-subj="my-test_dynamicColoring_stop_value_2"]') - .first() - .prop('value') - ).toBe('90'); - }); -}); diff --git a/x-pack/plugins/lens/public/shared_components/coloring/color_stops.tsx b/x-pack/plugins/lens/public/shared_components/coloring/color_stops.tsx deleted file mode 100644 index 37197b232ddf551..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/coloring/color_stops.tsx +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React, { useState, useCallback, useMemo } from 'react'; -import type { FocusEvent } from 'react'; -import { i18n } from '@kbn/i18n'; -import { - EuiFieldNumber, - EuiColorPicker, - EuiButtonIcon, - EuiFlexItem, - EuiFlexGroup, - EuiButtonEmpty, - EuiSpacer, - EuiScreenReaderOnly, - htmlIdGenerator, -} from '@elastic/eui'; -import useUnmount from 'react-use/lib/useUnmount'; -import { DEFAULT_COLOR } from './constants'; -import { getDataMinMax, getStepValue, isValidColor } from './utils'; -import { TooltipWrapper, useDebouncedValue } from '../index'; -import { ColorStop, CustomPaletteParams } from './types'; - -const idGeneratorFn = htmlIdGenerator(); - -function areStopsValid(colorStops: Array<{ color: string; stop: string }>) { - return colorStops.every( - ({ color, stop }) => isValidColor(color) && !Number.isNaN(parseFloat(stop)) - ); -} - -function shouldSortStops(colorStops: Array<{ color: string; stop: string | number }>) { - return colorStops.some(({ stop }, i) => { - const numberStop = Number(stop); - const prevNumberStop = Number(colorStops[i - 1]?.stop ?? -Infinity); - return numberStop < prevNumberStop; - }); -} - -export interface CustomStopsProps { - colorStops: ColorStop[]; - onChange: (colorStops: ColorStop[]) => void; - dataBounds: { min: number; max: number }; - paletteConfiguration: CustomPaletteParams | undefined; - 'data-test-prefix': string; -} -export const CustomStops = ({ - colorStops, - onChange, - paletteConfiguration, - dataBounds, - ['data-test-prefix']: dataTestPrefix, -}: CustomStopsProps) => { - const onChangeWithValidation = useCallback( - (newColorStops: Array<{ color: string; stop: string }>) => { - const areStopsValuesValid = areStopsValid(newColorStops); - const shouldSort = shouldSortStops(newColorStops); - if (areStopsValuesValid && !shouldSort) { - onChange(newColorStops.map(({ color, stop }) => ({ color, stop: Number(stop) }))); - } - }, - [onChange] - ); - - const memoizedValues = useMemo(() => { - return colorStops.map(({ color, stop }, i) => ({ - color, - stop: String(stop), - id: idGeneratorFn(), - })); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [paletteConfiguration?.name, paletteConfiguration?.reverse, paletteConfiguration?.rangeType]); - - const { inputValue: localColorStops, handleInputChange: setLocalColorStops } = useDebouncedValue({ - onChange: onChangeWithValidation, - value: memoizedValues, - }); - const [sortedReason, setSortReason] = useState(''); - const shouldEnableDelete = localColorStops.length > 2; - - const [popoverInFocus, setPopoverInFocus] = useState(false); - - // refresh on unmount: - // the onChange logic here is a bit different than the one above as it has to actively sort if required - useUnmount(() => { - const areStopsValuesValid = areStopsValid(localColorStops); - const shouldSort = shouldSortStops(localColorStops); - if (areStopsValuesValid && shouldSort) { - onChange( - localColorStops - .map(({ color, stop }) => ({ color, stop: Number(stop) })) - .sort(({ stop: stopA }, { stop: stopB }) => Number(stopA) - Number(stopB)) - ); - } - }); - - const rangeType = paletteConfiguration?.rangeType || 'percent'; - - return ( - <> - {sortedReason ? ( - -

- {i18n.translate('xpack.lens.dynamicColoring.customPalette.sortReason', { - defaultMessage: 'Color stops have been sorted due to new stop value {value}', - values: { - value: sortedReason, - }, - })} -

-
- ) : null} - - - {localColorStops.map(({ color, stop, id }, index) => { - const prevStopValue = Number(localColorStops[index - 1]?.stop ?? -Infinity); - const nextStopValue = Number(localColorStops[index + 1]?.stop ?? Infinity); - - return ( - ) => { - // sort the stops when the focus leaves the row container - const shouldSort = Number(stop) > nextStopValue || prevStopValue > Number(stop); - const isFocusStillInContent = - (e.currentTarget as Node)?.contains(e.relatedTarget as Node) || popoverInFocus; - const hasInvalidColor = !isValidColor(color); - if ((shouldSort && !isFocusStillInContent) || hasInvalidColor) { - // replace invalid color with previous valid one - const lastValidColor = hasInvalidColor ? colorStops[index].color : color; - const localColorStopsCopy = localColorStops.map((item, i) => - i === index ? { color: lastValidColor, stop, id } : item - ); - setLocalColorStops( - localColorStopsCopy.sort( - ({ stop: stopA }, { stop: stopB }) => Number(stopA) - Number(stopB) - ) - ); - setSortReason(stop); - } - }} - > - - - { - const newStopString = target.value.trim(); - const newColorStops = [...localColorStops]; - newColorStops[index] = { - color, - stop: newStopString, - id, - }; - setLocalColorStops(newColorStops); - }} - append={rangeType === 'percent' ? '%' : undefined} - aria-label={i18n.translate( - 'xpack.lens.dynamicColoring.customPalette.stopAriaLabel', - { - defaultMessage: 'Stop {index}', - values: { - index: index + 1, - }, - } - )} - /> - - - { - // make sure that the popover is closed - if (color === '' && !popoverInFocus) { - const newColorStops = [...localColorStops]; - newColorStops[index] = { color: colorStops[index].color, stop, id }; - setLocalColorStops(newColorStops); - } - }} - > - { - const newColorStops = [...localColorStops]; - newColorStops[index] = { color: newColor, stop, id }; - setLocalColorStops(newColorStops); - }} - secondaryInputDisplay="top" - color={color} - isInvalid={!isValidColor(color)} - showAlpha - compressed - onFocus={() => setPopoverInFocus(true)} - onBlur={() => { - setPopoverInFocus(false); - if (color === '') { - const newColorStops = [...localColorStops]; - newColorStops[index] = { color: colorStops[index].color, stop, id }; - setLocalColorStops(newColorStops); - } - }} - placeholder=" " - /> - - - - - { - const newColorStops = localColorStops.filter((_, i) => i !== index); - setLocalColorStops(newColorStops); - }} - data-test-subj={`${dataTestPrefix}_dynamicColoring_removeStop_${index}`} - isDisabled={!shouldEnableDelete} - /> - - - - - ); - })} - - - - - { - const newColorStops = [...localColorStops]; - const length = newColorStops.length; - const { max } = getDataMinMax(rangeType, dataBounds); - const step = getStepValue( - colorStops, - newColorStops.map(({ color, stop }) => ({ color, stop: Number(stop) })), - max - ); - const prevColor = localColorStops[length - 1].color || DEFAULT_COLOR; - const newStop = step + Number(localColorStops[length - 1].stop); - newColorStops.push({ - color: prevColor, - stop: String(newStop), - id: idGeneratorFn(), - }); - setLocalColorStops(newColorStops); - }} - > - {i18n.translate('xpack.lens.dynamicColoring.customPalette.addColorStop', { - defaultMessage: 'Add color stop', - })} - - - ); -}; diff --git a/x-pack/plugins/lens/public/shared_components/coloring/constants.ts b/x-pack/plugins/lens/public/shared_components/coloring/constants.ts deleted file mode 100644 index 5e6fc207656ac32..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/coloring/constants.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { RequiredPaletteParamTypes } from './types'; - -export const DEFAULT_PALETTE_NAME = 'positive'; -export const FIXED_PROGRESSION = 'fixed' as const; -export const CUSTOM_PALETTE = 'custom'; -export const DEFAULT_CONTINUITY = 'above'; -export const DEFAULT_MIN_STOP = 0; -export const DEFAULT_MAX_STOP = 100; -export const DEFAULT_COLOR_STEPS = 5; -export const DEFAULT_COLOR = '#6092C0'; // Same as EUI ColorStops default for new stops -export const defaultPaletteParams: RequiredPaletteParamTypes = { - name: DEFAULT_PALETTE_NAME, - reverse: false, - rangeType: 'percent', - rangeMin: DEFAULT_MIN_STOP, - rangeMax: DEFAULT_MAX_STOP, - progression: FIXED_PROGRESSION, - stops: [], - steps: DEFAULT_COLOR_STEPS, - colorStops: [], - continuity: DEFAULT_CONTINUITY, -}; diff --git a/x-pack/plugins/lens/public/shared_components/coloring/index.ts b/x-pack/plugins/lens/public/shared_components/coloring/index.ts deleted file mode 100644 index 3b34c6662c68191..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/coloring/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { CustomizablePalette } from './palette_configuration'; -export { CustomStops } from './color_stops'; -export * from './types'; -export * from './utils'; -export * from './constants'; diff --git a/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.scss b/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.scss deleted file mode 100644 index c6b14c5c5f9a359..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.scss +++ /dev/null @@ -1,7 +0,0 @@ -.lnsPalettePanel__section--shaded { - background-color: $euiColorLightestShade; -} - -.lnsPalettePanel__section { - padding: $euiSizeS; -} \ No newline at end of file diff --git a/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.test.tsx b/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.test.tsx deleted file mode 100644 index 28ba28a5801e402..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.test.tsx +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiColorPalettePickerPaletteProps } from '@elastic/eui'; -import { mountWithIntl } from '@kbn/test/jest'; -import { chartPluginMock } from 'src/plugins/charts/public/mocks'; -import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; -import { ReactWrapper } from 'enzyme'; -import { CustomPaletteParams } from './types'; -import { applyPaletteParams } from './utils'; -import { CustomizablePalette } from './palette_configuration'; - -describe('palette utilities', () => { - const paletteRegistry = chartPluginMock.createPaletteRegistry(); - describe('applyPaletteParams', () => { - it('should return a set of colors for a basic configuration', () => { - expect( - applyPaletteParams( - paletteRegistry, - { type: 'palette', name: 'positive' }, - { min: 0, max: 100 } - ) - ).toEqual([ - { color: 'blue', stop: 20 }, - { color: 'yellow', stop: 70 }, - ]); - }); - - it('should reverse the palette color stops correctly', () => { - expect( - applyPaletteParams( - paletteRegistry, - { - type: 'palette', - name: 'positive', - params: { reverse: true }, - }, - { min: 0, max: 100 } - ) - ).toEqual([ - { color: 'yellow', stop: 20 }, - { color: 'blue', stop: 70 }, - ]); - }); - }); -}); - -describe('palette panel', () => { - const paletteRegistry = chartPluginMock.createPaletteRegistry(); - let props: { - palettes: PaletteRegistry; - activePalette: PaletteOutput; - setPalette: (palette: PaletteOutput) => void; - dataBounds: { min: number; max: number }; - }; - - describe('palette picker', () => { - beforeEach(() => { - props = { - activePalette: { type: 'palette', name: 'positive' }, - palettes: paletteRegistry, - setPalette: jest.fn(), - dataBounds: { min: 0, max: 100 }, - }; - }); - - function changePaletteIn(instance: ReactWrapper, newPaletteName: string) { - return ((instance - .find('[data-test-subj="lnsDatatable_dynamicColoring_palette_picker"]') - .at(1) - .prop('onChange') as unknown) as (value: string) => void)?.(newPaletteName); - } - - it('should show only dynamic coloring enabled palette + custom option', () => { - const instance = mountWithIntl(); - const paletteOptions = instance - .find('[data-test-subj="lnsDatatable_dynamicColoring_palette_picker"]') - .at(1) - .prop('palettes') as EuiColorPalettePickerPaletteProps[]; - expect(paletteOptions.length).toEqual(2); - - expect(paletteOptions[paletteOptions.length - 1]).toEqual({ - title: 'Custom Mocked Palette', // <- picks the title of the custom palette - type: 'fixed', - value: 'custom', - palette: ['blue', 'yellow'], - 'data-test-subj': 'custom-palette', - }); - }); - - it('should set the colorStops and stops when selecting the Custom palette from the list', () => { - const instance = mountWithIntl(); - - changePaletteIn(instance, 'custom'); - - expect(props.setPalette).toHaveBeenCalledWith({ - type: 'palette', - name: 'custom', - params: expect.objectContaining({ - colorStops: [ - { color: 'blue', stop: 0 }, - { color: 'yellow', stop: 50 }, - ], - stops: [ - { color: 'blue', stop: 50 }, - { color: 'yellow', stop: 100 }, - ], - name: 'custom', - }), - }); - }); - - describe('reverse option', () => { - beforeEach(() => { - props = { - activePalette: { type: 'palette', name: 'positive' }, - palettes: paletteRegistry, - setPalette: jest.fn(), - dataBounds: { min: 0, max: 100 }, - }; - }); - - function toggleReverse(instance: ReactWrapper, checked: boolean) { - return instance - .find('[data-test-subj="lnsDatatable_dynamicColoring_reverse"]') - .first() - .prop('onClick')!({} as React.MouseEvent); - } - - it('should reverse the colorStops on click', () => { - const instance = mountWithIntl(); - - toggleReverse(instance, true); - - expect(props.setPalette).toHaveBeenCalledWith( - expect.objectContaining({ - params: expect.objectContaining({ - reverse: true, - }), - }) - ); - }); - }); - - describe('custom stops', () => { - beforeEach(() => { - props = { - activePalette: { type: 'palette', name: 'positive' }, - palettes: paletteRegistry, - setPalette: jest.fn(), - dataBounds: { min: 0, max: 100 }, - }; - }); - it('should be visible for predefined palettes', () => { - const instance = mountWithIntl(); - expect( - instance.find('[data-test-subj="lnsDatatable_dynamicColoring_custom_stops"]').exists() - ).toEqual(true); - }); - - it('should be visible for custom palettes', () => { - const instance = mountWithIntl( - - ); - expect( - instance.find('[data-test-subj="lnsDatatable_dynamicColoring_custom_stops"]').exists() - ).toEqual(true); - }); - }); - }); -}); diff --git a/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.tsx b/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.tsx deleted file mode 100644 index df01b3e57cd7dff..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.tsx +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; -import { - EuiFormRow, - htmlIdGenerator, - EuiButtonGroup, - EuiFlexGroup, - EuiFlexItem, - EuiSuperSelect, - EuiIcon, - EuiIconTip, - EuiLink, - EuiText, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { PalettePicker } from './palette_picker'; - -import './palette_configuration.scss'; - -import { CustomStops } from './color_stops'; -import { defaultPaletteParams, CUSTOM_PALETTE, DEFAULT_COLOR_STEPS } from './constants'; -import { CustomPaletteParams, RequiredPaletteParamTypes } from './types'; -import { - getColorStops, - getPaletteStops, - mergePaletteParams, - getDataMinMax, - remapStopsByNewInterval, - getSwitchToCustomParams, - reversePalette, - roundStopValues, -} from './utils'; -const idPrefix = htmlIdGenerator()(); - -/** - * Some name conventions here: - * * `displayStops` => It's an additional transformation of `stops` into a [0, N] domain for the EUIPaletteDisplay component. - * * `stops` => final steps used to table coloring. It is a rightShift of the colorStops - * * `colorStops` => user's color stop inputs. Used to compute range min. - * - * When the user inputs the colorStops, they are designed to be the initial part of the color segment, - * so the next stops indicate where the previous stop ends. - * Both table coloring logic and EuiPaletteDisplay format implementation works differently than our current `colorStops`, - * by having the stop values at the end of each color segment rather than at the beginning: `stops` values are computed by a rightShift of `colorStops`. - * EuiPaletteDisplay has an additional requirement as it is always mapped against a domain [0, N]: from `stops` the `displayStops` are computed with - * some continuity enrichment and a remap against a [0, 100] domain to make the palette component work ok. - * - * These naming conventions would be useful to track the code flow in this feature as multiple transformations are happening - * for a single change. - */ - -export function CustomizablePalette({ - palettes, - activePalette, - setPalette, - dataBounds, -}: { - palettes: PaletteRegistry; - activePalette: PaletteOutput; - setPalette: (palette: PaletteOutput) => void; - dataBounds: { min: number; max: number }; -}) { - const isCurrentPaletteCustom = activePalette.params?.name === CUSTOM_PALETTE; - - const colorStopsToShow = roundStopValues( - getColorStops(palettes, activePalette?.params?.colorStops || [], activePalette, dataBounds) - ); - - return ( - <> -
- - { - const isNewPaletteCustom = newPalette.name === CUSTOM_PALETTE; - const newParams: CustomPaletteParams = { - ...activePalette.params, - name: newPalette.name, - colorStops: undefined, - }; - - if (isNewPaletteCustom) { - newParams.colorStops = getColorStops(palettes, [], activePalette, dataBounds); - } - - newParams.stops = getPaletteStops(palettes, newParams, { - prevPalette: - isNewPaletteCustom || isCurrentPaletteCustom ? undefined : newPalette.name, - dataBounds, - }); - - setPalette({ - ...newPalette, - params: newParams, - }); - }} - showCustomPalette - showDynamicColorOnly - /> - - - ['continuity']) => - setPalette( - mergePaletteParams(activePalette, { - continuity, - }) - ) - } - /> - - - {i18n.translate('xpack.lens.table.dynamicColoring.rangeType.label', { - defaultMessage: 'Value type', - })}{' '} - - - } - display="rowCompressed" - > - { - const newRangeType = id.replace( - idPrefix, - '' - ) as RequiredPaletteParamTypes['rangeType']; - - const params: CustomPaletteParams = { rangeType: newRangeType }; - if (isCurrentPaletteCustom) { - const { min: newMin, max: newMax } = getDataMinMax(newRangeType, dataBounds); - const { min: oldMin, max: oldMax } = getDataMinMax( - activePalette.params?.rangeType, - dataBounds - ); - const newColorStops = remapStopsByNewInterval(colorStopsToShow, { - oldInterval: oldMax - oldMin, - newInterval: newMax - newMin, - newMin, - oldMin, - }); - const stops = getPaletteStops( - palettes, - { ...activePalette.params, colorStops: newColorStops, ...params }, - { dataBounds } - ); - params.colorStops = newColorStops; - params.stops = stops; - params.rangeMin = newColorStops[0].stop; - params.rangeMax = newColorStops[newColorStops.length - 1].stop; - } else { - params.stops = getPaletteStops( - palettes, - { ...activePalette.params, ...params }, - { prevPalette: activePalette.name, dataBounds } - ); - } - setPalette(mergePaletteParams(activePalette, params)); - }} - /> - - - { - const params: CustomPaletteParams = { reverse: !activePalette.params?.reverse }; - if (isCurrentPaletteCustom) { - params.colorStops = reversePalette(colorStopsToShow); - params.stops = getPaletteStops( - palettes, - { - ...(activePalette?.params || {}), - colorStops: params.colorStops, - }, - { dataBounds } - ); - } else { - params.stops = reversePalette( - activePalette?.params?.stops || - getPaletteStops( - palettes, - { ...activePalette.params, ...params }, - { prevPalette: activePalette.name, dataBounds } - ) - ); - } - setPalette(mergePaletteParams(activePalette, params)); - }} - > - - - - - - {i18n.translate('xpack.lens.table.dynamicColoring.reverse.label', { - defaultMessage: 'Reverse colors', - })} - - - - - } - > - { - const newParams = getSwitchToCustomParams( - palettes, - activePalette, - { - colorStops, - steps: activePalette.params!.steps || DEFAULT_COLOR_STEPS, - rangeMin: colorStops[0]?.stop, - rangeMax: colorStops[colorStops.length - 1]?.stop, - }, - dataBounds - ); - return setPalette(newParams); - }} - /> - -
- - ); -} diff --git a/x-pack/plugins/lens/public/shared_components/coloring/palette_picker.tsx b/x-pack/plugins/lens/public/shared_components/coloring/palette_picker.tsx deleted file mode 100644 index 164ed9bf067a662..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/coloring/palette_picker.tsx +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiColorPalettePicker, EuiColorPalettePickerPaletteProps } from '@elastic/eui'; -import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; -import { - CUSTOM_PALETTE, - DEFAULT_COLOR_STEPS, - FIXED_PROGRESSION, - defaultPaletteParams, -} from '../../shared_components/coloring/constants'; -import { CustomPaletteParams } from '../../shared_components/coloring/types'; -import { getStopsForFixedMode } from '../../shared_components/coloring/utils'; - -function getCustomPaletteConfig( - palettes: PaletteRegistry, - activePalette: PaletteOutput | undefined -) { - const { id, title } = palettes.get(CUSTOM_PALETTE); - - // Try to generate a palette from the current one - if (activePalette && activePalette.name !== CUSTOM_PALETTE) { - const currentPalette = palettes.get(activePalette.name); - if (currentPalette) { - const stops = currentPalette.getCategoricalColors(DEFAULT_COLOR_STEPS, activePalette?.params); - const palette = activePalette.params?.reverse ? stops.reverse() : stops; - return { - value: id, - title, - type: FIXED_PROGRESSION, - palette, - 'data-test-subj': `custom-palette`, - }; - } - } - // if not possible just show some text - if (!activePalette?.params?.stops) { - return { value: id, title, type: 'text' as const, 'data-test-subj': `custom-palette` }; - } - - // full custom palette - return { - value: id, - title, - type: FIXED_PROGRESSION, - 'data-test-subj': `custom-palette`, - palette: getStopsForFixedMode(activePalette.params.stops, activePalette.params.colorStops), - }; -} - -// Note: this is a special palette picker different from the one in the root shared folder -// ideally these should be merged together, but as for now this holds some custom logic hard to remove -export function PalettePicker({ - palettes, - activePalette, - setPalette, - showCustomPalette, - showDynamicColorOnly, - ...rest -}: { - palettes: PaletteRegistry; - activePalette?: PaletteOutput; - setPalette: (palette: PaletteOutput) => void; - showCustomPalette?: boolean; - showDynamicColorOnly?: boolean; -}) { - const palettesToShow: EuiColorPalettePickerPaletteProps[] = palettes - .getAll() - .filter(({ internal, canDynamicColoring }) => - showDynamicColorOnly ? canDynamicColoring : !internal - ) - .map(({ id, title, getCategoricalColors }) => { - const colors = getCategoricalColors( - DEFAULT_COLOR_STEPS, - id === activePalette?.name ? activePalette?.params : undefined - ); - return { - value: id, - title, - type: FIXED_PROGRESSION, - palette: activePalette?.params?.reverse ? colors.reverse() : colors, - 'data-test-subj': `${id}-palette`, - }; - }); - if (showCustomPalette) { - palettesToShow.push(getCustomPaletteConfig(palettes, activePalette)); - } - return ( - { - setPalette({ - type: 'palette', - name: newPalette, - }); - }} - valueOfSelected={activePalette?.name || defaultPaletteParams.name} - selectionDisplay="palette" - {...rest} - /> - ); -} diff --git a/x-pack/plugins/lens/public/shared_components/coloring/types.ts b/x-pack/plugins/lens/public/shared_components/coloring/types.ts deleted file mode 100644 index d9a8edf0ccb62bc..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/coloring/types.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -export interface ColorStop { - color: string; - stop: number; -} - -export interface CustomPaletteParams { - name?: string; - reverse?: boolean; - rangeType?: 'number' | 'percent'; - continuity?: 'above' | 'below' | 'all' | 'none'; - progression?: 'fixed'; - rangeMin?: number; - rangeMax?: number; - stops?: ColorStop[]; - colorStops?: ColorStop[]; - steps?: number; -} - -export type RequiredPaletteParamTypes = Required; diff --git a/x-pack/plugins/lens/public/shared_components/coloring/utils.test.ts b/x-pack/plugins/lens/public/shared_components/coloring/utils.test.ts deleted file mode 100644 index 8aaab0923584d82..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/coloring/utils.test.ts +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { chartPluginMock } from 'src/plugins/charts/public/mocks'; -import { - applyPaletteParams, - getContrastColor, - getDataMinMax, - getPaletteStops, - getStepValue, - isValidColor, - mergePaletteParams, - remapStopsByNewInterval, - reversePalette, - roundStopValues, -} from './utils'; - -describe('applyPaletteParams', () => { - const paletteRegistry = chartPluginMock.createPaletteRegistry(); - it('should return a palette stops array only by the name', () => { - expect( - applyPaletteParams( - paletteRegistry, - { name: 'default', type: 'palette', params: { name: 'default' } }, - { min: 0, max: 100 } - ) - ).toEqual([ - // stops are 0 and 50 by with a 20 offset (100 divided by 5 steps) for display - // the mock palette service has only 2 colors so tests are a bit off by that - { color: 'red', stop: 20 }, - { color: 'black', stop: 70 }, - ]); - }); - - it('should return a palette stops array reversed', () => { - expect( - applyPaletteParams( - paletteRegistry, - { name: 'default', type: 'palette', params: { name: 'default', reverse: true } }, - { min: 0, max: 100 } - ) - ).toEqual([ - { color: 'black', stop: 20 }, - { color: 'red', stop: 70 }, - ]); - }); -}); - -describe('remapStopsByNewInterval', () => { - it('should correctly remap the current palette from 0..1 to 0...100', () => { - expect( - remapStopsByNewInterval( - [ - { color: 'black', stop: 0 }, - { color: 'green', stop: 0.5 }, - { color: 'red', stop: 0.9 }, - ], - { newInterval: 100, oldInterval: 1, newMin: 0, oldMin: 0 } - ) - ).toEqual([ - { color: 'black', stop: 0 }, - { color: 'green', stop: 50 }, - { color: 'red', stop: 90 }, - ]); - - // now test the other way around - expect( - remapStopsByNewInterval( - [ - { color: 'black', stop: 0 }, - { color: 'green', stop: 50 }, - { color: 'red', stop: 90 }, - ], - { newInterval: 1, oldInterval: 100, newMin: 0, oldMin: 0 } - ) - ).toEqual([ - { color: 'black', stop: 0 }, - { color: 'green', stop: 0.5 }, - { color: 'red', stop: 0.9 }, - ]); - }); - - it('should correctly handle negative numbers to/from', () => { - expect( - remapStopsByNewInterval( - [ - { color: 'black', stop: -100 }, - { color: 'green', stop: -50 }, - { color: 'red', stop: -1 }, - ], - { newInterval: 100, oldInterval: 100, newMin: 0, oldMin: -100 } - ) - ).toEqual([ - { color: 'black', stop: 0 }, - { color: 'green', stop: 50 }, - { color: 'red', stop: 99 }, - ]); - - // now map the other way around - expect( - remapStopsByNewInterval( - [ - { color: 'black', stop: 0 }, - { color: 'green', stop: 50 }, - { color: 'red', stop: 99 }, - ], - { newInterval: 100, oldInterval: 100, newMin: -100, oldMin: 0 } - ) - ).toEqual([ - { color: 'black', stop: -100 }, - { color: 'green', stop: -50 }, - { color: 'red', stop: -1 }, - ]); - - // and test also palettes that also contains negative values - expect( - remapStopsByNewInterval( - [ - { color: 'black', stop: -50 }, - { color: 'green', stop: 0 }, - { color: 'red', stop: 50 }, - ], - { newInterval: 100, oldInterval: 100, newMin: 0, oldMin: -50 } - ) - ).toEqual([ - { color: 'black', stop: 0 }, - { color: 'green', stop: 50 }, - { color: 'red', stop: 100 }, - ]); - }); -}); - -describe('getDataMinMax', () => { - it('should pick the correct min/max based on the current range type', () => { - expect(getDataMinMax('percent', { min: -100, max: 0 })).toEqual({ min: 0, max: 100 }); - }); - - it('should pick the correct min/max apply percent by default', () => { - expect(getDataMinMax(undefined, { min: -100, max: 0 })).toEqual({ min: 0, max: 100 }); - }); -}); - -describe('getPaletteStops', () => { - const paletteRegistry = chartPluginMock.createPaletteRegistry(); - it('should correctly compute a predefined palette stops definition from only the name', () => { - expect( - getPaletteStops(paletteRegistry, { name: 'mock' }, { dataBounds: { min: 0, max: 100 } }) - ).toEqual([ - { color: 'blue', stop: 20 }, - { color: 'yellow', stop: 70 }, - ]); - }); - - it('should correctly compute a predefined palette stops definition from explicit prevPalette (override)', () => { - expect( - getPaletteStops( - paletteRegistry, - { name: 'default' }, - { dataBounds: { min: 0, max: 100 }, prevPalette: 'mock' } - ) - ).toEqual([ - { color: 'blue', stop: 20 }, - { color: 'yellow', stop: 70 }, - ]); - }); - - it('should infer the domain from dataBounds but start from 0', () => { - expect( - getPaletteStops( - paletteRegistry, - { name: 'default', rangeType: 'number' }, - { dataBounds: { min: 1, max: 11 }, prevPalette: 'mock' } - ) - ).toEqual([ - { color: 'blue', stop: 2 }, - { color: 'yellow', stop: 7 }, - ]); - }); - - it('should override the minStop when requested', () => { - expect( - getPaletteStops( - paletteRegistry, - { name: 'default', rangeType: 'number' }, - { dataBounds: { min: 1, max: 11 }, mapFromMinValue: true } - ) - ).toEqual([ - { color: 'red', stop: 1 }, - { color: 'black', stop: 6 }, - ]); - }); - - it('should compute a display stop palette from custom colorStops defined by the user', () => { - expect( - getPaletteStops( - paletteRegistry, - { - name: 'custom', - rangeType: 'number', - colorStops: [ - { color: 'green', stop: 0 }, - { color: 'blue', stop: 40 }, - { color: 'red', stop: 80 }, - ], - }, - { dataBounds: { min: 0, max: 100 } } - ) - ).toEqual([ - { color: 'green', stop: 40 }, - { color: 'blue', stop: 80 }, - { color: 'red', stop: 100 }, - ]); - }); - - it('should compute a display stop palette from custom colorStops defined by the user - handle stop at the end', () => { - expect( - getPaletteStops( - paletteRegistry, - { - name: 'custom', - rangeType: 'number', - colorStops: [ - { color: 'green', stop: 0 }, - { color: 'blue', stop: 40 }, - { color: 'red', stop: 100 }, - ], - }, - { dataBounds: { min: 0, max: 100 } } - ) - ).toEqual([ - { color: 'green', stop: 40 }, - { color: 'blue', stop: 100 }, - { color: 'red', stop: 101 }, - ]); - }); - - it('should compute a display stop palette from custom colorStops defined by the user - handle stop at the end (fractional)', () => { - expect( - getPaletteStops( - paletteRegistry, - { - name: 'custom', - rangeType: 'number', - colorStops: [ - { color: 'green', stop: 0 }, - { color: 'blue', stop: 0.4 }, - { color: 'red', stop: 1 }, - ], - }, - { dataBounds: { min: 0, max: 1 } } - ) - ).toEqual([ - { color: 'green', stop: 0.4 }, - { color: 'blue', stop: 1 }, - { color: 'red', stop: 2 }, - ]); - }); - - it('should compute a display stop palette from custom colorStops defined by the user - stretch the stops to 100% percent', () => { - expect( - getPaletteStops( - paletteRegistry, - { - name: 'custom', - colorStops: [ - { color: 'green', stop: 0 }, - { color: 'blue', stop: 0.4 }, - { color: 'red', stop: 1 }, - ], - }, - { dataBounds: { min: 0, max: 1 } } - ) - ).toEqual([ - { color: 'green', stop: 0.4 }, - { color: 'blue', stop: 1 }, - { color: 'red', stop: 100 }, // default rangeType is percent, hence stretch to 100% - ]); - }); -}); - -describe('reversePalette', () => { - it('should correctly reverse color and stops', () => { - expect( - reversePalette([ - { color: 'red', stop: 0 }, - { color: 'green', stop: 0.5 }, - { color: 'blue', stop: 0.9 }, - ]) - ).toEqual([ - { color: 'blue', stop: 0 }, - { color: 'green', stop: 0.5 }, - { color: 'red', stop: 0.9 }, - ]); - }); -}); - -describe('mergePaletteParams', () => { - it('should return a full palette', () => { - expect(mergePaletteParams({ type: 'palette', name: 'myPalette' }, { reverse: true })).toEqual({ - type: 'palette', - name: 'myPalette', - params: { reverse: true }, - }); - }); -}); - -describe('isValidColor', () => { - it('should return ok for valid hex color notation', () => { - expect(isValidColor('#fff')).toBe(true); - expect(isValidColor('#ffffff')).toBe(true); - expect(isValidColor('#ffffffaa')).toBe(true); - }); - - it('should return false for non valid strings', () => { - expect(isValidColor('')).toBe(false); - expect(isValidColor('#')).toBe(false); - expect(isValidColor('#ff')).toBe(false); - expect(isValidColor('123')).toBe(false); - expect(isValidColor('rgb(1, 1, 1)')).toBe(false); - expect(isValidColor('rgba(1, 1, 1, 0)')).toBe(false); - expect(isValidColor('#ffffffgg')).toBe(false); - expect(isValidColor('#fff00')).toBe(false); - // this version of chroma does not support hex4 format - expect(isValidColor('#fffa')).toBe(false); - }); -}); - -describe('roundStopValues', () => { - it('should round very long values', () => { - expect(roundStopValues([{ color: 'red', stop: 0.1515 }])).toEqual([ - { color: 'red', stop: 0.15 }, - ]); - }); -}); - -describe('getStepValue', () => { - it('should compute the next step based on the last 2 stops', () => { - expect( - getStepValue( - // first arg is taken as max reference - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 50 }, - ], - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 50 }, - ], - 100 - ) - ).toBe(50); - - expect( - getStepValue( - // first arg is taken as max reference - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 80 }, - ], - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 50 }, - ], - 90 - ) - ).toBe(10); // 90 - 80 - - expect( - getStepValue( - // first arg is taken as max reference - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 100 }, - ], - [ - { color: 'red', stop: 0 }, - { color: 'red', stop: 50 }, - ], - 100 - ) - ).toBe(1); - }); -}); - -describe('getContrastColor', () => { - it('should pick the light color when the passed one is dark', () => { - expect(getContrastColor('#000', true)).toBe('#ffffff'); - expect(getContrastColor('#000', false)).toBe('#ffffff'); - }); - - it('should pick the dark color when the passed one is light', () => { - expect(getContrastColor('#fff', true)).toBe('#000000'); - expect(getContrastColor('#fff', false)).toBe('#000000'); - }); -}); diff --git a/x-pack/plugins/lens/public/shared_components/coloring/utils.ts b/x-pack/plugins/lens/public/shared_components/coloring/utils.ts deleted file mode 100644 index 89fceec533493f7..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/coloring/utils.ts +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import chroma from 'chroma-js'; -import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; -import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps/theme'; -import { isColorDark } from '@elastic/eui'; -import { - CUSTOM_PALETTE, - defaultPaletteParams, - DEFAULT_COLOR_STEPS, - DEFAULT_MAX_STOP, - DEFAULT_MIN_STOP, -} from './constants'; -import { CustomPaletteParams, ColorStop } from './types'; - -/** - * Some name conventions here: - * * `displayStops` => It's an additional transformation of `stops` into a [0, N] domain for the EUIPaletteDisplay component. - * * `stops` => final steps used to table coloring. It is a rightShift of the colorStops - * * `colorStops` => user's color stop inputs. Used to compute range min. - * - * When the user inputs the colorStops, they are designed to be the initial part of the color segment, - * so the next stops indicate where the previous stop ends. - * Both table coloring logic and EuiPaletteDisplay format implementation works differently than our current `colorStops`, - * by having the stop values at the end of each color segment rather than at the beginning: `stops` values are computed by a rightShift of `colorStops`. - * EuiPaletteDisplay has an additional requirement as it is always mapped against a domain [0, N]: from `stops` the `displayStops` are computed with - * some continuity enrichment and a remap against a [0, 100] domain to make the palette component work ok. - * - * These naming conventions would be useful to track the code flow in this feature as multiple transformations are happening - * for a single change. - */ - -export function applyPaletteParams( - palettes: PaletteRegistry, - activePalette: PaletteOutput, - dataBounds: { min: number; max: number } -) { - // make a copy of it as they have to be manipulated later on - let displayStops = getPaletteStops(palettes, activePalette?.params || {}, { - dataBounds, - }); - - if (activePalette?.params?.reverse && activePalette?.params?.name !== CUSTOM_PALETTE) { - displayStops = reversePalette(displayStops); - } - return displayStops; -} - -// Need to shift the Custom palette in order to correctly visualize it when in display mode -function shiftPalette(stops: ColorStop[], max: number) { - // shift everything right and add an additional stop at the end - const result = stops.map((entry, i, array) => ({ - ...entry, - stop: i + 1 < array.length ? array[i + 1].stop : max, - })); - if (stops[stops.length - 1].stop === max) { - // extends the range by a fair amount to make it work the extra case for the last stop === max - const computedStep = getStepValue(stops, result, max) || 1; - // do not go beyond the unit step in this case - const step = Math.min(1, computedStep); - result[stops.length - 1].stop = max + step; - } - return result; -} - -// Utility to remap color stops within new domain -export function remapStopsByNewInterval( - controlStops: ColorStop[], - { - newInterval, - oldInterval, - newMin, - oldMin, - }: { newInterval: number; oldInterval: number; newMin: number; oldMin: number } -) { - return (controlStops || []).map(({ color, stop }) => { - return { - color, - stop: newMin + ((stop - oldMin) * newInterval) / oldInterval, - }; - }); -} - -function getOverallMinMax( - params: CustomPaletteParams | undefined, - dataBounds: { min: number; max: number } -) { - const { min: dataMin, max: dataMax } = getDataMinMax(params?.rangeType, dataBounds); - const minStopValue = params?.colorStops?.[0]?.stop ?? Infinity; - const maxStopValue = params?.colorStops?.[params.colorStops.length - 1]?.stop ?? -Infinity; - const overallMin = Math.min(dataMin, minStopValue); - const overallMax = Math.max(dataMax, maxStopValue); - return { min: overallMin, max: overallMax }; -} - -export function getDataMinMax( - rangeType: CustomPaletteParams['rangeType'] | undefined, - dataBounds: { min: number; max: number } -) { - const dataMin = rangeType === 'number' ? dataBounds.min : DEFAULT_MIN_STOP; - const dataMax = rangeType === 'number' ? dataBounds.max : DEFAULT_MAX_STOP; - return { min: dataMin, max: dataMax }; -} - -/** - * This is a generic function to compute stops from the current parameters. - */ -export function getPaletteStops( - palettes: PaletteRegistry, - activePaletteParams: CustomPaletteParams, - // used to customize color resolution - { - prevPalette, - dataBounds, - mapFromMinValue, - }: { prevPalette?: string; dataBounds: { min: number; max: number }; mapFromMinValue?: boolean } -) { - const { min: minValue, max: maxValue } = getOverallMinMax(activePaletteParams, dataBounds); - const interval = maxValue - minValue; - const { stops: currentStops, ...otherParams } = activePaletteParams || {}; - - if (activePaletteParams.name === 'custom' && activePaletteParams?.colorStops) { - // need to generate the palette from the existing controlStops - return shiftPalette(activePaletteParams.colorStops, maxValue); - } - // generate a palette from predefined ones and customize the domain - const colorStopsFromPredefined = palettes - .get(prevPalette || activePaletteParams?.name || defaultPaletteParams.name) - .getCategoricalColors(defaultPaletteParams.steps, otherParams); - - const newStopsMin = mapFromMinValue ? minValue : interval / defaultPaletteParams.steps; - - const stops = remapStopsByNewInterval( - colorStopsFromPredefined.map((color, index) => ({ color, stop: index })), - { - newInterval: interval, - oldInterval: colorStopsFromPredefined.length, - newMin: newStopsMin, - oldMin: 0, - } - ); - return stops; -} - -export function reversePalette(paletteColorRepresentation: ColorStop[] = []) { - const stops = paletteColorRepresentation.map(({ stop }) => stop); - return paletteColorRepresentation - .map(({ color }, i) => ({ - color, - stop: stops[paletteColorRepresentation.length - i - 1], - })) - .reverse(); -} - -export function mergePaletteParams( - activePalette: PaletteOutput, - newParams: CustomPaletteParams -): PaletteOutput { - return { - ...activePalette, - params: { - ...activePalette.params, - ...newParams, - }, - }; -} - -function isValidPonyfill(colorString: string) { - // we're using an old version of chroma without the valid function - try { - chroma(colorString); - return true; - } catch (e) { - return false; - } -} - -export function isValidColor(colorString: string) { - // chroma can handle also hex values with alpha channel/transparency - // chroma accepts also hex without #, so test for it - return colorString !== '' && /^#/.test(colorString) && isValidPonyfill(colorString); -} - -export function roundStopValues(colorStops: ColorStop[]) { - return colorStops.map(({ color, stop }) => { - const roundedStop = Number(stop.toFixed(2)); - return { color, stop: roundedStop }; - }); -} - -// very simple heuristic: pick last two stops and compute a new stop based on the same distance -// if the new stop is above max, then reduce the step to reach max, or if zero then just 1. -// -// it accepts two series of stops as the function is used also when computing stops from colorStops -export function getStepValue(colorStops: ColorStop[], newColorStops: ColorStop[], max: number) { - const length = newColorStops.length; - // workout the steps from the last 2 items - const dataStep = newColorStops[length - 1].stop - newColorStops[length - 2].stop || 1; - let step = Number(dataStep.toFixed(2)); - if (max < colorStops[length - 1].stop + step) { - const diffToMax = max - colorStops[length - 1].stop; - // if the computed step goes way out of bound, fallback to 1, otherwise reach max - step = diffToMax > 0 ? diffToMax : 1; - } - return step; -} - -export function getSwitchToCustomParams( - palettes: PaletteRegistry, - activePalette: PaletteOutput, - newParams: CustomPaletteParams, - dataBounds: { min: number; max: number } -) { - // if it's already a custom palette just return the params - if (activePalette?.params?.name === CUSTOM_PALETTE) { - const stops = getPaletteStops( - palettes, - { - steps: DEFAULT_COLOR_STEPS, - ...activePalette.params, - ...newParams, - }, - { - dataBounds, - } - ); - return mergePaletteParams(activePalette, { - ...newParams, - stops, - }); - } - // prepare everything to switch to custom palette - const newPaletteParams = { - steps: DEFAULT_COLOR_STEPS, - ...activePalette.params, - ...newParams, - name: CUSTOM_PALETTE, - }; - - const stops = getPaletteStops(palettes, newPaletteParams, { - prevPalette: newPaletteParams.colorStops ? undefined : activePalette.name, - dataBounds, - }); - return mergePaletteParams( - { name: CUSTOM_PALETTE, type: 'palette' }, - { - ...newPaletteParams, - stops, - } - ); -} - -export function getColorStops( - palettes: PaletteRegistry, - colorStops: Required['stops'], - activePalette: PaletteOutput, - dataBounds: { min: number; max: number } -) { - // just forward the current stops if custom - if (activePalette?.name === CUSTOM_PALETTE) { - return colorStops; - } - // for predefined palettes create some stops, then drop the last one. - // we're using these as starting point for the user - let freshColorStops = getPaletteStops( - palettes, - { ...activePalette?.params }, - // mapFromMinValue is a special flag to offset the stops values - // used here to avoid a new remap/left shift - { dataBounds, mapFromMinValue: true } - ); - if (activePalette?.params?.reverse) { - freshColorStops = reversePalette(freshColorStops); - } - return freshColorStops; -} - -export function getContrastColor(color: string, isDarkTheme: boolean) { - const darkColor = isDarkTheme ? euiDarkVars.euiColorInk : euiLightVars.euiColorInk; - const lightColor = isDarkTheme ? euiDarkVars.euiColorGhost : euiLightVars.euiColorGhost; - return isColorDark(...chroma(color).rgb()) ? lightColor : darkColor; -} - -/** - * Same as stops, but remapped against a range 0-100 - */ -export function getStopsForFixedMode(stops: ColorStop[], colorStops?: ColorStop[]) { - const referenceStops = - colorStops || stops.map(({ color }, index) => ({ color, stop: 20 * index })); - const fallbackStops = stops; - - // what happens when user set two stops with the same value? we'll fallback to the display interval - const oldInterval = - referenceStops[referenceStops.length - 1].stop - referenceStops[0].stop || - fallbackStops[fallbackStops.length - 1].stop - fallbackStops[0].stop; - - return remapStopsByNewInterval(stops, { - newInterval: 100, - oldInterval, - newMin: 0, - oldMin: referenceStops[0].stop, - }); -} diff --git a/x-pack/plugins/lens/public/shared_components/debounced_value.ts b/x-pack/plugins/lens/public/shared_components/debounced_value.ts index 1f8ba0fa765b2e5..5447384ce38ea5b 100644 --- a/x-pack/plugins/lens/public/shared_components/debounced_value.ts +++ b/x-pack/plugins/lens/public/shared_components/debounced_value.ts @@ -6,7 +6,7 @@ */ import { useState, useMemo, useEffect, useRef } from 'react'; -import { debounce } from 'lodash'; +import _ from 'lodash'; /** * Debounces value changes and updates inputValue on root state changes if no debounced changes @@ -27,7 +27,7 @@ export const useDebouncedValue = ({ const initialValue = useRef(value); const onChangeDebounced = useMemo(() => { - const callback = debounce((val: T) => { + const callback = _.debounce((val: T) => { onChange(val); unflushedChanges.current = false; }, 256); diff --git a/x-pack/plugins/lens/public/shared_components/helpers.ts b/x-pack/plugins/lens/public/shared_components/helpers.ts deleted file mode 100644 index a9f35757c4cbfe6..000000000000000 --- a/x-pack/plugins/lens/public/shared_components/helpers.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useRef } from 'react'; -import useDebounce from 'react-use/lib/useDebounce'; - -export const useDebounceWithOptions = ( - fn: Function, - { skipFirstRender }: { skipFirstRender: boolean } = { skipFirstRender: false }, - ms?: number | undefined, - deps?: React.DependencyList | undefined -) => { - const isFirstRender = useRef(true); - const newDeps = [...(deps || []), isFirstRender]; - - return useDebounce( - () => { - if (skipFirstRender && isFirstRender.current) { - isFirstRender.current = false; - return; - } - return fn(); - }, - ms, - newDeps - ); -}; diff --git a/x-pack/plugins/lens/public/shared_components/index.ts b/x-pack/plugins/lens/public/shared_components/index.ts index cf8536884acdf8d..ae57da976a88172 100644 --- a/x-pack/plugins/lens/public/shared_components/index.ts +++ b/x-pack/plugins/lens/public/shared_components/index.ts @@ -9,7 +9,4 @@ export * from './empty_placeholder'; export { ToolbarPopoverProps, ToolbarPopover } from './toolbar_popover'; export { LegendSettingsPopover } from './legend_settings_popover'; export { PalettePicker } from './palette_picker'; -export { TooltipWrapper } from './tooltip_wrapper'; -export * from './coloring'; export { useDebouncedValue } from './debounced_value'; -export * from './helpers'; diff --git a/x-pack/plugins/lens/public/shared_components/palette_picker.tsx b/x-pack/plugins/lens/public/shared_components/palette_picker.tsx index 6424dc8143f9576..b15a6749d4c2d10 100644 --- a/x-pack/plugins/lens/public/shared_components/palette_picker.tsx +++ b/x-pack/plugins/lens/public/shared_components/palette_picker.tsx @@ -7,9 +7,10 @@ import React from 'react'; import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; -import { EuiColorPalettePicker, EuiColorPalettePickerPaletteProps } from '@elastic/eui'; +import { EuiColorPalettePicker } from '@elastic/eui'; import { EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { NativeRenderer } from '../native_renderer'; export function PalettePicker({ palettes, @@ -20,20 +21,6 @@ export function PalettePicker({ activePalette?: PaletteOutput; setPalette: (palette: PaletteOutput) => void; }) { - const palettesToShow: EuiColorPalettePickerPaletteProps[] = palettes - .getAll() - .filter(({ internal }) => !internal) - .map(({ id, title, getCategoricalColors }) => { - return { - value: id, - title, - type: 'fixed', - palette: getCategoricalColors( - 10, - id === activePalette?.name ? activePalette?.params : undefined - ), - }; - }); return ( !internal) + .map(({ id, title, getColors }) => { + return { + value: id, + title, + type: 'fixed', + palette: getColors( + 10, + id === activePalette?.name ? activePalette?.params : undefined + ), + }; + })} onChange={(newPalette) => { setPalette({ type: 'palette', @@ -56,6 +56,21 @@ export function PalettePicker({ valueOfSelected={activePalette?.name || 'default'} selectionDisplay={'palette'} /> + {activePalette && palettes.get(activePalette.name).renderEditor && ( + { + setPalette({ + type: 'palette', + name: activePalette.name, + params: updater(activePalette.params), + }); + }, + }} + /> + )} ); diff --git a/x-pack/plugins/lens/public/state_management/app_slice.ts b/x-pack/plugins/lens/public/state_management/app_slice.ts deleted file mode 100644 index 29d5b0bee843f63..000000000000000 --- a/x-pack/plugins/lens/public/state_management/app_slice.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { isEqual } from 'lodash'; -import { LensAppState } from './types'; - -export const initialState: LensAppState = { - searchSessionId: '', - filters: [], - query: { language: 'kuery', query: '' }, - resolvedDateRange: { fromDate: '', toDate: '' }, - - indexPatternsForTopNav: [], - isSaveable: false, - isAppLoading: false, - isLinkedToOriginatingApp: false, -}; - -export const appSlice = createSlice({ - name: 'app', - initialState, - reducers: { - setState: (state, { payload }: PayloadAction>) => { - return { - ...state, - ...payload, - }; - }, - onChangeFromEditorFrame: (state, { payload }: PayloadAction>) => { - return { - ...state, - ...payload, - }; - }, - onActiveDataChange: (state, { payload }: PayloadAction>) => { - if (!isEqual(state.activeData, payload?.activeData)) { - return { - ...state, - ...payload, - }; - } - return state; - }, - navigateAway: (state) => state, - }, -}); - -export const reducer = { - app: appSlice.reducer, -}; diff --git a/x-pack/plugins/lens/public/state_management/external_context_middleware.ts b/x-pack/plugins/lens/public/state_management/external_context_middleware.ts deleted file mode 100644 index 35d0f7cf197eddb..000000000000000 --- a/x-pack/plugins/lens/public/state_management/external_context_middleware.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { delay, finalize, switchMap, tap } from 'rxjs/operators'; -import _, { debounce } from 'lodash'; -import { Dispatch, MiddlewareAPI, PayloadAction } from '@reduxjs/toolkit'; -import { trackUiEvent } from '../lens_ui_telemetry'; - -import { - waitUntilNextSessionCompletes$, - DataPublicPluginStart, -} from '../../../../../src/plugins/data/public'; -import { setState, LensGetState, LensDispatch } from '.'; -import { LensAppState } from './types'; -import { getResolvedDateRange } from '../utils'; - -export const externalContextMiddleware = (data: DataPublicPluginStart) => ( - store: MiddlewareAPI -) => { - const unsubscribeFromExternalContext = subscribeToExternalContext( - data, - store.getState, - store.dispatch - ); - return (next: Dispatch) => (action: PayloadAction>) => { - if (action.type === 'app/navigateAway') { - unsubscribeFromExternalContext(); - } - next(action); - }; -}; - -function subscribeToExternalContext( - data: DataPublicPluginStart, - getState: LensGetState, - dispatch: LensDispatch -) { - const { query: queryService, search } = data; - const { filterManager } = queryService; - - const dispatchFromExternal = (searchSessionId = search.session.start()) => { - const globalFilters = filterManager.getFilters(); - const filters = _.isEqual(getState().app.filters, globalFilters) - ? null - : { filters: globalFilters }; - dispatch( - setState({ - searchSessionId, - ...filters, - resolvedDateRange: getResolvedDateRange(queryService.timefilter.timefilter), - }) - ); - }; - - const debounceDispatchFromExternal = debounce(dispatchFromExternal, 100); - - const sessionSubscription = search.session - .getSession$() - // wait for a tick to filter/timerange subscribers the chance to update the session id in the state - .pipe(delay(0)) - // then update if it didn't get updated yet - .subscribe((newSessionId?: string) => { - if (newSessionId && getState().app.searchSessionId !== newSessionId) { - debounceDispatchFromExternal(newSessionId); - } - }); - - const filterSubscription = filterManager.getUpdates$().subscribe({ - next: () => { - debounceDispatchFromExternal(); - trackUiEvent('app_filters_updated'); - }, - }); - - const timeSubscription = data.query.timefilter.timefilter.getTimeUpdate$().subscribe({ - next: () => { - debounceDispatchFromExternal(); - }, - }); - - const autoRefreshSubscription = data.query.timefilter.timefilter - .getAutoRefreshFetch$() - .pipe( - tap(() => { - debounceDispatchFromExternal(); - }), - switchMap((done) => - // best way in lens to estimate that all panels are updated is to rely on search session service state - waitUntilNextSessionCompletes$(search.session).pipe(finalize(done)) - ) - ) - .subscribe(); - return () => { - filterSubscription.unsubscribe(); - timeSubscription.unsubscribe(); - autoRefreshSubscription.unsubscribe(); - sessionSubscription.unsubscribe(); - }; -} diff --git a/x-pack/plugins/lens/public/state_management/index.ts b/x-pack/plugins/lens/public/state_management/index.ts deleted file mode 100644 index 429978e60756b81..000000000000000 --- a/x-pack/plugins/lens/public/state_management/index.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { configureStore, DeepPartial, getDefaultMiddleware } from '@reduxjs/toolkit'; -import logger from 'redux-logger'; -import { useDispatch, useSelector, TypedUseSelectorHook } from 'react-redux'; -import { appSlice, initialState } from './app_slice'; -import { timeRangeMiddleware } from './time_range_middleware'; -import { externalContextMiddleware } from './external_context_middleware'; - -import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; -import { LensAppState, LensState } from './types'; -export * from './types'; - -export const reducer = { - app: appSlice.reducer, -}; - -export const { - setState, - navigateAway, - onChangeFromEditorFrame, - onActiveDataChange, -} = appSlice.actions; - -export const getPreloadedState = (initializedState: Partial) => { - const state = { - app: { - ...initialState, - ...initializedState, - }, - } as DeepPartial; - return state; -}; - -type PreloadedState = ReturnType; - -export const makeConfigureStore = ( - preloadedState: PreloadedState, - { data }: { data: DataPublicPluginStart } -) => { - const middleware = [ - ...getDefaultMiddleware({ - serializableCheck: { - ignoredActions: [ - 'app/setState', - 'app/onChangeFromEditorFrame', - 'app/onActiveDataChange', - 'app/navigateAway', - ], - }, - }), - timeRangeMiddleware(data), - externalContextMiddleware(data), - ]; - if (process.env.NODE_ENV === 'development') middleware.push(logger); - - return configureStore({ - reducer, - middleware, - preloadedState, - }); -}; - -export type LensRootStore = ReturnType; - -export type LensDispatch = LensRootStore['dispatch']; -export type LensGetState = LensRootStore['getState']; -export type LensRootState = ReturnType; - -export const useLensDispatch = () => useDispatch(); -export const useLensSelector: TypedUseSelectorHook = useSelector; diff --git a/x-pack/plugins/lens/public/state_management/time_range_middleware.test.ts b/x-pack/plugins/lens/public/state_management/time_range_middleware.test.ts deleted file mode 100644 index 4145f8ed5e52cf8..000000000000000 --- a/x-pack/plugins/lens/public/state_management/time_range_middleware.test.ts +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// /* -// * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -// * or more contributor license agreements. Licensed under the Elastic License -// * 2.0; you may not use this file except in compliance with the Elastic License -// * 2.0. -// */ - -import { timeRangeMiddleware } from './time_range_middleware'; - -import { Observable, Subject } from 'rxjs'; -import { DataPublicPluginStart, esFilters } from '../../../../../src/plugins/data/public'; -import moment from 'moment'; -import { initialState } from './app_slice'; -import { LensAppState } from './types'; -import { PayloadAction } from '@reduxjs/toolkit'; -import { Document } from '../persistence'; - -const sessionIdSubject = new Subject(); - -function createMockSearchService() { - let sessionIdCounter = 1; - return { - session: { - start: jest.fn(() => `sessionId-${sessionIdCounter++}`), - clear: jest.fn(), - getSessionId: jest.fn(() => `sessionId-${sessionIdCounter}`), - getSession$: jest.fn(() => sessionIdSubject.asObservable()), - }, - }; -} - -function createMockFilterManager() { - const unsubscribe = jest.fn(); - - let subscriber: () => void; - let filters: unknown = []; - - return { - getUpdates$: () => ({ - subscribe: ({ next }: { next: () => void }) => { - subscriber = next; - return unsubscribe; - }, - }), - setFilters: jest.fn((newFilters: unknown[]) => { - filters = newFilters; - if (subscriber) subscriber(); - }), - setAppFilters: jest.fn((newFilters: unknown[]) => { - filters = newFilters; - if (subscriber) subscriber(); - }), - getFilters: () => filters, - getGlobalFilters: () => { - // @ts-ignore - return filters.filter(esFilters.isFilterPinned); - }, - removeAll: () => { - filters = []; - subscriber(); - }, - }; -} - -function createMockQueryString() { - return { - getQuery: jest.fn(() => ({ query: '', language: 'kuery' })), - setQuery: jest.fn(), - getDefaultQuery: jest.fn(() => ({ query: '', language: 'kuery' })), - }; -} - -function createMockTimefilter() { - const unsubscribe = jest.fn(); - - let timeFilter = { from: 'now-7d', to: 'now' }; - let subscriber: () => void; - return { - getTime: jest.fn(() => timeFilter), - setTime: jest.fn((newTimeFilter) => { - timeFilter = newTimeFilter; - if (subscriber) { - subscriber(); - } - }), - getTimeUpdate$: () => ({ - subscribe: ({ next }: { next: () => void }) => { - subscriber = next; - return unsubscribe; - }, - }), - calculateBounds: jest.fn(() => ({ - min: moment('2021-01-10T04:00:00.000Z'), - max: moment('2021-01-10T08:00:00.000Z'), - })), - getBounds: jest.fn(() => timeFilter), - getRefreshInterval: () => {}, - getRefreshIntervalDefaults: () => {}, - getAutoRefreshFetch$: () => new Observable(), - }; -} - -function makeDefaultData(): jest.Mocked { - return ({ - query: { - filterManager: createMockFilterManager(), - timefilter: { - timefilter: createMockTimefilter(), - }, - queryString: createMockQueryString(), - state$: new Observable(), - }, - indexPatterns: { - get: jest.fn((id) => { - return new Promise((resolve) => resolve({ id })); - }), - }, - search: createMockSearchService(), - nowProvider: { - get: jest.fn(), - }, - } as unknown) as DataPublicPluginStart; -} - -const createMiddleware = (data: DataPublicPluginStart) => { - const middleware = timeRangeMiddleware(data); - const store = { - getState: jest.fn(() => ({ app: initialState })), - dispatch: jest.fn(), - }; - const next = jest.fn(); - - const invoke = (action: PayloadAction>) => middleware(store)(next)(action); - - return { store, next, invoke }; -}; - -describe('timeRangeMiddleware', () => { - describe('time update', () => { - it('does update the searchSessionId when the state changes and too much time passed', () => { - const data = makeDefaultData(); - (data.nowProvider.get as jest.Mock).mockReturnValue(new Date(Date.now() - 30000)); - (data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({ - from: 'now-2m', - to: 'now', - }); - (data.query.timefilter.timefilter.getBounds as jest.Mock).mockReturnValue({ - min: moment(Date.now() - 100000), - max: moment(Date.now() - 30000), - }); - const { next, invoke, store } = createMiddleware(data); - const action = { - type: 'app/setState', - payload: { lastKnownDoc: ('new' as unknown) as Document }, - }; - invoke(action); - expect(store.dispatch).toHaveBeenCalledWith({ - payload: { - resolvedDateRange: { - fromDate: '2021-01-10T04:00:00.000Z', - toDate: '2021-01-10T08:00:00.000Z', - }, - searchSessionId: 'sessionId-1', - }, - type: 'app/setState', - }); - expect(next).toHaveBeenCalledWith(action); - }); - it('does not update the searchSessionId when the state changes and too little time has passed', () => { - const data = makeDefaultData(); - // time range is 100,000ms ago to 300ms ago (that's a lag of .3 percent, not enough to trigger a session update) - (data.nowProvider.get as jest.Mock).mockReturnValue(new Date(Date.now() - 300)); - (data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({ - from: 'now-2m', - to: 'now', - }); - (data.query.timefilter.timefilter.getBounds as jest.Mock).mockReturnValue({ - min: moment(Date.now() - 100000), - max: moment(Date.now() - 300), - }); - const { next, invoke, store } = createMiddleware(data); - const action = { - type: 'app/setState', - payload: { lastKnownDoc: ('new' as unknown) as Document }, - }; - invoke(action); - expect(store.dispatch).not.toHaveBeenCalled(); - expect(next).toHaveBeenCalledWith(action); - }); - }); -}); diff --git a/x-pack/plugins/lens/public/state_management/time_range_middleware.ts b/x-pack/plugins/lens/public/state_management/time_range_middleware.ts deleted file mode 100644 index a6c868be6056507..000000000000000 --- a/x-pack/plugins/lens/public/state_management/time_range_middleware.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { isEqual } from 'lodash'; -import { Dispatch, MiddlewareAPI, PayloadAction } from '@reduxjs/toolkit'; -import moment from 'moment'; - -import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; -import { setState, LensDispatch } from '.'; -import { LensAppState } from './types'; -import { getResolvedDateRange, containsDynamicMath, TIME_LAG_PERCENTAGE_LIMIT } from '../utils'; - -export const timeRangeMiddleware = (data: DataPublicPluginStart) => (store: MiddlewareAPI) => { - return (next: Dispatch) => (action: PayloadAction>) => { - // if document was modified or sessionId check if too much time passed to update searchSessionId - if ( - action.payload?.lastKnownDoc && - !isEqual(action.payload?.lastKnownDoc, store.getState().app.lastKnownDoc) - ) { - updateTimeRange(data, store.dispatch); - } - next(action); - }; -}; -function updateTimeRange(data: DataPublicPluginStart, dispatch: LensDispatch) { - const timefilter = data.query.timefilter.timefilter; - const unresolvedTimeRange = timefilter.getTime(); - if ( - !containsDynamicMath(unresolvedTimeRange.from) && - !containsDynamicMath(unresolvedTimeRange.to) - ) { - return; - } - - const { min, max } = timefilter.getBounds(); - - if (!min || !max) { - // bounds not fully specified, bailing out - return; - } - - // calculate length of currently configured range in ms - const timeRangeLength = moment.duration(max.diff(min)).asMilliseconds(); - - // calculate lag of managed "now" for date math - const nowDiff = Date.now() - data.nowProvider.get().valueOf(); - - // if the lag is signifcant, start a new session to clear the cache - if (nowDiff > timeRangeLength * TIME_LAG_PERCENTAGE_LIMIT) { - dispatch( - setState({ - searchSessionId: data.search.session.start(), - resolvedDateRange: getResolvedDateRange(timefilter), - }) - ); - } -} diff --git a/x-pack/plugins/lens/public/state_management/types.ts b/x-pack/plugins/lens/public/state_management/types.ts deleted file mode 100644 index 87045d15cc9946d..000000000000000 --- a/x-pack/plugins/lens/public/state_management/types.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Filter, IndexPattern, Query, SavedQuery } from '../../../../../src/plugins/data/public'; -import { Document } from '../persistence'; - -import { TableInspectorAdapter } from '../editor_frame_service/types'; -import { DateRange } from '../../common'; - -export interface LensAppState { - persistedDoc?: Document; - lastKnownDoc?: Document; - - // index patterns used to determine which filters are available in the top nav. - indexPatternsForTopNav: IndexPattern[]; - // Determines whether the lens editor shows the 'save and return' button, and the originating app breadcrumb. - isLinkedToOriginatingApp?: boolean; - isSaveable: boolean; - activeData?: TableInspectorAdapter; - - isAppLoading: boolean; - query: Query; - filters: Filter[]; - savedQuery?: SavedQuery; - searchSessionId: string; - resolvedDateRange: DateRange; -} - -export type DispatchSetState = ( - state: Partial -) => { - payload: Partial; - type: string; -}; - -export interface LensState { - app: LensAppState; -} diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 984fbf5555949b1..9cde4eb8a15616d 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -9,7 +9,6 @@ import { IconType } from '@elastic/eui/src/components/icon/icon'; import { CoreSetup } from 'kibana/public'; import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; import { SavedObjectReference } from 'kibana/public'; -import { MutableRefObject } from 'react'; import { RowClickContext } from '../../../../src/plugins/ui_actions/public'; import { ExpressionAstExpression, @@ -19,8 +18,9 @@ import { SerializedFieldFormat, } from '../../../../src/plugins/expressions/public'; import { DraggingIdentifier, DragDropIdentifier, DragContextState } from './drag_drop'; +import { Document } from './persistence'; import { DateRange } from '../common'; -import { Query, Filter, IFieldFormat } from '../../../../src/plugins/data/public'; +import { Query, Filter, SavedQuery, IFieldFormat } from '../../../../src/plugins/data/public'; import { VisualizeFieldContext } from '../../../../src/plugins/ui_actions/public'; import { RangeSelectContext, ValueClickContext } from '../../../../src/plugins/embeddable/public'; import { @@ -46,7 +46,22 @@ export interface PublicAPIProps { export interface EditorFrameProps { onError: ErrorCallback; + doc?: Document; + dateRange: DateRange; + query: Query; + filters: Filter[]; + savedQuery?: SavedQuery; + searchSessionId: string; initialContext?: VisualizeFieldContext; + + // Frame loader (app or embeddable) is expected to call this when it loads and updates + // This should be replaced with a top-down state + onChange: (newState: { + filterableIndexPatterns: string[]; + doc: Document; + isSaveable: boolean; + activeData?: Record; + }) => void; showNoDataPopover: () => void; } export interface EditorFrameInstance { @@ -392,14 +407,13 @@ export type VisualizationDimensionEditorProps = VisualizationConfig groupId: string; accessor: string; setState: (newState: T) => void; - panelRef: MutableRefObject; }; export interface AccessorConfig { columnId: string; triggerIcon?: 'color' | 'disabled' | 'colorBy' | 'none' | 'invisible'; color?: string; - palette?: string[] | Array<{ color: string; stop: number }>; + palette?: string[]; } export type VisualizationDimensionGroupConfig = SharedDimensionProps & { diff --git a/x-pack/plugins/lens/public/utils.ts b/x-pack/plugins/lens/public/utils.ts index c1aab4c18f5297c..2d8cfee2185fa27 100644 --- a/x-pack/plugins/lens/public/utils.ts +++ b/x-pack/plugins/lens/public/utils.ts @@ -6,7 +6,6 @@ */ import { i18n } from '@kbn/i18n'; -import { IndexPattern, IndexPatternsContract, TimefilterContract } from 'src/plugins/data/public'; import { LensFilterEvent } from './types'; /** replaces the value `(empty) to empty string for proper filtering` */ @@ -50,32 +49,3 @@ export function getVisualizeGeoFieldMessage(fieldType: string) { values: { fieldType }, }); } - -export const getResolvedDateRange = function (timefilter: TimefilterContract) { - const { from, to } = timefilter.getTime(); - const { min, max } = timefilter.calculateBounds({ - from, - to, - }); - return { fromDate: min?.toISOString() || from, toDate: max?.toISOString() || to }; -}; - -export function containsDynamicMath(dateMathString: string) { - return dateMathString.includes('now'); -} -export const TIME_LAG_PERCENTAGE_LIMIT = 0.02; - -export async function getAllIndexPatterns( - ids: string[], - indexPatternsService: IndexPatternsContract -): Promise<{ indexPatterns: IndexPattern[]; rejectedIds: string[] }> { - const responses = await Promise.allSettled(ids.map((id) => indexPatternsService.get(id))); - const fullfilled = responses.filter( - (response): response is PromiseFulfilledResult => response.status === 'fulfilled' - ); - const rejectedIds = responses - .map((_response, i) => ids[i]) - .filter((id, i) => responses[i].status === 'rejected'); - // return also the rejected ids in case we want to show something later on - return { indexPatterns: fullfilled.map((response) => response.value), rejectedIds }; -} diff --git a/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts b/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts index ef0c350f2096195..d2e87ece5b5ec89 100644 --- a/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts +++ b/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts @@ -118,7 +118,7 @@ export function getAccessorColorConfig( ); const customColor = currentYConfig?.color || - paletteService.get(currentPalette.name).getCategoricalColor( + paletteService.get(currentPalette.name).getColor( [ { name: columnToLabel[accessor] || accessor, diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 608971d281981f2..e3b4565913ad87c 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -798,7 +798,7 @@ export function XYChart({ ), }, ]; - return paletteService.get(palette.name).getCategoricalColor( + return paletteService.get(palette.name).getColor( seriesLayers, { maxDepth: 1, diff --git a/x-pack/plugins/lens/public/shared_components/tooltip_wrapper.tsx b/x-pack/plugins/lens/public/xy_visualization/tooltip_wrapper.tsx similarity index 100% rename from x-pack/plugins/lens/public/shared_components/tooltip_wrapper.tsx rename to x-pack/plugins/lens/public/xy_visualization/tooltip_wrapper.tsx diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx index 843680e3f28ac63..b07feb85892e53e 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx @@ -7,13 +7,14 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { ToolbarPopover, TooltipWrapper } from '../../shared_components'; +import { ToolbarPopover } from '../../shared_components'; import { MissingValuesOptions } from './missing_values_option'; import { LineCurveOption } from './line_curve_option'; import { FillOpacityOption } from './fill_opacity_option'; import { XYState } from '../types'; import { hasHistogramSeries } from '../state_helpers'; import { ValidLayer } from '../types'; +import { TooltipWrapper } from '../tooltip_wrapper'; import { FramePublicAPI } from '../../types'; function getValueLabelDisableReason({ diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts index 8fbc8e8b2ef7abe..aa4b91b840db37f 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts @@ -481,12 +481,12 @@ describe('xy_visualization', () => { it('should query palette to fill in colors for other dimensions', () => { const palette = paletteServiceMock.get('default'); - (palette.getCategoricalColor as jest.Mock).mockClear(); + (palette.getColor as jest.Mock).mockClear(); const accessorConfig = callConfigAndFindYConfig({}, 'c'); expect(accessorConfig.triggerIcon).toEqual('color'); // black is the color returned from the palette mock expect(accessorConfig.color).toEqual('black'); - expect(palette.getCategoricalColor).toHaveBeenCalledWith( + expect(palette.getColor).toHaveBeenCalledWith( [ { name: 'c', @@ -505,9 +505,9 @@ describe('xy_visualization', () => { label: 'Overwritten label', }); const palette = paletteServiceMock.get('default'); - (palette.getCategoricalColor as jest.Mock).mockClear(); + (palette.getColor as jest.Mock).mockClear(); callConfigAndFindYConfig({}, 'c'); - expect(palette.getCategoricalColor).toHaveBeenCalledWith( + expect(palette.getColor).toHaveBeenCalledWith( [ expect.objectContaining({ name: 'Overwritten label', @@ -526,7 +526,7 @@ describe('xy_visualization', () => { }, 'c' ); - expect(palette.getCategoricalColor).toHaveBeenCalled(); + expect(palette.getColor).toHaveBeenCalled(); }); it('should not show any indicator as long as there is no data', () => { @@ -551,7 +551,7 @@ describe('xy_visualization', () => { it('should show current palette for break down by dimension', () => { const palette = paletteServiceMock.get('mock'); const customColors = ['yellow', 'green']; - (palette.getCategoricalColors as jest.Mock).mockReturnValue(customColors); + (palette.getColors as jest.Mock).mockReturnValue(customColors); const breakdownConfig = callConfigForBreakdownConfigs({ palette: { type: 'palette', name: 'mock', params: {} }, splitAccessor: 'd', @@ -570,9 +570,9 @@ describe('xy_visualization', () => { paletteGetter.mockReturnValue({ id: 'default', title: '', - getCategoricalColors: jest.fn(), + getColors: jest.fn(), toExpression: jest.fn(), - getCategoricalColor: jest.fn().mockReturnValueOnce('blue').mockReturnValueOnce('green'), + getColor: jest.fn().mockReturnValueOnce('blue').mockReturnValueOnce('green'), }); const yConfigs = callConfigForYConfigs({}); diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx index fa9d46be11d6862..dda1a444f454488 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { uniq } from 'lodash'; +import _ from 'lodash'; import { render } from 'react-dom'; import { Position } from '@elastic/charts'; import { I18nProvider } from '@kbn/i18n/react'; @@ -43,7 +43,7 @@ function getVisualizationType(state: State): VisualizationType | 'mixed' { ); } const visualizationType = visualizationTypes.find((t) => t.id === state.layers[0].seriesType); - const seriesTypes = uniq(state.layers.map((l) => l.seriesType)); + const seriesTypes = _.uniq(state.layers.map((l) => l.seriesType)); return visualizationType && seriesTypes.length === 1 ? visualizationType : 'mixed'; } @@ -111,7 +111,7 @@ export const getXyVisualization = ({ }, appendLayer(state, layerId) { - const usedSeriesTypes = uniq(state.layers.map((layer) => layer.seriesType)); + const usedSeriesTypes = _.uniq(state.layers.map((layer) => layer.seriesType)); return { ...state, layers: [ @@ -235,7 +235,7 @@ export const getXyVisualization = ({ triggerIcon: 'colorBy', palette: paletteService .get(layer.palette?.name || 'default') - .getCategoricalColors(10, layer.palette?.params), + .getColors(10, layer.palette?.params), }, ] : [], @@ -255,11 +255,10 @@ export const getXyVisualization = ({ }, setDimension({ prevState, layerId, columnId, groupId }) { - const foundLayer = prevState.layers.find((l) => l.layerId === layerId); - if (!foundLayer) { + const newLayer = prevState.layers.find((l) => l.layerId === layerId); + if (!newLayer) { return prevState; } - const newLayer = { ...foundLayer }; if (groupId === 'x') { newLayer.xAccessor = columnId; @@ -278,11 +277,11 @@ export const getXyVisualization = ({ }, removeDimension({ prevState, layerId, columnId }) { - const foundLayer = prevState.layers.find((l) => l.layerId === layerId); - if (!foundLayer) { + const newLayer = prevState.layers.find((l) => l.layerId === layerId); + if (!newLayer) { return prevState; } - const newLayer = { ...foundLayer }; + if (newLayer.xAccessor === columnId) { delete newLayer.xAccessor; } else if (newLayer.splitAccessor === columnId) { diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx index bc10236cf1977e8..0bafbead7d54389 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx @@ -260,7 +260,6 @@ describe('XY Config panels', () => { state={{ ...state, layers: [{ ...state.layers[0], seriesType: 'bar_horizontal' }] }} formatFactory={jest.fn()} paletteService={chartPluginMock.createPaletteRegistry()} - panelRef={React.createRef()} /> ); @@ -284,7 +283,6 @@ describe('XY Config panels', () => { state={state} formatFactory={jest.fn()} paletteService={chartPluginMock.createPaletteRegistry()} - panelRef={React.createRef()} /> ); @@ -328,7 +326,6 @@ describe('XY Config panels', () => { }} formatFactory={jest.fn()} paletteService={chartPluginMock.createPaletteRegistry()} - panelRef={React.createRef()} /> ); @@ -368,7 +365,6 @@ describe('XY Config panels', () => { }} formatFactory={jest.fn()} paletteService={chartPluginMock.createPaletteRegistry()} - panelRef={React.createRef()} /> ); diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx index 48f0cacf75938a3..a6517894654edec 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx @@ -41,8 +41,9 @@ import { isHorizontalChart, isHorizontalSeries, getSeriesColor } from './state_h import { trackUiEvent } from '../lens_ui_telemetry'; import { LegendSettingsPopover } from '../shared_components'; import { AxisSettingsPopover } from './axis_settings_popover'; +import { TooltipWrapper } from './tooltip_wrapper'; import { getAxesConfiguration, GroupsConfiguration } from './axes_configuration'; -import { PalettePicker, TooltipWrapper } from '../shared_components'; +import { PalettePicker } from '../shared_components'; import { getAccessorColorConfig, getColorAssignments } from './color_assignment'; import { getScaleType, getSortedAccessors } from './to_expression'; import { VisualOptionsPopover } from './visual_options_popover/visual_options_popover'; diff --git a/x-pack/plugins/lists/server/routes/index.ts b/x-pack/plugins/lists/server/routes/index.ts index f8d4deea344b2f4..aa6749d179971fc 100644 --- a/x-pack/plugins/lists/server/routes/index.ts +++ b/x-pack/plugins/lists/server/routes/index.ts @@ -36,7 +36,6 @@ export * from './read_list_index_route'; export * from './read_list_item_route'; export * from './read_list_route'; export * from './read_privileges_route'; -export * from './summary_exception_list_route'; export * from './update_endpoint_list_item_route'; export * from './update_exception_list_item_route'; export * from './update_exception_list_route'; diff --git a/x-pack/plugins/lists/server/routes/init_routes.ts b/x-pack/plugins/lists/server/routes/init_routes.ts index 2511596ca846305..430dad953a32fe6 100644 --- a/x-pack/plugins/lists/server/routes/init_routes.ts +++ b/x-pack/plugins/lists/server/routes/init_routes.ts @@ -39,7 +39,6 @@ import { readListItemRoute, readListRoute, readPrivilegesRoute, - summaryExceptionListRoute, updateEndpointListItemRoute, updateExceptionListItemRoute, updateExceptionListRoute, @@ -96,7 +95,4 @@ export const initRoutes = (router: ListsPluginRouter, config: ConfigType): void updateEndpointListItemRoute(router); deleteEndpointListItemRoute(router); findEndpointListItemRoute(router); - - // exception list items summary - summaryExceptionListRoute(router); }; diff --git a/x-pack/plugins/lists/server/routes/summary_exception_list_route.ts b/x-pack/plugins/lists/server/routes/summary_exception_list_route.ts deleted file mode 100644 index 0db189fb70759bc..000000000000000 --- a/x-pack/plugins/lists/server/routes/summary_exception_list_route.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { validate } from '@kbn/securitysolution-io-ts-utils'; -import { transformError } from '@kbn/securitysolution-es-utils'; -import { - SummaryExceptionListSchemaDecoded, - exceptionListSummarySchema, - summaryExceptionListSchema, -} from '@kbn/securitysolution-io-ts-list-types'; -import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; - -import type { ListsPluginRouter } from '../types'; - -import { - buildRouteValidation, - buildSiemResponse, - getErrorMessageExceptionList, - getExceptionListClient, -} from './utils'; - -export const summaryExceptionListRoute = (router: ListsPluginRouter): void => { - router.get( - { - options: { - tags: ['access:lists-summary'], - }, - path: `${EXCEPTION_LIST_URL}/summary`, - validate: { - query: buildRouteValidation< - typeof summaryExceptionListSchema, - SummaryExceptionListSchemaDecoded - >(summaryExceptionListSchema), - }, - }, - async (context, request, response) => { - const siemResponse = buildSiemResponse(response); - try { - const { id, list_id: listId, namespace_type: namespaceType } = request.query; - const exceptionLists = getExceptionListClient(context); - if (id != null || listId != null) { - const exceptionListSummary = await exceptionLists.getExceptionListSummary({ - id, - listId, - namespaceType, - }); - if (exceptionListSummary == null) { - return siemResponse.error({ - body: getErrorMessageExceptionList({ id, listId }), - statusCode: 404, - }); - } else { - const [validated, errors] = validate(exceptionListSummary, exceptionListSummarySchema); - if (errors != null) { - return response.ok({ body: exceptionListSummary }); - } else { - return response.ok({ body: validated ?? {} }); - } - } - } else { - return siemResponse.error({ body: 'id or list_id required', statusCode: 400 }); - } - } catch (err) { - const error = transformError(err); - return siemResponse.error({ - body: error.message, - statusCode: error.statusCode, - }); - } - } - ); -}; diff --git a/x-pack/plugins/lists/server/scripts/summary_exception_list.sh b/x-pack/plugins/lists/server/scripts/summary_exception_list.sh deleted file mode 100755 index 54daeee7cb38762..000000000000000 --- a/x-pack/plugins/lists/server/scripts/summary_exception_list.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -# -# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -# or more contributor license agreements. Licensed under the Elastic License -# 2.0; you may not use this file except in compliance with the Elastic License -# 2.0. -# - -set -e -./check_env_variables.sh - - -LIST_ID=${1:-endpoint_list} -NAMESPACE_TYPE=${2-agnostic} - -# First, post a exception list and two list items for the example to work -# ./post_exception_list.sh ./exception_lists/new/exception_list_agnostic.json -# ./post_exception_list_item.sh ./exception_lists/new/exception_list_item_agnostic.json - -# Retrieve exception list stats by os -# Example: ./summary_exception_list.sh endpoint_list agnostic -curl -s -k \ - -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X GET "${KIBANA_URL}${SPACE_URL}/api/exception_lists/summary?list_id=${LIST_ID}&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts index 4ccff2dd000b9bf..803cd04c1d1b442 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts @@ -9,7 +9,6 @@ import { SavedObjectsClientContract } from 'kibana/server'; import type { ExceptionListItemSchema, ExceptionListSchema, - ExceptionListSummarySchema, FoundExceptionListItemSchema, FoundExceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; @@ -32,13 +31,11 @@ import { GetEndpointListItemOptions, GetExceptionListItemOptions, GetExceptionListOptions, - GetExceptionListSummaryOptions, UpdateEndpointListItemOptions, UpdateExceptionListItemOptions, UpdateExceptionListOptions, } from './exception_list_client_types'; import { getExceptionList } from './get_exception_list'; -import { getExceptionListSummary } from './get_exception_list_summary'; import { createExceptionList } from './create_exception_list'; import { getExceptionListItem } from './get_exception_list_item'; import { createExceptionListItem } from './create_exception_list_item'; @@ -75,15 +72,6 @@ export class ExceptionListClient { return getExceptionList({ id, listId, namespaceType, savedObjectsClient }); }; - public getExceptionListSummary = async ({ - listId, - id, - namespaceType, - }: GetExceptionListSummaryOptions): Promise => { - const { savedObjectsClient } = this; - return getExceptionListSummary({ id, listId, namespaceType, savedObjectsClient }); - }; - public getExceptionListItem = async ({ itemId, id, diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts index b734d3a7b1a3b9f..cbbf7f151344441 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts @@ -56,12 +56,6 @@ export interface GetExceptionListOptions { namespaceType: NamespaceType; } -export interface GetExceptionListSummaryOptions { - listId: ListIdOrUndefined; - id: IdOrUndefined; - namespaceType: NamespaceType; -} - export interface CreateExceptionListOptions { listId: ListId; namespaceType: NamespaceType; diff --git a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts b/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts deleted file mode 100644 index f5722ea26ccf7d5..000000000000000 --- a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { - ExceptionListSummarySchema, - IdOrUndefined, - ListIdOrUndefined, - NamespaceType, -} from '@kbn/securitysolution-io-ts-list-types'; -import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; - -import { - SavedObjectsClientContract, - SavedObjectsErrorHelpers, -} from '../../../../../../src/core/server/'; -import { ExceptionListSoSchema } from '../../schemas/saved_objects'; - -interface GetExceptionListSummaryOptions { - id: IdOrUndefined; - listId: ListIdOrUndefined; - savedObjectsClient: SavedObjectsClientContract; - namespaceType: NamespaceType; -} - -interface ByOsAggBucketType { - key: string; - doc_count: number; -} -interface ByOsAggType { - by_os: { - buckets: ByOsAggBucketType[]; - }; -} - -export const getExceptionListSummary = async ({ - id, - listId, - savedObjectsClient, - namespaceType, -}: GetExceptionListSummaryOptions): Promise => { - const savedObjectType = getSavedObjectType({ namespaceType }); - let finalListId: string = listId ?? ''; - - // If id and no listId, get the list by id to use the list_id for the find below - if (listId === null && id != null) { - try { - const savedObject = await savedObjectsClient.get(savedObjectType, id); - finalListId = savedObject.attributes.list_id; - } catch (err) { - if (SavedObjectsErrorHelpers.isNotFoundError(err)) { - return null; - } else { - throw err; - } - } - } - - const savedObject = await savedObjectsClient.find({ - aggs: { - by_os: { - terms: { - field: `${savedObjectType}.attributes.os_types`, - }, - }, - }, - filter: `${savedObjectType}.attributes.list_type: item`, - perPage: 0, - search: finalListId, - searchFields: ['list_id'], - sortField: 'tie_breaker_id', - sortOrder: 'desc', - type: savedObjectType, - }); - - if (!savedObject.aggregations) { - return null; - } - - const summary: ExceptionListSummarySchema = savedObject.aggregations.by_os.buckets.reduce( - (acc, item: ByOsAggBucketType) => ({ - ...acc, - [item.key]: item.doc_count, - total: acc.total + item.doc_count, - }), - { linux: 0, macos: 0, total: 0, windows: 0 } - ); - - return summary; -}; diff --git a/x-pack/plugins/lists/server/services/exception_lists/index.ts b/x-pack/plugins/lists/server/services/exception_lists/index.ts index e6a6dd7ef8c3c68..21041b9d5d9bd8c 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/index.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/index.ts @@ -15,6 +15,5 @@ export * from './find_exception_list_item'; export * from './find_exception_list_items'; export * from './get_exception_list'; export * from './get_exception_list_item'; -export * from './get_exception_list_summary'; export * from './update_exception_list'; export * from './update_exception_list_item'; diff --git a/x-pack/plugins/maps/public/kibana_services.ts b/x-pack/plugins/maps/public/kibana_services.ts index 4fce4c276c3360e..1652e78d3d2cbfc 100644 --- a/x-pack/plugins/maps/public/kibana_services.ts +++ b/x-pack/plugins/maps/public/kibana_services.ts @@ -112,7 +112,7 @@ export async function getChartsPaletteServiceGetColor(): Promise< const chartConfiguration = { syncColors: true }; return (value: string) => { const series = [{ name: value, rankAtDepth: 0, totalSeriesAtDepth: 1 }]; - const color = paletteDefinition.getCategoricalColor(series, chartConfiguration); + const color = paletteDefinition.getColor(series, chartConfiguration); return color ? color : '#3d3d3d'; }; } diff --git a/x-pack/plugins/ml/common/types/ml_url_generator.ts b/x-pack/plugins/ml/common/types/ml_url_generator.ts index 2b05f231e509ffd..c7c3f3ae9b2804d 100644 --- a/x-pack/plugins/ml/common/types/ml_url_generator.ts +++ b/x-pack/plugins/ml/common/types/ml_url_generator.ts @@ -112,10 +112,6 @@ export interface ExplorerAppState { viewByFieldName?: string; viewByPerPage?: number; viewByFromPage?: number; - /** - * Indicated severity threshold for both swim lanes - */ - severity?: number; }; mlExplorerFilter: { influencersFilterQuery?: InfluencersFilterQuery; diff --git a/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx b/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx index 719b5c4aa4ad585..12fbaece54fac15 100644 --- a/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx +++ b/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx @@ -13,7 +13,7 @@ import { JobSelectorControl } from './job_selector'; import { useMlKibana } from '../application/contexts/kibana'; import { jobsApiProvider } from '../application/services/ml_api_service/jobs'; import { HttpService } from '../application/services/http_service'; -import { SeverityControl } from '../application/components/severity_control'; +import { SeverityControl } from './severity_control'; import { ResultTypeSelector } from './result_type_selector'; import { alertingApiProvider } from '../application/services/ml_api_service/alerting'; import { PreviewAlertCondition } from './preview_alert_condition'; diff --git a/x-pack/plugins/ml/public/application/components/severity_control/index.ts b/x-pack/plugins/ml/public/alerting/severity_control/index.ts similarity index 100% rename from x-pack/plugins/ml/public/application/components/severity_control/index.ts rename to x-pack/plugins/ml/public/alerting/severity_control/index.ts diff --git a/x-pack/plugins/ml/public/alerting/severity_control/severity_control.tsx b/x-pack/plugins/ml/public/alerting/severity_control/severity_control.tsx new file mode 100644 index 000000000000000..b1cd808643ca2fb --- /dev/null +++ b/x-pack/plugins/ml/public/alerting/severity_control/severity_control.tsx @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiFormRow, EuiRange, EuiRangeProps } from '@elastic/eui'; +import { SEVERITY_OPTIONS } from '../../application/components/controls/select_severity/select_severity'; +import { ANOMALY_THRESHOLD } from '../../../common'; +import './styles.scss'; + +export interface SeveritySelectorProps { + value: number | undefined; + onChange: (value: number) => void; +} + +const MAX_ANOMALY_SCORE = 100; + +export const SeverityControl: FC = React.memo(({ value, onChange }) => { + const levels: EuiRangeProps['levels'] = [ + { + min: ANOMALY_THRESHOLD.LOW, + max: ANOMALY_THRESHOLD.MINOR - 1, + color: 'success', + }, + { + min: ANOMALY_THRESHOLD.MINOR, + max: ANOMALY_THRESHOLD.MAJOR - 1, + color: 'primary', + }, + { + min: ANOMALY_THRESHOLD.MAJOR, + max: ANOMALY_THRESHOLD.CRITICAL, + color: 'warning', + }, + { + min: ANOMALY_THRESHOLD.CRITICAL, + max: MAX_ANOMALY_SCORE, + color: 'danger', + }, + ]; + + const toggleButtons = SEVERITY_OPTIONS.map((v) => ({ + value: v.val, + label: v.display, + })); + + return ( + + } + > + { + // @ts-ignore Property 'value' does not exist on type 'EventTarget' | (EventTarget & HTMLInputElement) + onChange(Number(e.target.value)); + }} + showLabels + showValue + aria-label={i18n.translate('xpack.ml.severitySelector.formControlLabel', { + defaultMessage: 'Select severity threshold', + })} + showTicks + ticks={toggleButtons} + levels={levels} + data-test-subj={'mlAnomalyAlertScoreSelection'} + /> + + ); +}); diff --git a/x-pack/plugins/ml/public/application/components/severity_control/styles.scss b/x-pack/plugins/ml/public/alerting/severity_control/styles.scss similarity index 100% rename from x-pack/plugins/ml/public/application/components/severity_control/styles.scss rename to x-pack/plugins/ml/public/alerting/severity_control/styles.scss diff --git a/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts b/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts index 9fb41d15dd94a53..f8e9a3b44e7e839 100644 --- a/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts +++ b/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts @@ -25,7 +25,7 @@ export function checkGetManagementMlJobsResolver() { if (isManageML === true && isPlatinumOrTrialLicense === true) { return resolve({ mlFeatureEnabledInSpace }); } else { - return reject({ capabilities, isPlatinumOrTrialLicense, mlFeatureEnabledInSpace }); + return reject(); } }) .catch((e) => { diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js b/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js index 262daae9d6469c9..7339b50d4ab3403 100644 --- a/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js +++ b/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js @@ -232,7 +232,6 @@ class LinksMenuUI extends Component { } const categorizationFieldName = job.analysis_config.categorization_field_name; const datafeedIndices = job.datafeed_config.indices; - // Find the type of the categorization field i.e. text (preferred) or keyword. // Uses the first matching field found in the list of indices in the datafeed_config. // attempt to load the field type using each index. we have to do it this way as _field_caps @@ -350,7 +349,7 @@ class LinksMenuUI extends Component { getFieldTypeFromMapping(index, categorizationFieldName) .then((resp) => { if (resp !== '') { - createAndOpenUrl(datafeedIndices.join(), resp); + createAndOpenUrl(index, resp); } else { i++; if (i < datafeedIndices.length) { diff --git a/x-pack/plugins/ml/public/application/components/controls/select_interval/select_interval.tsx b/x-pack/plugins/ml/public/application/components/controls/select_interval/select_interval.tsx index f1ef62ddc90d498..348c400b6d5a9c6 100644 --- a/x-pack/plugins/ml/public/application/components/controls/select_interval/select_interval.tsx +++ b/x-pack/plugins/ml/public/application/components/controls/select_interval/select_interval.tsx @@ -6,7 +6,7 @@ */ import React, { FC } from 'react'; -import { EuiIcon, EuiSelect, EuiToolTip } from '@elastic/eui'; +import { EuiSelect } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { usePageUrlState } from '../../../util/url_state'; @@ -78,22 +78,8 @@ export const SelectIntervalUI: FC = ({ interval, onChange return ( - - - } - compressed - id="selectInterval" options={OPTIONS} + className="ml-select-interval" value={interval.val} onChange={handleOnChange} /> diff --git a/x-pack/plugins/ml/public/application/components/controls/select_severity/select_severity.tsx b/x-pack/plugins/ml/public/application/components/controls/select_severity/select_severity.tsx index 3fe50a8b46d550c..e8766ea16c00211 100644 --- a/x-pack/plugins/ml/public/application/components/controls/select_severity/select_severity.tsx +++ b/x-pack/plugins/ml/public/application/components/controls/select_severity/select_severity.tsx @@ -8,11 +8,11 @@ /* * React component for rendering a select element with threshold levels. */ -import React, { Fragment, FC, useMemo } from 'react'; +import React, { Fragment, FC } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiHealth, EuiSpacer, EuiSuperSelect, EuiText, EuiSuperSelectProps } from '@elastic/eui'; +import { EuiHealth, EuiSpacer, EuiSuperSelect, EuiText } from '@elastic/eui'; import { getSeverityColor } from '../../../../../common/util/anomaly_utils'; import { usePageUrlState } from '../../../util/url_state'; @@ -124,34 +124,23 @@ export const SelectSeverity: FC = ({ classNames } = { classNames: '' }) = return ; }; -export const SelectSeverityUI: FC< - Omit, 'onChange' | 'options'> & { - classNames?: string; - severity: TableSeverity; - onChange: (s: TableSeverity) => void; - } -> = ({ classNames = '', severity, onChange, compressed }) => { +export const SelectSeverityUI: FC<{ + classNames?: string; + severity: TableSeverity; + onChange: (s: TableSeverity) => void; +}> = ({ classNames = '', severity, onChange }) => { const handleOnChange = (valueDisplay: string) => { onChange(optionValueToThreshold(optionsMap[valueDisplay])); }; - const options = useMemo(() => { - return getSeverityOptions(); - }, []); - return ( ); }; diff --git a/x-pack/plugins/ml/public/application/components/severity_control/severity_control.tsx b/x-pack/plugins/ml/public/application/components/severity_control/severity_control.tsx deleted file mode 100644 index 7be72b843023347..000000000000000 --- a/x-pack/plugins/ml/public/application/components/severity_control/severity_control.tsx +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { FC } from 'react'; -import { i18n } from '@kbn/i18n'; -import { - EuiFieldNumber, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiRange, - EuiRangeProps, -} from '@elastic/eui'; -import { ANOMALY_THRESHOLD } from '../../../../common'; -import './styles.scss'; - -export interface SeveritySelectorProps { - value: number | undefined; - onChange: (value: number) => void; -} - -const MAX_ANOMALY_SCORE = 100; - -export const SeverityControl: FC = React.memo(({ value, onChange }) => { - const levels: EuiRangeProps['levels'] = [ - { - min: ANOMALY_THRESHOLD.LOW, - max: ANOMALY_THRESHOLD.MINOR - 1, - color: 'success', - }, - { - min: ANOMALY_THRESHOLD.MINOR, - max: ANOMALY_THRESHOLD.MAJOR - 1, - color: 'primary', - }, - { - min: ANOMALY_THRESHOLD.MAJOR, - max: ANOMALY_THRESHOLD.CRITICAL, - color: 'warning', - }, - { - min: ANOMALY_THRESHOLD.CRITICAL, - max: MAX_ANOMALY_SCORE, - color: 'danger', - }, - ]; - - const label = i18n.translate('xpack.ml.severitySelector.formControlLabel', { - defaultMessage: 'Severity', - }); - - const resultValue = value ?? ANOMALY_THRESHOLD.LOW; - - const onChangeCallback = ( - e: React.ChangeEvent | React.MouseEvent - ) => { - // @ts-ignore Property 'value' does not exist on type 'EventTarget' | (EventTarget & HTMLInputElement) - onChange(Number(e.target.value)); - }; - - const ticks = new Array(5).fill(null).map((x, i) => { - const v = i * 25; - return { value: v, label: v }; - }); - - return ( - - - - - - - - - - - ); -}); diff --git a/x-pack/plugins/ml/public/application/explorer/_explorer.scss b/x-pack/plugins/ml/public/application/explorer/_explorer.scss index d9d60ecfae67df2..c08020325428dd3 100644 --- a/x-pack/plugins/ml/public/application/explorer/_explorer.scss +++ b/x-pack/plugins/ml/public/application/explorer/_explorer.scss @@ -40,6 +40,14 @@ $borderRadius: $euiBorderRadius / 2; font-size: $euiFontSizeXS; } } + + .ml-anomalies-controls { + padding-top: $euiSizeXS; + + #show_charts_checkbox_control { + padding-top: $euiSizeL; + } + } } .mlSwimLaneContainer { diff --git a/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts b/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts index 621ce4420473093..a5d50f1070f5bad 100644 --- a/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts +++ b/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts @@ -83,7 +83,6 @@ export interface LoadExplorerDataConfig { viewByFromPage: number; viewByPerPage: number; swimlaneContainerWidth: number; - swimLaneSeverity: number; } export const isLoadExplorerDataConfig = (arg: any): arg is LoadExplorerDataConfig => { @@ -136,7 +135,6 @@ const loadExplorerDataProvider = ( swimlaneContainerWidth, viewByFromPage, viewByPerPage, - swimLaneSeverity, } = config; const combinedJobRecords: Record = selectedJobs.reduce((acc, job) => { @@ -194,13 +192,7 @@ const loadExplorerDataProvider = ( influencersFilterQuery ) : Promise.resolve({}), - overallState: memoizedLoadOverallData( - lastRefresh, - selectedJobs, - swimlaneContainerWidth, - undefined, - swimLaneSeverity - ), + overallState: memoizedLoadOverallData(lastRefresh, selectedJobs, swimlaneContainerWidth), tableData: memoizedLoadAnomaliesTableData( lastRefresh, selectedCells, @@ -286,9 +278,7 @@ const loadExplorerDataProvider = ( viewByPerPage, viewByFromPage, swimlaneContainerWidth, - influencersFilterQuery, - undefined, - swimLaneSeverity + influencersFilterQuery ), }).pipe( map(({ viewBySwimlaneState, filteredTopInfluencers }) => { diff --git a/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx b/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx index 8375b0a0b1dfc58..1e8f54d10491d94 100644 --- a/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx +++ b/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useCallback, useMemo, useState } from 'react'; +import React, { FC, useMemo, useState } from 'react'; import { isEqual } from 'lodash'; import { EuiPanel, @@ -14,6 +14,7 @@ import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, + EuiFormRow, EuiSelect, EuiTitle, EuiSpacer, @@ -34,9 +35,7 @@ import { ExplorerNoInfluencersFound } from './components/explorer_no_influencers import { SwimlaneContainer } from './swimlane_container'; import { AppStateSelectedCells, OverallSwimlaneData, ViewBySwimLaneData } from './explorer_utils'; import { NoOverallData } from './components/no_overall_data'; -import { SeverityControl } from '../components/severity_control'; import { AnomalyTimelineHelpPopover } from './anomaly_timeline_help_popover'; -import { isDefined } from '../../../common/types/guards'; function mapSwimlaneOptionsToEuiOptions(options: string[]) { return options.map((option) => ({ @@ -77,8 +76,10 @@ export const AnomalyTimeline: FC = React.memo( filterActive, filteredFields, maskAll, + overallSwimlaneData, selectedCells, viewByLoadedForTimeFormatted, + viewBySwimlaneData, viewBySwimlaneDataLoading, viewBySwimlaneFieldName, viewBySwimlaneOptions, @@ -88,9 +89,6 @@ export const AnomalyTimeline: FC = React.memo( swimlaneLimit, loading, overallAnnotations, - swimLaneSeverity, - overallSwimlaneData, - viewBySwimlaneData, } = explorerState; const annotations = useMemo(() => overallAnnotations.annotationsData, [overallAnnotations]); @@ -130,7 +128,7 @@ export const AnomalyTimeline: FC = React.memo( return ( <> - +

@@ -141,10 +139,68 @@ export const AnomalyTimeline: FC = React.memo(

- - - - + {viewBySwimlaneOptions.length > 0 && ( + <> + + + + + } + display={'columnCompressed'} + > + explorerService.setViewBySwimlaneFieldName(e.target.value)} + /> + + + {selectedCells ? ( + + + + + + ) : null} + +
+ {viewByLoadedForTimeFormatted && ( + + )} + {viewByLoadedForTimeFormatted === undefined && ( + + )} + {filterActive === true && viewBySwimlaneFieldName === VIEW_BY_JOB_LABEL && ( + + )} +
+
+ + )} {menuItems.length > 0 && ( @@ -170,79 +226,10 @@ export const AnomalyTimeline: FC = React.memo( )} -
- - - - - {viewBySwimlaneOptions.length > 0 && ( - <> - - explorerService.setViewBySwimlaneFieldName(e.target.value)} - /> - - - )} - - - { - explorerService.setSwimLaneSeverity(update); - }, [])} - /> - - - - - -
- {viewByLoadedForTimeFormatted && ( - - )} - {isDefined(viewByLoadedForTimeFormatted) ? null : ( - - )} - {filterActive === true && viewBySwimlaneFieldName === VIEW_BY_JOB_LABEL && ( - - )} -
+
- - {selectedCells ? ( - - - - - - ) : null}
@@ -262,7 +249,6 @@ export const AnomalyTimeline: FC = React.memo( noDataWarning={} showTimeline={false} annotationsData={annotations} - showLegend={false} /> @@ -280,7 +266,7 @@ export const AnomalyTimeline: FC = React.memo( }) } timeBuckets={timeBuckets} - showLegend={false} + showLegend={true} swimlaneData={viewBySwimlaneData as ViewBySwimLaneData} swimlaneType={SWIMLANE_TYPE.VIEW_BY} selection={selectedCells} diff --git a/x-pack/plugins/ml/public/application/explorer/explorer.js b/x-pack/plugins/ml/public/application/explorer/explorer.js index 4b241c47a267b0d..7cc1d0d86e2ff2d 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer.js @@ -19,7 +19,9 @@ import { EuiCallOut, EuiFlexGroup, EuiFlexItem, + EuiFormRow, EuiHorizontalRule, + EuiIcon, EuiIconTip, EuiPage, EuiPageBody, @@ -27,6 +29,7 @@ import { EuiPageHeaderSection, EuiSpacer, EuiTitle, + EuiToolTip, EuiLoadingContent, EuiPanel, EuiAccordion, @@ -75,7 +78,6 @@ import { ANOMALY_DETECTION_DEFAULT_TIME_RANGE } from '../../../common/constants/ import { withKibana } from '../../../../../../src/plugins/kibana_react/public'; import { ML_APP_URL_GENERATOR } from '../../../common/constants/ml_url_generator'; import { AnomalyContextMenu } from './anomaly_context_menu'; -import { isDefined } from '../../../common/types/guards'; const ExplorerPage = ({ children, @@ -261,7 +263,6 @@ export class ExplorerUI extends React.Component { selectedCells, selectedJobs, tableData, - swimLaneSeverity, } = this.props.explorerState; const { annotationsData, aggregations, error: annotationsError } = annotations; @@ -275,8 +276,6 @@ export class ExplorerUI extends React.Component { (hasResults && overallSwimlaneData.points.some((v) => v.value > 0)) || tableData.anomalies?.length > 0; - const hasActiveFilter = isDefined(swimLaneSeverity); - if (noJobsFound && !loading) { return ( @@ -285,7 +284,7 @@ export class ExplorerUI extends React.Component { ); } - if (!hasResultsWithAnomalies && !loading && !hasActiveFilter) { + if (hasResultsWithAnomalies === false && !loading) { return ( - - {annotationsError !== undefined && ( <> )} - {loading === false && tableData.anomalies?.length ? ( + {loading === false && tableData.anomalies?.length && ( - ) : null} + )} {annotationsData.length > 0 && ( <> @@ -479,16 +476,47 @@ export class ExplorerUI extends React.Component {
- - - + + + + + - - + + + + {i18n.translate('xpack.ml.explorer.intervalLabel', { + defaultMessage: 'Interval', + })} + + + + } + > + + {chartsData.seriesToPlot.length > 0 && selectedCells !== undefined && ( - - + + + + )} @@ -496,7 +524,7 @@ export class ExplorerUI extends React.Component {
- {showCharts ? ( + {showCharts && ( - ) : null} + )}
= ( }) => { return ( <> - - - + + + + + diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts b/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts index d737c4733b9cba1..4398a4b2c2be759 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts @@ -33,7 +33,6 @@ export const EXPLORER_ACTION = { SET_VIEW_BY_SWIMLANE_LOADING: 'setViewBySwimlaneLoading', SET_VIEW_BY_PER_PAGE: 'setViewByPerPage', SET_VIEW_BY_FROM_PAGE: 'setViewByFromPage', - SET_SWIM_LANE_SEVERITY: 'setSwimLaneSeverity', }; export const FILTER_ACTION = { diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts b/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts index 7721532b34338f3..343ba88655e4e08 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts @@ -79,10 +79,6 @@ const explorerAppState$: Observable = explorerState$.pipe( appState.mlExplorerSwimlane.viewByPerPage = state.viewByPerPage; } - if (state.swimLaneSeverity !== undefined) { - appState.mlExplorerSwimlane.severity = state.swimLaneSeverity; - } - if (state.filterActive) { appState.mlExplorerFilter.influencersFilterQuery = state.influencersFilterQuery; appState.mlExplorerFilter.filterActive = state.filterActive; @@ -165,9 +161,6 @@ export const explorerService = { setViewByPerPage: (payload: number) => { explorerAction$.next({ type: EXPLORER_ACTION.SET_VIEW_BY_PER_PAGE, payload }); }, - setSwimLaneSeverity: (payload: number) => { - explorerAction$.next({ type: EXPLORER_ACTION.SET_SWIM_LANE_SEVERITY, payload }); - }, }; export type ExplorerService = typeof explorerService; diff --git a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts index 74867af5f89879f..15e0caa29af39fa 100644 --- a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts +++ b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts @@ -149,15 +149,6 @@ export const explorerReducer = (state: ExplorerState, nextAction: Action): Explo }; break; - case EXPLORER_ACTION.SET_SWIM_LANE_SEVERITY: - nextState = { - ...state, - // reset current page on the page size change - viewByFromPage: 1, - swimLaneSeverity: payload, - }; - break; - default: nextState = state; } @@ -190,9 +181,7 @@ export const explorerReducer = (state: ExplorerState, nextAction: Action): Explo ...nextState, swimlaneBucketInterval, viewByLoadedForTimeFormatted: timeRange - ? `${formatHumanReadableDateTime(timeRange.earliestMs)} - ${formatHumanReadableDateTime( - timeRange.latestMs - )}` + ? formatHumanReadableDateTime(timeRange.earliestMs) : null, viewBySwimlaneFieldName, viewBySwimlaneOptions, diff --git a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts index 8a152ab1cadc318..2365e4e46890265 100644 --- a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts +++ b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts @@ -58,7 +58,6 @@ export interface ExplorerState { viewByFromPage: number; viewBySwimlaneOptions: string[]; swimlaneLimit?: number; - swimLaneSeverity?: number; } function getDefaultIndexPattern() { diff --git a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx index d959328218a1877..41bbe5b66a605fe 100644 --- a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx +++ b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx @@ -68,10 +68,6 @@ declare global { const RESIZE_THROTTLE_TIME_MS = 500; const CELL_HEIGHT = 30; const LEGEND_HEIGHT = 34; -/** - * Minimum container height to make sure "No data" message is displayed without overflow. - */ -const MIN_CONTAINER_HEIGHT = 40; const Y_AXIS_HEIGHT = 24; @@ -249,10 +245,7 @@ export const SwimlaneContainer: FC = ({ return isLoading ? containerHeightRef.current : // TODO update when elastic charts X label will be fixed - Math.max( - rowsCount * CELL_HEIGHT + (showLegend ? LEGEND_HEIGHT : 0) + (true ? Y_AXIS_HEIGHT : 0), - MIN_CONTAINER_HEIGHT - ); + rowsCount * CELL_HEIGHT + LEGEND_HEIGHT + (true ? Y_AXIS_HEIGHT : 0); }, [isLoading, rowsCount, showTimeline]); useEffect(() => { @@ -338,7 +331,7 @@ export const SwimlaneContainer: FC = ({ brushArea: { stroke: isDarkTheme ? 'rgb(255, 255, 255)' : 'rgb(105, 112, 125)', }, - ...(showLegend ? { maxLegendHeight: LEGEND_HEIGHT } : {}), + maxLegendHeight: LEGEND_HEIGHT, timeZone: 'UTC', }; }, [ @@ -470,7 +463,7 @@ export const SwimlaneContainer: FC = ({ )} {!isLoading && !showSwimlane && ( {noDataWarning}} /> diff --git a/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.js b/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.js index 9da97f40f5ec663..75bc93c8dc65eaa 100644 --- a/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.js +++ b/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.js @@ -15,7 +15,6 @@ import { DASHBOARD_APP_URL_GENERATOR } from '../../../../../../../../src/plugins import { getPartitioningFieldNames } from '../../../../../common/util/job_utils'; import { parseInterval } from '../../../../../common/util/parse_interval'; import { replaceTokensInUrlValue, isValidLabel } from '../../../util/custom_url_utils'; -import { getIndexPatternIdFromName } from '../../../util/index_utils'; import { ml } from '../../../services/ml_api_service'; import { mlJobService } from '../../../services/job_service'; import { escapeForElasticsearchQuery } from '../../../util/string_utils'; @@ -39,7 +38,7 @@ export function getNewCustomUrlDefaults(job, dashboards, indexPatterns) { } // For the Discover option, set the default index pattern to that - // which matches the indices configured in the job datafeed. + // which matches the (first) index configured in the job datafeed. const datafeedConfig = job.datafeed_config; if ( indexPatterns !== undefined && @@ -48,9 +47,16 @@ export function getNewCustomUrlDefaults(job, dashboards, indexPatterns) { datafeedConfig.indices !== undefined && datafeedConfig.indices.length > 0 ) { - const defaultIndexPatternId = - getIndexPatternIdFromName(datafeedConfig.indices.join()) ?? indexPatterns[0].id; - kibanaSettings.discoverIndexPatternId = defaultIndexPatternId; + const datafeedIndex = datafeedConfig.indices[0]; + let defaultIndexPattern = indexPatterns.find((indexPattern) => { + return indexPattern.title === datafeedIndex; + }); + + if (defaultIndexPattern === undefined) { + defaultIndexPattern = indexPatterns[0]; + } + + kibanaSettings.discoverIndexPatternId = defaultIndexPattern.id; } return { diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/access_denied_page.tsx b/x-pack/plugins/ml/public/application/management/jobs_list/components/access_denied_page.tsx index 0d785f1918b0b5f..18d8a42b76cb077 100644 --- a/x-pack/plugins/ml/public/application/management/jobs_list/components/access_denied_page.tsx +++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/access_denied_page.tsx @@ -31,8 +31,8 @@ export const AccessDeniedPage = () => (

@@ -42,7 +42,7 @@ export const AccessDeniedPage = () => ( = ({ basePath }) => ( - - - - - - -

- -

-
-
-
- - - - -

- - - - ), - }} - /> -

-
-
-
-
-
-
-); diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx index ca62ef9aaf0af13..2dc46bcf8fb41a9 100644 --- a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx +++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx @@ -38,7 +38,6 @@ import { getDocLinks } from '../../../../util/dependency_cache'; import { JobsListView } from '../../../../jobs/jobs_list/components/jobs_list_view/index'; import { DataFrameAnalyticsList } from '../../../../data_frame_analytics/pages/analytics_management/components/analytics_list'; import { AccessDeniedPage } from '../access_denied_page'; -import { InsufficientLicensePage } from '../insufficient_license_page'; import { SharePluginStart } from '../../../../../../../../../src/plugins/share/public'; import type { SpacesPluginStart } from '../../../../../../../spaces/public'; import { JobSpacesSyncFlyout } from '../../../../components/job_spaces_sync'; @@ -129,7 +128,6 @@ export const JobsListPage: FC<{ const spacesEnabled = spacesApi !== undefined; const [initialized, setInitialized] = useState(false); const [accessDenied, setAccessDenied] = useState(false); - const [isPlatinumOrTrialLicense, setIsPlatinumOrTrialLicense] = useState(true); const [showSyncFlyout, setShowSyncFlyout] = useState(false); const [isMlEnabledInSpace, setIsMlEnabledInSpace] = useState(false); const tabs = useTabs(isMlEnabledInSpace, spacesApi); @@ -141,11 +139,7 @@ export const JobsListPage: FC<{ const { mlFeatureEnabledInSpace } = await checkGetManagementMlJobsResolver(); setIsMlEnabledInSpace(mlFeatureEnabledInSpace); } catch (e) { - if (e.mlFeatureEnabledInSpace && e.isPlatinumOrTrialLicense === false) { - setIsPlatinumOrTrialLicense(false); - } else { - setAccessDenied(true); - } + setAccessDenied(true); } setInitialized(true); }; @@ -197,10 +191,6 @@ export const JobsListPage: FC<{ return ; } - if (isPlatinumOrTrialLicense === false) { - return ; - } - return ( diff --git a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx index a0a81f77b7b0870..3e5cf252230a267 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx @@ -177,7 +177,7 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim explorerService.setFilterData(filterData); } - const { viewByFieldName, viewByFromPage, viewByPerPage, severity } = + const { viewByFieldName, viewByFromPage, viewByPerPage } = explorerUrlState?.mlExplorerSwimlane ?? {}; if (viewByFieldName !== undefined) { @@ -191,10 +191,6 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim if (viewByFromPage !== undefined) { explorerService.setViewByFromPage(viewByFromPage); } - - if (severity !== undefined) { - explorerService.setSwimLaneSeverity(severity); - } }, []); /** Sync URL state with {@link explorerService} state */ @@ -242,7 +238,6 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim swimlaneContainerWidth: explorerState.swimlaneContainerWidth, viewByPerPage: explorerState.viewByPerPage, viewByFromPage: explorerState.viewByFromPage, - swimLaneSeverity: explorerState.swimLaneSeverity, } : undefined; diff --git a/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts b/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts index e11eb4048c374b2..54d9626edf26c0e 100644 --- a/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts +++ b/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts @@ -98,8 +98,7 @@ export class AnomalyTimelineService { public async loadOverallData( selectedJobs: ExplorerJob[], chartWidth?: number, - bucketInterval?: TimeBucketsInterval, - overallScore?: number + bucketInterval?: TimeBucketsInterval ): Promise { const interval = bucketInterval ?? this.getSwimlaneBucketInterval(selectedJobs, chartWidth!); @@ -128,8 +127,7 @@ export class AnomalyTimelineService { 1, overallBucketsBounds.min.valueOf(), overallBucketsBounds.max.valueOf(), - interval.asSeconds() + 's', - overallScore + interval.asSeconds() + 's' ); const overallSwimlaneData = this.processOverallResults( resp.results, @@ -163,8 +161,7 @@ export class AnomalyTimelineService { fromPage: number, swimlaneContainerWidth?: number, influencersFilterQuery?: any, - bucketInterval?: TimeBucketsInterval, - swimLaneSeverity?: number + bucketInterval?: TimeBucketsInterval ): Promise { const timefilterBounds = this.getTimeBounds(); @@ -198,8 +195,7 @@ export class AnomalyTimelineService { searchBounds.max.valueOf(), intervalMs, perPage, - fromPage, - swimLaneSeverity + fromPage ); } else { response = await this.mlResultsService.getInfluencerValueMaxScoreByTime( @@ -212,8 +208,7 @@ export class AnomalyTimelineService { swimlaneLimit, perPage, fromPage, - influencersFilterQuery, - swimLaneSeverity + influencersFilterQuery ); } diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts index f8ec4b648831605..bf6b752faa8da6f 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts @@ -323,22 +323,14 @@ export function mlApiServicesProvider(httpService: HttpService) { bucketSpan, start, end, - overallScore, }: { jobId: string; topN: string; bucketSpan: string; start: number; end: number; - overallScore?: number; }) { - const body = JSON.stringify({ - topN, - bucketSpan, - start, - end, - ...(overallScore ? { overall_score: overallScore } : {}), - }); + const body = JSON.stringify({ topN, bucketSpan, start, end }); return httpService.http({ path: `${basePath()}/anomaly_detectors/${jobId}/results/overall_buckets`, method: 'POST', diff --git a/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts b/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts index ea07d32bfff1d02..6161eeb4e794084 100644 --- a/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts +++ b/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts @@ -22,8 +22,7 @@ export function resultsServiceProvider( latestMs: number, intervalMs: number, perPage?: number, - fromPage?: number, - swimLaneSeverity?: number + fromPage?: number ): Promise; getTopInfluencers( selectedJobIds: string[], @@ -41,8 +40,7 @@ export function resultsServiceProvider( topN: any, earliestMs: any, latestMs: any, - interval?: any, - overallScore?: number + interval?: any ): Promise; getInfluencerValueMaxScoreByTime( jobIds: string[], @@ -54,8 +52,7 @@ export function resultsServiceProvider( maxResults: number, perPage: number, fromPage: number, - influencersFilterQuery: InfluencersFilterQuery, - swimLaneSeverity?: number + influencersFilterQuery: InfluencersFilterQuery ): Promise; getRecordInfluencers(): Promise; getRecordsForDetector(): Promise; diff --git a/x-pack/plugins/ml/public/application/services/results_service/results_service.js b/x-pack/plugins/ml/public/application/services/results_service/results_service.js index bb6f6b5969ac4d4..71be7bcd2b7eb75 100644 --- a/x-pack/plugins/ml/public/application/services/results_service/results_service.js +++ b/x-pack/plugins/ml/public/application/services/results_service/results_service.js @@ -30,15 +30,7 @@ export function resultsServiceProvider(mlApiServices) { // Pass an empty array or ['*'] to search over all job IDs. // Returned response contains a results property, with a key for job // which has results for the specified time range. - getScoresByBucket( - jobIds, - earliestMs, - latestMs, - intervalMs, - perPage = 10, - fromPage = 1, - swimLaneSeverity = 0 - ) { + getScoresByBucket(jobIds, earliestMs, latestMs, intervalMs, perPage = 10, fromPage = 1) { return new Promise((resolve, reject) => { const obj = { success: true, @@ -57,13 +49,6 @@ export function resultsServiceProvider(mlApiServices) { }, }, }, - { - range: { - anomaly_score: { - gt: swimLaneSeverity, - }, - }, - }, ]; if (jobIds && jobIds.length > 0 && !(jobIds.length === 1 && jobIds[0] === '*')) { @@ -478,7 +463,7 @@ export function resultsServiceProvider(mlApiServices) { // Obtains the overall bucket scores for the specified job ID(s). // Pass ['*'] to search over all job IDs. // Returned response contains a results property as an object of max score by time. - getOverallBucketScores(jobIds, topN, earliestMs, latestMs, interval, overallScore) { + getOverallBucketScores(jobIds, topN, earliestMs, latestMs, interval) { return new Promise((resolve, reject) => { const obj = { success: true, results: {} }; @@ -489,7 +474,6 @@ export function resultsServiceProvider(mlApiServices) { bucketSpan: interval, start: earliestMs, end: latestMs, - overallScore, }) .then((resp) => { const dataByTime = get(resp, ['overall_buckets'], []); @@ -523,8 +507,7 @@ export function resultsServiceProvider(mlApiServices) { maxResults = ANOMALY_SWIM_LANE_HARD_LIMIT, perPage = SWIM_LANE_DEFAULT_PAGE_SIZE, fromPage = 1, - influencersFilterQuery, - swimLaneSeverity + influencersFilterQuery ) { return new Promise((resolve, reject) => { const obj = { success: true, results: {} }; @@ -544,7 +527,7 @@ export function resultsServiceProvider(mlApiServices) { { range: { influencer_score: { - gt: swimLaneSeverity !== undefined ? swimLaneSeverity : 0, + gt: 0, }, }, }, diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss b/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss index cfd521c882fb71d..33f6c65e03e77f9 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss @@ -19,6 +19,10 @@ float: right; } + .ml-anomalies-controls { + padding-top: $euiSizeXS; + } + .ml-timeseries-chart { svg { font-size: $euiFontSizeXS; diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index c2b806abcf28607..c33b780631f1666 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -26,9 +26,11 @@ import { EuiFlexGroup, EuiFlexItem, EuiFormRow, + EuiIcon, EuiSpacer, EuiPanel, EuiTitle, + EuiToolTip, EuiAccordion, EuiBadge, } from '@elastic/eui'; @@ -1271,12 +1273,41 @@ export class TimeSeriesExplorer extends React.Component { /> - - - + + + + + - - + + + + {i18n.translate('xpack.ml.timeSeriesExplorer.intervalLabel', { + defaultMessage: 'Interval', + })} + + + + } + > + + diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index 1f41f0a1d25c300..c9fde252fc26dd7 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -53,7 +53,6 @@ import { } from '../../triggers_actions_ui/public'; import { FileDataVisualizerPluginStart } from '../../file_data_visualizer/public'; import { PluginSetupContract as AlertingSetup } from '../../alerting/public'; -import { registerManagementSection } from './application/management'; export interface MlStartDependencies { data: DataPublicPluginStart; @@ -134,10 +133,6 @@ export class MlPlugin implements Plugin { this.urlGenerator = registerUrlGenerator(pluginsSetup.share, core); } - if (pluginsSetup.management) { - registerManagementSection(pluginsSetup.management, core).enable(); - } - const licensing = pluginsSetup.licensing.license$.pipe(take(1)); licensing.subscribe(async (license) => { const [coreStart] = await core.getStartServices(); @@ -165,6 +160,7 @@ export class MlPlugin implements Plugin { // note including registerFeature in register_helper would cause the page bundle size to increase significantly const { registerEmbeddables, + registerManagementSection, registerMlUiActions, registerSearchLinks, registerMlAlerts, @@ -176,6 +172,11 @@ export class MlPlugin implements Plugin { registerSearchLinks(this.appUpdater$, fullLicense); if (fullLicense) { + const canManageMLJobs = + capabilities.management?.insightsAndAlerting?.jobsListLink ?? false; + if (canManageMLJobs && pluginsSetup.management !== undefined) { + registerManagementSection(pluginsSetup.management, core).enable(); + } registerEmbeddables(pluginsSetup.embeddable, core); registerMlUiActions(pluginsSetup.uiActions, core); diff --git a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts index 5205ea7353ac619..6adf6fa474cad05 100644 --- a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts +++ b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts @@ -522,7 +522,6 @@ export function jobRoutes({ router, routeGuard }: RouteInitialization) { bucket_span: request.body.bucketSpan, start: request.body.start !== undefined ? String(request.body.start) : undefined, end: request.body.end !== undefined ? String(request.body.end) : undefined, - overall_score: request.body.overall_score ?? 0, }, }); return response.ok({ diff --git a/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts b/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts index 392c0d3514d6482..4217002e61ef729 100644 --- a/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts +++ b/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts @@ -186,7 +186,6 @@ export const getOverallBucketsSchema = schema.object({ bucketSpan: schema.string(), start: schema.number(), end: schema.number(), - overall_score: schema.maybe(schema.number()), }); export const getCategoriesSchema = schema.object({ diff --git a/x-pack/plugins/observability/public/components/shared/header_menu_portal.test.tsx b/x-pack/plugins/observability/public/components/shared/header_menu_portal.test.tsx deleted file mode 100644 index 4e9a1ae2c587f04..000000000000000 --- a/x-pack/plugins/observability/public/components/shared/header_menu_portal.test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { render } from '@testing-library/react'; -import React from 'react'; -import HeaderMenuPortal from './header_menu_portal'; - -describe('HeaderMenuPortal', () => { - describe('when unmounted', () => { - it('calls setHeaderActionMenu with undefined', () => { - const setHeaderActionMenu = jest.fn(); - - const { unmount } = render( - test - ); - - unmount(); - - expect(setHeaderActionMenu).toHaveBeenCalledWith(undefined); - }); - }); -}); diff --git a/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx b/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx index 6c3b558c5e61dff..54949c1d860d837 100644 --- a/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx +++ b/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx @@ -15,14 +15,17 @@ export default function HeaderMenuPortal({ children, setHeaderActionMenu }: Head const portalNode = useMemo(() => createPortalNode(), []); useEffect(() => { + let unmount = () => {}; + setHeaderActionMenu((element) => { const mount = toMountPoint(); - return mount(element); + unmount = mount(element); + return unmount; }); return () => { portalNode.unmount(); - setHeaderActionMenu(undefined); + unmount(); }; }, [portalNode, setHeaderActionMenu]); diff --git a/x-pack/plugins/observability/public/components/shared/page_template/README.md b/x-pack/plugins/observability/public/components/shared/page_template/README.md index fb2a603cc7a7fac..e360e6d95a9d8a2 100644 --- a/x-pack/plugins/observability/public/components/shared/page_template/README.md +++ b/x-pack/plugins/observability/public/components/shared/page_template/README.md @@ -17,8 +17,6 @@ Now within your solution's **public** plugin `setup` lifecycle method you can ca ```typescript // x-pack/plugins/example_plugin/public/plugin.ts -import { of } from 'rxjs'; - export class Plugin implements PluginClass { constructor(_context: PluginInitializerContext) {} @@ -66,7 +64,7 @@ This can be accessed like so: ``` const [coreStart, pluginsStart] = await core.getStartServices(); -const ObservabilityPageTemplate = pluginsStart.observability.navigation.PageTemplate; +const pageTemplateComponent = pluginsStart.observability.navigation.PageTemplate; ``` Now that you have access to the component you can render your solution's content using it. @@ -103,4 +101,4 @@ The `` component is a wrapper around the ` '' } }, }, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), - ObservabilityPageTemplate: KibanaPageTemplate, } as unknown) as PluginContextValue } > diff --git a/x-pack/plugins/rule_registry/README.md b/x-pack/plugins/rule_registry/README.md index e12c2b29ed37380..cfbde612b45a6d9 100644 --- a/x-pack/plugins/rule_registry/README.md +++ b/x-pack/plugins/rule_registry/README.md @@ -145,6 +145,3 @@ The following fields are defined in the technical field component template and s - `kibana.rac.alert.severity.value`: the severity of the alert, as a numerical value, which allows sorting. - `kibana.rac.alert.evaluation.value`: The measured (numerical value). - `kibana.rac.alert.threshold.value`: The threshold that was defined (or, in case of multiple thresholds, the one that was exceeded). -- `kibana.rac.alert.ancestors`: the array of ancestors (if any) for the alert. -- `kibana.rac.alert.depth`: the depth of the alert in the ancestral tree (default 0). -- `kibana.rac.alert.building_block_type`: the building block type of the alert (default undefined). diff --git a/x-pack/plugins/rule_registry/server/index.ts b/x-pack/plugins/rule_registry/server/index.ts index 9eefc19f34670e7..9547f165cd70584 100644 --- a/x-pack/plugins/rule_registry/server/index.ts +++ b/x-pack/plugins/rule_registry/server/index.ts @@ -14,7 +14,6 @@ export { RuleDataClient } from './rule_data_client'; export { IRuleDataClient } from './rule_data_client/types'; export { getRuleExecutorData, RuleExecutorData } from './utils/get_rule_executor_data'; export { createLifecycleRuleTypeFactory } from './utils/create_lifecycle_rule_type_factory'; -export { createPersistenceRuleTypeFactory } from './utils/create_persistence_rule_type_factory'; export const plugin = (initContext: PluginInitializerContext) => new RuleRegistryPlugin(initContext); diff --git a/x-pack/plugins/rule_registry/server/rule_data_client/index.ts b/x-pack/plugins/rule_registry/server/rule_data_client/index.ts index 43122ba49519a41..135c870f207272b 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_client/index.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_client/index.ts @@ -73,8 +73,8 @@ export class RuleDataClient implements IRuleDataClient { return clusterClient.bulk(requestWithDefaultParameters).then((response) => { if (response.body.errors) { if ( - response.body.items.length > 0 && - response.body.items?.[0]?.index?.error?.type === 'index_not_found_exception' + response.body.items.length === 1 && + response.body.items[0]?.index?.error?.type === 'index_not_found_exception' ) { return this.createOrUpdateWriteTarget({ namespace }).then(() => { return clusterClient.bulk(requestWithDefaultParameters); diff --git a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_factory.ts b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_factory.ts deleted file mode 100644 index 0e244fbaa2ee35c..000000000000000 --- a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_factory.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { ESSearchRequest } from 'typings/elasticsearch'; -import v4 from 'uuid/v4'; -import { Logger } from '@kbn/logging'; - -import { AlertInstance } from '../../../alerting/server'; -import { - AlertInstanceContext, - AlertInstanceState, - AlertTypeParams, -} from '../../../alerting/common'; -import { RuleDataClient } from '../rule_data_client'; -import { AlertTypeWithExecutor } from '../types'; - -type PersistenceAlertService> = ( - alerts: Array> -) => Array>; - -type PersistenceAlertQueryService = ( - query: ESSearchRequest -) => Promise>>; - -type CreatePersistenceRuleTypeFactory = (options: { - ruleDataClient: RuleDataClient; - logger: Logger; -}) => < - TParams extends AlertTypeParams, - TAlertInstanceContext extends AlertInstanceContext, - TServices extends { - alertWithPersistence: PersistenceAlertService; - findAlerts: PersistenceAlertQueryService; - } ->( - type: AlertTypeWithExecutor -) => AlertTypeWithExecutor; - -export const createPersistenceRuleTypeFactory: CreatePersistenceRuleTypeFactory = ({ - logger, - ruleDataClient, -}) => (type) => { - return { - ...type, - executor: async (options) => { - const { - services: { alertInstanceFactory, scopedClusterClient }, - } = options; - - const currentAlerts: Array> = []; - const timestamp = options.startedAt.toISOString(); - - const state = await type.executor({ - ...options, - services: { - ...options.services, - alertWithPersistence: (alerts) => { - alerts.forEach((alert) => currentAlerts.push(alert)); - return alerts.map((alert) => - alertInstanceFactory(alert['kibana.rac.alert.uuid']! as string) - ); - }, - findAlerts: async (query) => { - const { body } = await scopedClusterClient.asCurrentUser.search({ - ...query, - body: { - ...query.body, - }, - ignore_unavailable: true, - }); - return body.hits.hits - .map((event: { _source: any }) => event._source!) - .map((event: { [x: string]: any }) => { - const alertUuid = event['kibana.rac.alert.uuid']; - const isAlert = alertUuid != null; - return { - ...event, - 'event.kind': 'signal', - 'kibana.rac.alert.id': '???', - 'kibana.rac.alert.status': 'open', - 'kibana.rac.alert.uuid': v4(), - 'kibana.rac.alert.ancestors': isAlert - ? ((event['kibana.rac.alert.ancestors'] as string[]) ?? []).concat([ - alertUuid!, - ] as string[]) - : [], - 'kibana.rac.alert.depth': isAlert - ? ((event['kibana.rac.alert.depth'] as number) ?? 0) + 1 - : 0, - '@timestamp': timestamp, - }; - }); - }, - }, - }); - - const numAlerts = currentAlerts.length; - logger.debug(`Found ${numAlerts} alerts.`); - - if (ruleDataClient && numAlerts) { - await ruleDataClient.getWriter().bulk({ - body: currentAlerts.flatMap((event) => [{ index: {} }, event]), - }); - } - - return state; - }, - }; -}; diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 91b48afdc4ed1e1..effefdd438c5cc3 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -25,7 +25,6 @@ export const DEFAULT_TIME_RANGE = 'timepicker:timeDefaults'; export const DEFAULT_REFRESH_RATE_INTERVAL = 'timepicker:refreshIntervalDefaults'; export const DEFAULT_APP_TIME_RANGE = 'securitySolution:timeDefaults'; export const DEFAULT_APP_REFRESH_INTERVAL = 'securitySolution:refreshIntervalDefaults'; -export const DEFAULT_ALERTS_INDEX = '.alerts-security-solution'; export const DEFAULT_SIGNALS_INDEX = '.siem-signals'; export const DEFAULT_LISTS_INDEX = '.lists'; export const DEFAULT_ITEMS_INDEX = '.items'; @@ -149,18 +148,6 @@ export const DEFAULT_TRANSFORMS_SETTING = JSON.stringify(defaultTransformsSettin */ export const SIGNALS_ID = `siem.signals`; -/** - * Id's for reference rule types - */ -export const REFERENCE_RULE_ALERT_TYPE_ID = `siem.referenceRule`; -export const REFERENCE_RULE_PERSISTENCE_ALERT_TYPE_ID = `siem.referenceRulePersistence`; - -export const CUSTOM_ALERT_TYPE_ID = `siem.customRule`; -export const EQL_ALERT_TYPE_ID = `siem.eqlRule`; -export const INDICATOR_ALERT_TYPE_ID = `siem.indicatorRule`; -export const ML_ALERT_TYPE_ID = `siem.mlRule`; -export const THRESHOLD_ALERT_TYPE_ID = `siem.thresholdRule`; - /** * Id for the notifications alerting type */ diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts index 35c976fbdfb1d15..c0888a6c2a4bd49 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts @@ -9,8 +9,6 @@ import seedrandom from 'seedrandom'; import uuid from 'uuid'; const OS_FAMILY = ['windows', 'macos', 'linux']; -/** Array of 14 day offsets */ -const DAY_OFFSETS = Array.from({ length: 14 }, (_, i) => 8.64e7 * (i + 1)); /** * A generic base class to assist in creating domain specific data generators. It includes @@ -18,7 +16,6 @@ const DAY_OFFSETS = Array.from({ length: 14 }, (_, i) => 8.64e7 * (i + 1)); * public method named `generate()` which should be implemented by sub-classes. */ export class BaseDataGenerator { - /** A javascript seeded random number (float between 0 and 1). Don't use `Math.random()` */ protected random: seedrandom.prng; constructor(seed: string | seedrandom.prng = Math.random().toString()) { @@ -36,23 +33,6 @@ export class BaseDataGenerator { throw new Error('method not implemented!'); } - /** Returns a future ISO date string */ - protected randomFutureDate(from?: Date): string { - const now = from ? from.getTime() : Date.now(); - return new Date(now + this.randomChoice(DAY_OFFSETS)).toISOString(); - } - - /** Returns a past ISO date string */ - protected randomPastDate(from?: Date): string { - const now = from ? from.getTime() : Date.now(); - return new Date(now - this.randomChoice(DAY_OFFSETS)).toISOString(); - } - - /** Generate either `true` or `false` */ - protected randomBoolean(): boolean { - return this.random() < 0.5; - } - /** generate random OS family value */ protected randomOSFamily(): string { return this.randomChoice(OS_FAMILY); diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts deleted file mode 100644 index af799de782f48cb..000000000000000 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DeepPartial } from 'utility-types'; -import { merge } from 'lodash'; -import { BaseDataGenerator } from './base_data_generator'; -import { EndpointAction, EndpointActionResponse, ISOLATION_ACTIONS } from '../types'; - -const ISOLATION_COMMANDS: ISOLATION_ACTIONS[] = ['isolate', 'unisolate']; - -export class FleetActionGenerator extends BaseDataGenerator { - /** Generate an Action */ - generate(overrides: DeepPartial = {}): EndpointAction { - const timeStamp = new Date(this.randomPastDate()); - - return merge( - { - action_id: this.randomUUID(), - '@timestamp': timeStamp.toISOString(), - expiration: this.randomFutureDate(timeStamp), - type: 'INPUT_ACTION', - input_type: 'endpoint', - agents: [this.randomUUID()], - user_id: 'elastic', - data: { - command: this.randomIsolateCommand(), - comment: this.randomString(15), - }, - }, - overrides - ); - } - - /** Generates an action response */ - generateResponse(overrides: DeepPartial = {}): EndpointActionResponse { - const timeStamp = new Date(); - - return merge( - { - action_data: { - command: this.randomIsolateCommand(), - comment: '', - }, - action_id: this.randomUUID(), - agent_id: this.randomUUID(), - started_at: this.randomPastDate(), - completed_at: timeStamp.toISOString(), - error: 'some error happen', - '@timestamp': timeStamp.toISOString(), - }, - overrides - ); - } - - protected randomIsolateCommand() { - return this.randomChoice(ISOLATION_COMMANDS); - } -} diff --git a/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts b/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts index 301a032fb47dfbc..e29a121668bd3b2 100644 --- a/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts +++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts @@ -87,9 +87,7 @@ describe('data generator', () => { expect(event2.event?.sequence).toBe((firstNonNullValue(event1.event?.sequence) ?? 0) + 1); }); - // Lets run this one multiple times just to ensure that the randomness - // is truly predicable based on the seed passed - it.each([1, 2, 3, 4, 5])('[%#] creates the same documents with same random seed', () => { + it('creates the same documents with same random seed', () => { const generator1 = new EndpointDocGenerator('seed'); const generator2 = new EndpointDocGenerator('seed'); const timestamp = new Date().getTime(); diff --git a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts index 436f1573639c833..fa7ee84441a9bcb 100644 --- a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts @@ -439,8 +439,6 @@ export class EndpointDocGenerator extends BaseDataGenerator { private createHostData(): HostInfo { const hostName = this.randomHostname(); - const isIsolated = this.randomBoolean(); - return { agent: { version: this.randomVersion(), @@ -467,10 +465,10 @@ export class EndpointDocGenerator extends BaseDataGenerator { applied: this.randomChoice(APPLIED_POLICIES), }, configuration: { - isolation: isIsolated, + isolation: false, }, state: { - isolation: isIsolated, + isolation: false, }, }, }; diff --git a/x-pack/plugins/security_solution/common/endpoint/index_data.ts b/x-pack/plugins/security_solution/common/endpoint/index_data.ts index 021b9bcb1ecccf6..0dc7891560c2d86 100644 --- a/x-pack/plugins/security_solution/common/endpoint/index_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/index_data.ts @@ -28,10 +28,8 @@ import { policyFactory as policyConfigFactory } from './models/policy_config'; import { HostMetadata } from './types'; import { KbnClientWithApiKeySupport } from '../../scripts/endpoint/kbn_client_with_api_key_support'; import { FleetAgentGenerator } from './data_generators/fleet_agent_generator'; -import { FleetActionGenerator } from './data_generators/fleet_action_generator'; const fleetAgentGenerator = new FleetAgentGenerator(); -const fleetActionGenerator = new FleetActionGenerator(); export async function indexHostsAndAlerts( client: Client, @@ -177,9 +175,6 @@ async function indexHostDocs({ }, }, }; - - // Create some actions for this Host - await indexFleetActionsForHost(client, hostMetadata); } await client.index({ @@ -402,43 +397,3 @@ const indexFleetAgentForHost = async ( return agentDoc; }; - -const indexFleetActionsForHost = async ( - esClient: Client, - endpointHost: HostMetadata -): Promise => { - const ES_INDEX_OPTIONS = { headers: { 'X-elastic-product-origin': 'fleet' } }; - const agentId = endpointHost.elastic.agent.id; - - for (let i = 0; i < 5; i++) { - // create an action - const isolateAction = fleetActionGenerator.generate({ - data: { comment: 'data generator: this host is bad' }, - }); - - isolateAction.agents = [agentId]; - - await esClient.index( - { - index: '.fleet-actions', - body: isolateAction, - }, - ES_INDEX_OPTIONS - ); - - // Create an action response for the above - const unIsolateAction = fleetActionGenerator.generateResponse({ - action_id: isolateAction.action_id, - agent_id: agentId, - action_data: isolateAction.data, - }); - - await esClient.index( - { - index: '.fleet-actions-results', - body: unIsolateAction, - }, - ES_INDEX_OPTIONS - ); - } -}; diff --git a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts index fcfda9c9a30d947..99dac5ea5cda67f 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts @@ -24,21 +24,6 @@ export interface EndpointAction { }; } -export interface EndpointActionResponse { - '@timestamp': string; - /** The id of the action for which this response is associated with */ - action_id: string; - /** The agent id that sent this action response */ - agent_id: string; - started_at: string; - completed_at: string; - error: string; - action_data: { - command: ISOLATION_ACTIONS; - comment?: string; - }; -} - export type HostIsolationRequestBody = TypeOf; export interface HostIsolationResponse { diff --git a/x-pack/plugins/security_solution/common/endpoint/types/index.ts b/x-pack/plugins/security_solution/common/endpoint/types/index.ts index c084dd8ca76680c..dd0ff540cb4af00 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts @@ -1095,13 +1095,3 @@ export interface GetAgentSummaryResponse { versions_count: { [key: string]: number }; }; } - -/** - * REST API response for retrieving exception summary - */ -export interface GetExceptionSummaryResponse { - total: number; - windows: number; - macos: number; - linux: number; -} diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 02006fdb29d475c..6195dd61a798419 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -15,7 +15,6 @@ const allowedExperimentalValues = Object.freeze({ trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, hostIsolationEnabled: false, - ruleRegistryEnabled: false, }); type ExperimentalConfigKeys = Array; diff --git a/x-pack/plugins/security_solution/kibana.json b/x-pack/plugins/security_solution/kibana.json index 02dbc56bd339768..50a5f62740271fa 100644 --- a/x-pack/plugins/security_solution/kibana.json +++ b/x-pack/plugins/security_solution/kibana.json @@ -8,7 +8,6 @@ "actions", "alerting", "cases", - "ruleRegistry", "data", "dataEnhanced", "embeddable", diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.test.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.test.tsx index e4a015525dfb442..3d29650b750dc91 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.test.tsx @@ -21,7 +21,7 @@ import type { CreateExceptionListItemSchema, UpdateExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { TestProviders } from '../../mock'; + import { useAddOrUpdateException, UseAddOrUpdateExceptionProps, @@ -134,16 +134,12 @@ describe('useAddOrUpdateException', () => { addOrUpdateItemsArgs = [ruleId, itemsToAddOrUpdate]; render = () => - renderHook( - () => - useAddOrUpdateException({ - http: mockKibanaHttpService, - onError, - onSuccess, - }), - { - wrapper: TestProviders, - } + renderHook(() => + useAddOrUpdateException({ + http: mockKibanaHttpService, + onError, + onSuccess, + }) ); }); diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.tsx index dbae0964b41a8c3..5ba73ba2c905884 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.tsx @@ -19,11 +19,9 @@ import { getUpdateAlertsQuery } from '../../../detections/components/alerts_tabl import { buildAlertStatusFilter, buildAlertsRuleIdFilter, - buildAlertStatusFilterRuleRegistry, } from '../../../detections/components/alerts_table/default_config'; import { getQueryFilter } from '../../../../common/detection_engine/get_query_filter'; import { Index } from '../../../../common/detection_engine/schemas/common/schemas'; -import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; import { formatExceptionItemForUpdate, prepareExceptionItemsForBulkClose } from './helpers'; import { useKibana } from '../../lib/kibana'; @@ -84,8 +82,6 @@ export const useAddOrUpdateException = ({ }, [] ); - // TODO: Once we are past experimental phase this code should be removed - const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); useEffect(() => { let isSubscribed = true; @@ -131,15 +127,10 @@ export const useAddOrUpdateException = ({ } if (bulkCloseIndex != null) { - // TODO: Once we are past experimental phase this code should be removed - const alertStatusFilter = ruleRegistryEnabled - ? buildAlertStatusFilterRuleRegistry('open') - : buildAlertStatusFilter('open'); - const filter = getQueryFilter( '', 'kuery', - [...buildAlertsRuleIdFilter(ruleId), ...alertStatusFilter], + [...buildAlertsRuleIdFilter(ruleId), ...buildAlertStatusFilter('open')], bulkCloseIndex, prepareExceptionItemsForBulkClose(exceptionItemsToAddOrUpdate), false @@ -185,14 +176,7 @@ export const useAddOrUpdateException = ({ isSubscribed = false; abortCtrl.abort(); }; - }, [ - addExceptionListItem, - http, - onSuccess, - onError, - ruleRegistryEnabled, - updateExceptionListItem, - ]); + }, [http, onSuccess, onError, updateExceptionListItem, addExceptionListItem]); return [{ isLoading }, addOrUpdateException]; }; diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index 71e33c603b65b28..af278b09e719c4f 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -43,7 +43,6 @@ export const mockGlobalState: State = { trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, hostIsolationEnabled: false, - ruleRegistryEnabled: false, }, }, hosts: { diff --git a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx index 9ac7ae0f2432253..90526e84a2262bf 100644 --- a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx @@ -24,12 +24,11 @@ import { import { FieldHook } from '../../shared_imports'; import { SUB_PLUGINS_REDUCER } from './utils'; import { createSecuritySolutionStorageMock, localStorageMock } from './mock_local_storage'; -import { UserPrivilegesProvider } from '../../detections/components/user_privileges'; const state: State = mockGlobalState; interface Props { - children?: React.ReactNode; + children: React.ReactNode; store?: Store; onDragEnd?: (result: DropResult, provided: ResponderProvided) => void; } @@ -60,30 +59,7 @@ const TestProvidersComponent: React.FC = ({ ); -/** - * A utility for wrapping children in the providers required to run most tests - * WITH user privileges provider. - */ -const TestProvidersWithPrivilegesComponent: React.FC = ({ - children, - store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage), - onDragEnd = jest.fn(), -}) => ( - - - - ({ eui: euiDarkVars, darkMode: true })}> - - {children} - - - - - -); - export const TestProviders = React.memo(TestProvidersComponent); -export const TestProvidersWithPrivileges = React.memo(TestProvidersWithPrivilegesComponent); export const useFormFieldMock = (options?: Partial>): FieldHook => { return { diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx index 02a815bc59f3bdd..478c8930b8dd3bc 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx @@ -5,12 +5,11 @@ * 2.0. */ -import { defaultColumnHeaderType } from '../../../timelines/components/timeline/body/column_headers/default_headers'; import { RowRendererId } from '../../../../common/types/timeline'; import { Status } from '../../../../common/detection_engine/schemas/common/schemas'; import { Filter } from '../../../../../../../src/plugins/data/common/es_query'; -import { ColumnHeaderOptions, SubsetTimelineModel } from '../../../timelines/store/timeline/model'; +import { SubsetTimelineModel } from '../../../timelines/store/timeline/model'; import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import { columns } from '../../configurations/security_solution_detections/columns'; @@ -125,76 +124,3 @@ export const requiredFieldsForActions = [ 'host.os.family', 'event.code', ]; - -// TODO: Once we are past experimental phase this code should be removed -export const buildAlertStatusFilterRuleRegistry = (status: Status): Filter[] => [ - { - meta: { - alias: null, - negate: false, - disabled: false, - type: 'phrase', - key: 'kibana.rac.alert.status', - params: { - query: status, - }, - }, - query: { - term: { - 'kibana.rac.alert.status': status, - }, - }, - }, -]; - -export const buildShowBuildingBlockFilterRuleRegistry = ( - showBuildingBlockAlerts: boolean -): Filter[] => - showBuildingBlockAlerts - ? [] - : [ - { - meta: { - alias: null, - negate: true, - disabled: false, - type: 'exists', - key: 'kibana.rac.rule.building_block_type', - value: 'exists', - }, - // @ts-expect-error TODO: Rework parent typings to support ExistsFilter[] - exists: { field: 'kibana.rac.rule.building_block_type' }, - }, - ]; - -export const requiredFieldMappingsForActionsRuleRegistry = { - '@timestamp': '@timestamp', - 'alert.id': 'kibana.rac.alert.id', - 'event.kind': 'event.kind', - 'alert.start': 'kibana.rac.alert.start', - 'alert.uuid': 'kibana.rac.alert.uuid', - 'event.action': 'event.action', - 'alert.status': 'kibana.rac.alert.status', - 'alert.duration.us': 'kibana.rac.alert.duration.us', - 'rule.uuid': 'rule.uuid', - 'rule.id': 'rule.id', - 'rule.name': 'rule.name', - 'rule.category': 'rule.category', - producer: 'kibana.rac.alert.producer', - tags: 'tags', -}; - -export const alertsHeadersRuleRegistry: ColumnHeaderOptions[] = Object.entries( - requiredFieldMappingsForActionsRuleRegistry -).map(([alias, field]) => ({ - columnHeaderType: defaultColumnHeaderType, - displayAsText: alias, - id: field, -})); - -export const alertsDefaultModelRuleRegistry: SubsetTimelineModel = { - ...timelineDefaults, - columns: alertsHeadersRuleRegistry, - showCheckboxes: true, - excludedRowRendererIds: Object.values(RowRendererId), -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx index f20754fc446d6e8..9dc83d7898963db 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx @@ -16,7 +16,6 @@ import { TimelineIdLiteral } from '../../../../common/types/timeline'; import { useAppToasts } from '../../../common/hooks/use_app_toasts'; import { StatefulEventsViewer } from '../../../common/components/events_viewer'; import { HeaderSection } from '../../../common/components/header_section'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { combineQueries } from '../../../timelines/components/timeline/helpers'; import { useKibana } from '../../../common/lib/kibana'; import { inputsSelectors, State, inputsModel } from '../../../common/store'; @@ -30,8 +29,6 @@ import { requiredFieldsForActions, alertsDefaultModel, buildAlertStatusFilter, - alertsDefaultModelRuleRegistry, - buildAlertStatusFilterRuleRegistry, } from './default_config'; import { FILTER_OPEN, AlertsTableFilterGroup } from './alerts_filter_group'; import { AlertsUtilityBar } from './alerts_utility_bar'; @@ -107,8 +104,6 @@ export const AlertsTableComponent: React.FC = ({ const [, dispatchToaster] = useStateToaster(); const { addWarning } = useAppToasts(); const { initializeTimeline, setSelectAll } = useManageTimeline(); - // TODO: Once we are past experimental phase this code should be removed - const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); const getGlobalQuery = useCallback( (customFilters: Filter[]) => { @@ -241,11 +236,7 @@ export const AlertsTableComponent: React.FC = ({ refetchQuery: inputsModel.Refetch, { status, selectedStatus }: UpdateAlertsStatusProps ) => { - // TODO: Once we are past experimental phase this code should be removed - const currentStatusFilter = ruleRegistryEnabled - ? buildAlertStatusFilterRuleRegistry(status) - : buildAlertStatusFilter(status); - + const currentStatusFilter = buildAlertStatusFilter(status); await updateAlertStatusAction({ query: showClearSelectionAction ? getGlobalQuery(currentStatusFilter)?.filterQuery @@ -267,7 +258,6 @@ export const AlertsTableComponent: React.FC = ({ showClearSelectionAction, onAlertStatusUpdateSuccess, onAlertStatusUpdateFailure, - ruleRegistryEnabled, ] ); @@ -311,28 +301,18 @@ export const AlertsTableComponent: React.FC = ({ ); const defaultFiltersMemo = useMemo(() => { - // TODO: Once we are past experimental phase this code should be removed - const alertStatusFilter = ruleRegistryEnabled - ? buildAlertStatusFilterRuleRegistry(filterGroup) - : buildAlertStatusFilter(filterGroup); - if (isEmpty(defaultFilters)) { - return alertStatusFilter; + return buildAlertStatusFilter(filterGroup); } else if (defaultFilters != null && !isEmpty(defaultFilters)) { - return [...defaultFilters, ...alertStatusFilter]; + return [...defaultFilters, ...buildAlertStatusFilter(filterGroup)]; } - }, [defaultFilters, filterGroup, ruleRegistryEnabled]); + }, [defaultFilters, filterGroup]); const { filterManager } = useKibana().services.data.query; - // TODO: Once we are past experimental phase this code should be removed - const defaultTimelineModel = ruleRegistryEnabled - ? alertsDefaultModelRuleRegistry - : alertsDefaultModel; - useEffect(() => { initializeTimeline({ defaultModel: { - ...defaultTimelineModel, + ...alertsDefaultModel, columns, }, documentType: i18n.ALERTS_DOCUMENT_TYPE, @@ -364,7 +344,7 @@ export const AlertsTableComponent: React.FC = ({ return ( ( + {children} +); + describe('useSignalIndex', () => { let appToastsMock: jest.Mocked>; @@ -28,9 +33,7 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { - wrapper: TestProvidersWithPrivileges, - } + { wrapper: Wrapper } ); await waitForNextUpdate(); expect(result.current).toEqual({ @@ -47,9 +50,7 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { - wrapper: TestProvidersWithPrivileges, - } + { wrapper: Wrapper } ); await waitForNextUpdate(); await waitForNextUpdate(); @@ -68,9 +69,7 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { - wrapper: TestProvidersWithPrivileges, - } + { wrapper: Wrapper } ); await waitForNextUpdate(); await waitForNextUpdate(); @@ -94,9 +93,7 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { - wrapper: TestProvidersWithPrivileges, - } + { wrapper: Wrapper } ); await waitForNextUpdate(); await waitForNextUpdate(); @@ -117,9 +114,7 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { - wrapper: TestProvidersWithPrivileges, - } + { wrapper: Wrapper } ); await waitForNextUpdate(); await waitForNextUpdate(); @@ -145,9 +140,7 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { - wrapper: TestProvidersWithPrivileges, - } + { wrapper: Wrapper } ); await waitForNextUpdate(); await waitForNextUpdate(); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx index 84eaf8e3aa93c31..fdbeab26f11f3a0 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx @@ -6,10 +6,8 @@ */ import { useEffect, useState } from 'react'; -import { DEFAULT_ALERTS_INDEX } from '../../../../../common/constants'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { createSignalIndex, getSignalIndex } from './api'; import * as i18n from './translations'; import { isSecurityAppError } from '../../../../common/utils/api'; @@ -40,8 +38,6 @@ export const useSignalIndex = (): ReturnSignalIndex => { }); const { addError } = useAppToasts(); const { hasIndexRead } = useAlertsPrivileges(); - // TODO: Once we are past experimental phase this code should be removed - const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); useEffect(() => { let isSubscribed = true; @@ -52,15 +48,10 @@ export const useSignalIndex = (): ReturnSignalIndex => { setLoading(true); const signal = await getSignalIndex({ signal: abortCtrl.signal }); - // TODO: Once we are past experimental phase we can update `getSignalIndex` to return the space-aware DEFAULT_ALERTS_INDEX - const signalIndices = ruleRegistryEnabled - ? `${DEFAULT_ALERTS_INDEX},${signal.name}` - : signal.name; - if (isSubscribed && signal != null) { setSignalIndex({ signalIndexExists: true, - signalIndexName: signalIndices, + signalIndexName: signal.name, signalIndexMappingOutdated: signal.index_mapping_outdated, createDeSignalIndex: createIndex, }); @@ -124,7 +115,7 @@ export const useSignalIndex = (): ReturnSignalIndex => { isSubscribed = false; abortCtrl.abort(); }; - }, [addError, hasIndexRead, ruleRegistryEnabled]); + }, [addError, hasIndexRead]); return { loading, ...signalIndex }; }; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx index 8ae7e4fb2852b52..c1c7e4688bbbe3a 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx @@ -11,7 +11,6 @@ import { noop } from 'lodash/fp'; import React, { useCallback, useMemo, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; import { useHistory } from 'react-router-dom'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { useDeepEqualSelector, useShallowEqualSelector } from '../../../common/hooks/use_selector'; import { SecurityPageName } from '../../../app/types'; @@ -52,7 +51,6 @@ import { timelineSelectors } from '../../../timelines/store/timeline'; import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import { buildShowBuildingBlockFilter, - buildShowBuildingBlockFilterRuleRegistry, buildThreatMatchFilter, } from '../../components/alerts_table/default_config'; import { useSourcererScope } from '../../../common/containers/sourcerer'; @@ -83,8 +81,6 @@ const DetectionEnginePageComponent = () => { const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []); const query = useDeepEqualSelector(getGlobalQuerySelector); const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); - // TODO: Once we are past experimental phase this code should be removed - const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); const { to, from, deleteQuery, setQuery } = useGlobalTime(); const { globalFullScreen } = useGlobalFullScreen(); @@ -138,23 +134,19 @@ const DetectionEnginePageComponent = () => { const alertsHistogramDefaultFilters = useMemo( () => [ ...filters, - ...(ruleRegistryEnabled - ? buildShowBuildingBlockFilterRuleRegistry(showBuildingBlockAlerts) // TODO: Once we are past experimental phase this code should be removed - : buildShowBuildingBlockFilter(showBuildingBlockAlerts)), + ...buildShowBuildingBlockFilter(showBuildingBlockAlerts), ...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts), ], - [filters, ruleRegistryEnabled, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] + [filters, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] ); // AlertsTable manages global filters itself, so not including `filters` const alertsTableDefaultFilters = useMemo( () => [ - ...(ruleRegistryEnabled - ? buildShowBuildingBlockFilterRuleRegistry(showBuildingBlockAlerts) // TODO: Once we are past experimental phase this code should be removed - : buildShowBuildingBlockFilter(showBuildingBlockAlerts)), + ...buildShowBuildingBlockFilter(showBuildingBlockAlerts), ...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts), ], - [ruleRegistryEnabled, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] + [showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] ); const onShowBuildingBlockAlertsChangedCallback = useCallback( diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx index 8dac9e03514d1c0..d3793dad8ff1a47 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx @@ -36,7 +36,6 @@ import { useDeepEqualSelector, useShallowEqualSelector, } from '../../../../../common/hooks/use_selector'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { useKibana } from '../../../../../common/lib/kibana'; import { TimelineId } from '../../../../../../common/types/timeline'; import { UpdateDateRange } from '../../../../../common/components/charts/common'; @@ -65,7 +64,6 @@ import { StepScheduleRule } from '../../../../components/rules/step_schedule_rul import { buildAlertsRuleIdFilter, buildShowBuildingBlockFilter, - buildShowBuildingBlockFilterRuleRegistry, buildThreatMatchFilter, } from '../../../../components/alerts_table/default_config'; import { RuleSwitch } from '../../../../components/rules/rule_switch'; @@ -224,9 +222,6 @@ const RuleDetailsPageComponent = () => { const { formatUrl } = useFormatUrl(SecurityPageName.detections); const { globalFullScreen } = useGlobalFullScreen(); - // TODO: Once we are past experimental phase this code should be removed - const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); - // TODO: Refactor license check + hasMlAdminPermissions to common check const hasMlPermissions = hasMlLicense(mlCapabilities) && hasMlAdminPermissions(mlCapabilities); const { @@ -312,12 +307,10 @@ const RuleDetailsPageComponent = () => { const alertDefaultFilters = useMemo( () => [ ...buildAlertsRuleIdFilter(ruleId), - ...(ruleRegistryEnabled - ? buildShowBuildingBlockFilterRuleRegistry(showBuildingBlockAlerts) // TODO: Once we are past experimental phase this code should be removed - : buildShowBuildingBlockFilter(showBuildingBlockAlerts)), + ...buildShowBuildingBlockFilter(showBuildingBlockAlerts), ...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts), ], - [ruleId, ruleRegistryEnabled, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] + [ruleId, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] ); const alertMergedFilters = useMemo(() => [...alertDefaultFilters, ...filters], [ diff --git a/x-pack/plugins/security_solution/public/management/components/search_bar/index.tsx b/x-pack/plugins/security_solution/public/management/components/search_bar/index.tsx index 5ace2b901da11c9..3c92ab31680c20f 100644 --- a/x-pack/plugins/security_solution/public/management/components/search_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/management/components/search_bar/index.tsx @@ -25,7 +25,7 @@ export const SearchBar = memo(({ defaultValue = '', onSearch, pl const handleOnSearch = useCallback(() => onSearch(query), [query, onSearch]); return ( - + { - return (await this.httpWrapper()).get( - `${EXCEPTION_LIST_URL}/summary`, - { - query: { - list_id: ENDPOINT_EVENT_FILTERS_LIST_ID, - namespace_type: 'agnostic', - }, - } - ); - } } diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/store/middleware.test.ts b/x-pack/plugins/security_solution/public/management/pages/event_filters/store/middleware.test.ts index 5229e4078eb0dc1..b55a32a937c4588 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/store/middleware.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/store/middleware.test.ts @@ -29,7 +29,6 @@ const createEventFiltersServiceMock = (): jest.Mocked => ({ getOne: jest.fn(), updateOne: jest.fn(), deleteOne: jest.fn(), - getSummary: jest.fn(), }); const createStoreSetup = (eventFiltersService: EventFiltersService) => { diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts b/x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts index 3bcf6a336930295..be6689b7e5b57b5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts @@ -10,7 +10,6 @@ import type { CreateExceptionListItemSchema, ExceptionListItemSchema, UpdateExceptionListItemSchema, - ExceptionListSummarySchema, } from '@kbn/securitysolution-io-ts-list-types'; import { AsyncResourceState } from '../../state/async_resource_state'; import { Immutable } from '../../../../common/endpoint/types'; @@ -50,7 +49,6 @@ export interface EventFiltersService { getOne(id: string): Promise; updateOne(exception: Immutable): Promise; deleteOne(id: string): Promise; - getSummary(): Promise; } export interface EventFiltersListPageData { diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx deleted file mode 100644 index 6f368a89eb5f931..000000000000000 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, useMemo, useState, useEffect } from 'react'; -import { ApplicationStart, CoreStart } from 'kibana/public'; -import { EuiPanel, EuiText } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - PackageCustomExtensionComponentProps, - pagePathGetters, -} from '../../../../../../../../../fleet/public'; -import { useKibana } from '../../../../../../../../../../../src/plugins/kibana_react/public'; -import { getEventFiltersListPath } from '../../../../../../common/routing'; -import { GetExceptionSummaryResponse } from '../../../../../../../../common/endpoint/types'; -import { PLUGIN_ID as FLEET_PLUGIN_ID } from '../../../../../../../../../fleet/common'; -import { MANAGEMENT_APP_ID } from '../../../../../../common/constants'; -import { useToasts } from '../../../../../../../common/lib/kibana'; -import { LinkWithIcon } from './link_with_icon'; -import { ExceptionItemsSummary } from './exception_items_summary'; -import { EventFiltersHttpService } from '../../../../../event_filters/service'; -import { StyledEuiFlexGridGroup, StyledEuiFlexGridItem } from './styled_components'; - -export const FleetEventFiltersCard = memo(({ pkgkey }) => { - const { - services: { - application: { getUrlForApp }, - http, - }, - } = useKibana(); - const toasts = useToasts(); - const [stats, setStats] = useState(); - const eventFiltersListUrlPath = getEventFiltersListPath(); - const eventFiltersApi = useMemo(() => new EventFiltersHttpService(http), [http]); - - useEffect(() => { - const fetchStats = async () => { - try { - const summary = await eventFiltersApi.getSummary(); - setStats(summary); - } catch (error) { - toasts.addDanger( - i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.eventFiltersSummaryError', - { - defaultMessage: 'There was an error trying to fetch event filters stats: "{error}"', - values: { error }, - } - ) - ); - } - }; - fetchStats(); - }, [eventFiltersApi, toasts]); - - const eventFiltersRouteState = useMemo(() => { - const fleetPackageCustomUrlPath = `#${pagePathGetters.integration_details_custom({ pkgkey })}`; - return { - backButtonLabel: i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.backButtonLabel', - { defaultMessage: 'Back to Endpoint Integration' } - ), - onBackButtonNavigateTo: [ - FLEET_PLUGIN_ID, - { - path: fleetPackageCustomUrlPath, - }, - ], - backButtonUrl: getUrlForApp(FLEET_PLUGIN_ID, { - path: fleetPackageCustomUrlPath, - }), - }; - }, [getUrlForApp, pkgkey]); - - return ( - - - - -

- -

-
-
- - - - - <> - - - - - -
-
- ); -}); - -FleetEventFiltersCard.displayName = 'FleetEventFiltersCard'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx index ec1479643999a9c..fe6f82e632f734b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx @@ -5,9 +5,9 @@ * 2.0. */ -import React, { memo, useMemo, useState, useEffect } from 'react'; -import { ApplicationStart, CoreStart } from 'kibana/public'; -import { EuiPanel, EuiText } from '@elastic/eui'; +import React, { memo, useMemo } from 'react'; +import { ApplicationStart } from 'kibana/public'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { @@ -16,48 +16,19 @@ import { } from '../../../../../../../../../fleet/public'; import { useKibana } from '../../../../../../../../../../../src/plugins/kibana_react/public'; import { getTrustedAppsListPath } from '../../../../../../common/routing'; -import { - TrustedAppsListPageRouteState, - GetExceptionSummaryResponse, -} from '../../../../../../../../common/endpoint/types'; +import { TrustedAppsListPageRouteState } from '../../../../../../../../common/endpoint/types'; import { PLUGIN_ID as FLEET_PLUGIN_ID } from '../../../../../../../../../fleet/common'; import { MANAGEMENT_APP_ID } from '../../../../../../common/constants'; -import { useToasts } from '../../../../../../../common/lib/kibana'; import { LinkWithIcon } from './link_with_icon'; -import { ExceptionItemsSummary } from './exception_items_summary'; -import { TrustedAppsHttpService } from '../../../../../trusted_apps/service'; -import { StyledEuiFlexGridGroup, StyledEuiFlexGridItem } from './styled_components'; +import { TrustedAppItemsSummary } from './trusted_app_items_summary'; export const FleetTrustedAppsCard = memo(({ pkgkey }) => { const { services: { application: { getUrlForApp }, - http, }, - } = useKibana(); - const toasts = useToasts(); - const [stats, setStats] = useState(); - const trustedAppsApi = useMemo(() => new TrustedAppsHttpService(http), [http]); + } = useKibana<{ application: ApplicationStart }>(); - useEffect(() => { - const fetchStats = async () => { - try { - const response = await trustedAppsApi.getTrustedAppsSummary(); - setStats(response); - } catch (error) { - toasts.addDanger( - i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppsSummaryError', - { - defaultMessage: 'There was an error trying to fetch trusted apps stats: "{error}"', - values: { error }, - } - ) - ); - } - }; - fetchStats(); - }, [toasts, trustedAppsApi]); const trustedAppsListUrlPath = getTrustedAppsListPath(); const trustedAppRouteState = useMemo(() => { @@ -81,8 +52,8 @@ export const FleetTrustedAppsCard = memo(( return ( - - + +

(( />

-
- - - - - <> +
+ + + + + (( defaultMessage="Manage trusted applications" /> - - - + + +
); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx deleted file mode 100644 index 8791f7fa8728311..000000000000000 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import styled from 'styled-components'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - -export const StyledEuiFlexGridGroup = styled(EuiFlexGroup)` - display: grid; - grid-template-columns: 25% 45% 30%; - grid-template-areas: 'title summary link'; -`; - -export const StyledEuiFlexGridItem = styled(EuiFlexItem)<{ - gridArea: string; - alignItems?: string; -}>` - grid-area: ${({ gridArea }) => gridArea}; - align-items: ${({ alignItems }) => alignItems ?? 'center'}; - margin: 0px; - padding: 12px; -`; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/trusted_app_items_summary.tsx similarity index 52% rename from x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx rename to x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/trusted_app_items_summary.tsx index f42304ffb89aed2..fae65def7e2f6e3 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/trusted_app_items_summary.tsx @@ -6,45 +6,56 @@ */ import { EuiBadge, EuiBadgeProps, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; -import React, { FC, memo } from 'react'; +import React, { FC, memo, useEffect, useState } from 'react'; +import { CoreStart } from 'kibana/public'; import { i18n } from '@kbn/i18n'; -import { GetExceptionSummaryResponse } from '../../../../../../../../common/endpoint/types'; +import { useKibana } from '../../../../../../../../../../../src/plugins/kibana_react/public'; +import { TrustedAppsHttpService } from '../../../../../trusted_apps/service'; +import { GetTrustedAppsSummaryResponse } from '../../../../../../../../common/endpoint/types'; -const SUMMARY_KEYS: Readonly> = [ +const SUMMARY_KEYS: Readonly> = [ 'windows', 'macos', 'linux', 'total', ]; -const SUMMARY_LABELS: Readonly<{ [key in keyof GetExceptionSummaryResponse]: string }> = { +const SUMMARY_LABELS: Readonly<{ [key in keyof GetTrustedAppsSummaryResponse]: string }> = { windows: i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.exceptionItemsSummary.windows', + 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.windows', { defaultMessage: 'Windows' } ), linux: i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.exceptionItemsSummary.linux', + 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.linux', { defaultMessage: 'Linux' } ), macos: i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.exceptionItemsSummary.macos', + 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.macos', { defaultMessage: 'Mac' } ), total: i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.exceptionItemsSummary.total', + 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.total', { defaultMessage: 'Total' } ), }; const CSS_BOLD: Readonly = { fontWeight: 'bold' }; -interface ExceptionItemsSummaryProps { - stats: GetExceptionSummaryResponse | undefined; -} +export const TrustedAppItemsSummary = memo(() => { + const { + services: { http }, + } = useKibana(); + const [stats, setStats] = useState(); + const [trustedAppsApi] = useState(() => new TrustedAppsHttpService(http)); + + useEffect(() => { + trustedAppsApi.getTrustedAppsSummary().then((response) => { + setStats(response); + }); + }, [trustedAppsApi]); -export const ExceptionItemsSummary = memo(({ stats }) => { return ( - + {SUMMARY_KEYS.map((stat) => { return ( @@ -62,13 +73,18 @@ export const ExceptionItemsSummary = memo(({ stats } ); }); -ExceptionItemsSummary.displayName = 'ExceptionItemsSummary'; +TrustedAppItemsSummary.displayName = 'TrustedAppItemsSummary'; const SummaryStat: FC<{ value: number; color?: EuiBadgeProps['color'] }> = memo( ({ children, value, color, ...commonProps }) => { return ( - + {children} diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx index 094f1131d7034f4..c127a60d84ccffe 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx @@ -5,19 +5,15 @@ * 2.0. */ -import { EuiSpacer } from '@elastic/eui'; import React, { memo } from 'react'; import { PackageCustomExtensionComponentProps } from '../../../../../../../../fleet/public'; import { FleetTrustedAppsCard } from './components/fleet_trusted_apps_card'; -import { FleetEventFiltersCard } from './components/fleet_event_filters_card'; export const EndpointPackageCustomExtension = memo( (props) => { return (
- -
); } diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx index 3f02d505daea1e9..874d1a4a969c4c0 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx @@ -169,15 +169,10 @@ describe('When on the Trusted Apps Page', () => { it('should display a Add Trusted App button', async () => { const { getByTestId } = await renderWithListData(); - const addButton = getByTestId('trustedAppsListAddButton'); + const addButton = await getByTestId('trustedAppsListAddButton'); expect(addButton.textContent).toBe('Add Trusted Application'); }); - it('should display the searchbar', async () => { - const renderResult = await renderWithListData(); - expect(await renderResult.findByTestId('searchBar')).not.toBeNull(); - }); - describe('and the Grid view is being displayed', () => { describe('and the edit trusted app button is clicked', () => { let renderResult: ReturnType; @@ -560,7 +555,7 @@ describe('When on the Trusted Apps Page', () => { // to test the UI behaviours while the API call is in flight coreStart.http.post.mockImplementation( // @ts-ignore - async (_, options: HttpFetchOptions) => { + async (path: string, options: HttpFetchOptions) => { return new Promise((resolve, reject) => { httpPostBody = options.body as string; resolveHttpPost = resolve; @@ -866,14 +861,6 @@ describe('When on the Trusted Apps Page', () => { expect(await renderResult.findByTestId('trustedAppEmptyState')).not.toBeNull(); }); - - it('should not display the searchbar', async () => { - const renderResult = render(); - await act(async () => { - await waitForAction('trustedAppsExistStateChanged'); - }); - expect(renderResult.queryByTestId('searchBar')).toBeNull(); - }); }); describe('and the search is dispatched', () => { diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx index 5603b8e2d61c908..ac06254a5310013 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx @@ -96,36 +96,34 @@ export const TrustedAppsPage = memo(() => { /> )} + {doEntriesExist ? ( - <> - - + + + + + - - - - - - - - - {location.view_type === 'grid' && } - {location.view_type === 'list' && } - - - +
+ + + + {location.view_type === 'grid' && } + {location.view_type === 'list' && } + +
) : ( )} diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index 2e41e291156aaae..c1f501d3f709454 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -44,7 +44,6 @@ import { APP_PATH, DEFAULT_INDEX_KEY, DETECTION_ENGINE_INDEX_URL, - DEFAULT_ALERTS_INDEX, } from '../common/constants'; import { SecurityPageName } from './app/types'; @@ -447,9 +446,6 @@ export class Plugin implements IPlugin { if (!this._store) { - const experimentalFeatures = parseExperimentalConfigValue( - this.config.enableExperimental || [] - ); const defaultIndicesName = coreStart.uiSettings.get(DEFAULT_INDEX_KEY); const [ { createStore, createInitialState }, @@ -478,15 +474,9 @@ export class Plugin implements IPlugin +export const skipQueryForDetectionsPage = (id: string, defaultIndex: string[]) => id != null && detectionsTimelineIds.some((timelineId) => timelineId === id) && - !defaultIndex.some((di) => - di.toLowerCase().startsWith(useRuleRegistry ? DEFAULT_ALERTS_INDEX : '.siem-signals') - ); + !defaultIndex.some((di) => di.toLowerCase().startsWith('.siem-signals')); diff --git a/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx index 62846eb01e60f6b..1032d0ec1672acd 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx @@ -9,7 +9,6 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { initSortDefault, TimelineArgs, useTimelineEvents, UseTimelineEventsProps } from '.'; import { SecurityPageName } from '../../../common/constants'; import { TimelineId } from '../../../common/types/timeline'; -import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { mockTimelineData } from '../../common/mock'; import { useRouteSpy } from '../../common/utils/route/use_route_spy'; @@ -27,9 +26,6 @@ const mockEvents = mockTimelineData.filter((i, index) => index <= 11); const mockSearch = jest.fn(); -jest.mock('../../common/hooks/use_experimental_features'); -const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; - jest.mock('../../common/lib/kibana', () => ({ useToasts: jest.fn().mockReturnValue({ addError: jest.fn(), @@ -97,7 +93,6 @@ mockUseRouteSpy.mockReturnValue([ ]); describe('useTimelineEvents', () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(false); beforeEach(() => { mockSearch.mockReset(); }); diff --git a/x-pack/plugins/security_solution/public/timelines/containers/index.tsx b/x-pack/plugins/security_solution/public/timelines/containers/index.tsx index 17c107899d85ab3..92199336b978c16 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/index.tsx @@ -13,7 +13,6 @@ import { Subscription } from 'rxjs'; import { ESQuery } from '../../../common/typed_json'; import { isCompleteResponse, isErrorResponse } from '../../../../../../src/plugins/data/public'; -import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { inputsModel, KueryFilterQueryKind } from '../../common/store'; import { useKibana } from '../../common/lib/kibana'; import { createFilter } from '../../common/containers/helpers'; @@ -198,9 +197,6 @@ export const useTimelineEvents = ({ }); const { addError, addWarning } = useAppToasts(); - // TODO: Once we are past experimental phase this code should be removed - const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); - const timelineSearch = useCallback( (request: TimelineRequest | null) => { if (request == null || pageName === '' || skip) { @@ -309,10 +305,7 @@ export const useTimelineEvents = ({ ); useEffect(() => { - if ( - skipQueryForDetectionsPage(id, indexNames, ruleRegistryEnabled) || - indexNames.length === 0 - ) { + if (skipQueryForDetectionsPage(id, indexNames) || indexNames.length === 0) { return; } @@ -371,10 +364,7 @@ export const useTimelineEvents = ({ activeTimeline.setActivePage(newActivePage); } } - if ( - !skipQueryForDetectionsPage(id, indexNames, ruleRegistryEnabled) && - !deepEqual(prevRequest, currentRequest) - ) { + if (!skipQueryForDetectionsPage(id, indexNames) && !deepEqual(prevRequest, currentRequest)) { return currentRequest; } return prevRequest; @@ -390,7 +380,6 @@ export const useTimelineEvents = ({ id, language, limit, - ruleRegistryEnabled, startDate, sort, fields, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/rule_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/rule_type.ts deleted file mode 100644 index f7e0dd9eb362052..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/rule_type.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { of } from 'rxjs'; -import { v4 } from 'uuid'; - -import { Logger } from 'kibana/server'; -import { elasticsearchServiceMock } from 'src/core/server/mocks'; - -import type { RuleDataClient } from '../../../../../../rule_registry/server'; -import { PluginSetupContract as AlertingPluginSetupContract } from '../../../../../../alerting/server'; -import { ConfigType } from '../../../../config'; - -export const createRuleTypeMocks = () => { - /* eslint-disable @typescript-eslint/no-explicit-any */ - let alertExecutor: (...args: any[]) => Promise; - - const mockedConfig$ = of({} as ConfigType); - - const loggerMock = ({ - debug: jest.fn(), - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - } as unknown) as Logger; - - const alerting = { - registerType: ({ executor }) => { - alertExecutor = executor; - }, - } as AlertingPluginSetupContract; - - const scheduleActions = jest.fn(); - - const services = { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertInstanceFactory: jest.fn(() => ({ scheduleActions })), - findAlerts: jest.fn(), // TODO: does this stay? - alertWithPersistence: jest.fn(), - logger: loggerMock, - }; - - return { - dependencies: { - alerting, - config$: mockedConfig$, - logger: loggerMock, - ruleDataClient: ({ - getReader: () => { - return { - search: jest.fn(), - }; - }, - getWriter: () => { - return { - bulk: jest.fn(), - }; - }, - } as unknown) as RuleDataClient, - }, - services, - scheduleActions, - executor: async ({ params }: { params: Record }) => { - return alertExecutor({ - services, - params, - alertId: v4(), - startedAt: new Date(), - }); - }, - }; -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/threshold.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/threshold.ts deleted file mode 100644 index 40d2ed37a557693..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/threshold.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { sampleDocNoSortId } from '../../signals/__mocks__/es_results'; - -export const mockThresholdResults = { - rawResponse: { - body: { - is_partial: false, - is_running: false, - took: 527, - timed_out: false, - hits: { - total: { - value: 0, - relation: 'eq', - }, - hits: [], - }, - aggregations: { - 'threshold_0:source.ip': { - buckets: [ - { - key: '127.0.0.1', - doc_count: 5, - 'threshold_1:host.name': { - buckets: [ - { - key: 'tardigrade', - doc_count: 3, - top_threshold_hits: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - hits: [ - { - ...sampleDocNoSortId(), - 'host.name': 'tardigrade', - }, - ], - }, - }, - cardinality_count: { - value: 3, - }, - }, - ], - }, - }, - ], - }, - }, - }, - }, -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.test.ts deleted file mode 100644 index 6529c594dd5a510..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; - -import { sequenceResponse } from '../../../search_strategy/timeline/eql/__mocks__'; - -import { createEqlAlertType } from './eql'; -import { createRuleTypeMocks } from './__mocks__/rule_type'; - -describe('EQL alerts', () => { - it('does not send an alert when sequence not found', async () => { - const { services, dependencies, executor } = createRuleTypeMocks(); - const eqlAlertType = createEqlAlertType(dependencies.ruleDataClient, dependencies.logger); - - dependencies.alerting.registerType(eqlAlertType); - - const params = { - eqlQuery: 'sequence by host.name↵[any where true]↵[any where true]↵[any where true]', - indexPatterns: ['*'], - }; - - services.scopedClusterClient.asCurrentUser.transport.request.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise({ - hits: { - hits: [], - sequences: [], - events: [], - total: { - relation: 'eq', - value: 0, - }, - }, - took: 0, - timed_out: false, - _shards: { - failed: 0, - skipped: 0, - successful: 1, - total: 1, - }, - }) - ); - - await executor({ params }); - expect(services.alertInstanceFactory).not.toBeCalled(); - }); - - it('sends a properly formatted alert when sequence is found', async () => { - const { services, dependencies, executor } = createRuleTypeMocks(); - const eqlAlertType = createEqlAlertType(dependencies.ruleDataClient, dependencies.logger); - - dependencies.alerting.registerType(eqlAlertType); - - const params = { - eqlQuery: 'sequence by host.name↵[any where true]↵[any where true]↵[any where true]', - indexPatterns: ['*'], - }; - - services.scopedClusterClient.asCurrentUser.transport.request.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise({ - hits: sequenceResponse.rawResponse.body.hits, - took: 0, - timed_out: false, - _shards: { - failed: 0, - skipped: 0, - successful: 1, - total: 1, - }, - }) - ); - - await executor({ params }); - expect(services.alertInstanceFactory).toBeCalled(); - /* - expect(services.alertWithPersistence).toBeCalledWith( - expect.arrayContaining([ - expect.objectContaining({ - 'event.kind': 'signal', - 'kibana.rac.alert.building_block_type': 'default', - }), - ]) - ); - */ - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts deleted file mode 100644 index 39d02c808d09e54..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import moment from 'moment'; -import v4 from 'uuid/v4'; - -import { ApiResponse } from '@elastic/elasticsearch'; -import { schema } from '@kbn/config-schema'; -import { Logger } from '@kbn/logging'; - -import { - RuleDataClient, - createPersistenceRuleTypeFactory, -} from '../../../../../rule_registry/server'; -import { EQL_ALERT_TYPE_ID } from '../../../../common/constants'; -import { buildEqlSearchRequest } from '../../../../common/detection_engine/get_query_filter'; -import { BaseSignalHit, EqlSignalSearchResponse } from '../signals/types'; - -export const createEqlAlertType = (ruleDataClient: RuleDataClient, logger: Logger) => { - const createPersistenceRuleType = createPersistenceRuleTypeFactory({ - ruleDataClient, - logger, - }); - return createPersistenceRuleType({ - id: EQL_ALERT_TYPE_ID, - name: 'EQL Rule', - validate: { - params: schema.object({ - eqlQuery: schema.string(), - indexPatterns: schema.arrayOf(schema.string()), - }), - }, - actionGroups: [ - { - id: 'default', - name: 'Default', - }, - ], - defaultActionGroupId: 'default', - actionVariables: { - context: [{ name: 'server', description: 'the server' }], - }, - minimumLicenseRequired: 'basic', - producer: 'security-solution', - async executor({ - startedAt, - services: { alertWithPersistence, findAlerts, scopedClusterClient }, - params: { indexPatterns, eqlQuery }, - }) { - const from = moment(startedAt).subtract(moment.duration(5, 'm')).toISOString(); // hardcoded 5-minute rule interval - const to = startedAt.toISOString(); - - const request = buildEqlSearchRequest( - eqlQuery, - indexPatterns, - from, - to, - 10, - undefined, - [], - undefined - ); - const { body: response } = (await scopedClusterClient.asCurrentUser.transport.request( - request - )) as ApiResponse; - - const buildSignalFromEvent = (event: BaseSignalHit) => { - return { - ...event, - 'event.kind': 'signal', - 'kibana.rac.alert.id': '???', - 'kibana.rac.alert.uuid': v4(), - '@timestamp': new Date().toISOString(), - }; - }; - - /* eslint-disable @typescript-eslint/no-explicit-any */ - let alerts: any[] = []; - if (response.hits.sequences !== undefined) { - alerts = response.hits.sequences.reduce((allAlerts: any[], sequence) => { - let previousAlertUuid: string | undefined; - return [ - ...allAlerts, - ...sequence.events.map((event, idx) => { - const alert = { - ...buildSignalFromEvent(event), - 'kibana.rac.alert.ancestors': previousAlertUuid != null ? [previousAlertUuid] : [], - 'kibana.rac.alert.building_block_type': 'default', - 'kibana.rac.alert.depth': idx, - }; - previousAlertUuid = alert['kibana.rac.alert.uuid']; - return alert; - }), - ]; - }, []); - } else if (response.hits.events !== undefined) { - alerts = response.hits.events.map((event) => { - return buildSignalFromEvent(event); - }, []); - } else { - throw new Error( - 'eql query response should have either `sequences` or `events` but had neither' - ); - } - - if (alerts.length > 0) { - alertWithPersistence(alerts).forEach((alert) => { - alert.scheduleActions('default', { server: 'server-test' }); - }); - } - - return { - lastChecked: new Date(), - }; - }, - }); -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts deleted file mode 100644 index c07d0436cc90d02..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/* - -import { schema } from '@kbn/config-schema'; -import { KibanaRequest, Logger } from 'src/core/server'; -import { SavedObject } from 'src/core/types'; - -import { buildEsQuery, IIndexPattern } from '../../../../../../../src/plugins/data/common'; - -import { createPersistenceRuleTypeFactory } from '../../../../../rule_registry/server'; -import { ML_ALERT_TYPE_ID } from '../../../../common/constants'; -import { SecurityRuleRegistry } from '../../../plugin'; - -const createSecurityMlRuleType = createPersistenceRuleTypeFactory(); - -import { - AlertInstanceContext, - AlertInstanceState, - AlertServices, -} from '../../../../../alerting/server'; -import { ListClient } from '../../../../../lists/server'; -import { isJobStarted } from '../../../../common/machine_learning/helpers'; -import { ExceptionListItemSchema } from '../../../../common/shared_imports'; -import { SetupPlugins } from '../../../plugin'; -import { RefreshTypes } from '../types'; -import { bulkCreateMlSignals } from '../signals/bulk_create_ml_signals'; -import { filterEventsAgainstList } from '../signals/filters/filter_events_against_list'; -import { findMlSignals } from '../signals/find_ml_signals'; -import { BuildRuleMessage } from '../signals/rule_messages'; -import { RuleStatusService } from '../signals/rule_status_service'; -import { MachineLearningRuleAttributes } from '../signals/types'; -import { createErrorsFromShard, createSearchAfterReturnType, mergeReturns } from '../signals/utils'; - -export const mlAlertType = createSecurityMlRuleType({ - id: ML_ALERT_TYPE_ID, - name: 'Machine Learning Rule', - validate: { - params: schema.object({ - indexPatterns: schema.arrayOf(schema.string()), - customQuery: schema.string(), - }), - }, - actionGroups: [ - { - id: 'default', - name: 'Default', - }, - ], - defaultActionGroupId: 'default', - actionVariables: { - context: [{ name: 'server', description: 'the server' }], - }, - minimumLicenseRequired: 'basic', - producer: 'security-solution', - async executor({ - services: { alertWithPersistence, findAlerts }, - params: { indexPatterns, customQuery }, - }) { - return { - lastChecked: new Date(), - }; - }, -}); -*/ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.test.ts deleted file mode 100644 index e8c45e9ab705682..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { v4 } from 'uuid'; - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; - -import { sampleDocNoSortId } from '../signals/__mocks__/es_results'; - -import { createQueryAlertType } from './query'; -import { createRuleTypeMocks } from './__mocks__/rule_type'; - -describe('Custom query alerts', () => { - it('does not send an alert when no events found', async () => { - const { services, dependencies, executor } = createRuleTypeMocks(); - const queryAlertType = createQueryAlertType(dependencies.ruleDataClient, dependencies.logger); - - dependencies.alerting.registerType(queryAlertType); - - const params = { - customQuery: 'dne:42', - indexPatterns: ['*'], - }; - - services.scopedClusterClient.asCurrentUser.search.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise({ - hits: { - hits: [], - sequences: [], - events: [], - total: { - relation: 'eq', - value: 0, - }, - }, - took: 0, - timed_out: false, - _shards: { - failed: 0, - skipped: 0, - successful: 1, - total: 1, - }, - }) - ); - - await executor({ params }); - expect(services.alertInstanceFactory).not.toBeCalled(); - }); - - it('sends a properly formatted alert when events are found', async () => { - const { services, dependencies, executor } = createRuleTypeMocks(); - const queryAlertType = createQueryAlertType(dependencies.ruleDataClient, dependencies.logger); - - dependencies.alerting.registerType(queryAlertType); - - const params = { - customQuery: '*:*', - indexPatterns: ['*'], - }; - - services.scopedClusterClient.asCurrentUser.search.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise({ - hits: { - hits: [sampleDocNoSortId(v4()), sampleDocNoSortId(v4()), sampleDocNoSortId(v4())], - total: { - relation: 'eq', - value: 3, - }, - }, - took: 0, - timed_out: false, - _shards: { - failed: 0, - skipped: 0, - successful: 1, - total: 1, - }, - }) - ); - - await executor({ params }); - expect(services.alertInstanceFactory).toBeCalled(); - /* - expect(services.alertWithPersistence).toBeCalledWith( - expect.arrayContaining([ - expect.objectContaining({ - 'event.kind': 'signal', - }), - ]) - ); - */ - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts deleted file mode 100644 index 3911dcabc34de8d..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { QueryContainer } from '@elastic/elasticsearch/api/types'; -import { schema } from '@kbn/config-schema'; -import { Logger } from '@kbn/logging'; -import { ESSearchRequest } from 'typings/elasticsearch'; - -import { buildEsQuery, IIndexPattern } from '../../../../../../../src/plugins/data/common'; - -import { - RuleDataClient, - createPersistenceRuleTypeFactory, -} from '../../../../../rule_registry/server'; -import { CUSTOM_ALERT_TYPE_ID } from '../../../../common/constants'; - -export const createQueryAlertType = (ruleDataClient: RuleDataClient, logger: Logger) => { - const createPersistenceRuleType = createPersistenceRuleTypeFactory({ - ruleDataClient, - logger, - }); - return createPersistenceRuleType({ - id: CUSTOM_ALERT_TYPE_ID, - name: 'Custom Query Rule', - validate: { - params: schema.object({ - indexPatterns: schema.arrayOf(schema.string()), - customQuery: schema.string(), - }), - }, - actionGroups: [ - { - id: 'default', - name: 'Default', - }, - ], - defaultActionGroupId: 'default', - actionVariables: { - context: [{ name: 'server', description: 'the server' }], - }, - minimumLicenseRequired: 'basic', - producer: 'security-solution', - async executor({ - services: { alertWithPersistence, findAlerts }, - params: { indexPatterns, customQuery }, - }) { - try { - const indexPattern: IIndexPattern = { - fields: [], - title: indexPatterns.join(), - }; - - // TODO: kql or lucene? - - const esQuery = buildEsQuery( - indexPattern, - { query: customQuery, language: 'kuery' }, - [] - ) as QueryContainer; - const query: ESSearchRequest = { - body: { - query: esQuery, - fields: ['*'], - sort: { - '@timestamp': 'asc' as const, - }, - }, - }; - - const alerts = await findAlerts(query); - // console.log('alerts', alerts); - alertWithPersistence(alerts).forEach((alert) => { - alert.scheduleActions('default', { server: 'server-test' }); - }); - - return { - lastChecked: new Date(), - }; - } catch (error) { - logger.error(error); - } - }, - }); -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_eql.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_eql.sh deleted file mode 100755 index 25e247a08ef46dc..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_eql.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -# or more contributor license agreements. Licensed under the Elastic License -# 2.0; you may not use this file except in compliance with the Elastic License -# 2.0. -# - -curl -X POST http://localhost:5601/${BASE_PATH}/api/alerts/alert \ - -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -H 'kbn-xsrf: true' \ - -H 'Content-Type: application/json' \ - --verbose \ - -d ' -{ - "params":{ - "indexPatterns": ["*"], - "eqlQuery": "sequence by host.name↵[any where true]↵[any where true]↵[any where true]" - }, - "consumer":"alerts", - "alertTypeId":"siem.eqlRule", - "schedule":{ - "interval":"1m" - }, - "actions":[], - "tags":[ - "eql", - "persistence" - ], - "notifyWhen":"onActionGroupChange", - "name":"Basic EQL rule" -}' - - diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_query.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_query.sh deleted file mode 100755 index c34af7dee4044de..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_query.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -# or more contributor license agreements. Licensed under the Elastic License -# 2.0; you may not use this file except in compliance with the Elastic License -# 2.0. -# - -curl -X POST http://localhost:5601/${BASE_PATH}/api/alerts/alert \ - -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -H 'kbn-xsrf: true' \ - -H 'Content-Type: application/json' \ - --verbose \ - -d ' -{ - "params":{ - "indexPatterns": ["*"], - "customQuery": "*:*" - }, - "consumer":"alerts", - "alertTypeId":"siem.customRule", - "schedule":{ - "interval":"1m" - }, - "actions":[], - "tags":[ - "custom", - "persistence" - ], - "notifyWhen":"onActionGroupChange", - "name":"Basic custom query rule" -}' - - diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_threshold.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_threshold.sh deleted file mode 100755 index 8b486b165c34b36..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_threshold.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -# -# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -# or more contributor license agreements. Licensed under the Elastic License -# 2.0; you may not use this file except in compliance with the Elastic License -# 2.0. -# - -curl -X POST http://localhost:5601/${BASE_PATH}/api/alerts/alert \ - -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -H 'kbn-xsrf: true' \ - -H 'Content-Type: application/json' \ - --verbose \ - -d ' -{ - "params":{ - "indexPatterns": ["*"], - "customQuery": "*:*", - "thresholdFields": ["source.ip", "destination.ip"], - "thresholdValue": 50, - "thresholdCardinality": [] - }, - "consumer":"alerts", - "alertTypeId":"siem.thresholdRule", - "schedule":{ - "interval":"1m" - }, - "actions":[], - "tags":[ - "persistence", - "threshold" - ], - "notifyWhen":"onActionGroupChange", - "name":"Basic Threshold rule" -}' - - diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.test.ts deleted file mode 100644 index 36e53b8154e70f9..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.test.ts +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; - -import { createRuleTypeMocks } from './__mocks__/rule_type'; -import { mockThresholdResults } from './__mocks__/threshold'; -import { createThresholdAlertType } from './threshold'; - -describe('Threshold alerts', () => { - it('does not send an alert when threshold is not met', async () => { - const { services, dependencies, executor } = createRuleTypeMocks(); - const thresholdAlertType = createThresholdAlertType( - dependencies.ruleDataClient, - dependencies.logger - ); - - dependencies.alerting.registerType(thresholdAlertType); - - const params = { - indexPatterns: ['*'], - customQuery: '*:*', - thresholdFields: ['source.ip', 'host.name'], - thresholdValue: 4, - }; - - services.scopedClusterClient.asCurrentUser.search.mockReturnValue( - elasticsearchClientMock.createSuccessTransportRequestPromise({ - hits: { - hits: [], - sequences: [], - events: [], - total: { - relation: 'eq', - value: 0, - }, - }, - aggregations: { - 'threshold_0:source.ip': { - buckets: [], - }, - }, - took: 0, - timed_out: false, - _shards: { - failed: 0, - skipped: 0, - successful: 1, - total: 1, - }, - }) - ); - - await executor({ params }); - expect(services.alertInstanceFactory).not.toBeCalled(); - }); - - it('sends a properly formatted alert when threshold is met', async () => { - const { services, dependencies, executor } = createRuleTypeMocks(); - const thresholdAlertType = createThresholdAlertType( - dependencies.ruleDataClient, - dependencies.logger - ); - - dependencies.alerting.registerType(thresholdAlertType); - - const params = { - indexPatterns: ['*'], - customQuery: '*:*', - thresholdFields: ['source.ip', 'host.name'], - thresholdValue: 4, - }; - - services.scopedClusterClient.asCurrentUser.search - .mockReturnValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise({ - hits: { - hits: [], - total: { - relation: 'eq', - value: 0, - }, - }, - took: 0, - timed_out: false, - _shards: { - failed: 0, - skipped: 0, - successful: 1, - total: 1, - }, - }) - ) - .mockReturnValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise({ - hits: { - hits: [], - total: { - relation: 'eq', - value: 0, - }, - }, - aggregations: mockThresholdResults.rawResponse.body.aggregations, - took: 0, - timed_out: false, - _shards: { - failed: 0, - skipped: 0, - successful: 1, - total: 1, - }, - }) - ); - - await executor({ params }); - expect(services.alertInstanceFactory).toBeCalled(); - /* - expect(services.alertWithPersistence).toBeCalledWith( - expect.arrayContaining([ - expect.objectContaining({ - 'event.kind': 'signal', - }), - ]) - ); - */ - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts deleted file mode 100644 index d4721e8bab11dc4..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import moment from 'moment'; -import v4 from 'uuid/v4'; - -import { schema } from '@kbn/config-schema'; -import { Logger } from '@kbn/logging'; - -import { AlertServices } from '../../../../../alerting/server'; -import { - RuleDataClient, - createPersistenceRuleTypeFactory, -} from '../../../../../rule_registry/server'; -import { THRESHOLD_ALERT_TYPE_ID } from '../../../../common/constants'; -import { SignalSearchResponse, ThresholdSignalHistory } from '../signals/types'; -import { - findThresholdSignals, - getThresholdBucketFilters, - getThresholdSignalHistory, - transformThresholdResultsToEcs, -} from '../signals/threshold'; -import { getFilter } from '../signals/get_filter'; -import { BuildRuleMessage } from '../signals/rule_messages'; - -interface RuleParams { - indexPatterns: string[]; - customQuery: string; - thresholdFields: string[]; - thresholdValue: number; - thresholdCardinality: Array<{ - field: string; - value: number; - }>; -} - -interface BulkCreateThresholdSignalParams { - results: SignalSearchResponse; - ruleParams: RuleParams; - services: AlertServices & { logger: Logger }; - inputIndexPattern: string[]; - ruleId: string; - startedAt: Date; - from: Date; - thresholdSignalHistory: ThresholdSignalHistory; - buildRuleMessage: BuildRuleMessage; -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const formatThresholdSignals = (params: BulkCreateThresholdSignalParams): any[] => { - const thresholdResults = params.results; - const threshold = { - field: params.ruleParams.thresholdFields, - value: params.ruleParams.thresholdValue, - }; - const results = transformThresholdResultsToEcs( - thresholdResults, - params.ruleParams.indexPatterns.join(','), - params.startedAt, - params.from, - undefined, - params.services.logger, - threshold, - params.ruleId, - undefined, - params.thresholdSignalHistory - ); - return results.hits.hits.map((hit) => { - return { - ...hit, - 'event.kind': 'signal', - 'kibana.rac.alert.id': '???', - 'kibana.rac.alert.uuid': v4(), - '@timestamp': new Date().toISOString(), - }; - }); -}; - -export const createThresholdAlertType = (ruleDataClient: RuleDataClient, logger: Logger) => { - const createPersistenceRuleType = createPersistenceRuleTypeFactory({ - ruleDataClient, - logger, - }); - return createPersistenceRuleType({ - id: THRESHOLD_ALERT_TYPE_ID, - name: 'Threshold Rule', - validate: { - params: schema.object({ - indexPatterns: schema.arrayOf(schema.string()), - customQuery: schema.string(), - thresholdFields: schema.arrayOf(schema.string()), - thresholdValue: schema.number(), - thresholdCardinality: schema.arrayOf( - schema.object({ - field: schema.string(), - value: schema.number(), - }) - ), - }), - }, - actionGroups: [ - { - id: 'default', - name: 'Default', - }, - ], - defaultActionGroupId: 'default', - actionVariables: { - context: [{ name: 'server', description: 'the server' }], - }, - minimumLicenseRequired: 'basic', - producer: 'security-solution', - async executor({ startedAt, services, params, alertId }) { - const fromDate = moment(startedAt).subtract(moment.duration(5, 'm')); // hardcoded 5-minute rule interval - const from = fromDate.toISOString(); - const to = startedAt.toISOString(); - - // TODO: how to get the output index? - const outputIndex = ['.kibana-madi-8-alerts-security-solution-8.0.0-000001']; - const buildRuleMessage = (...messages: string[]) => messages.join(); - const timestampOverride = undefined; - - const { - thresholdSignalHistory, - searchErrors: previousSearchErrors, - } = await getThresholdSignalHistory({ - indexPattern: outputIndex, - from, - to, - services: (services as unknown) as AlertServices, - logger, - ruleId: alertId, - bucketByFields: params.thresholdFields, - timestampOverride, - buildRuleMessage, - }); - - const bucketFilters = await getThresholdBucketFilters({ - thresholdSignalHistory, - timestampOverride, - }); - - const esFilter = await getFilter({ - type: 'threshold', - filters: bucketFilters, - language: 'kuery', - query: params.customQuery, - savedId: undefined, - services: (services as unknown) as AlertServices, - index: params.indexPatterns, - lists: [], - }); - - const { - searchResult: thresholdResults, - searchErrors, - searchDuration: thresholdSearchDuration, - } = await findThresholdSignals({ - inputIndexPattern: params.indexPatterns, - from, - to, - services: (services as unknown) as AlertServices, - logger, - filter: esFilter, - threshold: { - field: params.thresholdFields, - value: params.thresholdValue, - cardinality: params.thresholdCardinality, - }, - timestampOverride, - buildRuleMessage, - }); - - logger.info(`Threshold search took ${thresholdSearchDuration}ms`); // TODO: rule status service - - const alerts = formatThresholdSignals({ - results: thresholdResults, - ruleParams: params, - services: (services as unknown) as AlertServices & { logger: Logger }, - inputIndexPattern: ['TODO'], - ruleId: alertId, - startedAt, - from: fromDate.toDate(), - thresholdSignalHistory, - buildRuleMessage, - }); - - const errors = searchErrors.concat(previousSearchErrors); - if (errors.length === 0) { - services.alertWithPersistence(alerts).forEach((alert) => { - alert.scheduleActions('default', { server: 'server-test' }); - }); - } else { - throw new Error(errors.join('\n')); - } - - return { - lastChecked: new Date(), - }; - }, - }); -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 857762dec45e944..433772510191765 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -491,72 +491,6 @@ export const getFindResultStatus = (): SavedObjectsFindResponse => ({ - page: 1, - per_page: 6, - total: 2, - saved_objects: [], - aggregations: { - alertIds: { - buckets: [ - { - key: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', - most_recent_statuses: { - hits: { - hits: [ - { - _source: { - 'siem-detection-engine-rule-status': { - alertId: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', - statusDate: '2020-02-18T15:26:49.783Z', - status: 'succeeded', - lastFailureAt: undefined, - lastSuccessAt: '2020-02-18T15:26:49.783Z', - lastFailureMessage: undefined, - lastSuccessMessage: 'succeeded', - lastLookBackDate: new Date('2020-02-18T15:14:58.806Z').toISOString(), - gap: '500.32', - searchAfterTimeDurations: ['200.00'], - bulkCreateTimeDurations: ['800.43'], - }, - }, - }, - ], - }, - }, - }, - { - key: '1ea5a820-4da1-4e82-92a1-2b43a7bece08', - most_recent_statuses: { - hits: { - hits: [ - { - _source: { - 'siem-detection-engine-rule-status': { - alertId: '1ea5a820-4da1-4e82-92a1-2b43a7bece08', - statusDate: '2020-02-18T15:15:58.806Z', - status: 'failed', - lastFailureAt: '2020-02-18T15:15:58.806Z', - lastSuccessAt: '2020-02-13T20:31:59.855Z', - lastFailureMessage: - 'Signal rule name: "Query with a rule id Number 1", id: "1ea5a820-4da1-4e82-92a1-2b43a7bece08", rule_id: "query-rule-id-1" has a time gap of 5 days (412682928ms), and could be missing signals within that time. Consider increasing your look behind time or adding more Kibana instances.', - lastSuccessMessage: 'succeeded', - lastLookBackDate: new Date('2020-02-18T15:14:58.806Z').toISOString(), - gap: '500.32', - searchAfterTimeDurations: ['200.00'], - bulkCreateTimeDurations: ['800.43'], - }, - }, - }, - ], - }, - }, - }, - ], - }, - }, -}); - export const getEmptySignalsResponse = (): SignalSearchResponse => ({ took: 1, timed_out: false, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts index 3527e43c03d52ba..6af4397a4193a60 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts @@ -6,17 +6,15 @@ */ import { transformError, getIndexExists } from '@kbn/securitysolution-es-utils'; -import { parseExperimentalConfigValue } from '../../../../../common/experimental_features'; -import { ConfigType } from '../../../../config'; import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DEFAULT_ALERTS_INDEX, DETECTION_ENGINE_INDEX_URL } from '../../../../../common/constants'; +import { DETECTION_ENGINE_INDEX_URL } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; import { SIGNALS_TEMPLATE_VERSION } from './get_signals_template'; import { getIndexVersion } from './get_index_version'; import { isOutdated } from '../../migrations/helpers'; -export const readIndexRoute = (router: SecuritySolutionPluginRouter, config: ConfigType) => { +export const readIndexRoute = (router: SecuritySolutionPluginRouter) => { router.get( { path: DETECTION_ENGINE_INDEX_URL, @@ -36,16 +34,8 @@ export const readIndexRoute = (router: SecuritySolutionPluginRouter, config: Con return siemResponse.error({ statusCode: 404 }); } - // TODO: Once we are past experimental phase this code should be removed - const { ruleRegistryEnabled } = parseExperimentalConfigValue(config.enableExperimental); - if (ruleRegistryEnabled) { - return response.ok({ - body: { name: DEFAULT_ALERTS_INDEX, index_mapping_outdated: false }, - }); - } - const index = siemClient.getSignalsIndex(); - const indexExists = ruleRegistryEnabled ? true : await getIndexExists(esClient, index); + const indexExists = await getIndexExists(esClient, index); if (indexExists) { let mappingOutdated: boolean | null = null; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts index 993d9300e414f46..9b7e7bb42f42364 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts @@ -6,7 +6,6 @@ */ import { transformError, getIndexExists } from '@kbn/securitysolution-es-utils'; -import { RuleDataClient } from '../../../../../../rule_registry/server'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { SetupPlugins } from '../../../../plugin'; @@ -25,8 +24,7 @@ import { convertCreateAPIToInternalSchema } from '../../schemas/rule_converters' export const createRulesRoute = ( router: SecuritySolutionPluginRouter, - ml: SetupPlugins['ml'], - ruleDataClient?: RuleDataClient | null + ml: SetupPlugins['ml'] ): void => { router.post( { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts index 4b05f603b85b7c8..76fb9ac0c77e33b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts @@ -6,7 +6,6 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { RuleDataClient } from '../../../../../../rule_registry/server'; import { queryRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/query_rules_type_dependents'; import { queryRulesSchema, @@ -23,10 +22,7 @@ import { deleteNotifications } from '../../notifications/delete_notifications'; import { deleteRuleActionsSavedObject } from '../../rule_actions/delete_rule_actions_saved_object'; import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client'; -export const deleteRulesRoute = ( - router: SecuritySolutionPluginRouter, - ruleDataClient?: RuleDataClient | null -) => { +export const deleteRulesRoute = (router: SecuritySolutionPluginRouter) => { router.delete( { path: DETECTION_ENGINE_RULES_URL, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts index 06f3ca83c4722af..434ef0f88b19699 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts @@ -10,7 +10,7 @@ import { getAlertMock, getFindRequest, getFindResultWithSingleHit, - getFindBulkResultStatus, + getFindResultStatus, } from '../__mocks__/request_responses'; import { requestContextMock, serverMock, requestMock } from '../__mocks__'; import { findRulesRoute } from './find_rules_route'; @@ -27,7 +27,7 @@ describe('find_rules', () => { clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); clients.alertsClient.get.mockResolvedValue(getAlertMock(getQueryRuleParams())); - clients.savedObjectsClient.find.mockResolvedValue(getFindBulkResultStatus()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); findRulesRoute(server.router); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts index 428978fe1d82076..ccf0a59e87c7494 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts @@ -6,7 +6,6 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { RuleDataClient } from '../../../../../../rule_registry/server'; import { findRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/find_rules_type_dependents'; import { findRulesSchema, @@ -16,15 +15,13 @@ import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { findRules } from '../../rules/find_rules'; import { buildSiemResponse } from '../utils'; + +import { getRuleActionsSavedObject } from '../../rule_actions/get_rule_actions_saved_object'; import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; import { transformFindAlerts } from './utils'; -import { getBulkRuleActionsSavedObject } from '../../rule_actions/get_bulk_rule_actions_saved_object'; -export const findRulesRoute = ( - router: SecuritySolutionPluginRouter, - ruleDataClient?: RuleDataClient | null -) => { +export const findRulesRoute = (router: SecuritySolutionPluginRouter) => { router.get( { path: `${DETECTION_ENGINE_RULES_URL}/_find`, @@ -63,11 +60,44 @@ export const findRulesRoute = ( filter: query.filter, fields: query.fields, }); - const alertIds = rules.data.map((rule) => rule.id); - const [ruleStatuses, ruleActions] = await Promise.all([ - ruleStatusClient.findBulk(alertIds, 1), - getBulkRuleActionsSavedObject({ alertIds, savedObjectsClient }), - ]); + + // if any rules attempted to execute but failed before the rule executor is called, + // an execution status will be written directly onto the rule via the kibana alerting framework, + // which we are filtering on and will write a failure status + // for any rules found to be in a failing state into our rule status saved objects + const failingRules = rules.data.filter( + (rule) => rule.executionStatus != null && rule.executionStatus.status === 'error' + ); + + const ruleStatuses = await Promise.all( + rules.data.map(async (rule) => { + const results = await ruleStatusClient.find({ + perPage: 1, + sortField: 'statusDate', + sortOrder: 'desc', + search: rule.id, + searchFields: ['alertId'], + }); + const failingRule = failingRules.find((badRule) => badRule.id === rule.id); + if (failingRule != null) { + if (results.saved_objects.length > 0) { + results.saved_objects[0].attributes.status = 'failed'; + results.saved_objects[0].attributes.lastFailureAt = failingRule.executionStatus.lastExecutionDate.toISOString(); + } + } + return results; + }) + ); + const ruleActions = await Promise.all( + rules.data.map(async (rule) => { + const results = await getRuleActionsSavedObject({ + savedObjectsClient, + ruleAlertId: rule.id, + }); + + return results; + }) + ); const transformed = transformFindAlerts(rules, ruleActions, ruleStatuses); if (transformed == null) { return siemResponse.error({ statusCode: 500, body: 'Internal error transforming' }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts index 73f076649b72fe5..c3a53a1f393ec52 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts @@ -7,9 +7,9 @@ import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { + getFindResultStatus, ruleStatusRequest, getAlertMock, - getFindBulkResultStatus, } from '../__mocks__/request_responses'; import { serverMock, requestContextMock, requestMock } from '../__mocks__'; import { findRulesStatusesRoute } from './find_rules_status_route'; @@ -26,7 +26,7 @@ describe('find_statuses', () => { beforeEach(async () => { server = serverMock.create(); ({ clients, context } = requestContextMock.createTools()); - clients.savedObjectsClient.find.mockResolvedValue(getFindBulkResultStatus()); // successful status search + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); // successful status search clients.alertsClient.get.mockResolvedValue(getAlertMock(getQueryRuleParams())); findRulesStatusesRoute(server.router); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.ts index aed8b80e4f13320..bd6e8fc9e7aadb0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.ts @@ -9,13 +9,14 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; +import { RuleStatusResponse } from '../../rules/types'; import { buildSiemResponse, mergeStatuses, getFailingRules } from '../utils'; + import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client'; import { findRulesStatusesSchema, FindRulesStatusesSchemaDecoded, } from '../../../../../common/detection_engine/schemas/request/find_rule_statuses_schema'; -import { mergeAlertWithSidecarStatus } from '../../schemas/rule_converters'; /** * Given a list of rule ids, return the current status and @@ -50,27 +51,45 @@ export const findRulesStatusesRoute = (router: SecuritySolutionPluginRouter) => const ids = body.ids; try { const ruleStatusClient = ruleStatusSavedObjectsClientFactory(savedObjectsClient); - const [statusesById, failingRules] = await Promise.all([ - ruleStatusClient.findBulk(ids, 6), - getFailingRules(ids, alertsClient), - ]); + const failingRules = await getFailingRules(ids, alertsClient); - const statuses = ids.reduce((acc, id) => { - const lastFiveErrorsForId = statusesById[id]; + const statuses = await ids.reduce(async (acc, id) => { + const accumulated = await acc; + const lastFiveErrorsForId = await ruleStatusClient.find({ + perPage: 6, + sortField: 'statusDate', + sortOrder: 'desc', + search: id, + searchFields: ['alertId'], + }); - if (lastFiveErrorsForId == null || lastFiveErrorsForId.length === 0) { - return acc; + if (lastFiveErrorsForId.saved_objects.length === 0) { + return accumulated; } const failingRule = failingRules[id]; + const lastFailureAt = lastFiveErrorsForId.saved_objects[0].attributes.lastFailureAt; + + if ( + failingRule != null && + (lastFailureAt == null || + new Date(failingRule.executionStatus.lastExecutionDate) > new Date(lastFailureAt)) + ) { + const currentStatus = lastFiveErrorsForId.saved_objects[0]; + currentStatus.attributes.lastFailureMessage = `Reason: ${failingRule.executionStatus.error?.reason} Message: ${failingRule.executionStatus.error?.message}`; + currentStatus.attributes.lastFailureAt = failingRule.executionStatus.lastExecutionDate.toISOString(); + currentStatus.attributes.statusDate = failingRule.executionStatus.lastExecutionDate.toISOString(); + currentStatus.attributes.status = 'failed'; + const updatedLastFiveErrorsSO = [ + currentStatus, + ...lastFiveErrorsForId.saved_objects.slice(1), + ]; - if (failingRule != null) { - const currentStatus = mergeAlertWithSidecarStatus(failingRule, lastFiveErrorsForId[0]); - const updatedLastFiveErrorsSO = [currentStatus, ...lastFiveErrorsForId.slice(1)]; - return mergeStatuses(id, updatedLastFiveErrorsSO, acc); + return mergeStatuses(id, updatedLastFiveErrorsSO, accumulated); } - return mergeStatuses(id, [...lastFiveErrorsForId], acc); - }, {}); + return mergeStatuses(id, [...lastFiveErrorsForId.saved_objects], accumulated); + }, Promise.resolve({})); + return response.ok({ body: statuses }); } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts index eaaa44fcf19160d..780c248183ab96b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts @@ -6,7 +6,6 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { RuleDataClient } from '../../../../../../rule_registry/server'; import { RuleAlertAction } from '../../../../../common/detection_engine/types'; import { patchRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/patch_rules_type_dependents'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; @@ -29,11 +28,7 @@ import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_s import { readRules } from '../../rules/read_rules'; import { PartialFilter } from '../../types'; -export const patchRulesRoute = ( - router: SecuritySolutionPluginRouter, - ml: SetupPlugins['ml'], - ruleDataClient?: RuleDataClient | null -) => { +export const patchRulesRoute = (router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml']) => { router.patch( { path: DETECTION_ENGINE_RULES_URL, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts index 917da6c9708d54e..ac45e5d2ed3b207 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts @@ -6,7 +6,6 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { RuleDataClient } from '../../../../../../rule_registry/server'; import { queryRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/query_rules_type_dependents'; import { queryRulesSchema, @@ -22,10 +21,7 @@ import { readRules } from '../../rules/read_rules'; import { getRuleActionsSavedObject } from '../../rule_actions/get_rule_actions_saved_object'; import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client'; -export const readRulesRoute = ( - router: SecuritySolutionPluginRouter, - ruleDataClient?: RuleDataClient | null -) => { +export const readRulesRoute = (router: SecuritySolutionPluginRouter) => { router.get( { path: DETECTION_ENGINE_RULES_URL, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts index 0ff6cb3cd2d0f04..aad0068758f7dcb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -6,7 +6,6 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { RuleDataClient } from '../../../../../../rule_registry/server'; import { updateRulesSchema } from '../../../../../common/detection_engine/schemas/request'; import { updateRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/update_rules_type_dependents'; import type { SecuritySolutionPluginRouter } from '../../../../types'; @@ -23,11 +22,7 @@ import { updateRulesNotifications } from '../../rules/update_rules_notifications import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -export const updateRulesRoute = ( - router: SecuritySolutionPluginRouter, - ml: SetupPlugins['ml'], - ruleDataClient?: RuleDataClient | null -) => { +export const updateRulesRoute = (router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml']) => { router.put( { path: DETECTION_ENGINE_RULES_URL, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts index 29e322d7fcab5fa..f2788ab1bd4c99f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts @@ -27,6 +27,7 @@ import { PartialFilter } from '../../types'; import { BulkError, ImportSuccessError } from '../utils'; import { getOutputRuleAlertForRest } from '../__mocks__/utils'; import { PartialAlert } from '../../../../../../alerting/server'; +import { SanitizedAlert } from '../../../../../../alerting/server/types'; import { createRulesStreamFromNdJson } from '../../rules/create_rules_stream_from_ndjson'; import { RuleAlertType } from '../../rules/types'; import { ImportRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/import_rules_schema'; @@ -255,7 +256,7 @@ describe('utils', () => { describe('transformFindAlerts', () => { test('outputs empty data set when data set is empty correct', () => { - const output = transformFindAlerts({ data: [], page: 1, perPage: 0, total: 0 }, {}, {}); + const output = transformFindAlerts({ data: [], page: 1, perPage: 0, total: 0 }, []); expect(output).toEqual({ data: [], page: 1, perPage: 0, total: 0 }); }); @@ -267,8 +268,7 @@ describe('utils', () => { total: 0, data: [getAlertMock(getQueryRuleParams())], }, - {}, - {} + [] ); const expected = getOutputRuleAlertForRest(); expect(output).toEqual({ @@ -278,6 +278,20 @@ describe('utils', () => { data: [expected], }); }); + + test('returns 500 if the data is not of type siem alert', () => { + const unsafeCast = ([{ name: 'something else' }] as unknown) as SanitizedAlert[]; + const output = transformFindAlerts( + { + data: unsafeCast, + page: 1, + perPage: 1, + total: 1, + }, + [] + ); + expect(output).toBeNull(); + }); }); describe('transform', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts index dc0cd2e497215f4..466b8dd1842276f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts @@ -6,7 +6,7 @@ */ import { countBy } from 'lodash/fp'; -import { SavedObject } from 'kibana/server'; +import { SavedObject, SavedObjectsFindResponse } from 'kibana/server'; import uuid from 'uuid'; import { RulesSchema } from '../../../../../common/detection_engine/schemas/response/rules_schema'; @@ -17,10 +17,11 @@ import { INTERNAL_IDENTIFIER } from '../../../../../common/constants'; import { RuleAlertType, isAlertType, + isAlertTypes, IRuleSavedAttributesSavedObjectAttributes, isRuleStatusFindType, + isRuleStatusFindTypes, isRuleStatusSavedObjectType, - IRuleStatusSOAttributes, } from '../../rules/types'; import { createBulkErrorObject, @@ -33,7 +34,6 @@ import { import { RuleActions } from '../../rule_actions/types'; import { internalRuleToAPIResponse } from '../../schemas/rule_converters'; import { RuleParams } from '../../schemas/rule_schemas'; -import { SanitizedAlert } from '../../../../../../alerting/common'; type PromiseFromStreams = ImportRulesSchemaDecoded | Error; @@ -103,11 +103,11 @@ export const transformTags = (tags: string[]): string[] => { // Transforms the data but will remove any null or undefined it encounters and not include // those on the export export const transformAlertToRule = ( - alert: SanitizedAlert, + alert: RuleAlertType, ruleActions?: RuleActions | null, ruleStatus?: SavedObject ): Partial => { - return internalRuleToAPIResponse(alert, ruleActions, ruleStatus?.attributes); + return internalRuleToAPIResponse(alert, ruleActions, ruleStatus); }; export const transformAlertsToRules = (alerts: RuleAlertType[]): Array> => { @@ -116,24 +116,33 @@ export const transformAlertsToRules = (alerts: RuleAlertType[]): Array, - ruleActions: { [key: string]: RuleActions | undefined }, - ruleStatuses: { [key: string]: IRuleStatusSOAttributes[] | undefined } + ruleActions: Array, + ruleStatuses?: Array> ): { page: number; perPage: number; total: number; data: Array>; } | null => { - return { - page: findResults.page, - perPage: findResults.perPage, - total: findResults.total, - data: findResults.data.map((alert) => { - const statuses = ruleStatuses[alert.id]; - const status = statuses ? statuses[0] : undefined; - return internalRuleToAPIResponse(alert, ruleActions[alert.id], status); - }), - }; + if (!ruleStatuses && isAlertTypes(findResults.data)) { + return { + page: findResults.page, + perPage: findResults.perPage, + total: findResults.total, + data: findResults.data.map((alert, idx) => transformAlertToRule(alert, ruleActions[idx])), + }; + } else if (isAlertTypes(findResults.data) && isRuleStatusFindTypes(ruleStatuses)) { + return { + page: findResults.page, + perPage: findResults.perPage, + total: findResults.total, + data: findResults.data.map((alert, idx) => + transformAlertToRule(alert, ruleActions[idx], ruleStatuses[idx].saved_objects[0]) + ), + }; + } else { + return null; + } }; export const transform = ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts index d6b998e3142349f..909c94f145528cc 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts @@ -14,7 +14,7 @@ import { getSignalsAggsAndQueryRequest, getEmptySignalsResponse, } from '../__mocks__/request_responses'; -import { requestContextMock, serverMock, requestMock, createMockConfig } from '../__mocks__'; +import { requestContextMock, serverMock, requestMock } from '../__mocks__'; import { querySignalsRoute } from './query_signals_route'; describe('query for signal', () => { @@ -27,7 +27,7 @@ describe('query for signal', () => { clients.clusterClient.callAsCurrentUser.mockResolvedValue(getEmptySignalsResponse()); - querySignalsRoute(server.router, createMockConfig()); + querySignalsRoute(server.router); }); describe('query and agg on signals index', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts index 770c1a5da344f6f..91172a277bf54a0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts @@ -6,13 +6,8 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; -import { parseExperimentalConfigValue } from '../../../../../common/experimental_features'; -import { ConfigType } from '../../../../config'; import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { - DEFAULT_ALERTS_INDEX, - DETECTION_ENGINE_QUERY_SIGNALS_URL, -} from '../../../../../common/constants'; +import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; @@ -21,7 +16,7 @@ import { QuerySignalsSchemaDecoded, } from '../../../../../common/detection_engine/schemas/request/query_signals_index_schema'; -export const querySignalsRoute = (router: SecuritySolutionPluginRouter, config: ConfigType) => { +export const querySignalsRoute = (router: SecuritySolutionPluginRouter) => { router.post( { path: DETECTION_ENGINE_QUERY_SIGNALS_URL, @@ -53,12 +48,9 @@ export const querySignalsRoute = (router: SecuritySolutionPluginRouter, config: const clusterClient = context.core.elasticsearch.legacy.client; const siemClient = context.securitySolution!.getAppClient(); - // TODO: Once we are past experimental phase this code should be removed - const { ruleRegistryEnabled } = parseExperimentalConfigValue(config.enableExperimental); - try { const result = await clusterClient.callAsCurrentUser('search', { - index: ruleRegistryEnabled ? DEFAULT_ALERTS_INDEX : siemClient.getSignalsIndex(), + index: siemClient.getSignalsIndex(), body: { query, aggs, _source, track_total_hits, size }, ignoreUnavailable: true, }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts index ce7d4b31733700c..a09c4cd257618d6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts @@ -25,7 +25,7 @@ import { getFailingRules, } from './utils'; import { responseMock } from './__mocks__'; -import { exampleRuleStatus } from '../signals/__mocks__/es_results'; +import { exampleRuleStatus, exampleFindRuleStatusResponse } from '../signals/__mocks__/es_results'; import { getAlertMock } from './__mocks__/request_responses'; import { AlertExecutionStatusErrorReasons } from '../../../../../alerting/common'; import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; @@ -301,8 +301,8 @@ describe('utils', () => { const statusTwo = exampleRuleStatus(); statusTwo.attributes.status = 'failed'; const currentStatus = exampleRuleStatus(); - const foundRules = [currentStatus.attributes, statusOne.attributes, statusTwo.attributes]; - const res = mergeStatuses(currentStatus.attributes.alertId, foundRules, { + const foundRules = exampleFindRuleStatusResponse([currentStatus, statusOne, statusTwo]); + const res = mergeStatuses(currentStatus.attributes.alertId, foundRules.saved_objects, { 'myfakealertid-8cfac': { current_status: { alert_id: 'myfakealertid-8cfac', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts index 9ff75726322a17b..130084da21591bf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts @@ -14,12 +14,11 @@ import { RouteValidationFunction, KibanaResponseFactory, CustomHttpResponseOptions, + SavedObjectsFindResult, } from '../../../../../../../src/core/server'; import { AlertsClient } from '../../../../../alerting/server'; import { RuleStatusResponse, IRuleStatusSOAttributes } from '../rules/types'; -import { RuleParams } from '../schemas/rule_schemas'; - export interface OutputError { message: string; statusCode: number; @@ -278,7 +277,7 @@ export const convertToSnakeCase = >( */ export const mergeStatuses = ( id: string, - currentStatusAndFailures: IRuleStatusSOAttributes[], + currentStatusAndFailures: Array>, acc: RuleStatusResponse ): RuleStatusResponse => { if (currentStatusAndFailures.length === 0) { @@ -287,7 +286,7 @@ export const mergeStatuses = ( }; } const convertedCurrentStatus = convertToSnakeCase( - currentStatusAndFailures[0] + currentStatusAndFailures[0].attributes ); return { ...acc, @@ -295,12 +294,12 @@ export const mergeStatuses = ( current_status: convertedCurrentStatus, failures: currentStatusAndFailures .slice(1) - .map((errorItem) => convertToSnakeCase(errorItem)), + .map((errorItem) => convertToSnakeCase(errorItem.attributes)), }, } as RuleStatusResponse; }; -export type GetFailingRulesResult = Record>; +export type GetFailingRulesResult = Record; export const getFailingRules = async ( ids: string[], @@ -317,11 +316,13 @@ export const getFailingRules = async ( return errorRules .filter((rule) => rule.executionStatus.status === 'error') .reduce((acc, failingRule) => { + const accum = acc; + const theRule = failingRule; return { - [failingRule.id]: { - ...failingRule, + [theRule.id]: { + ...theRule, }, - ...acc, + ...accum, }; }, {}); } catch (exc) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/get_bulk_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/get_bulk_rule_actions_saved_object.ts deleted file mode 100644 index 1abb16ba4612c1d..000000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/get_bulk_rule_actions_saved_object.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { AlertServices } from '../../../../../alerting/server'; -import { ruleActionsSavedObjectType } from './saved_object_mappings'; -import { IRuleActionsAttributesSavedObjectAttributes } from './types'; -import { getRuleActionsFromSavedObject } from './utils'; -import { RulesActionsSavedObject } from './get_rule_actions_saved_object'; -import { buildChunkedOrFilter } from '../signals/utils'; - -interface GetBulkRuleActionsSavedObject { - alertIds: string[]; - savedObjectsClient: AlertServices['savedObjectsClient']; -} - -export const getBulkRuleActionsSavedObject = async ({ - alertIds, - savedObjectsClient, -}: GetBulkRuleActionsSavedObject): Promise> => { - const filter = buildChunkedOrFilter( - `${ruleActionsSavedObjectType}.attributes.ruleAlertId`, - alertIds - ); - const { - // eslint-disable-next-line @typescript-eslint/naming-convention - saved_objects, - } = await savedObjectsClient.find({ - type: ruleActionsSavedObjectType, - perPage: 10000, - filter, - }); - return saved_objects.reduce((acc: { [key: string]: RulesActionsSavedObject }, savedObject) => { - acc[savedObject.attributes.ruleAlertId] = getRuleActionsFromSavedObject(savedObject); - return acc; - }, {}); -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts index 601f3ebaa0f9e65..380eb085e0d5a80 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts @@ -211,6 +211,12 @@ export const isRuleStatusFindType = ( return get('saved_objects', obj) != null; }; +export const isRuleStatusFindTypes = ( + obj: unknown[] | undefined +): obj is Array> => { + return obj ? obj.every((ruleStatus) => isRuleStatusFindType(ruleStatus)) : false; +}; + export interface CreateRulesOptions { alertsClient: AlertsClient; anomalyThreshold: AnomalyThresholdOrUndefined; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts index a215da021d15ad7..ee7ecaadfd95c02 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts @@ -6,6 +6,7 @@ */ import uuid from 'uuid'; +import { SavedObject } from 'kibana/server'; import { normalizeMachineLearningJobIds, normalizeThresholdObject, @@ -28,8 +29,8 @@ import { AppClient } from '../../../types'; import { addTags } from '../rules/add_tags'; import { DEFAULT_MAX_SIGNALS, SERVER_APP_ID, SIGNALS_ID } from '../../../../common/constants'; import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions'; -import { SanitizedAlert } from '../../../../../alerting/common'; -import { IRuleStatusSOAttributes } from '../rules/types'; +import { Alert } from '../../../../../alerting/common'; +import { IRuleSavedAttributesSavedObjectAttributes } from '../rules/types'; import { transformTags } from '../routes/rules/utils'; // These functions provide conversions from the request API schema to the internal rule schema and from the internal rule schema @@ -269,11 +270,10 @@ export const commonParamsCamelToSnake = (params: BaseRuleParams) => { }; export const internalRuleToAPIResponse = ( - rule: SanitizedAlert, + rule: Alert, ruleActions?: RuleActions | null, - ruleStatus?: IRuleStatusSOAttributes + ruleStatus?: SavedObject ): FullResponseSchema => { - const mergedStatus = ruleStatus ? mergeAlertWithSidecarStatus(rule, ruleStatus) : undefined; return { // Alerting framework params id: rule.id, @@ -293,30 +293,11 @@ export const internalRuleToAPIResponse = ( throttle: ruleActions?.ruleThrottle || 'no_actions', actions: ruleActions?.actions ?? [], // Rule status - status: mergedStatus?.status ?? undefined, - status_date: mergedStatus?.statusDate ?? undefined, - last_failure_at: mergedStatus?.lastFailureAt ?? undefined, - last_success_at: mergedStatus?.lastSuccessAt ?? undefined, - last_failure_message: mergedStatus?.lastFailureMessage ?? undefined, - last_success_message: mergedStatus?.lastSuccessMessage ?? undefined, + status: ruleStatus?.attributes.status ?? undefined, + status_date: ruleStatus?.attributes.statusDate ?? undefined, + last_failure_at: ruleStatus?.attributes.lastFailureAt ?? undefined, + last_success_at: ruleStatus?.attributes.lastSuccessAt ?? undefined, + last_failure_message: ruleStatus?.attributes.lastFailureMessage ?? undefined, + last_success_message: ruleStatus?.attributes.lastSuccessMessage ?? undefined, }; }; - -export const mergeAlertWithSidecarStatus = ( - alert: SanitizedAlert, - status: IRuleStatusSOAttributes -): IRuleStatusSOAttributes => { - if ( - new Date(alert.executionStatus.lastExecutionDate) > new Date(status.statusDate) && - alert.executionStatus.status === 'error' - ) { - return { - ...status, - lastFailureMessage: `Reason: ${alert.executionStatus.error?.reason} Message: ${alert.executionStatus.error?.message}`, - lastFailureAt: alert.executionStatus.lastExecutionDate.toISOString(), - statusDate: alert.executionStatus.lastExecutionDate.toISOString(), - status: 'failed', - }; - } - return status; -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/rule_status_saved_objects_client.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/rule_status_saved_objects_client.mock.ts index 3dd328a94993866..b760cec9226db08 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/rule_status_saved_objects_client.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/rule_status_saved_objects_client.mock.ts @@ -9,7 +9,6 @@ import { RuleStatusSavedObjectsClient } from '../rule_status_saved_objects_clien const createMockRuleStatusSavedObjectsClient = (): jest.Mocked => ({ find: jest.fn(), - findBulk: jest.fn(), create: jest.fn(), update: jest.fn(), delete: jest.fn(), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/rule_status_saved_objects_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/rule_status_saved_objects_client.ts index 25d315279ad60f7..ff1b0e27019edbe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/rule_status_saved_objects_client.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/rule_status_saved_objects_client.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { get } from 'lodash'; import { SavedObjectsClientContract, SavedObject, @@ -15,13 +14,11 @@ import { } from '../../../../../../../src/core/server'; import { ruleStatusSavedObjectType } from '../rules/saved_object_mappings'; import { IRuleStatusSOAttributes } from '../rules/types'; -import { buildChunkedOrFilter } from './utils'; export interface RuleStatusSavedObjectsClient { find: ( options?: Omit ) => Promise>; - findBulk: (ids: string[], statusesPerId: number) => Promise; create: (attributes: IRuleStatusSOAttributes) => Promise>; update: ( id: string, @@ -30,10 +27,6 @@ export interface RuleStatusSavedObjectsClient { delete: (id: string) => Promise<{}>; } -interface FindBulkResponse { - [key: string]: IRuleStatusSOAttributes[] | undefined; -} - export const ruleStatusSavedObjectsClientFactory = ( savedObjectsClient: SavedObjectsClientContract ): RuleStatusSavedObjectsClient => ({ @@ -42,50 +35,6 @@ export const ruleStatusSavedObjectsClientFactory = ( ...options, type: ruleStatusSavedObjectType, }), - findBulk: async (ids, statusesPerId) => { - if (ids.length === 0) { - return {}; - } - const filter = buildChunkedOrFilter(`${ruleStatusSavedObjectType}.attributes.alertId`, ids); - const order: 'desc' = 'desc'; - const aggs = { - alertIds: { - terms: { - field: `${ruleStatusSavedObjectType}.attributes.alertId`, - size: ids.length, - }, - aggs: { - most_recent_statuses: { - top_hits: { - sort: [ - { - [`${ruleStatusSavedObjectType}.statusDate`]: { - order, - }, - }, - ], - size: statusesPerId, - }, - }, - }, - }, - }; - const results = await savedObjectsClient.find({ - filter, - aggs, - type: ruleStatusSavedObjectType, - perPage: 0, - }); - const buckets = get(results, 'aggregations.alertIds.buckets'); - return buckets.reduce((acc: Record, bucket: unknown) => { - const key = get(bucket, 'key'); - const hits = get(bucket, 'most_recent_statuses.hits.hits'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const statuses = hits.map((hit: any) => hit._source['siem-detection-engine-rule-status']); - acc[key] = statuses; - return acc; - }, {}); - }, create: (attributes) => savedObjectsClient.create(ruleStatusSavedObjectType, attributes), update: (id, attributes) => savedObjectsClient.update(ruleStatusSavedObjectType, id, attributes), delete: (id) => savedObjectsClient.delete(ruleStatusSavedObjectType, id), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts index ca7f22e4a75707b..986393d6d345467 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts @@ -138,7 +138,7 @@ export const findThresholdSignals = async ({ logger, // @ts-expect-error refactor to pass type explicitly instead of unknown filter, - pageSize: 0, + pageSize: 1, sortOrder: 'desc', buildRuleMessage, }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts index f49492939eeb108..b04eab1496e960e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts @@ -39,7 +39,6 @@ import { createTotalHitsFromSearchResult, lastValidDate, calculateThresholdSignalUuid, - buildChunkedOrFilter, } from './utils'; import { BulkResponseErrorAggregation, SearchAfterAndBulkCreateReturnType } from './types'; import { @@ -1474,26 +1473,4 @@ describe('utils', () => { expect(signalUuid).toEqual('ee8870dc-45ff-5e6c-a2f9-80886651ce03'); }); }); - - describe('buildChunkedOrFilter', () => { - test('should return undefined if no values are provided', () => { - const filter = buildChunkedOrFilter('field.name', []); - expect(filter).toEqual(undefined); - }); - - test('should return a filter with a single value', () => { - const filter = buildChunkedOrFilter('field.name', ['id-1']); - expect(filter).toEqual('field.name: ("id-1")'); - }); - - test('should return a filter with a multiple values', () => { - const filter = buildChunkedOrFilter('field.name', ['id-1', 'id-2']); - expect(filter).toEqual('field.name: ("id-1" OR "id-2")'); - }); - - test('should return a filter with a multiple values chunked', () => { - const filter = buildChunkedOrFilter('field.name', ['id-1', 'id-2', 'id-3'], 2); - expect(filter).toEqual('field.name: ("id-1" OR "id-2") OR field.name: ("id-3")'); - }); - }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts index cc4ed6a45807b1f..03a067af6066d48 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts @@ -10,7 +10,7 @@ import moment from 'moment'; import uuidv5 from 'uuid/v5'; import dateMath from '@elastic/datemath'; import type { estypes } from '@elastic/elasticsearch'; -import { chunk, isEmpty, partition } from 'lodash'; +import { isEmpty, partition } from 'lodash'; import { ApiResponse, Context } from '@elastic/elasticsearch/lib/Transport'; import { SortResults } from '@elastic/elasticsearch/api/types'; @@ -868,16 +868,3 @@ export const getSafeSortIds = (sortIds: SortResults | undefined) => { return sortId; }); }; - -export const buildChunkedOrFilter = (field: string, values: string[], chunkSize: number = 1024) => { - if (values.length === 0) { - return undefined; - } - const chunkedValues = chunk(values, chunkSize); - return chunkedValues - .map((subArray) => { - const joinedValues = subArray.map((value) => `"${value}"`).join(' OR '); - return `${field}: (${joinedValues})`; - }) - .join(' OR '); -}; diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 2507475592e8888..aa37a0dc1f6270d 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { once } from 'lodash'; import { Observable } from 'rxjs'; import { i18n } from '@kbn/i18n'; import LRU from 'lru-cache'; @@ -28,18 +27,8 @@ import { PluginSetupContract as AlertingSetup, PluginStartContract as AlertPluginStartContract, } from '../../alerting/server'; - import { PluginStartContract as CasesPluginStartContract } from '../../cases/server'; -import { - ECS_COMPONENT_TEMPLATE_NAME, - TECHNICAL_COMPONENT_TEMPLATE_NAME, -} from '../../rule_registry/common/assets'; import { SecurityPluginSetup as SecuritySetup, SecurityPluginStart } from '../../security/server'; -import { - RuleDataClient, - RuleRegistryPluginSetupContract, - RuleRegistryPluginStartContract, -} from '../../rule_registry/server'; import { PluginSetupContract as FeaturesSetup } from '../../features/server'; import { MlPluginSetup as MlSetup } from '../../ml/server'; import { ListPluginSetup } from '../../lists/server'; @@ -49,9 +38,6 @@ import { ILicense, LicensingPluginStart } from '../../licensing/server'; import { FleetStartContract } from '../../fleet/server'; import { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server'; import { compose } from './lib/compose/kibana'; -import { createQueryAlertType } from './lib/detection_engine/reference_rules/query'; -import { createEqlAlertType } from './lib/detection_engine/reference_rules/eql'; -import { createThresholdAlertType } from './lib/detection_engine/reference_rules/threshold'; import { initRoutes } from './routes'; import { isAlertExecutor } from './lib/detection_engine/signals/types'; import { signalRulesAlertType } from './lib/detection_engine/signals/signal_rule_alert_type'; @@ -68,8 +54,6 @@ import { SecurityPageName, SIGNALS_ID, NOTIFICATIONS_ID, - REFERENCE_RULE_ALERT_TYPE_ID, - REFERENCE_RULE_PERSISTENCE_ALERT_TYPE_ID, } from '../common/constants'; import { registerEndpointRoutes } from './endpoint/routes/metadata'; import { registerLimitedConcurrencyRoutes } from './endpoint/routes/limited_concurrency'; @@ -103,7 +87,6 @@ export interface SetupPlugins { features: FeaturesSetup; lists?: ListPluginSetup; ml?: MlSetup; - ruleRegistry: RuleRegistryPluginSetupContract; security?: SecuritySetup; spaces?: SpacesSetup; taskManager?: TaskManagerSetupContract; @@ -116,7 +99,6 @@ export interface StartPlugins { data: DataPluginStart; fleet?: FleetStartContract; licensing: LicensingPluginStart; - ruleRegistry: RuleRegistryPluginStartContract; taskManager?: TaskManagerStartContract; telemetry?: TelemetryPluginStart; security: SecurityPluginStart; @@ -153,7 +135,6 @@ export class Plugin implements IPlugin, plugins: SetupPlugins) { this.logger.debug('plugin setup'); - this.setupPlugins = plugins; const config = this.config; const globalConfig = this.context.config.legacy.get(); @@ -215,75 +195,13 @@ export class Plugin implements IPlugin core.getStartServices().then(([coreStart]) => coreStart); - - const ready = once(async () => { - const componentTemplateName = ruleDataService.getFullAssetName( - 'security-solution-mappings' - ); - - if (!ruleDataService.isWriteEnabled()) { - return; - } - - await ruleDataService.createOrUpdateComponentTemplate({ - name: componentTemplateName, - body: { - template: { - settings: { - number_of_shards: 1, - }, - mappings: {}, // TODO: Add mappings here via `mappingFromFieldMap()` - }, - }, - }); - - await ruleDataService.createOrUpdateIndexTemplate({ - name: ruleDataService.getFullAssetName('security-solution-index-template'), - body: { - index_patterns: [ruleDataService.getFullAssetName('security-solution*')], - composed_of: [ - ruleDataService.getFullAssetName(TECHNICAL_COMPONENT_TEMPLATE_NAME), - ruleDataService.getFullAssetName(ECS_COMPONENT_TEMPLATE_NAME), - componentTemplateName, - ], - }, - }); - }); - - ready().catch((err) => { - this.logger!.error(err); - }); - - ruleDataClient = new RuleDataClient({ - alias: plugins.ruleRegistry.ruleDataService.getFullAssetName('security-solution'), - getClusterClient: async () => { - const coreStart = await start(); - return coreStart.elasticsearch.client.asInternalUser; - }, - ready, - }); - - // Register reference rule types via rule-registry - this.setupPlugins.alerting.registerType(createQueryAlertType(ruleDataClient, this.logger)); - this.setupPlugins.alerting.registerType(createEqlAlertType(ruleDataClient, this.logger)); - this.setupPlugins.alerting.registerType( - createThresholdAlertType(ruleDataClient, this.logger) - ); - } - // TO DO We need to get the endpoint routes inside of initRoutes initRoutes( router, config, plugins.encryptedSavedObjects?.canEncrypt === true, plugins.security, - plugins.ml, - ruleDataClient + plugins.ml ); registerEndpointRoutes(router, endpointContext); registerLimitedConcurrencyRoutes(core); @@ -292,16 +210,6 @@ export class Plugin implements IPlugin { // Detection Engine Rule routes that have the REST endpoints of /api/detection_engine/rules // All REST rule creation, deletion, updating, etc...... - createRulesRoute(router, ml, ruleDataClient); - readRulesRoute(router, ruleDataClient); - updateRulesRoute(router, ml, ruleDataClient); - patchRulesRoute(router, ml, ruleDataClient); - deleteRulesRoute(router, ruleDataClient); - findRulesRoute(router, ruleDataClient); - - // TODO: pass ruleDataClient to all relevant routes + createRulesRoute(router, ml); + readRulesRoute(router); + updateRulesRoute(router, ml); + patchRulesRoute(router, ml); + deleteRulesRoute(router); + findRulesRoute(router); addPrepackedRulesRoute(router, config, security); getPrepackagedRulesStatusRoute(router, config, security); @@ -107,7 +102,7 @@ export const initRoutes = ( // POST /api/detection_engine/signals/status // Example usage can be found in security_solution/server/lib/detection_engine/scripts/signals setSignalsStatusRoute(router); - querySignalsRoute(router, config); + querySignalsRoute(router); getSignalsMigrationStatusRoute(router); createSignalsMigrationRoute(router, security); finalizeSignalsMigrationRoute(router, security); @@ -116,7 +111,7 @@ export const initRoutes = ( // Detection Engine index routes that have the REST endpoints of /api/detection_engine/index // All REST index creation, policy management for spaces createIndexRoute(router); - readIndexRoute(router, config); + readIndexRoute(router); deleteIndexRoute(router); // Detection Engine tags routes that have the REST endpoints of /api/detection_engine/tags diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx index f489fd0c16455b1..e43db6b86f8b90e 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx @@ -33,7 +33,6 @@ const mockDeps = { trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, hostIsolationEnabled: false, - ruleRegistryEnabled: false, }, service: {} as EndpointAppContextService, } as EndpointAppContext, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 8473a663084f5fd..d829c8eb22a98bb 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -125,6 +125,133 @@ "advancedSettings.searchBar.unableToParseQueryErrorMessage": "クエリをパースできません", "advancedSettings.searchBarAriaLabel": "高度な設定を検索", "advancedSettings.voiceAnnouncement.ariaLabel": "詳細設定結果情報", + "apmOss.tutorial.apmAgents.statusCheck.btnLabel": "エージェントステータスを確認", + "apmOss.tutorial.apmAgents.statusCheck.errorMessage": "エージェントからまだデータを受け取っていません", + "apmOss.tutorial.apmAgents.statusCheck.successMessage": "1 つまたは複数のエージェントからデータを受け取りました", + "apmOss.tutorial.apmAgents.statusCheck.text": "アプリケーションが実行されていてエージェントがデータを送信していることを確認してください。", + "apmOss.tutorial.apmAgents.statusCheck.title": "エージェントステータス", + "apmOss.tutorial.apmAgents.title": "APM エージェント", + "apmOss.tutorial.apmServer.callOut.message": "ご使用の APM Server を 7.0 以上に更新してあることを確認してください。 Kibana の管理セクションにある移行アシスタントで 6.x データを移行することもできます。", + "apmOss.tutorial.apmServer.callOut.title": "重要:7.0 以上に更新中", + "apmOss.tutorial.apmServer.statusCheck.btnLabel": "APM Server ステータスを確認", + "apmOss.tutorial.apmServer.statusCheck.errorMessage": "APM Server が検出されました。7.0 以上に更新され、動作中であることを確認してください。", + "apmOss.tutorial.apmServer.statusCheck.successMessage": "APM Server が正しくセットアップされました", + "apmOss.tutorial.apmServer.statusCheck.text": "APM エージェントの導入を開始する前に、APM Server が動作していることを確認してください。", + "apmOss.tutorial.apmServer.statusCheck.title": "APM Server ステータス", + "apmOss.tutorial.apmServer.title": "APM Server", + "apmOss.tutorial.djangoClient.configure.commands.addAgentComment": "インストールされたアプリにエージェントを追加します", + "apmOss.tutorial.djangoClient.configure.commands.addTracingMiddlewareComment": "パフォーマンスメトリックを送信するには、追跡ミドルウェアを追加します。", + "apmOss.tutorial.djangoClient.configure.commands.allowedCharactersComment": "a-z、A-Z、0-9、-、_、スペース", + "apmOss.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト:{defaultApmServerUrl}) を設定します", + "apmOss.tutorial.djangoClient.configure.commands.setRequiredServiceNameComment": "任意のサービス名を設定します。使用できる文字:", + "apmOss.tutorial.djangoClient.configure.commands.setServiceEnvironmentComment": "サービス環境を設定します", + "apmOss.tutorial.djangoClient.configure.commands.useIfApmServerRequiresTokenComment": "APM Server でシークレットトークンが必要な場合に使います", + "apmOss.tutorial.djangoClient.configure.textPost": "高度な用途に関しては [ドキュメンテーション] ({documentationLink}) をご覧ください。", + "apmOss.tutorial.djangoClient.configure.textPre": "エージェントとは、アプリケーションプロセス内で実行されるライブラリです。APM サービスは「SERVICE_NAME」に基づいてプログラムで作成されます。", + "apmOss.tutorial.djangoClient.configure.title": "エージェントの構成", + "apmOss.tutorial.djangoClient.install.textPre": "Python 用の APM エージェントを依存関係としてインストールします。", + "apmOss.tutorial.djangoClient.install.title": "APM エージェントのインストール", + "apmOss.tutorial.dotNetClient.configureAgent.textPost": "エージェントに「IConfiguration」インスタンスが渡されていない場合、 (例:非 ASP.NET Core アプリケーションの場合) 、エージェントを環境変数で構成することもできます。\n 高度な用途に関しては [ドキュメンテーション] ({documentationLink}) をご覧ください。", + "apmOss.tutorial.dotNetClient.configureAgent.title": "appsettings.json ファイルの例:", + "apmOss.tutorial.dotNetClient.configureApplication.textPost": "「IConfiguration」インスタンスを渡すのは任意であり、これにより、エージェントはこの「IConfiguration」インスタンス (例:「appsettings.json」ファイル) から構成を読み込みます。", + "apmOss.tutorial.dotNetClient.configureApplication.textPre": "「Elastic.Apm.NetCoreAll」パッケージの ASP.NET Core の場合、「Startup.cs」ファイル内の「Configure」メソドの「UseElasticApm」メソドを呼び出します。", + "apmOss.tutorial.dotNetClient.configureApplication.title": "エージェントをアプリケーションに追加", + "apmOss.tutorial.dotNetClient.download.textPre": "[NuGet] ({allNuGetPackagesLink}) から .NET アプリケーションにエージェントパッケージを追加してください。用途の異なる複数の NuGet パッケージがあります。\n\nEntity Framework Core の ASP.NET Core アプリケーションの場合は、[Elastic.Apm.NetCoreAll] ({netCoreAllApmPackageLink}) パッケージをダウンロードしてください。このパッケージは、自動的にすべてのエージェントコンポーネントをアプリケーションに追加します。\n\n 依存性を最低限に抑えたい場合、ASP.NET Coreの監視のみに[Elastic.Apm.AspNetCore] ({aspNetCorePackageLink}) パッケージ、またはEntity Framework Coreの監視のみに[Elastic.Apm.EfCore] ({efCorePackageLink}) パッケージを使用することができます。\n\n 手動インストルメンテーションのみにパブリック Agent API を使用する場合は、[Elastic.Apm] ({elasticApmPackageLink}) パッケージを使用してください。", + "apmOss.tutorial.dotNetClient.download.title": "APM エージェントのダウンロード", + "apmOss.tutorial.downloadServer.title": "APM Server をダウンロードして展開します", + "apmOss.tutorial.downloadServerRpm": "32 ビットパッケージをお探しですか?[ダウンロードページ] ({downloadPageLink}) をご覧ください。", + "apmOss.tutorial.downloadServerTitle": "32 ビットパッケージをお探しですか?[ダウンロードページ] ({downloadPageLink}) をご覧ください。", + "apmOss.tutorial.editConfig.textPre": "Elastic Stack の X-Pack セキュアバージョンをご使用の場合、「apm-server.yml」構成ファイルで認証情報を指定する必要があります。", + "apmOss.tutorial.editConfig.title": "構成を編集する", + "apmOss.tutorial.flaskClient.configure.commands.allowedCharactersComment": "a-z、A-Z、0-9、-、_、スペース", + "apmOss.tutorial.flaskClient.configure.commands.configureElasticApmComment": "またはアプリケーションの設定で ELASTIC_APM を使用するよう構成します。", + "apmOss.tutorial.flaskClient.configure.commands.initializeUsingEnvironmentVariablesComment": "環境変数を使用して初期化します", + "apmOss.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト:{defaultApmServerUrl}) を設定します", + "apmOss.tutorial.flaskClient.configure.commands.setRequiredServiceNameComment": "任意のサービス名を設定します。使用できる文字:", + "apmOss.tutorial.flaskClient.configure.commands.setServiceEnvironmentComment": "サービス環境を設定します", + "apmOss.tutorial.flaskClient.configure.commands.useIfApmServerRequiresTokenComment": "APM Server でシークレットトークンが必要な場合に使います", + "apmOss.tutorial.flaskClient.configure.textPost": "高度な用途に関しては [ドキュメンテーション] ({documentationLink}) をご覧ください。", + "apmOss.tutorial.flaskClient.configure.textPre": "エージェントとは、アプリケーションプロセス内で実行されるライブラリです。APM サービスは「SERVICE_NAME」に基づいてプログラムで作成されます。", + "apmOss.tutorial.flaskClient.configure.title": "エージェントの構成", + "apmOss.tutorial.flaskClient.install.textPre": "Python 用の APM エージェントを依存関係としてインストールします。", + "apmOss.tutorial.flaskClient.install.title": "APM エージェントのインストール", + "apmOss.tutorial.goClient.configure.commands.initializeUsingEnvironmentVariablesComment": "環境変数を使用して初期化します:", + "apmOss.tutorial.goClient.configure.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト:{defaultApmServerUrl}) を設定します", + "apmOss.tutorial.goClient.configure.commands.setServiceEnvironment": "サービス環境を設定します", + "apmOss.tutorial.goClient.configure.commands.setServiceNameComment": "サービス名を設定します。使用できる文字は # a-z、A-Z、0-9、-、_、スペースです。", + "apmOss.tutorial.goClient.configure.commands.usedExecutableNameComment": "ELASTIC_APM_SERVICE_NAME が指定されていない場合、実行ファイルの名前が使用されます。", + "apmOss.tutorial.goClient.configure.commands.useIfApmRequiresTokenComment": "APM Server でシークレットトークンが必要な場合に使います", + "apmOss.tutorial.goClient.configure.textPost": "高度な構成に関しては [ドキュメンテーション] ({documentationLink}) をご覧ください。", + "apmOss.tutorial.goClient.configure.textPre": "エージェントとは、アプリケーションプロセス内で実行されるライブラリです。APM サービスは実行ファイル名または「ELASTIC_APM_SERVICE_NAME」環境変数に基づいてプログラムで作成されます。", + "apmOss.tutorial.goClient.configure.title": "エージェントの構成", + "apmOss.tutorial.goClient.install.textPre": "Go の APM エージェントパッケージをインストールします。", + "apmOss.tutorial.goClient.install.title": "APM エージェントのインストール", + "apmOss.tutorial.goClient.instrument.textPost": "Go のソースコードのインストルメンテーションの詳細ガイドは、[ドキュメンテーション] ({documentationLink}) をご覧ください。", + "apmOss.tutorial.goClient.instrument.textPre": "提供されたインストルメンテーションモジュールの 1 つ、またはトレーサー API を直接使用して、Go アプリケーションにインストルメンテーションを設定します。", + "apmOss.tutorial.goClient.instrument.title": "アプリケーションのインストルメンテーション", + "apmOss.tutorial.introduction": "アプリケーション内から詳細なパフォーマンスメトリックやエラーを収集します。", + "apmOss.tutorial.javaClient.download.textPre": "[Maven Central] ({mavenCentralLink}) からエージェントをダウンロードします。アプリケーションにエージェントを依存関係として「追加しない」でください。", + "apmOss.tutorial.javaClient.download.title": "APM エージェントのダウンロード", + "apmOss.tutorial.javaClient.startApplication.textPost": "構成オプションと高度な用途に関しては、[ドキュメンテーション] ({documentationLink}) をご覧ください。", + "apmOss.tutorial.javaClient.startApplication.textPre": "「-javaagent」フラグを追加し、システムプロパティを使用してエージェントを構成します。\n\n * 任意のサービス名を設定します (使用可能な文字は a-z、A-Z、0-9、-、_、スペースです) \n * カスタム APM Server URL (デフォルト:{customApmServerUrl}) を設定します\n * APM Server シークレットトークンを設定します\n * サービス環境を設定します\n * アプリケーションのベースパッケージを設定します", + "apmOss.tutorial.javaClient.startApplication.title": "javaagent フラグでアプリケーションを起動", + "apmOss.tutorial.jsClient.enableRealUserMonitoring.textPre": "デフォルトでは、APM Server を実行すると RUM サポートは無効になります。RUM サポートを有効にする手順については、[ドキュメンテーション] ({documentationLink}) をご覧ください。", + "apmOss.tutorial.jsClient.enableRealUserMonitoring.title": "APM Server のリアルユーザー監視サポートを有効にする", + "apmOss.tutorial.jsClient.installDependency.commands.setCustomApmServerUrlComment": "カスタム APM Server URL (デフォルト:{defaultApmServerUrl}) を設定します", + "apmOss.tutorial.jsClient.installDependency.commands.setRequiredServiceNameComment": "任意のサービス名を設定します (使用可能な文字は a-z、A-Z、0-9、-、_、スペースです) ", + "apmOss.tutorial.jsClient.installDependency.commands.setServiceEnvironmentComment": "サービス環境を設定します", + "apmOss.tutorial.jsClient.installDependency.commands.setServiceVersionComment": "サービスバージョンを設定します (ソースマップ機能に必要) ", + "apmOss.tutorial.jsClient.installDependency.textPost": "React や Angular などのフレームワーク統合には、カスタム依存関係があります。詳細は [統合ドキュメント] ({docLink}) をご覧ください。", + "apmOss.tutorial.jsClient.installDependency.textPre": "「npm install @elastic/apm-rum --save」でエージェントをアプリケーションへの依存関係としてインストールできます。\n\nその後で以下のようにアプリケーションでエージェントを初期化して構成できます。", + "apmOss.tutorial.jsClient.installDependency.title": "エージェントを依存関係としてセットアップ", + "apmOss.tutorial.jsClient.scriptTags.textPre": "または、スクリプトタグを使用してエージェントのセットアップと構成ができます。` を追加