From ce08d4e37343d425580a74f6e8a95ff443971a95 Mon Sep 17 00:00:00 2001 From: Hannah Mudge Date: Thu, 26 Sep 2024 12:10:33 -0600 Subject: [PATCH 1/4] [Dashboard] Cleanup services (#193644) Closes https://github.com/elastic/kibana/issues/167437 ## Summary This PR refactors the Dashboard services to no longer use the `PluginServiceProvider` from the `PresentationUtil` plugin. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- src/plugins/dashboard/jest_setup.ts | 36 ++- .../add_to_library_action.tsx | 42 ++-- .../dashboard_actions/clone_panel_action.tsx | 2 - .../copy_to_dashboard_action.tsx | 36 +-- .../copy_to_dashboard_modal.tsx | 19 +- .../dashboard_actions/expand_panel_action.tsx | 2 - .../dashboard_actions/export_csv_action.tsx | 24 +- .../filters_notification_action.tsx | 30 +-- .../public/dashboard_actions/index.ts | 5 +- .../legacy_add_to_library_action.test.tsx | 6 +- .../legacy_add_to_library_action.tsx | 15 +- ...legacy_unlink_from_library_action.test.tsx | 6 +- .../legacy_unlink_from_library_action.tsx | 14 +- .../unlink_from_library_action.tsx | 40 ++-- .../dashboard/public/dashboard_api/types.ts | 2 +- .../dashboard_app/dashboard_app.test.tsx | 32 +-- .../public/dashboard_app/dashboard_app.tsx | 104 ++++---- .../public/dashboard_app/dashboard_router.tsx | 66 +++--- .../use_dashboard_outcome_validation.tsx | 21 +- ...use_observability_ai_assistant_context.tsx | 30 +-- .../dashboard_listing_page.test.tsx | 22 +- .../listing_page/dashboard_listing_page.tsx | 46 ++-- .../listing_page/dashboard_no_match.tsx | 28 +-- .../get_dashboard_list_item_link.ts | 16 +- .../no_data/dashboard_app_no_data.tsx | 63 ++--- .../dashboard_tab_title_setter.tsx | 11 +- .../use_get_dashboard_panels.test.ts | 39 ++- .../add_new_panel/use_get_dashboard_panels.ts | 30 ++- .../top_nav/dashboard_editing_toolbar.tsx | 42 ++-- .../top_nav/editor_menu.test.tsx | 36 +-- .../dashboard_app/top_nav/editor_menu.tsx | 14 +- .../top_nav/share/show_share_modal.test.tsx | 17 +- .../top_nav/share/show_share_modal.tsx | 44 ++-- .../top_nav/use_dashboard_menu_items.tsx | 56 ++--- .../url/search_sessions_integration.ts | 25 +- .../public/dashboard_app/url/url_utils.ts | 16 +- .../dashboard_empty_screen.test.tsx | 20 +- .../empty_screen/dashboard_empty_screen.tsx | 46 ++-- .../component/grid/dashboard_grid_item.tsx | 24 +- .../component/settings/settings_flyout.tsx | 48 ++-- .../api/duplicate_dashboard_panel.test.tsx | 8 +- .../api/duplicate_dashboard_panel.ts | 16 +- .../embeddable/api/open_settings_flyout.tsx | 16 +- .../embeddable/api/overlays/save_modal.tsx | 16 +- .../embeddable/api/run_save_functions.tsx | 58 ++--- .../create/create_dashboard.test.ts | 222 ++++++++---------- .../embeddable/create/create_dashboard.ts | 80 ++++--- .../data_views/sync_dashboard_data_views.ts | 16 +- .../query_performance_tracking.test.ts | 6 +- .../performance/query_performance_tracking.ts | 11 +- ...rt_dashboard_search_session_integration.ts | 23 +- .../sync_dashboard_unified_search_state.ts | 16 +- .../embeddable/dashboard_container.test.tsx | 8 +- .../embeddable/dashboard_container.tsx | 168 ++++++------- .../dashboard_container_factory.tsx | 2 +- .../external_api/dashboard_renderer.test.tsx | 50 ++-- .../external_api/dashboard_renderer.tsx | 14 +- .../external_api/lazy_dashboard_renderer.tsx | 6 +- .../public/dashboard_container/index.ts | 2 +- .../diffing/dashboard_diffing_functions.ts | 11 +- .../diffing/dashboard_diffing_integration.ts | 9 +- .../dashboard_listing/confirm_overlays.tsx | 42 ++-- .../dashboard_listing.test.tsx | 18 +- .../dashboard_listing/dashboard_listing.tsx | 86 +++---- .../dashboard_listing_empty_prompt.test.tsx | 16 +- .../dashboard_listing_empty_prompt.tsx | 34 ++- .../dashboard_listing_table.tsx | 60 +---- .../dashboard_unsaved_listing.test.tsx | 49 ++-- .../dashboard_unsaved_listing.tsx | 73 +++--- .../use_dashboard_listing_table.test.tsx | 40 ++-- .../hooks/use_dashboard_listing_table.tsx | 161 +++++++------ .../public/dashboard_listing/types.ts | 7 - .../public/dashboard_top_nav/index.tsx | 4 +- .../internal_dashboard_top_nav.test.tsx | 9 +- .../internal_dashboard_top_nav.tsx | 154 +++++------- src/plugins/dashboard/public/index.ts | 2 + src/plugins/dashboard/public/mocks.tsx | 6 - src/plugins/dashboard/public/plugin.tsx | 149 ++++++------ .../services/analytics/analytics.stub.ts | 22 -- .../services/analytics/analytics_service.ts | 27 --- .../public/services/analytics/types.ts | 14 -- .../services/application/application.stub.ts | 31 --- .../application/application_service.ts | 42 ---- .../public/services/application/types.ts | 23 -- .../public/services/chrome/chrome.stub.ts | 29 --- .../public/services/chrome/chrome_service.ts | 43 ---- .../dashboard/public/services/chrome/types.ts | 21 -- .../content_management_service.stub.ts | 18 -- .../content_management_service.ts | 25 -- .../core_context/core_context.stub.ts | 22 -- .../core_context/core_context_service.ts | 29 --- .../public/services/core_context/types.ts | 15 -- .../custom_branding/custom_branding.stub.ts | 22 -- .../custom_branding_service.ts | 25 -- .../public/services/custom_branding/types.ts | 15 -- .../dashboard_backup/dashboard_backup.stub.ts | 27 --- .../public/services/dashboard_backup/types.ts | 31 --- .../dashboard_backup_service.ts | 74 +++--- .../dashboard_capabilities.stub.ts | 30 --- .../services/dashboard_capabilities/types.ts | 19 -- .../dashboard_content_insights.stub.ts | 24 -- .../dashboard_content_insights_service.ts | 34 --- .../dashboard_content_insights/types.ts | 15 -- .../dashboard_content_management.stub.ts | 80 ------- .../dashboard_content_management_service.ts | 101 -------- .../dashboard_content_management_cache.ts | 0 .../index.ts | 45 ++++ ...heck_for_duplicate_dashboard_title.test.ts | 52 ++-- .../check_for_duplicate_dashboard_title.ts | 21 +- .../lib/dashboard_versioning.ts | 0 .../lib/delete_dashboards.ts | 15 +- .../lib/find_dashboards.ts | 31 +-- .../lib/load_dashboard_state.test.ts | 25 +- .../lib/load_dashboard_state.ts | 78 +++--- .../lib/migrate_dashboard_input.test.ts | 14 +- .../lib/migrate_dashboard_input.ts | 15 +- .../lib/save_dashboard_state.test.ts | 60 ++--- .../lib/save_dashboard_state.ts | 56 ++--- .../lib/update_dashboard_meta.ts | 27 +-- .../types.ts | 26 +- .../dashboard_favorites_service.stub.ts | 21 -- .../dashboard_favorites_service.ts | 29 --- .../services/dashboard_favorites/types.ts | 12 - .../dashboard_recently_accessed.stub.ts | 23 -- .../dashboard_recently_accessed.ts | 33 --- .../dashboard_recently_accessed/types.ts | 12 - ...=> dashboard_recently_accessed_service.ts} | 19 +- .../public/services/data/data.stub.ts | 24 -- .../public/services/data/data_service.ts | 30 --- .../dashboard/public/services/data/types.ts | 17 -- .../data_view_editor/data_view_editor.stub.ts | 23 -- .../data_view_editor_service.ts | 28 --- .../public/services/data_view_editor/types.ts | 14 -- .../documentation_links.stub.ts | 25 -- .../documentation_links_service.ts | 39 --- .../services/documentation_links/types.ts | 17 -- .../services/embeddable/embeddable.stub.ts | 29 --- .../services/embeddable/embeddable_service.ts | 34 --- .../public/services/embeddable/types.ts | 22 -- .../public/services/http/http.stub.ts | 23 -- .../public/services/http/http_service.ts | 27 --- .../dashboard/public/services/http/types.ts | 15 -- .../public/services/i18n/i18n_service.ts | 22 -- .../dashboard/public/services/i18n/types.ts | 12 - .../initializer_context.stub.ts | 24 -- .../initializer_context_service.ts | 32 --- .../services/initializer_context/types.ts | 13 - .../public/services/kibana_services.ts | 90 +++++++ .../dashboard/public/services/mocks.ts | 149 +++++++++++- .../services/navigation/navigation.stub.ts | 22 -- .../services/navigation/navigation_service.ts | 28 --- .../public/services/navigation/types.ts | 14 -- .../no_data_page/no_data_page_service.stub.ts | 17 -- .../no_data_page/no_data_page_service.ts | 25 -- .../public/services/no_data_page/types.ts | 14 -- .../notifications/notifications.stub.ts | 23 -- .../notifications/notifications_service.ts | 28 --- .../public/services/notifications/types.ts | 15 -- ...observability_ai_assistant_service.stub.ts | 22 -- .../observability_ai_assistant_service.ts | 24 -- .../observability_ai_assistant/types.ts | 14 -- .../public/services/overlays/overlays.stub.ts | 25 -- .../services/overlays/overlays_service.ts | 30 --- .../public/services/overlays/types.ts | 17 -- .../public/services/plugin_services.stub.ts | 94 -------- .../public/services/plugin_services.ts | 112 --------- .../saved_objects_management_service.stub.ts | 18 -- .../saved_objects_management_service.ts | 25 -- .../saved_objects_tagging.stub.ts | 29 --- .../saved_objects_tagging_service.ts | 51 ---- .../services/saved_objects_tagging/types.ts | 22 -- .../screenshot_mode/screenshot_mode.stub.ts | 23 -- .../screenshot_mode_service.ts | 27 --- .../public/services/screenshot_mode/types.ts | 15 -- .../serverless/serverless_service.stub.ts | 17 -- .../services/serverless/serverless_service.ts | 23 -- .../public/services/serverless/types.ts | 14 -- .../public/services/settings/settings.stub.ts | 25 -- .../services/settings/settings_service.ts | 34 --- .../public/services/settings/types.ts | 18 -- .../public/services/share/share.stub.ts | 23 -- .../public/services/share/share_services.ts | 29 --- .../dashboard/public/services/share/types.ts | 15 -- .../public/services/spaces/spaces.stub.ts | 24 -- .../public/services/spaces/spaces_service.ts | 34 --- .../dashboard/public/services/spaces/types.ts | 16 -- .../dashboard/public/services/types.ts | 92 -------- .../public/services/ui_actions/types.ts | 14 -- .../ui_actions/ui_actions_service.stub.ts | 19 -- .../services/ui_actions/ui_actions_service.ts | 26 -- .../public/services/url_forwarding/types.ts | 14 -- .../url_forwarding/url_forwarding_service.ts | 26 -- .../url_forwarding/url_fowarding.stub.ts | 22 -- .../public/services/usage_collection/types.ts | 14 -- .../usage_collection/usage_collection.stub.ts | 22 -- .../usage_collection_service.ts | 26 -- .../public/services/user_profile/types.ts | 14 -- .../user_profile/user_profile_service.stub.ts | 18 -- .../user_profile/user_profile_service.ts | 23 -- .../public/services/visualizations/types.ts | 17 -- .../visualizations/visualizations.stub.ts | 25 -- .../visualizations/visualizations_service.ts | 30 --- .../get_dashboard_capabilities.ts} | 19 +- src/plugins/dashboard/tsconfig.json | 11 +- src/plugins/links/jest_setup.ts | 2 +- .../public/hooks/use_dashboards_fetcher.ts | 2 +- .../hooks/use_dashboards_fetcher.ts | 2 +- 207 files changed, 1722 insertions(+), 4746 deletions(-) delete mode 100644 src/plugins/dashboard/public/services/analytics/analytics.stub.ts delete mode 100644 src/plugins/dashboard/public/services/analytics/analytics_service.ts delete mode 100644 src/plugins/dashboard/public/services/analytics/types.ts delete mode 100644 src/plugins/dashboard/public/services/application/application.stub.ts delete mode 100644 src/plugins/dashboard/public/services/application/application_service.ts delete mode 100644 src/plugins/dashboard/public/services/application/types.ts delete mode 100644 src/plugins/dashboard/public/services/chrome/chrome.stub.ts delete mode 100644 src/plugins/dashboard/public/services/chrome/chrome_service.ts delete mode 100644 src/plugins/dashboard/public/services/chrome/types.ts delete mode 100644 src/plugins/dashboard/public/services/content_management/content_management_service.stub.ts delete mode 100644 src/plugins/dashboard/public/services/content_management/content_management_service.ts delete mode 100644 src/plugins/dashboard/public/services/core_context/core_context.stub.ts delete mode 100644 src/plugins/dashboard/public/services/core_context/core_context_service.ts delete mode 100644 src/plugins/dashboard/public/services/core_context/types.ts delete mode 100644 src/plugins/dashboard/public/services/custom_branding/custom_branding.stub.ts delete mode 100644 src/plugins/dashboard/public/services/custom_branding/custom_branding_service.ts delete mode 100644 src/plugins/dashboard/public/services/custom_branding/types.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup.stub.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_backup/types.ts rename src/plugins/dashboard/public/services/{dashboard_backup => }/dashboard_backup_service.ts (78%) delete mode 100644 src/plugins/dashboard/public/services/dashboard_capabilities/dashboard_capabilities.stub.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_capabilities/types.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_content_insights/dashboard_content_insights.stub.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_content_insights/dashboard_content_insights_service.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_content_insights/types.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management.stub.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management_service.ts rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/dashboard_content_management_cache.ts (100%) create mode 100644 src/plugins/dashboard/public/services/dashboard_content_management_service/index.ts rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/check_for_duplicate_dashboard_title.test.ts (64%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/check_for_duplicate_dashboard_title.ts (86%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/dashboard_versioning.ts (100%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/delete_dashboards.ts (68%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/find_dashboards.ts (78%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/load_dashboard_state.test.ts (76%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/load_dashboard_state.ts (84%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/migrate_dashboard_input.test.ts (84%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/migrate_dashboard_input.ts (83%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/save_dashboard_state.test.ts (75%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/save_dashboard_state.ts (82%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/lib/update_dashboard_meta.ts (56%) rename src/plugins/dashboard/public/services/{dashboard_content_management => dashboard_content_management_service}/types.ts (72%) delete mode 100644 src/plugins/dashboard/public/services/dashboard_favorites/dashboard_favorites_service.stub.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_favorites/dashboard_favorites_service.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_favorites/types.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_recently_accessed/dashboard_recently_accessed.stub.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_recently_accessed/dashboard_recently_accessed.ts delete mode 100644 src/plugins/dashboard/public/services/dashboard_recently_accessed/types.ts rename src/plugins/dashboard/public/services/{i18n/i18n.stub.ts => dashboard_recently_accessed_service.ts} (50%) delete mode 100644 src/plugins/dashboard/public/services/data/data.stub.ts delete mode 100644 src/plugins/dashboard/public/services/data/data_service.ts delete mode 100644 src/plugins/dashboard/public/services/data/types.ts delete mode 100644 src/plugins/dashboard/public/services/data_view_editor/data_view_editor.stub.ts delete mode 100644 src/plugins/dashboard/public/services/data_view_editor/data_view_editor_service.ts delete mode 100644 src/plugins/dashboard/public/services/data_view_editor/types.ts delete mode 100644 src/plugins/dashboard/public/services/documentation_links/documentation_links.stub.ts delete mode 100644 src/plugins/dashboard/public/services/documentation_links/documentation_links_service.ts delete mode 100644 src/plugins/dashboard/public/services/documentation_links/types.ts delete mode 100644 src/plugins/dashboard/public/services/embeddable/embeddable.stub.ts delete mode 100644 src/plugins/dashboard/public/services/embeddable/embeddable_service.ts delete mode 100644 src/plugins/dashboard/public/services/embeddable/types.ts delete mode 100644 src/plugins/dashboard/public/services/http/http.stub.ts delete mode 100644 src/plugins/dashboard/public/services/http/http_service.ts delete mode 100644 src/plugins/dashboard/public/services/http/types.ts delete mode 100644 src/plugins/dashboard/public/services/i18n/i18n_service.ts delete mode 100644 src/plugins/dashboard/public/services/i18n/types.ts delete mode 100644 src/plugins/dashboard/public/services/initializer_context/initializer_context.stub.ts delete mode 100644 src/plugins/dashboard/public/services/initializer_context/initializer_context_service.ts delete mode 100644 src/plugins/dashboard/public/services/initializer_context/types.ts create mode 100644 src/plugins/dashboard/public/services/kibana_services.ts delete mode 100644 src/plugins/dashboard/public/services/navigation/navigation.stub.ts delete mode 100644 src/plugins/dashboard/public/services/navigation/navigation_service.ts delete mode 100644 src/plugins/dashboard/public/services/navigation/types.ts delete mode 100644 src/plugins/dashboard/public/services/no_data_page/no_data_page_service.stub.ts delete mode 100644 src/plugins/dashboard/public/services/no_data_page/no_data_page_service.ts delete mode 100644 src/plugins/dashboard/public/services/no_data_page/types.ts delete mode 100644 src/plugins/dashboard/public/services/notifications/notifications.stub.ts delete mode 100644 src/plugins/dashboard/public/services/notifications/notifications_service.ts delete mode 100644 src/plugins/dashboard/public/services/notifications/types.ts delete mode 100644 src/plugins/dashboard/public/services/observability_ai_assistant/observability_ai_assistant_service.stub.ts delete mode 100644 src/plugins/dashboard/public/services/observability_ai_assistant/observability_ai_assistant_service.ts delete mode 100644 src/plugins/dashboard/public/services/observability_ai_assistant/types.ts delete mode 100644 src/plugins/dashboard/public/services/overlays/overlays.stub.ts delete mode 100644 src/plugins/dashboard/public/services/overlays/overlays_service.ts delete mode 100644 src/plugins/dashboard/public/services/overlays/types.ts delete mode 100644 src/plugins/dashboard/public/services/plugin_services.stub.ts delete mode 100644 src/plugins/dashboard/public/services/plugin_services.ts delete mode 100644 src/plugins/dashboard/public/services/saved_objects_management/saved_objects_management_service.stub.ts delete mode 100644 src/plugins/dashboard/public/services/saved_objects_management/saved_objects_management_service.ts delete mode 100644 src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging.stub.ts delete mode 100644 src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging_service.ts delete mode 100644 src/plugins/dashboard/public/services/saved_objects_tagging/types.ts delete mode 100644 src/plugins/dashboard/public/services/screenshot_mode/screenshot_mode.stub.ts delete mode 100644 src/plugins/dashboard/public/services/screenshot_mode/screenshot_mode_service.ts delete mode 100644 src/plugins/dashboard/public/services/screenshot_mode/types.ts delete mode 100644 src/plugins/dashboard/public/services/serverless/serverless_service.stub.ts delete mode 100644 src/plugins/dashboard/public/services/serverless/serverless_service.ts delete mode 100644 src/plugins/dashboard/public/services/serverless/types.ts delete mode 100644 src/plugins/dashboard/public/services/settings/settings.stub.ts delete mode 100644 src/plugins/dashboard/public/services/settings/settings_service.ts delete mode 100644 src/plugins/dashboard/public/services/settings/types.ts delete mode 100644 src/plugins/dashboard/public/services/share/share.stub.ts delete mode 100644 src/plugins/dashboard/public/services/share/share_services.ts delete mode 100644 src/plugins/dashboard/public/services/share/types.ts delete mode 100644 src/plugins/dashboard/public/services/spaces/spaces.stub.ts delete mode 100644 src/plugins/dashboard/public/services/spaces/spaces_service.ts delete mode 100644 src/plugins/dashboard/public/services/spaces/types.ts delete mode 100644 src/plugins/dashboard/public/services/types.ts delete mode 100644 src/plugins/dashboard/public/services/ui_actions/types.ts delete mode 100644 src/plugins/dashboard/public/services/ui_actions/ui_actions_service.stub.ts delete mode 100644 src/plugins/dashboard/public/services/ui_actions/ui_actions_service.ts delete mode 100644 src/plugins/dashboard/public/services/url_forwarding/types.ts delete mode 100644 src/plugins/dashboard/public/services/url_forwarding/url_forwarding_service.ts delete mode 100644 src/plugins/dashboard/public/services/url_forwarding/url_fowarding.stub.ts delete mode 100644 src/plugins/dashboard/public/services/usage_collection/types.ts delete mode 100644 src/plugins/dashboard/public/services/usage_collection/usage_collection.stub.ts delete mode 100644 src/plugins/dashboard/public/services/usage_collection/usage_collection_service.ts delete mode 100644 src/plugins/dashboard/public/services/user_profile/types.ts delete mode 100644 src/plugins/dashboard/public/services/user_profile/user_profile_service.stub.ts delete mode 100644 src/plugins/dashboard/public/services/user_profile/user_profile_service.ts delete mode 100644 src/plugins/dashboard/public/services/visualizations/types.ts delete mode 100644 src/plugins/dashboard/public/services/visualizations/visualizations.stub.ts delete mode 100644 src/plugins/dashboard/public/services/visualizations/visualizations_service.ts rename src/plugins/dashboard/public/{services/dashboard_capabilities/dashboard_capabilities_service.ts => utils/get_dashboard_capabilities.ts} (56%) diff --git a/src/plugins/dashboard/jest_setup.ts b/src/plugins/dashboard/jest_setup.ts index 672e476fb852b..1b0de7854d3ac 100644 --- a/src/plugins/dashboard/jest_setup.ts +++ b/src/plugins/dashboard/jest_setup.ts @@ -7,8 +7,6 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { setStubDashboardServices } from './public/services/mocks'; - /** * CAUTION: Be very mindful of the things you import in to this `jest_setup` file - anything that is imported * here (either directly or implicitly through dependencies) will be **unable** to be mocked elsewhere! @@ -16,4 +14,36 @@ import { setStubDashboardServices } from './public/services/mocks'; * Refer to the "Caution" section here: * https://jestjs.io/docs/jest-object#jestmockmodulename-factory-options */ -setStubDashboardServices(); +import { + mockDashboardBackupService, + mockDashboardContentManagementCache, + mockDashboardContentManagementService, + setStubKibanaServices, +} from './public/services/mocks'; + +// Start the kibana services with stubs +setStubKibanaServices(); + +// Mock the dashboard services +jest.mock('./public/services/dashboard_content_management_service', () => { + return { + getDashboardContentManagementCache: () => mockDashboardContentManagementCache, + getDashboardContentManagementService: () => mockDashboardContentManagementService, + }; +}); + +jest.mock('./public/services/dashboard_backup_service', () => { + return { + getDashboardBackupService: () => mockDashboardBackupService, + }; +}); + +jest.mock('./public/services/dashboard_recently_accessed_service', () => { + return { + getDashboardRecentlyAccessedService: () => ({ + add: jest.fn(), + get: jest.fn(), + get$: jest.fn(), + }), + }; +}); diff --git a/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx b/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx index 95eab08a83cc6..acd46f2763bbc 100644 --- a/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx @@ -8,34 +8,36 @@ */ import React from 'react'; + +import { PresentationContainer } from '@kbn/presentation-containers'; import { - apiCanAccessViewMode, - apiHasLibraryTransforms, - EmbeddableApiContext, - getPanelTitle, - PublishesPanelTitle, CanAccessViewMode, - getInheritedViewMode, + EmbeddableApiContext, + HasInPlaceLibraryTransforms, HasLibraryTransforms, + HasParentApi, HasType, HasTypeDisplayName, - apiHasType, HasUniqueId, - HasParentApi, - apiHasUniqueId, - apiHasParentApi, - HasInPlaceLibraryTransforms, + PublishesPanelTitle, + apiCanAccessViewMode, apiHasInPlaceLibraryTransforms, + apiHasLibraryTransforms, + apiHasParentApi, + apiHasType, + apiHasUniqueId, + getInheritedViewMode, + getPanelTitle, } from '@kbn/presentation-publishing'; import { OnSaveProps, - SavedObjectSaveModal, SaveResult, + SavedObjectSaveModal, showSaveModal, } from '@kbn/saved-objects-plugin/public'; import { Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; -import { PresentationContainer } from '@kbn/presentation-containers'; -import { pluginServices } from '../services/plugin_services'; + +import { coreServices } from '../services/kibana_services'; import { dashboardAddToLibraryActionStrings } from './_dashboard_actions_strings'; export const ACTION_ADD_TO_LIBRARY = 'saveToLibrary'; @@ -62,14 +64,6 @@ export class AddToLibraryAction implements Action { public readonly id = ACTION_ADD_TO_LIBRARY; public order = 8; - private toastsService; - - constructor() { - ({ - notifications: { toasts: this.toastsService }, - } = pluginServices.getServices()); - } - public getDisplayName({ embeddable }: EmbeddableApiContext) { if (!isApiCompatible(embeddable)) throw new IncompatibleActionError(); return dashboardAddToLibraryActionStrings.getDisplayName(); @@ -134,12 +128,12 @@ export class AddToLibraryAction implements Action { initialState: byRefState, }); } - this.toastsService.addSuccess({ + coreServices.notifications.toasts.addSuccess({ title: dashboardAddToLibraryActionStrings.getSuccessMessage(title ? `'${title}'` : ''), 'data-test-subj': 'addPanelToLibrarySuccess', }); } catch (e) { - this.toastsService.addDanger({ + coreServices.notifications.toasts.addDanger({ title: dashboardAddToLibraryActionStrings.getErrorMessage(title), 'data-test-subj': 'addPanelToLibraryError', }); diff --git a/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx b/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx index 856ef173168fc..5eec25f1f052b 100644 --- a/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx @@ -42,8 +42,6 @@ export class ClonePanelAction implements Action { public readonly id = ACTION_CLONE_PANEL; public order = 45; - constructor() {} - public getDisplayName({ embeddable }: EmbeddableApiContext) { if (!isApiCompatible(embeddable)) throw new IncompatibleActionError(); return dashboardClonePanelActionStrings.getDisplayName(); diff --git a/src/plugins/dashboard/public/dashboard_actions/copy_to_dashboard_action.tsx b/src/plugins/dashboard/public/dashboard_actions/copy_to_dashboard_action.tsx index 83762f407f423..fb31886919773 100644 --- a/src/plugins/dashboard/public/dashboard_actions/copy_to_dashboard_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/copy_to_dashboard_action.tsx @@ -9,26 +9,26 @@ import React from 'react'; -import { CoreStart } from '@kbn/core-lifecycle-browser'; import { - apiIsOfType, - apiHasUniqueId, - apiHasParentApi, - apiPublishesSavedObjectId, - HasType, EmbeddableApiContext, - HasUniqueId, HasParentApi, + HasType, + HasUniqueId, PublishesSavedObjectId, + apiHasParentApi, + apiHasUniqueId, + apiIsOfType, + apiPublishesSavedObjectId, } from '@kbn/presentation-publishing'; import { toMountPoint } from '@kbn/react-kibana-mount'; import { Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; -import { DASHBOARD_CONTAINER_TYPE } from '../dashboard_container'; import { DashboardApi } from '../dashboard_api/types'; -import { pluginServices } from '../services/plugin_services'; -import { CopyToDashboardModal } from './copy_to_dashboard_modal'; +import { DASHBOARD_CONTAINER_TYPE } from '../dashboard_container'; +import { coreServices } from '../services/kibana_services'; +import { getDashboardCapabilities } from '../utils/get_dashboard_capabilities'; import { dashboardCopyToDashboardActionStrings } from './_dashboard_actions_strings'; +import { CopyToDashboardModal } from './copy_to_dashboard_modal'; export const ACTION_COPY_TO_DASHBOARD = 'copyToDashboard'; @@ -60,16 +60,6 @@ export class CopyToDashboardAction implements Action { public readonly id = ACTION_COPY_TO_DASHBOARD; public order = 1; - private dashboardCapabilities; - private openModal; - - constructor(private core: CoreStart) { - ({ - dashboardCapabilities: this.dashboardCapabilities, - overlays: { openModal: this.openModal }, - } = pluginServices.getServices()); - } - public getDisplayName({ embeddable }: EmbeddableApiContext) { if (!apiIsCompatible(embeddable)) throw new IncompatibleActionError(); @@ -84,15 +74,15 @@ export class CopyToDashboardAction implements Action { public async isCompatible({ embeddable }: EmbeddableApiContext) { if (!apiIsCompatible(embeddable)) return false; const { createNew: canCreateNew, showWriteControls: canEditExisting } = - this.dashboardCapabilities; + getDashboardCapabilities(); return Boolean(canCreateNew || canEditExisting); } public async execute({ embeddable }: EmbeddableApiContext) { if (!apiIsCompatible(embeddable)) throw new IncompatibleActionError(); - const { theme, i18n } = this.core; - const session = this.openModal( + const { theme, i18n } = coreServices; + const session = coreServices.overlays.openModal( toMountPoint( session.close()} api={embeddable} />, { theme, i18n, diff --git a/src/plugins/dashboard/public/dashboard_actions/copy_to_dashboard_modal.tsx b/src/plugins/dashboard/public/dashboard_actions/copy_to_dashboard_modal.tsx index 06af2abbe0b0c..66b0ed367481d 100644 --- a/src/plugins/dashboard/public/dashboard_actions/copy_to_dashboard_modal.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/copy_to_dashboard_modal.tsx @@ -22,11 +22,12 @@ import { EmbeddablePackageState, PanelNotFoundError } from '@kbn/embeddable-plug import { apiHasSnapshottableState } from '@kbn/presentation-containers/interfaces/serialized_state'; import { LazyDashboardPicker, withSuspense } from '@kbn/presentation-util-plugin/public'; import { omit } from 'lodash'; -import React, { useCallback, useState } from 'react'; -import { createDashboardEditUrl, CREATE_NEW_DASHBOARD_URL } from '../dashboard_constants'; -import { pluginServices } from '../services/plugin_services'; -import { CopyToDashboardAPI } from './copy_to_dashboard_action'; +import React, { useCallback, useMemo, useState } from 'react'; +import { CREATE_NEW_DASHBOARD_URL, createDashboardEditUrl } from '../dashboard_constants'; +import { embeddableService } from '../services/kibana_services'; +import { getDashboardCapabilities } from '../utils/get_dashboard_capabilities'; import { dashboardCopyToDashboardActionStrings } from './_dashboard_actions_strings'; +import { CopyToDashboardAPI } from './copy_to_dashboard_action'; interface CopyToDashboardModalProps { api: CopyToDashboardAPI; @@ -36,11 +37,11 @@ interface CopyToDashboardModalProps { const DashboardPicker = withSuspense(LazyDashboardPicker); export function CopyToDashboardModal({ api, closeModal }: CopyToDashboardModalProps) { - const { - embeddable: { getStateTransfer }, - dashboardCapabilities: { createNew: canCreateNew, showWriteControls: canEditExisting }, - } = pluginServices.getServices(); - const stateTransfer = getStateTransfer(); + const stateTransfer = useMemo(() => embeddableService.getStateTransfer(), []); + const { createNew: canCreateNew, showWriteControls: canEditExisting } = useMemo( + () => getDashboardCapabilities(), + [] + ); const [dashboardOption, setDashboardOption] = useState<'new' | 'existing'>('existing'); const [selectedDashboard, setSelectedDashboard] = useState<{ id: string; name: string } | null>( diff --git a/src/plugins/dashboard/public/dashboard_actions/expand_panel_action.tsx b/src/plugins/dashboard/public/dashboard_actions/expand_panel_action.tsx index 8a375734ef1ef..b4f2a06e6895a 100644 --- a/src/plugins/dashboard/public/dashboard_actions/expand_panel_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/expand_panel_action.tsx @@ -31,8 +31,6 @@ export class ExpandPanelAction implements Action { public readonly id = ACTION_EXPAND_PANEL; public order = 7; - constructor() {} - public getDisplayName({ embeddable }: EmbeddableApiContext) { if (!isApiCompatible(embeddable)) throw new IncompatibleActionError(); return embeddable.parentApi.expandedPanelId.value diff --git a/src/plugins/dashboard/public/dashboard_actions/export_csv_action.tsx b/src/plugins/dashboard/public/dashboard_actions/export_csv_action.tsx index fa8f8640cbb3a..fd55816134ed1 100644 --- a/src/plugins/dashboard/public/dashboard_actions/export_csv_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/export_csv_action.tsx @@ -14,16 +14,16 @@ import { downloadMultipleAs } from '@kbn/share-plugin/public'; import { Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; import { - apiHasInspectorAdapters, HasInspectorAdapters, + apiHasInspectorAdapters, type Adapters, } from '@kbn/inspector-plugin/public'; import { EmbeddableApiContext, - getPanelTitle, PublishesPanelTitle, + getPanelTitle, } from '@kbn/presentation-publishing'; -import { pluginServices } from '../services/plugin_services'; +import { coreServices, fieldFormatService } from '../services/kibana_services'; import { dashboardExportCsvActionStrings } from './_dashboard_actions_strings'; export const ACTION_EXPORT_CSV = 'ACTION_EXPORT_CSV'; @@ -43,16 +43,6 @@ export class ExportCSVAction implements Action { public readonly type = ACTION_EXPORT_CSV; public readonly order = 18; // right after Export in discover which is 19 - private fieldFormats; - private uiSettings; - - constructor() { - ({ - data: { fieldFormats: this.fieldFormats }, - settings: { uiSettings: this.uiSettings }, - } = pluginServices.getServices()); - } - public getIconType() { return 'exportAction'; } @@ -70,9 +60,7 @@ export class ExportCSVAction implements Action { }; private getFormatter = (): FormatFactory | undefined => { - if (this.fieldFormats) { - return this.fieldFormats.deserialize; - } + return fieldFormatService.deserialize; }; private getDataTableContent = (adapters: Adapters | undefined) => { @@ -105,8 +93,8 @@ export class ExportCSVAction implements Action { memo[`${getPanelTitle(embeddable) || untitledFilename}${postFix}.csv`] = { content: exporters.datatableToCSV(datatable, { - csvSeparator: this.uiSettings.get('csv:separator', ','), - quoteValues: this.uiSettings.get('csv:quoteValues', true), + csvSeparator: coreServices.uiSettings.get('csv:separator', ','), + quoteValues: coreServices.uiSettings.get('csv:quoteValues', true), formatFactory, escapeFormulaValues: false, }), diff --git a/src/plugins/dashboard/public/dashboard_actions/filters_notification_action.tsx b/src/plugins/dashboard/public/dashboard_actions/filters_notification_action.tsx index ef179c006666f..854ff5da948f4 100644 --- a/src/plugins/dashboard/public/dashboard_actions/filters_notification_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/filters_notification_action.tsx @@ -8,28 +8,28 @@ */ import React from 'react'; +import { merge } from 'rxjs'; import { isOfAggregateQueryType, isOfQueryType } from '@kbn/es-query'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; -import { Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; - import { - apiCanAccessViewMode, - apiPublishesPartialUnifiedSearch, - apiHasUniqueId, CanAccessViewMode, EmbeddableApiContext, - getInheritedViewMode, - getViewModeSubject, HasParentApi, - PublishesUnifiedSearch, HasUniqueId, PublishesDataViews, + PublishesUnifiedSearch, + apiCanAccessViewMode, + apiHasUniqueId, + apiPublishesPartialUnifiedSearch, + getInheritedViewMode, + getViewModeSubject, } from '@kbn/presentation-publishing'; -import { merge } from 'rxjs'; -import { pluginServices } from '../services/plugin_services'; -import { FiltersNotificationPopover } from './filters_notification_popover'; +import { Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; + +import { coreServices } from '../services/kibana_services'; import { dashboardFilterNotificationActionStrings } from './_dashboard_actions_strings'; +import { FiltersNotificationPopover } from './filters_notification_popover'; export const BADGE_FILTERS_NOTIFICATION = 'ACTION_FILTERS_NOTIFICATION'; @@ -58,18 +58,12 @@ export class FiltersNotificationAction implements Action { public readonly type = BADGE_FILTERS_NOTIFICATION; public readonly order = 2; - private settingsService; - - constructor() { - ({ settings: this.settingsService } = pluginServices.getServices()); - } - public readonly MenuItem = ({ context }: { context: EmbeddableApiContext }) => { const { embeddable } = context; if (!isApiCompatible(embeddable)) throw new IncompatibleActionError(); const { Provider: KibanaReactContextProvider } = createKibanaReactContext({ - uiSettings: this.settingsService.uiSettings, + uiSettings: coreServices.uiSettings, }); return ( diff --git a/src/plugins/dashboard/public/dashboard_actions/index.ts b/src/plugins/dashboard/public/dashboard_actions/index.ts index 30f6819bd37dd..55a371719d953 100644 --- a/src/plugins/dashboard/public/dashboard_actions/index.ts +++ b/src/plugins/dashboard/public/dashboard_actions/index.ts @@ -7,7 +7,6 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { CoreStart } from '@kbn/core/public'; import { CONTEXT_MENU_TRIGGER, PANEL_NOTIFICATION_TRIGGER } from '@kbn/embeddable-plugin/public'; import { DashboardStartDependencies } from '../plugin'; import { AddToLibraryAction } from './add_to_library_action'; @@ -21,13 +20,11 @@ import { UnlinkFromLibraryAction } from './unlink_from_library_action'; import { LegacyUnlinkFromLibraryAction } from './legacy_unlink_from_library_action'; interface BuildAllDashboardActionsProps { - core: CoreStart; allowByValueEmbeddables?: boolean; plugins: DashboardStartDependencies; } export const buildAllDashboardActions = async ({ - core, plugins, allowByValueEmbeddables, }: BuildAllDashboardActionsProps) => { @@ -66,7 +63,7 @@ export const buildAllDashboardActions = async ({ uiActions.registerAction(legacyUnlinkFromLibraryAction); uiActions.attachAction(CONTEXT_MENU_TRIGGER, legacyUnlinkFromLibraryAction.id); - const copyToDashboardAction = new CopyToDashboardAction(core); + const copyToDashboardAction = new CopyToDashboardAction(); uiActions.registerAction(copyToDashboardAction); uiActions.attachAction(CONTEXT_MENU_TRIGGER, copyToDashboardAction.id); } diff --git a/src/plugins/dashboard/public/dashboard_actions/legacy_add_to_library_action.test.tsx b/src/plugins/dashboard/public/dashboard_actions/legacy_add_to_library_action.test.tsx index 7495439e2164c..60367d7950d2e 100644 --- a/src/plugins/dashboard/public/dashboard_actions/legacy_add_to_library_action.test.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/legacy_add_to_library_action.test.tsx @@ -9,11 +9,11 @@ import { PublishesViewMode, ViewMode } from '@kbn/presentation-publishing'; import { BehaviorSubject } from 'rxjs'; -import { pluginServices } from '../services/plugin_services'; import { LegacyAddToLibraryAction, LegacyAddPanelToLibraryActionApi, } from './legacy_add_to_library_action'; +import { coreServices } from '../services/kibana_services'; describe('Add to library action', () => { let action: LegacyAddToLibraryAction; @@ -62,7 +62,7 @@ describe('Add to library action', () => { it('shows a toast with a title from the API when successful', async () => { await action.execute(context); - expect(pluginServices.getServices().notifications.toasts.addSuccess).toHaveBeenCalledWith({ + expect(coreServices.notifications.toasts.addSuccess).toHaveBeenCalledWith({ 'data-test-subj': 'addPanelToLibrarySuccess', title: "Panel 'A very compatible API' was added to the library", }); @@ -71,7 +71,7 @@ describe('Add to library action', () => { it('shows a danger toast when the link operation is unsuccessful', async () => { context.embeddable.linkToLibrary = jest.fn().mockRejectedValue(new Error('Oh dang')); await action.execute(context); - expect(pluginServices.getServices().notifications.toasts.addDanger).toHaveBeenCalledWith({ + expect(coreServices.notifications.toasts.addDanger).toHaveBeenCalledWith({ 'data-test-subj': 'addPanelToLibraryError', title: 'An error was encountered adding panel A very compatible API to the library', }); diff --git a/src/plugins/dashboard/public/dashboard_actions/legacy_add_to_library_action.tsx b/src/plugins/dashboard/public/dashboard_actions/legacy_add_to_library_action.tsx index e48fa3a02bd13..dee049dc2874e 100644 --- a/src/plugins/dashboard/public/dashboard_actions/legacy_add_to_library_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/legacy_add_to_library_action.tsx @@ -18,8 +18,9 @@ import { HasLegacyLibraryTransforms, } from '@kbn/presentation-publishing'; import { Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; -import { pluginServices } from '../services/plugin_services'; + import { dashboardAddToLibraryActionStrings } from './_dashboard_actions_strings'; +import { coreServices } from '../services/kibana_services'; export const ACTION_LEGACY_ADD_TO_LIBRARY = 'legacySaveToLibrary'; @@ -35,14 +36,6 @@ export class LegacyAddToLibraryAction implements Action { public readonly id = ACTION_LEGACY_ADD_TO_LIBRARY; public order = 15; - private toastsService; - - constructor() { - ({ - notifications: { toasts: this.toastsService }, - } = pluginServices.getServices()); - } - public getDisplayName({ embeddable }: EmbeddableApiContext) { if (!isApiCompatible(embeddable)) throw new IncompatibleActionError(); return dashboardAddToLibraryActionStrings.getDisplayName(); @@ -63,14 +56,14 @@ export class LegacyAddToLibraryAction implements Action { const panelTitle = getPanelTitle(embeddable); try { await embeddable.linkToLibrary(); - this.toastsService.addSuccess({ + coreServices.notifications.toasts.addSuccess({ title: dashboardAddToLibraryActionStrings.getSuccessMessage( panelTitle ? `'${panelTitle}'` : '' ), 'data-test-subj': 'addPanelToLibrarySuccess', }); } catch (e) { - this.toastsService.addDanger({ + coreServices.notifications.toasts.addDanger({ title: dashboardAddToLibraryActionStrings.getErrorMessage(panelTitle), 'data-test-subj': 'addPanelToLibraryError', }); diff --git a/src/plugins/dashboard/public/dashboard_actions/legacy_unlink_from_library_action.test.tsx b/src/plugins/dashboard/public/dashboard_actions/legacy_unlink_from_library_action.test.tsx index 135aac2cbf867..7a7e8836a305f 100644 --- a/src/plugins/dashboard/public/dashboard_actions/legacy_unlink_from_library_action.test.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/legacy_unlink_from_library_action.test.tsx @@ -9,7 +9,7 @@ import { PublishesViewMode, ViewMode } from '@kbn/presentation-publishing'; import { BehaviorSubject } from 'rxjs'; -import { pluginServices } from '../services/plugin_services'; +import { coreServices } from '../services/kibana_services'; import { LegacyUnlinkFromLibraryAction, LegacyUnlinkPanelFromLibraryActionApi, @@ -61,7 +61,7 @@ describe('Unlink from library action', () => { it('shows a toast with a title from the API when successful', async () => { await action.execute(context); - expect(pluginServices.getServices().notifications.toasts.addSuccess).toHaveBeenCalledWith({ + expect(coreServices.notifications.toasts.addSuccess).toHaveBeenCalledWith({ 'data-test-subj': 'unlinkPanelSuccess', title: "Panel 'A very compatible API' is no longer connected to the library.", }); @@ -70,7 +70,7 @@ describe('Unlink from library action', () => { it('shows a danger toast when the link operation is unsuccessful', async () => { context.embeddable.unlinkFromLibrary = jest.fn().mockRejectedValue(new Error('Oh dang')); await action.execute(context); - expect(pluginServices.getServices().notifications.toasts.addDanger).toHaveBeenCalledWith({ + expect(coreServices.notifications.toasts.addDanger).toHaveBeenCalledWith({ 'data-test-subj': 'unlinkPanelFailure', title: "An error occured while unlinking 'A very compatible API' from the library.", }); diff --git a/src/plugins/dashboard/public/dashboard_actions/legacy_unlink_from_library_action.tsx b/src/plugins/dashboard/public/dashboard_actions/legacy_unlink_from_library_action.tsx index 40e2ca12e42c0..96daab215dec6 100644 --- a/src/plugins/dashboard/public/dashboard_actions/legacy_unlink_from_library_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/legacy_unlink_from_library_action.tsx @@ -19,8 +19,8 @@ import { PublishesPanelTitle, HasLegacyLibraryTransforms, } from '@kbn/presentation-publishing'; -import { pluginServices } from '../services/plugin_services'; import { dashboardUnlinkFromLibraryActionStrings } from './_dashboard_actions_strings'; +import { coreServices } from '../services/kibana_services'; export const ACTION_LEGACY_UNLINK_FROM_LIBRARY = 'legacyUnlinkFromLibrary'; @@ -38,14 +38,6 @@ export class LegacyUnlinkFromLibraryAction implements Action { public readonly id = ACTION_UNLINK_FROM_LIBRARY; public order = 15; - private toastsService; - - constructor() { - ({ - notifications: { toasts: this.toastsService }, - } = pluginServices.getServices()); - } - public getDisplayName({ embeddable }: EmbeddableApiContext) { if (!isApiCompatible(embeddable)) throw new IncompatibleActionError(); return dashboardUnlinkFromLibraryActionStrings.getDisplayName(); @@ -107,12 +99,12 @@ export class UnlinkFromLibraryAction implements Action { } else { throw new IncompatibleActionError(); } - this.toastsService.addSuccess({ + coreServices.notifications.toasts.addSuccess({ title: dashboardUnlinkFromLibraryActionStrings.getSuccessMessage(title ? `'${title}'` : ''), 'data-test-subj': 'unlinkPanelSuccess', }); } catch (e) { - this.toastsService.addDanger({ + coreServices.notifications.toasts.addDanger({ title: dashboardUnlinkFromLibraryActionStrings.getFailureMessage(title ? `'${title}'` : ''), 'data-test-subj': 'unlinkPanelFailure', }); diff --git a/src/plugins/dashboard/public/dashboard_api/types.ts b/src/plugins/dashboard/public/dashboard_api/types.ts index 01d12c27ce443..bdd72afe9dc40 100644 --- a/src/plugins/dashboard/public/dashboard_api/types.ts +++ b/src/plugins/dashboard/public/dashboard_api/types.ts @@ -31,7 +31,7 @@ import { ControlGroupApi, ControlGroupSerializedState } from '@kbn/controls-plug import { Filter, Query, TimeRange } from '@kbn/es-query'; import { DefaultEmbeddableApi, ErrorEmbeddable, IEmbeddable } from '@kbn/embeddable-plugin/public'; import { DashboardPanelMap, DashboardPanelState } from '../../common'; -import { SaveDashboardReturn } from '../services/dashboard_content_management/types'; +import { SaveDashboardReturn } from '../services/dashboard_content_management_service/types'; import { DashboardStateFromSettingsFlyout, UnsavedPanelState } from '../dashboard_container/types'; export type DashboardApi = CanExpandPanels & diff --git a/src/plugins/dashboard/public/dashboard_app/dashboard_app.test.tsx b/src/plugins/dashboard/public/dashboard_app/dashboard_app.test.tsx index f04528e7bde2c..2bed3ce44ea61 100644 --- a/src/plugins/dashboard/public/dashboard_app/dashboard_app.test.tsx +++ b/src/plugins/dashboard/public/dashboard_app/dashboard_app.test.tsx @@ -7,22 +7,25 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { render, waitFor } from '@testing-library/react'; import { MemoryHistory, createMemoryHistory } from 'history'; import React, { useEffect } from 'react'; + +import { render, waitFor } from '@testing-library/react'; + +import { DashboardApi } from '..'; import type { DashboardRendererProps } from '../dashboard_container/external_api/dashboard_renderer'; +import { LazyDashboardRenderer } from '../dashboard_container/external_api/lazy_dashboard_renderer'; +import { DashboardTopNav } from '../dashboard_top_nav'; import { buildMockDashboard } from '../mocks'; +import { dataService } from '../services/kibana_services'; import { DashboardApp } from './dashboard_app'; -import * as dashboardRendererStuff from '../dashboard_container/external_api/lazy_dashboard_renderer'; -import { DashboardApi } from '..'; - -/* These tests circumvent the need to test the router and legacy code -/* the dashboard app will be passed the expanded panel id from the DashboardRouter through mountApp() -/* @link https://github.com/elastic/kibana/pull/190086/ -*/ +jest.mock('../dashboard_container/external_api/lazy_dashboard_renderer'); +jest.mock('../dashboard_top_nav'); describe('Dashboard App', () => { + dataService.query.filterManager.getFilters = jest.fn().mockImplementation(() => []); + const mockDashboard = buildMockDashboard(); let mockHistory: MemoryHistory; // this is in url_utils dashboardApi expandedPanel subscription @@ -35,19 +38,20 @@ describe('Dashboard App', () => { historySpy = jest.spyOn(mockHistory, 'replace'); /** - * Mock the LazyDashboardRenderer component to avoid rendering the actual dashboard + * Mock the DashboardTopNav + LazyDashboardRenderer component to avoid rendering the actual dashboard * and hitting errors that aren't relevant */ - jest - .spyOn(dashboardRendererStuff, 'LazyDashboardRenderer') - // we need overwrite the onApiAvailable prop to get the dashboard Api in the dashboard app - .mockImplementation(({ onApiAvailable }: DashboardRendererProps) => { + (DashboardTopNav as jest.Mock).mockImplementation(() => <>Top nav); + (LazyDashboardRenderer as jest.Mock).mockImplementation( + ({ onApiAvailable }: DashboardRendererProps) => { + // we need overwrite the onApiAvailable prop to get access to the dashboard API in this test useEffect(() => { onApiAvailable?.(mockDashboard as DashboardApi); }, [onApiAvailable]); return
Test renderer
; - }); + } + ); }); beforeEach(() => { diff --git a/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx b/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx index 759d817432c6a..ecb62bf8fc2b3 100644 --- a/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx +++ b/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx @@ -7,46 +7,52 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { v4 as uuidv4 } from 'uuid'; import { History } from 'history'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import useMount from 'react-use/lib/useMount'; import useObservable from 'react-use/lib/useObservable'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { debounceTime } from 'rxjs'; +import { v4 as uuidv4 } from 'uuid'; +import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { ViewMode } from '@kbn/embeddable-plugin/public'; import { useExecutionContext } from '@kbn/kibana-react-plugin/public'; import { createKbnUrlStateStorage, withNotifyOnErrors } from '@kbn/kibana-utils-plugin/public'; -import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; -import { debounceTime } from 'rxjs'; -import { - DashboardAppNoDataPage, - isDashboardAppInNoDataState, -} from './no_data/dashboard_app_no_data'; -import { loadAndRemoveDashboardState, startSyncingExpandedPanelState } from './url/url_utils'; -import { - getSessionURLObservable, - getSearchSessionIdFromURL, - removeSearchSessionIdFromURL, - createSessionRestorationDataProvider, -} from './url/search_sessions_integration'; import { DashboardApi, DashboardRenderer } from '..'; -import { type DashboardEmbedSettings } from './types'; -import { pluginServices } from '../services/plugin_services'; -import { DashboardRedirect } from '../dashboard_container/types'; -import { useDashboardMountContext } from './hooks/dashboard_mount_context'; +import { SharedDashboardState } from '../../common'; import { - createDashboardEditUrl, DASHBOARD_APP_ID, DASHBOARD_STATE_STORAGE_KEY, + createDashboardEditUrl, } from '../dashboard_constants'; -import { useDashboardOutcomeValidation } from './hooks/use_dashboard_outcome_validation'; -import { loadDashboardHistoryLocationState } from './locator/load_dashboard_history_location_state'; import type { DashboardCreationOptions } from '../dashboard_container/embeddable/dashboard_container_factory'; +import { DashboardRedirect } from '../dashboard_container/types'; import { DashboardTopNav } from '../dashboard_top_nav'; -import { DashboardTabTitleSetter } from './tab_title_setter/dashboard_tab_title_setter'; +import { + coreServices, + dataService, + embeddableService, + screenshotModeService, + shareService, +} from '../services/kibana_services'; +import { useDashboardMountContext } from './hooks/dashboard_mount_context'; +import { useDashboardOutcomeValidation } from './hooks/use_dashboard_outcome_validation'; import { useObservabilityAIAssistantContext } from './hooks/use_observability_ai_assistant_context'; -import { SharedDashboardState } from '../../common'; +import { loadDashboardHistoryLocationState } from './locator/load_dashboard_history_location_state'; +import { + DashboardAppNoDataPage, + isDashboardAppInNoDataState, +} from './no_data/dashboard_app_no_data'; +import { DashboardTabTitleSetter } from './tab_title_setter/dashboard_tab_title_setter'; +import { type DashboardEmbedSettings } from './types'; +import { + createSessionRestorationDataProvider, + getSearchSessionIdFromURL, + getSessionURLObservable, + removeSearchSessionIdFromURL, +} from './url/search_sessions_integration'; +import { loadAndRemoveDashboardState, startSyncingExpandedPanelState } from './url/url_utils'; export interface DashboardAppProps { history: History; @@ -71,31 +77,15 @@ export function DashboardApp({ }); const [dashboardApi, setDashboardApi] = useState(undefined); - /** - * Unpack & set up dashboard services - */ - const { - screenshotMode: { isScreenshotMode, getScreenshotContext }, - coreContext: { executionContext }, - embeddable: { getStateTransfer }, - notifications: { toasts }, - settings: { uiSettings }, - data: { search, dataViews }, - customBranding, - share: { url }, - observabilityAIAssistant, - } = pluginServices.getServices(); - const showPlainSpinner = useObservable(customBranding.hasCustomBranding$, false); + const showPlainSpinner = useObservable(coreServices.customBranding.hasCustomBranding$, false); + const { scopedHistory: getScopedHistory } = useDashboardMountContext(); useObservabilityAIAssistantContext({ - observabilityAIAssistant: observabilityAIAssistant.start, dashboardApi, - search, - dataViews, }); - useExecutionContext(executionContext, { + useExecutionContext(coreServices.executionContext, { type: 'application', page: 'app', id: savedDashboardId || 'new', @@ -105,10 +95,10 @@ export function DashboardApp({ () => createKbnUrlStateStorage({ history, - useHash: uiSettings.get('state:storeInSessionStorage'), - ...withNotifyOnErrors(toasts), + useHash: coreServices.uiSettings.get('state:storeInSessionStorage'), + ...withNotifyOnErrors(coreServices.notifications.toasts), }), - [toasts, history, uiSettings] + [history] ); /** @@ -116,9 +106,9 @@ export function DashboardApp({ */ useEffect(() => { return () => { - search.session.clear(); + dataService.search.session.clear(); }; - }, [search.session]); + }, []); /** * Validate saved object load outcome @@ -141,7 +131,8 @@ export function DashboardApp({ ...stateFromLocator, // if print mode is active, force viewMode.PRINT - ...(isScreenshotMode() && getScreenshotContext('layout') === 'print' + ...(screenshotModeService.isScreenshotMode() && + screenshotModeService.getScreenshotContext('layout') === 'print' ? { viewMode: ViewMode.PRINT } : {}), }; @@ -149,7 +140,7 @@ export function DashboardApp({ return Promise.resolve({ getIncomingEmbeddable: () => - getStateTransfer().getIncomingEmbeddablePackage(DASHBOARD_APP_ID, true), + embeddableService.getStateTransfer().getIncomingEmbeddablePackage(DASHBOARD_APP_ID, true), // integrations useControlGroupIntegration: true, @@ -174,16 +165,7 @@ export function DashboardApp({ getCurrentPath: () => `#${createDashboardEditUrl(dashboardId)}`, }), }); - }, [ - history, - embedSettings, - validateOutcome, - getScopedHistory, - isScreenshotMode, - getStateTransfer, - kbnUrlStateStorage, - getScreenshotContext, - ]); + }, [history, embedSettings, validateOutcome, getScopedHistory, kbnUrlStateStorage]); useEffect(() => { if (!dashboardApi) return; @@ -208,7 +190,7 @@ export function DashboardApp({ return () => appStateSubscription.unsubscribe(); }, [dashboardApi, kbnUrlStateStorage, savedDashboardId]); - const locator = useMemo(() => url?.locators.get(DASHBOARD_APP_LOCATOR), [url]); + const locator = useMemo(() => shareService?.url.locators.get(DASHBOARD_APP_LOCATOR), []); return showNoDataPage ? ( setShowNoDataPage(false)} /> diff --git a/src/plugins/dashboard/public/dashboard_app/dashboard_router.tsx b/src/plugins/dashboard/public/dashboard_app/dashboard_router.tsx index 8449ed9de1080..6ceaede806fed 100644 --- a/src/plugins/dashboard/public/dashboard_app/dashboard_router.tsx +++ b/src/plugins/dashboard/public/dashboard_app/dashboard_router.tsx @@ -9,32 +9,33 @@ import './_dashboard_app.scss'; -import React from 'react'; -import { parse, ParsedQuery } from 'query-string'; -import { render, unmountComponentAtNode } from 'react-dom'; -import { HashRouter, RouteComponentProps, Redirect } from 'react-router-dom'; -import { Routes, Route } from '@kbn/shared-ux-router'; -import { ViewMode } from '@kbn/embeddable-plugin/public'; import { AppMountParameters, CoreStart } from '@kbn/core/public'; -import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; +import { ViewMode } from '@kbn/embeddable-plugin/public'; import { createKbnUrlStateStorage, withNotifyOnErrors } from '@kbn/kibana-utils-plugin/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; +import { Route, Routes } from '@kbn/shared-ux-router'; +import { parse, ParsedQuery } from 'query-string'; +import React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { HashRouter, Redirect, RouteComponentProps } from 'react-router-dom'; import { - createDashboardListingFilterUrl, CREATE_NEW_DASHBOARD_URL, + createDashboardEditUrl, + createDashboardListingFilterUrl, DASHBOARD_APP_ID, LANDING_PAGE_PATH, VIEW_DASHBOARD_URL, } from '../dashboard_constants'; -import { DashboardApp } from './dashboard_app'; -import { pluginServices } from '../services/plugin_services'; import { RedirectToProps } from '../dashboard_container/types'; -import { createDashboardEditUrl } from '../dashboard_constants'; -import { DashboardNoMatch } from './listing_page/dashboard_no_match'; +import { coreServices, dataService, embeddableService } from '../services/kibana_services'; +import { getDashboardCapabilities } from '../utils/get_dashboard_capabilities'; +import { dashboardReadonlyBadge, getDashboardPageTitle } from './_dashboard_app_strings'; +import { DashboardApp } from './dashboard_app'; import { DashboardMountContext } from './hooks/dashboard_mount_context'; -import { DashboardEmbedSettings, DashboardMountContextProps } from './types'; import { DashboardListingPage } from './listing_page/dashboard_listing_page'; -import { dashboardReadonlyBadge, getDashboardPageTitle } from './_dashboard_app_strings'; +import { DashboardNoMatch } from './listing_page/dashboard_no_match'; +import { DashboardEmbedSettings, DashboardMountContextProps } from './types'; export const dashboardUrlParams = { showTopMenu: 'show-top-menu', @@ -56,24 +57,13 @@ export async function mountApp({ appUnMounted, mountContext, }: DashboardMountProps) { - const { - chrome: { setBadge, docTitle, setHelpExtension }, - dashboardCapabilities: { showWriteControls }, - documentationLinks: { dashboardDocLink }, - application: { navigateToApp }, - settings: { uiSettings }, - data: dataStart, - notifications, - embeddable, - } = pluginServices.getServices(); - let globalEmbedSettings: DashboardEmbedSettings | undefined; const getUrlStateStorage = (history: RouteComponentProps['history']) => createKbnUrlStateStorage({ history, - useHash: uiSettings.get('state:storeInSessionStorage'), - ...withNotifyOnErrors(notifications.toasts), + useHash: coreServices.uiSettings.get('state:storeInSessionStorage'), + ...withNotifyOnErrors(coreServices.notifications.toasts), }); const redirect = (redirectTo: RedirectToProps) => { @@ -87,7 +77,11 @@ export async function mountApp({ } else { path = createDashboardListingFilterUrl(redirectTo.filter); } - navigateToApp(DASHBOARD_APP_ID, { path: `#/${path}`, state, replace: redirectTo.useReplace }); + coreServices.application.navigateToApp(DASHBOARD_APP_ID, { + path: `#/${path}`, + state, + replace: redirectTo.useReplace, + }); }; const getDashboardEmbedSettings = ( @@ -120,7 +114,7 @@ export async function mountApp({ }; const renderListingPage = (routeProps: RouteComponentProps) => { - docTitle.change(getDashboardPageTitle()); + coreServices.chrome.docTitle.change(getDashboardPageTitle()); const routeParams = parse(routeProps.history.location.search); const title = (routeParams.title as string) || undefined; const filter = (routeParams.filter as string) || undefined; @@ -139,10 +133,10 @@ export async function mountApp({ }; const hasEmbeddableIncoming = Boolean( - embeddable.getStateTransfer().getIncomingEmbeddablePackage(DASHBOARD_APP_ID, false) + embeddableService.getStateTransfer().getIncomingEmbeddablePackage(DASHBOARD_APP_ID, false) ); if (!hasEmbeddableIncoming) { - dataStart.dataViews.clearCache(); + dataService.dataViews.clearCache(); } // dispatch synthetic hash change event to update hash history objects @@ -175,18 +169,18 @@ export async function mountApp({ ); - setHelpExtension({ + coreServices.chrome.setHelpExtension({ appName: getDashboardPageTitle(), links: [ { linkType: 'documentation', - href: `${dashboardDocLink}`, + href: `${coreServices.docLinks.links.dashboard.guide}`, }, ], }); - if (!showWriteControls) { - setBadge({ + if (!getDashboardCapabilities().showWriteControls) { + coreServices.chrome.setBadge({ text: dashboardReadonlyBadge.getText(), tooltip: dashboardReadonlyBadge.getTooltip(), iconType: 'glasses', @@ -194,7 +188,7 @@ export async function mountApp({ } render(app, element); return () => { - dataStart.search.session.clear(); + dataService.search.session.clear(); unlistenParentHistory(); unmountComponentAtNode(element); appUnMounted(); diff --git a/src/plugins/dashboard/public/dashboard_app/hooks/use_dashboard_outcome_validation.tsx b/src/plugins/dashboard/public/dashboard_app/hooks/use_dashboard_outcome_validation.tsx index 493c5b5f1c67e..fbcdb82ec3410 100644 --- a/src/plugins/dashboard/public/dashboard_app/hooks/use_dashboard_outcome_validation.tsx +++ b/src/plugins/dashboard/public/dashboard_app/hooks/use_dashboard_outcome_validation.tsx @@ -9,11 +9,11 @@ import { useCallback, useMemo, useState } from 'react'; -import { pluginServices } from '../../services/plugin_services'; +import { DashboardCreationOptions } from '../..'; import { createDashboardEditUrl } from '../../dashboard_constants'; +import { LoadDashboardReturn } from '../../services/dashboard_content_management_service/types'; +import { screenshotModeService, spacesService } from '../../services/kibana_services'; import { useDashboardMountContext } from './dashboard_mount_context'; -import { LoadDashboardReturn } from '../../services/dashboard_content_management/types'; -import { DashboardCreationOptions } from '../..'; export const useDashboardOutcomeValidation = () => { const [aliasId, setAliasId] = useState(); @@ -23,11 +23,6 @@ export const useDashboardOutcomeValidation = () => { const { scopedHistory: getScopedHistory } = useDashboardMountContext(); const scopedHistory = getScopedHistory?.(); - /** - * Unpack dashboard services - */ - const { screenshotMode, spaces } = pluginServices.getServices(); - const validateOutcome: DashboardCreationOptions['validateLoadedSavedObject'] = useCallback( ({ dashboardFound, resolveMeta, dashboardId }: LoadDashboardReturn) => { if (!dashboardFound) { @@ -41,10 +36,10 @@ export const useDashboardOutcomeValidation = () => { */ if (loadOutcome === 'aliasMatch' && dashboardId && alias) { const path = scopedHistory.location.hash.replace(dashboardId, alias); - if (screenshotMode.isScreenshotMode()) { + if (screenshotModeService.isScreenshotMode()) { scopedHistory.replace(path); // redirect without the toast when in screenshot mode. } else { - spaces.redirectLegacyUrl?.({ path, aliasPurpose }); + spacesService?.ui.redirectLegacyUrl({ path, aliasPurpose }); } return 'redirected'; // redirected. Stop loading dashboard. } @@ -54,20 +49,20 @@ export const useDashboardOutcomeValidation = () => { } return 'valid'; }, - [scopedHistory, screenshotMode, spaces] + [scopedHistory] ); const getLegacyConflictWarning = useMemo(() => { if (savedObjectId && outcome === 'conflict' && aliasId) { return () => - spaces.getLegacyUrlConflict?.({ + spacesService?.ui.components.getLegacyUrlConflict({ currentObjectId: savedObjectId, otherObjectId: aliasId, otherObjectPath: `#${createDashboardEditUrl(aliasId)}${scopedHistory.location.search}`, }); } return null; - }, [aliasId, outcome, savedObjectId, scopedHistory, spaces]); + }, [aliasId, outcome, savedObjectId, scopedHistory]); return { validateOutcome, getLegacyConflictWarning }; }; diff --git a/src/plugins/dashboard/public/dashboard_app/hooks/use_observability_ai_assistant_context.tsx b/src/plugins/dashboard/public/dashboard_app/hooks/use_observability_ai_assistant_context.tsx index 0348e68f77418..c20e8fcd1dc76 100644 --- a/src/plugins/dashboard/public/dashboard_app/hooks/use_observability_ai_assistant_context.tsx +++ b/src/plugins/dashboard/public/dashboard_app/hooks/use_observability_ai_assistant_context.tsx @@ -7,28 +7,26 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public'; -import { useEffect } from 'react'; import { getESQLQueryColumns } from '@kbn/esql-utils'; -import type { ISearchStart } from '@kbn/data-plugin/public'; import { LensConfigBuilder, + LensDataset, type LensConfig, - type LensMetricConfig, - type LensPieConfig, type LensGaugeConfig, - type LensXYConfig, type LensHeatmapConfig, + type LensMetricConfig, type LensMosaicConfig, + type LensPieConfig, type LensRegionMapConfig, type LensTableConfig, type LensTagCloudConfig, type LensTreeMapConfig, - LensDataset, + type LensXYConfig, } from '@kbn/lens-embeddable-utils/config_builder'; -import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { LensEmbeddableInput } from '@kbn/lens-plugin/public'; +import { useEffect } from 'react'; import { DashboardApi } from '../../dashboard_api/types'; +import { dataService, observabilityAssistantService } from '../../services/kibana_services'; const chartTypes = [ 'xy', @@ -45,25 +43,19 @@ const chartTypes = [ ] as const; export function useObservabilityAIAssistantContext({ - observabilityAIAssistant, dashboardApi, - search, - dataViews, }: { - observabilityAIAssistant: ObservabilityAIAssistantPublicStart | undefined; dashboardApi: DashboardApi | undefined; - search: ISearchStart; - dataViews: DataViewsPublicPluginStart; }) { useEffect(() => { - if (!observabilityAIAssistant) { + if (!observabilityAssistantService) { return; } const { service: { setScreenContext }, createScreenContextAction, - } = observabilityAIAssistant; + } = observabilityAssistantService; return setScreenContext({ screenDescription: @@ -205,12 +197,12 @@ export function useObservabilityAIAssistantContext({ const [columns] = await Promise.all([ getESQLQueryColumns({ esqlQuery: query, - search: search.search, + search: dataService.search.search, signal, }), ]); - const configBuilder = new LensConfigBuilder(dataViews); + const configBuilder = new LensConfigBuilder(dataService.dataViews); let config: LensConfig; @@ -382,5 +374,5 @@ export function useObservabilityAIAssistantContext({ ] : [], }); - }, [observabilityAIAssistant, dashboardApi, search, dataViews]); + }, [dashboardApi]); } diff --git a/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.test.tsx b/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.test.tsx index 4b0ad49ec9b14..5f41a0a872802 100644 --- a/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.test.tsx +++ b/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.test.tsx @@ -13,7 +13,6 @@ import { mount, ReactWrapper, ComponentType } from 'enzyme'; import { I18nProvider } from '@kbn/i18n-react'; import { createKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; -import { pluginServices } from '../../services/plugin_services'; import { DashboardListingPage, DashboardListingPageProps } from './dashboard_listing_page'; // Mock child components. The Dashboard listing page mostly passes down props to shared UX components which are tested in their own packages. @@ -26,7 +25,12 @@ jest.mock('../../dashboard_listing/dashboard_listing', () => { }); import { DashboardAppNoDataPage } from '../no_data/dashboard_app_no_data'; +import { dataService } from '../../services/kibana_services'; +import { getDashboardContentManagementService } from '../../services/dashboard_content_management_service'; + +const dashboardContentManagementService = getDashboardContentManagementService(); const mockIsDashboardAppInNoDataState = jest.fn().mockResolvedValue(false); + jest.mock('../no_data/dashboard_app_no_data', () => { const originalModule = jest.requireActual('../no_data/dashboard_app_no_data'); return { @@ -59,9 +63,7 @@ function mountWith({ props: incomingProps }: { props?: DashboardListingPageProps test('renders analytics no data page when the user has no data view', async () => { mockIsDashboardAppInNoDataState.mockResolvedValueOnce(true); - pluginServices.getServices().data.dataViews.hasData.hasUserDataView = jest - .fn() - .mockResolvedValue(false); + dataService.dataViews.hasData.hasUserDataView = jest.fn().mockResolvedValue(false); let component: ReactWrapper; await act(async () => { @@ -93,9 +95,9 @@ test('When given a title that matches multiple dashboards, filter on the title', const props = makeDefaultProps(); props.title = title; - ( - pluginServices.getServices().dashboardContentManagement.findDashboards.findByTitle as jest.Mock - ).mockResolvedValue(undefined); + (dashboardContentManagementService.findDashboards.findByTitle as jest.Mock).mockResolvedValue( + undefined + ); let component: ReactWrapper; @@ -115,9 +117,9 @@ test('When given a title that matches one dashboard, redirect to dashboard', asy const title = 'search by title'; const props = makeDefaultProps(); props.title = title; - ( - pluginServices.getServices().dashboardContentManagement.findDashboards.findByTitle as jest.Mock - ).mockResolvedValue({ id: 'you_found_me' }); + (dashboardContentManagementService.findDashboards.findByTitle as jest.Mock).mockResolvedValue({ + id: 'you_found_me', + }); let component: ReactWrapper; diff --git a/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.tsx b/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.tsx index 9b036ac98f6cb..034ee2f8e45f4 100644 --- a/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.tsx +++ b/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_listing_page.tsx @@ -9,19 +9,20 @@ import React, { useEffect, useState } from 'react'; -import { ViewMode } from '@kbn/embeddable-plugin/public'; import { syncGlobalQueryStateWithUrl } from '@kbn/data-plugin/public'; +import { ViewMode } from '@kbn/embeddable-plugin/public'; import type { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; +import { DashboardRedirect } from '../../dashboard_container/types'; +import { DashboardListing } from '../../dashboard_listing/dashboard_listing'; +import { coreServices, dataService, serverlessService } from '../../services/kibana_services'; +import { getDashboardBreadcrumb } from '../_dashboard_app_strings'; import { DashboardAppNoDataPage, isDashboardAppInNoDataState, } from '../no_data/dashboard_app_no_data'; -import { pluginServices } from '../../services/plugin_services'; -import { getDashboardBreadcrumb } from '../_dashboard_app_strings'; -import { DashboardRedirect } from '../../dashboard_container/types'; import { getDashboardListItemLink } from './get_dashboard_list_item_link'; -import { DashboardListing } from '../../dashboard_listing/dashboard_listing'; +import { getDashboardContentManagementService } from '../../services/dashboard_content_management_service'; export interface DashboardListingPageProps { kbnUrlStateStorage: IKbnUrlStateStorage; @@ -36,13 +37,6 @@ export const DashboardListingPage = ({ initialFilter, kbnUrlStateStorage, }: DashboardListingPageProps) => { - const { - data: { query }, - serverless, - chrome: { setBreadcrumbs }, - dashboardContentManagement: { findDashboards }, - } = pluginServices.getServices(); - const [showNoDataPage, setShowNoDataPage] = useState(); useEffect(() => { let isMounted = true; @@ -56,40 +50,42 @@ export const DashboardListingPage = ({ }, []); useEffect(() => { - setBreadcrumbs([ + coreServices.chrome.setBreadcrumbs([ { text: getDashboardBreadcrumb(), }, ]); - if (serverless?.setBreadcrumbs) { + if (serverlessService) { // if serverless breadcrumbs available, // reset any deeper context breadcrumbs to only keep the main "dashboard" part that comes from the navigation config - serverless.setBreadcrumbs([]); + serverlessService.setBreadcrumbs([]); } - }, [setBreadcrumbs, serverless]); + }, []); useEffect(() => { // syncs `_g` portion of url with query services const { stop: stopSyncingQueryServiceStateWithUrl } = syncGlobalQueryStateWithUrl( - query, + dataService.query, kbnUrlStateStorage ); if (title) { - findDashboards.findByTitle(title).then((result) => { - if (!result) return; - redirectTo({ - destination: 'dashboard', - id: result.id, - useReplace: true, + getDashboardContentManagementService() + .findDashboards.findByTitle(title) + .then((result) => { + if (!result) return; + redirectTo({ + destination: 'dashboard', + id: result.id, + useReplace: true, + }); }); - }); } return () => { stopSyncingQueryServiceStateWithUrl(); }; - }, [title, redirectTo, query, kbnUrlStateStorage, findDashboards]); + }, [title, redirectTo, kbnUrlStateStorage]); const titleFilter = title ? `${title}` : ''; diff --git a/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_no_match.tsx b/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_no_match.tsx index b89f993546cd3..3ad35d34b7fd1 100644 --- a/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_no_match.tsx +++ b/src/plugins/dashboard/public/dashboard_app/listing_page/dashboard_no_match.tsx @@ -10,29 +10,23 @@ import React, { useEffect } from 'react'; import { RouteComponentProps } from 'react-router-dom'; -import { i18n } from '@kbn/i18n'; import { EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { toMountPoint } from '@kbn/react-kibana-mount'; import { LANDING_PAGE_PATH } from '../../dashboard_constants'; -import { pluginServices } from '../../services/plugin_services'; +import { coreServices, urlForwardingService } from '../../services/kibana_services'; import { useDashboardMountContext } from '../hooks/dashboard_mount_context'; let bannerId: string | undefined; export const DashboardNoMatch = ({ history }: { history: RouteComponentProps['history'] }) => { const { restorePreviousUrl } = useDashboardMountContext(); - const { - analytics, - settings: { i18n: i18nStart, theme }, - overlays: { banners }, - urlForwarding: { navigateToLegacyKibanaUrl }, - } = pluginServices.getServices(); useEffect(() => { restorePreviousUrl(); - const { navigated } = navigateToLegacyKibanaUrl( + const { navigated } = urlForwardingService.navigateToLegacyKibanaUrl( history.location.pathname + history.location.search ); @@ -41,7 +35,7 @@ export const DashboardNoMatch = ({ history }: { history: RouteComponentProps['hi defaultMessage: 'Page not found', }); - bannerId = banners.replace( + bannerId = coreServices.overlays.banners.replace( bannerId, toMountPoint( @@ -55,28 +49,20 @@ export const DashboardNoMatch = ({ history }: { history: RouteComponentProps['hi />

, - { analytics, i18n: i18nStart, theme } + { analytics: coreServices.analytics, i18n: coreServices.i18n, theme: coreServices.theme } ) ); // hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around setTimeout(() => { if (bannerId) { - banners.remove(bannerId); + coreServices.overlays.banners.remove(bannerId); } }, 15000); history.replace(LANDING_PAGE_PATH); } - }, [ - restorePreviousUrl, - navigateToLegacyKibanaUrl, - banners, - analytics, - i18nStart, - theme, - history, - ]); + }, [restorePreviousUrl, history]); return null; }; diff --git a/src/plugins/dashboard/public/dashboard_app/listing_page/get_dashboard_list_item_link.ts b/src/plugins/dashboard/public/dashboard_app/listing_page/get_dashboard_list_item_link.ts index 4483634ddda89..aa932ebd8bf3a 100644 --- a/src/plugins/dashboard/public/dashboard_app/listing_page/get_dashboard_list_item_link.ts +++ b/src/plugins/dashboard/public/dashboard_app/listing_page/get_dashboard_list_item_link.ts @@ -8,27 +8,23 @@ */ import type { QueryState } from '@kbn/data-plugin/public'; -import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; -import { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; +import { IKbnUrlStateStorage, setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; + import { DASHBOARD_APP_ID, - createDashboardEditUrl, GLOBAL_STATE_STORAGE_KEY, + createDashboardEditUrl, } from '../../dashboard_constants'; -import { pluginServices } from '../../services/plugin_services'; +import { coreServices } from '../../services/kibana_services'; export const getDashboardListItemLink = ( kbnUrlStateStorage: IKbnUrlStateStorage, id: string, timeRestore: boolean ) => { - const { - application: { getUrlForApp }, - settings: { uiSettings }, - } = pluginServices.getServices(); - const useHash = uiSettings.get('state:storeInSessionStorage'); // use hash + const useHash = coreServices.uiSettings.get('state:storeInSessionStorage'); // use hash - let url = getUrlForApp(DASHBOARD_APP_ID, { + let url = coreServices.application.getUrlForApp(DASHBOARD_APP_ID, { path: `#${createDashboardEditUrl(id)}`, }); const globalStateInUrl = kbnUrlStateStorage.get(GLOBAL_STATE_STORAGE_KEY) || {}; diff --git a/src/plugins/dashboard/public/dashboard_app/no_data/dashboard_app_no_data.tsx b/src/plugins/dashboard/public/dashboard_app/no_data/dashboard_app_no_data.tsx index abf7799369284..15b3d00d07ec7 100644 --- a/src/plugins/dashboard/public/dashboard_app/no_data/dashboard_app_no_data.tsx +++ b/src/plugins/dashboard/public/dashboard_app/no_data/dashboard_app_no_data.tsx @@ -10,44 +10,30 @@ import React from 'react'; import { withSuspense } from '@kbn/shared-ux-utility'; -import { pluginServices } from '../../services/plugin_services'; + import { DASHBOARD_APP_ID } from '../../dashboard_constants'; +import { + coreServices, + dataService, + dataViewEditorService, + embeddableService, + noDataPageService, + shareService, +} from '../../services/kibana_services'; +import { getDashboardBackupService } from '../../services/dashboard_backup_service'; +import { getDashboardContentManagementService } from '../../services/dashboard_content_management_service'; export const DashboardAppNoDataPage = ({ onDataViewCreated, }: { onDataViewCreated: () => void; }) => { - const { - application, - data: { dataViews }, - dataViewEditor, - http: { basePath, get }, - documentationLinks: { indexPatternsDocLink, kibanaGuideDocLink, esqlDocLink }, - customBranding, - noDataPage, - share, - } = pluginServices.getServices(); - const analyticsServices = { - coreStart: { - docLinks: { - links: { - kibana: { guide: kibanaGuideDocLink }, - indexPatterns: { introduction: indexPatternsDocLink }, - query: { queryESQL: esqlDocLink }, - }, - }, - application, - http: { basePath, get }, - customBranding: { - hasCustomBranding$: customBranding.hasCustomBranding$, - }, - }, - dataViews, - dataViewEditor, - noDataPage, - share: share.url ? { url: share.url } : undefined, + coreStart: coreServices, + dataViews: dataService.dataViews, + dataViewEditor: dataViewEditorService, + noDataPage: noDataPageService, + share: shareService, }; const importPromise = import('@kbn/shared-ux-page-analytics-no-data'); @@ -74,29 +60,22 @@ export const DashboardAppNoDataPage = ({ }; export const isDashboardAppInNoDataState = async () => { - const { - data: { dataViews }, - embeddable, - dashboardContentManagement, - dashboardBackup, - } = pluginServices.getServices(); - - const hasUserDataView = await dataViews.hasData.hasUserDataView().catch(() => false); + const hasUserDataView = await dataService.dataViews.hasData.hasUserDataView().catch(() => false); if (hasUserDataView) return false; // consider has data if there is an incoming embeddable - const hasIncomingEmbeddable = embeddable + const hasIncomingEmbeddable = embeddableService .getStateTransfer() .getIncomingEmbeddablePackage(DASHBOARD_APP_ID, false); if (hasIncomingEmbeddable) return false; // consider has data if there is unsaved dashboard with edits - if (dashboardBackup.dashboardHasUnsavedEdits()) return false; + if (getDashboardBackupService().dashboardHasUnsavedEdits()) return false; // consider has data if there is at least one dashboard - const { total } = await dashboardContentManagement.findDashboards - .search({ search: '', size: 1 }) + const { total } = await getDashboardContentManagementService() + .findDashboards.search({ search: '', size: 1 }) .catch(() => ({ total: 0 })); if (total > 0) return false; diff --git a/src/plugins/dashboard/public/dashboard_app/tab_title_setter/dashboard_tab_title_setter.tsx b/src/plugins/dashboard/public/dashboard_app/tab_title_setter/dashboard_tab_title_setter.tsx index fab0a3cb91c37..e102e6f898c9b 100644 --- a/src/plugins/dashboard/public/dashboard_app/tab_title_setter/dashboard_tab_title_setter.tsx +++ b/src/plugins/dashboard/public/dashboard_app/tab_title_setter/dashboard_tab_title_setter.tsx @@ -10,14 +10,11 @@ import { useEffect } from 'react'; import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing'; -import { pluginServices } from '../../services/plugin_services'; import { DashboardApi } from '../..'; import { getNewDashboardTitle } from '../_dashboard_app_strings'; +import { coreServices } from '../../services/kibana_services'; export const DashboardTabTitleSetter = ({ dashboardApi }: { dashboardApi: DashboardApi }) => { - const { - chrome: { docTitle: chromeDocTitle }, - } = pluginServices.getServices(); const [title, lastSavedId] = useBatchedPublishingSubjects( dashboardApi.panelTitle, dashboardApi.savedObjectId @@ -27,8 +24,10 @@ export const DashboardTabTitleSetter = ({ dashboardApi }: { dashboardApi: Dashbo * Set chrome tab title when dashboard's title changes */ useEffect(() => { - chromeDocTitle.change(!lastSavedId ? getNewDashboardTitle() : title ?? lastSavedId); - }, [title, chromeDocTitle, lastSavedId]); + coreServices.chrome.docTitle.change( + !lastSavedId ? getNewDashboardTitle() : title ?? lastSavedId + ); + }, [title, lastSavedId]); return null; }; diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/use_get_dashboard_panels.test.ts b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/use_get_dashboard_panels.test.ts index 13ba9e7e37516..7a5a77bfc14fe 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/use_get_dashboard_panels.test.ts +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/use_get_dashboard_panels.test.ts @@ -7,14 +7,20 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { renderHook } from '@testing-library/react-hooks'; -import { ADD_PANEL_TRIGGER } from '@kbn/ui-actions-plugin/public'; -import type { PresentationContainer } from '@kbn/presentation-containers'; -import type { Action } from '@kbn/ui-actions-plugin/public'; -import { type BaseVisType, VisGroups, VisTypeAlias } from '@kbn/visualizations-plugin/public'; import { COMMON_EMBEDDABLE_GROUPING } from '@kbn/embeddable-plugin/public'; +import type { PresentationContainer } from '@kbn/presentation-containers'; +import type { Action, UiActionsService } from '@kbn/ui-actions-plugin/public'; +import { ADD_PANEL_TRIGGER } from '@kbn/ui-actions-plugin/public'; +import { + VisGroups, + VisTypeAlias, + VisualizationsStart, + type BaseVisType, +} from '@kbn/visualizations-plugin/public'; +import { renderHook } from '@testing-library/react-hooks'; + +import { uiActionsService, visualizationsService } from '../../../services/kibana_services'; import { useGetDashboardPanels } from './use_get_dashboard_panels'; -import { pluginServices } from '../../../services/plugin_services'; const mockApi = { addNewPanel: jest.fn() } as unknown as jest.Mocked; @@ -24,34 +30,25 @@ describe('Get dashboard panels hook', () => { createNewVisType: jest.fn(), }; - type PluginServices = ReturnType; - let compatibleTriggerActionsRequestSpy: jest.SpyInstance< - ReturnType> + ReturnType> >; let dashboardVisualizationGroupGetterSpy: jest.SpyInstance< - ReturnType + ReturnType >; let dashboardVisualizationAliasesGetterSpy: jest.SpyInstance< - ReturnType + ReturnType >; beforeAll(() => { - const _pluginServices = pluginServices.getServices(); - compatibleTriggerActionsRequestSpy = jest.spyOn( - _pluginServices.uiActions, + uiActionsService, 'getTriggerCompatibleActions' ); - - dashboardVisualizationGroupGetterSpy = jest.spyOn(_pluginServices.visualizations, 'getByGroup'); - - dashboardVisualizationAliasesGetterSpy = jest.spyOn( - _pluginServices.visualizations, - 'getAliases' - ); + dashboardVisualizationGroupGetterSpy = jest.spyOn(visualizationsService, 'getByGroup'); + dashboardVisualizationAliasesGetterSpy = jest.spyOn(visualizationsService, 'getAliases'); }); beforeEach(() => { diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/use_get_dashboard_panels.ts b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/use_get_dashboard_panels.ts index 493eeb004dd87..d074bcb98bd18 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/use_get_dashboard_panels.ts +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/use_get_dashboard_panels.ts @@ -7,19 +7,20 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { useMemo, useRef, useCallback } from 'react'; +import { useCallback, useMemo, useRef } from 'react'; +import { AsyncSubject, defer, from, lastValueFrom, map, type Subscription } from 'rxjs'; + import type { IconType } from '@elastic/eui'; -import { ADD_PANEL_TRIGGER } from '@kbn/ui-actions-plugin/public'; -import { type Subscription, AsyncSubject, from, defer, map, lastValueFrom } from 'rxjs'; -import { EmbeddableFactory, COMMON_EMBEDDABLE_GROUPING } from '@kbn/embeddable-plugin/public'; +import { COMMON_EMBEDDABLE_GROUPING, EmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { PresentationContainer } from '@kbn/presentation-containers'; -import { type BaseVisType, VisGroups, type VisTypeAlias } from '@kbn/visualizations-plugin/public'; +import { ADD_PANEL_TRIGGER } from '@kbn/ui-actions-plugin/public'; +import { VisGroups, type BaseVisType, type VisTypeAlias } from '@kbn/visualizations-plugin/public'; -import { pluginServices } from '../../../services/plugin_services'; +import { uiActionsService, visualizationsService } from '../../../services/kibana_services'; import { getAddPanelActionMenuItemsGroup, - type PanelSelectionMenuItem, type GroupedAddPanelActions, + type PanelSelectionMenuItem, } from './add_panel_action_menu_items'; interface UseGetDashboardPanelsArgs { @@ -46,13 +47,9 @@ export const useGetDashboardPanels = ({ api, createNewVisType }: UseGetDashboard const panelsComputeResultCache = useRef(new AsyncSubject()); const panelsComputeSubscription = useRef(null); - const { - uiActions, - visualizations: { getAliases: getVisTypeAliases, getByGroup: getVisTypesByGroup }, - } = pluginServices.getServices(); - const getSortedVisTypesByGroup = (group: VisGroups) => - getVisTypesByGroup(group) + visualizationsService + .getByGroup(group) .sort((a: BaseVisType | VisTypeAlias, b: BaseVisType | VisTypeAlias) => { const labelA = 'titleInWizard' in a ? a.titleInWizard || a.title : a.title; const labelB = 'titleInWizard' in b ? b.titleInWizard || a.title : a.title; @@ -70,7 +67,8 @@ export const useGetDashboardPanels = ({ api, createNewVisType }: UseGetDashboard const toolVisTypes = getSortedVisTypesByGroup(VisGroups.TOOLS); const legacyVisTypes = getSortedVisTypesByGroup(VisGroups.LEGACY); - const visTypeAliases = getVisTypeAliases() + const visTypeAliases = visualizationsService + .getAliases() .sort(({ promotion: a = false }: VisTypeAlias, { promotion: b = false }: VisTypeAlias) => a === b ? 0 : a ? -1 : 1 ) @@ -133,12 +131,12 @@ export const useGetDashboardPanels = ({ api, createNewVisType }: UseGetDashboard () => defer(() => { return from( - uiActions?.getTriggerCompatibleActions?.(ADD_PANEL_TRIGGER, { + uiActionsService.getTriggerCompatibleActions?.(ADD_PANEL_TRIGGER, { embeddable: api, }) ?? [] ); }), - [api, uiActions] + [api] ); const computeAvailablePanels = useCallback( diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx index ae91af4891bf2..ddc629854affe 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx @@ -7,40 +7,35 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; -import React, { useCallback } from 'react'; import { METRIC_TYPE } from '@kbn/analytics'; -import { useEuiTheme } from '@elastic/eui'; +import React, { useCallback, useMemo } from 'react'; import { AddFromLibraryButton, Toolbar, ToolbarButton } from '@kbn/shared-ux-button-toolbar'; import { BaseVisType, VisTypeAlias } from '@kbn/visualizations-plugin/public'; import { useStateFromPublishingSubject } from '@kbn/presentation-publishing'; +import { useDashboardApi } from '../../dashboard_api/use_dashboard_api'; +import { DASHBOARD_UI_METRIC_ID } from '../../dashboard_constants'; +import { + dataService, + embeddableService, + usageCollectionService, + visualizationsService, +} from '../../services/kibana_services'; import { getCreateVisualizationButtonTitle } from '../_dashboard_app_strings'; -import { EditorMenu } from './editor_menu'; -import { pluginServices } from '../../services/plugin_services'; import { ControlsToolbarButton } from './controls_toolbar_button'; -import { DASHBOARD_UI_METRIC_ID } from '../../dashboard_constants'; -import { useDashboardApi } from '../../dashboard_api/use_dashboard_api'; +import { EditorMenu } from './editor_menu'; export function DashboardEditingToolbar({ isDisabled }: { isDisabled?: boolean }) { - const { - usageCollection, - data: { search }, - embeddable: { getStateTransfer }, - visualizations: { getAliases: getVisTypeAliases }, - } = pluginServices.getServices(); const { euiTheme } = useEuiTheme(); const dashboardApi = useDashboardApi(); - const stateTransferService = getStateTransfer(); - - const lensAlias = getVisTypeAliases().find(({ name }) => name === 'lens'); - - const trackUiMetric = usageCollection.reportUiCounter?.bind( - usageCollection, - DASHBOARD_UI_METRIC_ID + const lensAlias = useMemo( + () => visualizationsService.getAliases().find(({ name }) => name === 'lens'), + [] ); const createNewVisType = useCallback( @@ -49,6 +44,10 @@ export function DashboardEditingToolbar({ isDisabled }: { isDisabled?: boolean } let appId = ''; if (visType) { + const trackUiMetric = usageCollectionService?.reportUiCounter.bind( + usageCollectionService, + DASHBOARD_UI_METRIC_ID + ); if (trackUiMetric) { trackUiMetric(METRIC_TYPE.CLICK, `${visType.name}:create`); } @@ -67,16 +66,17 @@ export function DashboardEditingToolbar({ isDisabled }: { isDisabled?: boolean } path = '#/create?'; } + const stateTransferService = embeddableService.getStateTransfer(); stateTransferService.navigateToEditor(appId, { path, state: { originatingApp: dashboardApi.getAppContext()?.currentAppId, originatingPath: dashboardApi.getAppContext()?.getCurrentPath?.(), - searchSessionId: search.session.getSessionId(), + searchSessionId: dataService.search.session.getSessionId(), }, }); }, - [stateTransferService, dashboardApi, search.session, trackUiMetric] + [dashboardApi] ); /** diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.test.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.test.tsx index a867d0133b46d..7850c1e9ed745 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.test.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.test.tsx @@ -7,35 +7,23 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React from 'react'; import { render } from '@testing-library/react'; -import { EditorMenu } from './editor_menu'; +import React from 'react'; import { buildMockDashboard } from '../../mocks'; +import { EditorMenu } from './editor_menu'; -import { pluginServices } from '../../services/plugin_services'; -import { DashboardContext } from '../../dashboard_api/use_dashboard_api'; import { DashboardApi } from '../../dashboard_api/types'; +import { DashboardContext } from '../../dashboard_api/use_dashboard_api'; +import { + embeddableService, + uiActionsService, + visualizationsService, +} from '../../services/kibana_services'; -jest.mock('../../services/plugin_services', () => { - const module = jest.requireActual('../../services/plugin_services'); - - const _pluginServices = (module.pluginServices as typeof pluginServices).getServices(); - - jest - .spyOn(_pluginServices.embeddable, 'getEmbeddableFactories') - .mockReturnValue(new Map().values()); - jest.spyOn(_pluginServices.uiActions, 'getTriggerCompatibleActions').mockResolvedValue([]); - jest.spyOn(_pluginServices.visualizations, 'getByGroup').mockReturnValue([]); - jest.spyOn(_pluginServices.visualizations, 'getAliases').mockReturnValue([]); - - return { - ...module, - pluginServices: { - ...module.pluginServices, - getServices: jest.fn().mockReturnValue(_pluginServices), - }, - }; -}); +jest.spyOn(embeddableService, 'getEmbeddableFactories').mockReturnValue(new Map().values()); +jest.spyOn(uiActionsService, 'getTriggerCompatibleActions').mockResolvedValue([]); +jest.spyOn(visualizationsService, 'getByGroup').mockReturnValue([]); +jest.spyOn(visualizationsService, 'getAliases').mockReturnValue([]); describe('editor menu', () => { it('renders without crashing', async () => { diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx index a79024fe8b9dc..2cad63c442026 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx @@ -16,8 +16,8 @@ import { toMountPoint } from '@kbn/react-kibana-mount'; import { ToolbarButton } from '@kbn/shared-ux-button-toolbar'; import { useGetDashboardPanels, DashboardPanelSelectionListFlyout } from './add_new_panel'; -import { pluginServices } from '../../services/plugin_services'; import { useDashboardApi } from '../../dashboard_api/use_dashboard_api'; +import { coreServices } from '../../services/kibana_services'; interface EditorMenuProps extends Pick[0], 'createNewVisType'> { @@ -27,12 +27,6 @@ interface EditorMenuProps export const EditorMenu = ({ createNewVisType, isDisabled }: EditorMenuProps) => { const dashboardApi = useDashboardApi(); - const { - overlays, - analytics, - settings: { i18n: i18nStart, theme }, - } = pluginServices.getServices(); - const fetchDashboardPanels = useGetDashboardPanels({ api: dashboardApi, createNewVisType, @@ -63,11 +57,11 @@ export const EditorMenu = ({ createNewVisType, isDisabled }: EditorMenuProps) => /> ); }), - { analytics, theme, i18n: i18nStart } + { analytics: coreServices.analytics, theme: coreServices.theme, i18n: coreServices.i18n } ); dashboardApi.openOverlay( - overlays.openFlyout(mount, { + coreServices.overlays.openFlyout(mount, { size: 'm', maxWidth: 500, paddingSize: flyoutPanelPaddingSize, @@ -80,7 +74,7 @@ export const EditorMenu = ({ createNewVisType, isDisabled }: EditorMenuProps) => }) ); }, - [analytics, theme, i18nStart, dashboardApi, overlays, fetchDashboardPanels] + [dashboardApi, fetchDashboardPanels] ); return ( diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx index ff91eaf896481..41c4a55f6ab8d 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx @@ -8,11 +8,12 @@ */ import { Capabilities } from '@kbn/core/public'; -import { DashboardLocatorParams } from '../../../dashboard_container'; import { convertPanelMapToSavedPanels, DashboardContainerInput } from '../../../../common'; +import { DashboardLocatorParams } from '../../../dashboard_container'; -import { pluginServices } from '../../../services/plugin_services'; +import { shareService } from '../../../services/kibana_services'; import { showPublicUrlSwitch, ShowShareModal, ShowShareModalProps } from './show_share_modal'; +import { getDashboardBackupService } from '../../../services/dashboard_backup_service'; describe('showPublicUrlSwitch', () => { test('returns false if "dashboard" app is not available', () => { @@ -56,13 +57,11 @@ describe('showPublicUrlSwitch', () => { }); describe('ShowShareModal', () => { + const dashboardBackupService = getDashboardBackupService(); const unsavedStateKeys = ['query', 'filters', 'options', 'savedQuery', 'panels'] as Array< keyof DashboardLocatorParams >; - const toggleShareMenuSpy = jest.spyOn( - pluginServices.getServices().share, - 'toggleShareContextMenu' - ); + const toggleShareMenuSpy = jest.spyOn(shareService!, 'toggleShareContextMenu'); afterEach(() => { jest.clearAllMocks(); @@ -71,9 +70,7 @@ describe('ShowShareModal', () => { const getPropsAndShare = ( unsavedState?: Partial ): ShowShareModalProps => { - pluginServices.getServices().dashboardBackup.getState = jest - .fn() - .mockReturnValue({ dashboardState: unsavedState }); + dashboardBackupService.getState = jest.fn().mockReturnValue({ dashboardState: unsavedState }); return { isDirty: true, anchorElement: document.createElement('div'), @@ -169,7 +166,7 @@ describe('ShowShareModal', () => { }, }; const props = getPropsAndShare(unsavedDashboardState); - pluginServices.getServices().dashboardBackup.getState = jest.fn().mockReturnValue({ + dashboardBackupService.getState = jest.fn().mockReturnValue({ dashboardState: unsavedDashboardState, panels: { panel_1: { changedKey1: 'changed' }, diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx index 81226fbb5b298..5dd56465de920 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx @@ -7,6 +7,10 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { omit } from 'lodash'; +import moment from 'moment'; +import React, { ReactElement, useState } from 'react'; + import { EuiCheckboxGroup } from '@elastic/eui'; import type { Capabilities } from '@kbn/core/public'; import { QueryState } from '@kbn/data-plugin/common'; @@ -14,15 +18,17 @@ import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { ViewMode } from '@kbn/embeddable-plugin/public'; import { i18n } from '@kbn/i18n'; import { getStateFromKbnUrl, setStateToKbnUrl, unhashUrl } from '@kbn/kibana-utils-plugin/public'; -import { omit } from 'lodash'; -import moment from 'moment'; -import React, { ReactElement, useState } from 'react'; + import { convertPanelMapToSavedPanels, DashboardPanelMap } from '../../../../common'; import { DashboardLocatorParams } from '../../../dashboard_container'; -import { pluginServices } from '../../../services/plugin_services'; -import { dashboardUrlParams } from '../../dashboard_router'; +import { + getDashboardBackupService, + PANELS_CONTROL_GROUP_KEY, +} from '../../../services/dashboard_backup_service'; +import { coreServices, dataService, shareService } from '../../../services/kibana_services'; +import { getDashboardCapabilities } from '../../../utils/get_dashboard_capabilities'; import { shareModalStrings } from '../../_dashboard_app_strings'; -import { PANELS_CONTROL_GROUP_KEY } from '../../../services/dashboard_backup/dashboard_backup_service'; +import { dashboardUrlParams } from '../../dashboard_router'; const showFilterBarId = 'showFilterBar'; @@ -49,21 +55,7 @@ export function ShowShareModal({ dashboardTitle, getPanelsState, }: ShowShareModalProps) { - const { - dashboardCapabilities: { createShortUrl: allowShortUrl }, - dashboardBackup, - data: { - query: { - timefilter: { - timefilter: { getTime }, - }, - }, - }, - notifications, - share: { toggleShareContextMenu }, - } = pluginServices.getServices(); - - if (!toggleShareContextMenu) return; // TODO: Make this logic cleaner once share is an optional service + if (!shareService) return; const EmbedUrlParamExtension = ({ setParamValue, @@ -125,7 +117,7 @@ export function ShowShareModal({ let unsavedStateForLocator: DashboardLocatorParams = {}; const { dashboardState: unsavedDashboardState, panels: panelModifications } = - dashboardBackup.getState(savedObjectId) ?? {}; + getDashboardBackupService().getState(savedObjectId) ?? {}; const allUnsavedPanels = (() => { if ( @@ -186,7 +178,7 @@ export function ShowShareModal({ refreshInterval: undefined, // We don't share refresh interval externally viewMode: ViewMode.VIEW, // For share locators we always load the dashboard in view mode useHash: false, - timeRange: getTime(), + timeRange: dataService.query.timefilter.timefilter.getTime(), ...unsavedStateForLocator, }; @@ -203,11 +195,11 @@ export function ShowShareModal({ unhashUrl(baseUrl) ); - toggleShareContextMenu({ + shareService.toggleShareContextMenu({ isDirty, anchorElement, allowEmbed: true, - allowShortUrl, + allowShortUrl: getDashboardCapabilities().createShortUrl, shareableUrl, objectId: savedObjectId, objectType: 'dashboard', @@ -238,6 +230,6 @@ export function ShowShareModal({ snapshotShareWarning: Boolean(unsavedDashboardState?.panels) ? shareModalStrings.getSnapshotShareWarning() : undefined, - toasts: notifications.toasts, + toasts: coreServices.notifications.toasts, }); } diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/use_dashboard_menu_items.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/use_dashboard_menu_items.tsx index 41ddee24a9330..ca58d3c74bd3f 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/use_dashboard_menu_items.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/use_dashboard_menu_items.tsx @@ -7,23 +7,25 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { batch } from 'react-redux'; import { Dispatch, SetStateAction, useCallback, useMemo, useState } from 'react'; +import { batch } from 'react-redux'; import { ViewMode } from '@kbn/embeddable-plugin/public'; -import { TopNavMenuData } from '@kbn/navigation-plugin/public'; +import type { TopNavMenuData } from '@kbn/navigation-plugin/public'; import useMountedState from 'react-use/lib/useMountedState'; import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing'; import { UI_SETTINGS } from '../../../common'; -import { topNavStrings } from '../_dashboard_app_strings'; -import { ShowShareModal } from './share/show_share_modal'; -import { pluginServices } from '../../services/plugin_services'; -import { CHANGE_CHECK_DEBOUNCE } from '../../dashboard_constants'; -import { confirmDiscardUnsavedChanges } from '../../dashboard_listing/confirm_overlays'; -import { SaveDashboardReturn } from '../../services/dashboard_content_management/types'; import { useDashboardApi } from '../../dashboard_api/use_dashboard_api'; +import { CHANGE_CHECK_DEBOUNCE } from '../../dashboard_constants'; import { openSettingsFlyout } from '../../dashboard_container/embeddable/api'; +import { confirmDiscardUnsavedChanges } from '../../dashboard_listing/confirm_overlays'; +import { getDashboardBackupService } from '../../services/dashboard_backup_service'; +import { SaveDashboardReturn } from '../../services/dashboard_content_management_service/types'; +import { coreServices, shareService } from '../../services/kibana_services'; +import { getDashboardCapabilities } from '../../utils/get_dashboard_capabilities'; +import { topNavStrings } from '../_dashboard_app_strings'; +import { ShowShareModal } from './share/show_share_modal'; export const useDashboardMenuItems = ({ isLabsShown, @@ -40,17 +42,6 @@ export const useDashboardMenuItems = ({ const [isSaveInProgress, setIsSaveInProgress] = useState(false); - /** - * Unpack dashboard services - */ - const { - share, - dashboardBackup, - settings: { uiSettings }, - dashboardCapabilities: { showWriteControls }, - } = pluginServices.getServices(); - const isLabsEnabled = uiSettings.get(UI_SETTINGS.ENABLE_LABS_UI); - /** * Unpack dashboard state from redux */ @@ -120,7 +111,7 @@ export const useDashboardMenuItems = ({ const switchModes = switchToViewMode ? () => { dashboardApi.setViewMode(ViewMode.VIEW); - dashboardBackup.storeViewMode(ViewMode.VIEW); + getDashboardBackupService().storeViewMode(ViewMode.VIEW); } : undefined; if (!hasUnsavedChanges) { @@ -138,7 +129,7 @@ export const useDashboardMenuItems = ({ }); }, viewMode as ViewMode); }, - [dashboardApi, dashboardBackup, hasUnsavedChanges, viewMode, isMounted] + [dashboardApi, hasUnsavedChanges, viewMode, isMounted] ); /** @@ -170,7 +161,7 @@ export const useDashboardMenuItems = ({ testId: 'dashboardEditMode', className: 'eui-hideFor--s eui-hideFor--xs', // hide for small screens - editing doesn't work in mobile mode. run: () => { - dashboardBackup.storeViewMode(ViewMode.EDIT); + getDashboardBackupService().storeViewMode(ViewMode.EDIT); dashboardApi.setViewMode(ViewMode.EDIT); dashboardApi.clearOverlays(); }, @@ -243,7 +234,6 @@ export const useDashboardMenuItems = ({ dashboardApi, setIsLabsShown, isLabsShown, - dashboardBackup, quickSaveDashboard, resetChanges, isResetting, @@ -275,9 +265,13 @@ export const useDashboardMenuItems = ({ /** * Build ordered menus for view and edit mode. */ + const isLabsEnabled = useMemo(() => coreServices.uiSettings.get(UI_SETTINGS.ENABLE_LABS_UI), []); + const viewModeTopNavConfig = useMemo(() => { + const { showWriteControls } = getDashboardCapabilities(); + const labsMenuItem = isLabsEnabled ? [menuItems.labs] : []; - const shareMenuItem = share ? [menuItems.share] : []; + const shareMenuItem = shareService ? [menuItems.share] : []; const duplicateMenuItem = showWriteControls ? [menuItems.interactiveSave] : []; const editMenuItem = showWriteControls && !managed ? [menuItems.edit] : []; const mayberesetChangesMenuItem = showResetChange ? [resetChangesMenuItem] : []; @@ -290,19 +284,11 @@ export const useDashboardMenuItems = ({ ...mayberesetChangesMenuItem, ...editMenuItem, ]; - }, [ - isLabsEnabled, - menuItems, - share, - showWriteControls, - managed, - showResetChange, - resetChangesMenuItem, - ]); + }, [isLabsEnabled, menuItems, managed, showResetChange, resetChangesMenuItem]); const editModeTopNavConfig = useMemo(() => { const labsMenuItem = isLabsEnabled ? [menuItems.labs] : []; - const shareMenuItem = share ? [menuItems.share] : []; + const shareMenuItem = shareService ? [menuItems.share] : []; const editModeItems: TopNavMenuData[] = []; if (lastSavedId) { @@ -317,7 +303,7 @@ export const useDashboardMenuItems = ({ editModeItems.push(menuItems.switchToViewMode, menuItems.interactiveSave); } return [...labsMenuItem, menuItems.settings, ...shareMenuItem, ...editModeItems]; - }, [isLabsEnabled, menuItems, share, lastSavedId, showResetChange, resetChangesMenuItem]); + }, [isLabsEnabled, menuItems, lastSavedId, showResetChange, resetChangesMenuItem]); return { viewModeTopNavConfig, editModeTopNavConfig }; }; diff --git a/src/plugins/dashboard/public/dashboard_app/url/search_sessions_integration.ts b/src/plugins/dashboard/public/dashboard_app/url/search_sessions_integration.ts index 8092f99a0bb3a..5ec8a0716d410 100644 --- a/src/plugins/dashboard/public/dashboard_app/url/search_sessions_integration.ts +++ b/src/plugins/dashboard/public/dashboard_app/url/search_sessions_integration.ts @@ -23,7 +23,7 @@ import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { SEARCH_SESSION_ID } from '../../dashboard_constants'; import { DashboardContainer, DashboardLocatorParams } from '../../dashboard_container'; import { convertPanelMapToSavedPanels } from '../../../common'; -import { pluginServices } from '../../services/plugin_services'; +import { dataService } from '../../services/kibana_services'; export const removeSearchSessionIdFromURL = (kbnUrlStateStorage: IKbnUrlStateStorage) => { kbnUrlStateStorage.kbnUrlControls.updateAsync((nextUrl) => { @@ -69,17 +69,6 @@ function getLocatorParams({ container: DashboardContainer; shouldRestoreSearchSession: boolean; }): DashboardLocatorParams { - const { - data: { - query: { - queryString, - filterManager, - timefilter: { timefilter }, - }, - search: { session }, - }, - } = pluginServices.getServices(); - const { componentState: { lastSavedId }, explicitInput: { panels, query, viewMode }, @@ -89,11 +78,15 @@ function getLocatorParams({ viewMode, useHash: false, preserveSavedFilters: false, - filters: filterManager.getFilters(), - query: queryString.formatQuery(query) as Query, + filters: dataService.query.filterManager.getFilters(), + query: dataService.query.queryString.formatQuery(query) as Query, dashboardId: container.getDashboardSavedObjectId(), - searchSessionId: shouldRestoreSearchSession ? session.getSessionId() : undefined, - timeRange: shouldRestoreSearchSession ? timefilter.getAbsoluteTime() : timefilter.getTime(), + searchSessionId: shouldRestoreSearchSession + ? dataService.search.session.getSessionId() + : undefined, + timeRange: shouldRestoreSearchSession + ? dataService.query.timefilter.timefilter.getAbsoluteTime() + : dataService.query.timefilter.timefilter.getTime(), refreshInterval: shouldRestoreSearchSession ? { pause: true, // force pause refresh interval when restoring a session diff --git a/src/plugins/dashboard/public/dashboard_app/url/url_utils.ts b/src/plugins/dashboard/public/dashboard_app/url/url_utils.ts index 09e15abe5eea1..b748909eac9ac 100644 --- a/src/plugins/dashboard/public/dashboard_app/url/url_utils.ts +++ b/src/plugins/dashboard/public/dashboard_app/url/url_utils.ts @@ -7,26 +7,26 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { History } from 'history'; import _ from 'lodash'; import { skip } from 'rxjs'; import semverSatisfies from 'semver/functions/satisfies'; -import { History } from 'history'; -import { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; import { replaceUrlHashQuery } from '@kbn/kibana-utils-plugin/common'; +import { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; import { + DashboardContainerInput, DashboardPanelMap, SharedDashboardState, convertSavedPanelsToPanelMap, - DashboardContainerInput, } from '../../../common'; -import { pluginServices } from '../../services/plugin_services'; -import { getPanelTooOldErrorString } from '../_dashboard_app_strings'; -import { DASHBOARD_STATE_STORAGE_KEY, createDashboardEditUrl } from '../../dashboard_constants'; import { SavedDashboardPanel } from '../../../common/content_management'; -import { migrateLegacyQuery } from '../../services/dashboard_content_management/lib/load_dashboard_state'; import { DashboardApi } from '../../dashboard_api/types'; +import { DASHBOARD_STATE_STORAGE_KEY, createDashboardEditUrl } from '../../dashboard_constants'; +import { migrateLegacyQuery } from '../../services/dashboard_content_management_service/lib/load_dashboard_state'; +import { coreServices } from '../../services/kibana_services'; +import { getPanelTooOldErrorString } from '../_dashboard_app_strings'; /** * We no longer support loading panels from a version older than 7.3 in the URL. @@ -54,7 +54,7 @@ function getPanelsMap(appStateInUrl: SharedDashboardState): DashboardPanelMap | } if (isPanelVersionTooOld(appStateInUrl.panels)) { - pluginServices.getServices().notifications.toasts.addWarning(getPanelTooOldErrorString()); + coreServices.notifications.toasts.addWarning(getPanelTooOldErrorString()); return undefined; } diff --git a/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.test.tsx b/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.test.tsx index 4204953e22696..b167f68e1595b 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.test.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.test.tsx @@ -7,20 +7,18 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React from 'react'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; import { findTestSubject } from '@elastic/eui/lib/test'; +import { mountWithIntl } from '@kbn/test-jest-helpers'; +import React from 'react'; +import { ViewMode } from '@kbn/embeddable-plugin/public'; +import { DashboardApi } from '../../../dashboard_api/types'; +import { DashboardContext } from '../../../dashboard_api/use_dashboard_api'; import { buildMockDashboard } from '../../../mocks'; +import { coreServices, visualizationsService } from '../../../services/kibana_services'; import { DashboardEmptyScreen } from './dashboard_empty_screen'; -import { pluginServices } from '../../../services/plugin_services'; -import { DashboardContext } from '../../../dashboard_api/use_dashboard_api'; -import { DashboardApi } from '../../../dashboard_api/types'; -import { ViewMode } from '@kbn/embeddable-plugin/public'; -pluginServices.getServices().visualizations.getAliases = jest - .fn() - .mockReturnValue([{ name: 'lens' }]); +visualizationsService.getAliases = jest.fn().mockReturnValue([{ name: 'lens' }]); describe('DashboardEmptyScreen', () => { function mountComponent(viewMode: ViewMode) { @@ -57,7 +55,7 @@ describe('DashboardEmptyScreen', () => { }); test('renders correctly with readonly mode', () => { - pluginServices.getServices().dashboardCapabilities.showWriteControls = false; + (coreServices.application.capabilities as any).dashboard.showWriteControls = false; const component = mountComponent(ViewMode.VIEW); expect(component.render()).toMatchSnapshot(); @@ -72,7 +70,7 @@ describe('DashboardEmptyScreen', () => { // even when in edit mode, readonly users should not have access to the editing buttons in the empty prompt. test('renders correctly with readonly and edit mode', () => { - pluginServices.getServices().dashboardCapabilities.showWriteControls = false; + (coreServices.application.capabilities as any).dashboard.showWriteControls = false; const component = mountComponent(ViewMode.EDIT); expect(component.render()).toMatchSnapshot(); diff --git a/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx b/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx index 91edfcc5fc3b2..e4e82339e7c22 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx @@ -21,33 +21,31 @@ import { } from '@elastic/eui'; import { METRIC_TYPE } from '@kbn/analytics'; import { ViewMode } from '@kbn/embeddable-plugin/public'; - import { useStateFromPublishingSubject } from '@kbn/presentation-publishing'; -import { DASHBOARD_UI_METRIC_ID } from '../../../dashboard_constants'; -import { pluginServices } from '../../../services/plugin_services'; + import { useDashboardApi } from '../../../dashboard_api/use_dashboard_api'; +import { DASHBOARD_UI_METRIC_ID } from '../../../dashboard_constants'; +import { + coreServices, + dataService, + embeddableService, + usageCollectionService, + visualizationsService, +} from '../../../services/kibana_services'; +import { getDashboardCapabilities } from '../../../utils/get_dashboard_capabilities'; import { emptyScreenStrings } from '../../_dashboard_container_strings'; export function DashboardEmptyScreen() { - const { - settings: { - theme: { theme$ }, - }, - usageCollection, - data: { search }, - http: { basePath }, - embeddable: { getStateTransfer }, - dashboardCapabilities: { showWriteControls }, - visualizations: { getAliases: getVisTypeAliases }, - } = pluginServices.getServices(); - const lensAlias = useMemo( - () => getVisTypeAliases().find(({ name }) => name === 'lens'), - [getVisTypeAliases] + () => visualizationsService.getAliases().find(({ name }) => name === 'lens'), + [] ); + const { showWriteControls } = useMemo(() => { + return getDashboardCapabilities(); + }, []); const dashboardApi = useDashboardApi(); - const isDarkTheme = useObservable(theme$)?.darkMode; + const isDarkTheme = useObservable(coreServices.theme.theme$)?.darkMode; const viewMode = useStateFromPublishingSubject(dashboardApi.viewMode); const isEditMode = useMemo(() => { return viewMode === 'edit'; @@ -55,8 +53,8 @@ export function DashboardEmptyScreen() { const goToLens = useCallback(() => { if (!lensAlias || !lensAlias.alias) return; - const trackUiMetric = usageCollection.reportUiCounter?.bind( - usageCollection, + const trackUiMetric = usageCollectionService?.reportUiCounter.bind( + usageCollectionService, DASHBOARD_UI_METRIC_ID ); @@ -64,18 +62,18 @@ export function DashboardEmptyScreen() { trackUiMetric(METRIC_TYPE.CLICK, `${lensAlias.name}:create`); } const appContext = dashboardApi.getAppContext(); - getStateTransfer().navigateToEditor(lensAlias.alias.app, { + embeddableService.getStateTransfer().navigateToEditor(lensAlias.alias.app, { path: lensAlias.alias.path, state: { originatingApp: appContext?.currentAppId, originatingPath: appContext?.getCurrentPath?.() ?? '', - searchSessionId: search.session.getSessionId(), + searchSessionId: dataService.search.session.getSessionId(), }, }); - }, [getStateTransfer, lensAlias, dashboardApi, search.session, usageCollection]); + }, [lensAlias, dashboardApi]); // TODO replace these SVGs with versions from EuiIllustration as soon as it becomes available. - const imageUrl = basePath.prepend( + const imageUrl = coreServices.http.basePath.prepend( `/plugins/dashboard/assets/${isDarkTheme ? 'dashboards_dark' : 'dashboards_light'}.svg` ); diff --git a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx index 0a116eae997d4..518b009571e27 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx @@ -7,15 +7,17 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import classNames from 'classnames'; +import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; + import { EuiLoadingChart } from '@elastic/eui'; import { css } from '@emotion/react'; import { EmbeddablePanel, ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; -import classNames from 'classnames'; -import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; + import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing'; import { DashboardPanelState } from '../../../../common'; -import { pluginServices } from '../../../services/plugin_services'; import { useDashboardApi } from '../../../dashboard_api/use_dashboard_api'; +import { embeddableService, presentationUtilService } from '../../../services/kibana_services'; type DivProps = Pick, 'className' | 'style' | 'children'>; @@ -97,10 +99,6 @@ export const Item = React.forwardRef( : undefined; const renderedEmbeddable = useMemo(() => { - const { - embeddable: { reactEmbeddableRegistryHasKey }, - } = pluginServices.getServices(); - const panelProps = { showBadges: true, showBorder: useMargins, @@ -109,7 +107,7 @@ export const Item = React.forwardRef( }; // render React embeddable - if (reactEmbeddableRegistryHasKey(type)) { + if (embeddableService.reactEmbeddableRegistryHasKey(type)) { return ( ((props, pane // ReactGridLayout passes ref to children. Functional component children require forwardRef to avoid react warning // https://github.com/react-grid-layout/react-grid-layout#custom-child-components-and-draggable-handles export const DashboardGridItem = React.forwardRef((props, ref) => { - const { - settings: { isProjectEnabledInLabs }, - } = pluginServices.getServices(); const dashboardApi = useDashboardApi(); const [focusedPanelId, viewMode] = useBatchedPublishingSubjects( dashboardApi.focusedPanelId$, dashboardApi.viewMode ); + const deferBelowFoldEnabled = useMemo( + () => presentationUtilService.labsService.isProjectEnabled('labs:dashboard:deferBelowFold'), + [] + ); + const isEnabled = viewMode !== 'print' && - isProjectEnabledInLabs('labs:dashboard:deferBelowFold') && + deferBelowFoldEnabled && (!focusedPanelId || focusedPanelId === props.id); return isEnabled ? : ; diff --git a/src/plugins/dashboard/public/dashboard_container/component/settings/settings_flyout.tsx b/src/plugins/dashboard/public/dashboard_container/component/settings/settings_flyout.tsx index d4160d7002949..20fd2b93119de 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/settings/settings_flyout.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/settings/settings_flyout.tsx @@ -9,29 +9,32 @@ import React, { useCallback, useState } from 'react'; import useMountedState from 'react-use/lib/useMountedState'; -import { i18n } from '@kbn/i18n'; + import { - EuiFormRow, - EuiFieldText, - EuiTextArea, - EuiForm, EuiButton, EuiButtonEmpty, + EuiCallOut, + EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiFlyoutBody, EuiFlyoutFooter, EuiFlyoutHeader, - EuiTitle, - EuiCallOut, + EuiForm, + EuiFormRow, + EuiIconTip, EuiSwitch, EuiText, - EuiIconTip, + EuiTextArea, + EuiTitle, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; + import { DashboardContainerInput } from '../../../../common'; -import { pluginServices } from '../../../services/plugin_services'; import { useDashboardApi } from '../../../dashboard_api/use_dashboard_api'; +import { getDashboardContentManagementService } from '../../../services/dashboard_content_management_service'; +import { savedObjectsTaggingService } from '../../../services/kibana_services'; interface DashboardSettingsProps { onClose: () => void; @@ -40,11 +43,6 @@ interface DashboardSettingsProps { const DUPLICATE_TITLE_CALLOUT_ID = 'duplicateTitleCallout'; export const DashboardSettings = ({ onClose }: DashboardSettingsProps) => { - const { - savedObjectsTagging: { components }, - dashboardContentManagement: { checkForDuplicateDashboardTitle }, - } = pluginServices.getServices(); - const dashboardApi = useDashboardApi(); const [localSettings, setLocalSettings] = useState(dashboardApi.getSettings()); @@ -63,13 +61,15 @@ export const DashboardSettings = ({ onClose }: DashboardSettingsProps) => { const onApply = async () => { setIsApplying(true); - const validTitle = await checkForDuplicateDashboardTitle({ - title: localSettings.title, - copyOnSave: false, - lastSavedTitle: dashboardApi.panelTitle.value ?? '', - onTitleDuplicate, - isTitleDuplicateConfirmed, - }); + const validTitle = await getDashboardContentManagementService().checkForDuplicateDashboardTitle( + { + title: localSettings.title, + copyOnSave: false, + lastSavedTitle: dashboardApi.panelTitle.value ?? '', + onTitleDuplicate, + isTitleDuplicateConfirmed, + } + ); if (!isMounted()) return; @@ -121,7 +121,9 @@ export const DashboardSettings = ({ onClose }: DashboardSettingsProps) => { }; const renderTagSelector = () => { - if (!components) return; + const savedObjectsTaggingApi = savedObjectsTaggingService?.getTaggingApi(); + if (!savedObjectsTaggingApi) return; + return ( { /> } > - updateDashboardSetting({ tags: selectedTags })} /> diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.tsx index 72dfc8659ae24..47732d52ad40c 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.tsx @@ -15,11 +15,11 @@ import { ReferenceOrValueEmbeddable, } from '@kbn/embeddable-plugin/public'; import { + CONTACT_CARD_EMBEDDABLE, ContactCardEmbeddable, ContactCardEmbeddableFactory, ContactCardEmbeddableInput, ContactCardEmbeddableOutput, - CONTACT_CARD_EMBEDDABLE, } from '@kbn/embeddable-plugin/public/lib/test_samples/embeddables'; import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; import { @@ -34,7 +34,7 @@ import { render } from '@testing-library/react'; import React from 'react'; import { BehaviorSubject, lastValueFrom, Subject } from 'rxjs'; import { buildMockDashboard, getSampleDashboardPanel } from '../../../mocks'; -import { pluginServices } from '../../../services/plugin_services'; +import { embeddableService } from '../../../services/kibana_services'; import { DashboardContainer } from '../dashboard_container'; import { duplicateDashboardPanel, incrementPanelTitle } from './duplicate_dashboard_panel'; @@ -54,9 +54,7 @@ describe('Legacy embeddables', () => { const mockEmbeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any); - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(mockEmbeddableFactory); + embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockEmbeddableFactory); container = buildMockDashboard({ overrides: { panels: { diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.ts index 76a600a10decd..d62bb78b3b645 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.ts @@ -7,6 +7,9 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { filter, map, max } from 'lodash'; +import { v4 as uuidv4 } from 'uuid'; + import { isReferenceOrValueEmbeddable, PanelNotFoundError } from '@kbn/embeddable-plugin/public'; import { apiHasSnapshottableState } from '@kbn/presentation-containers/interfaces/serialized_state'; import { @@ -16,11 +19,10 @@ import { getPanelTitle, stateHasTitles, } from '@kbn/presentation-publishing'; -import { filter, map, max } from 'lodash'; -import { v4 as uuidv4 } from 'uuid'; + import { DashboardPanelState, prefixReferencesFromPanel } from '../../../../common'; import { dashboardClonePanelActionStrings } from '../../../dashboard_actions/_dashboard_actions_strings'; -import { pluginServices } from '../../../services/plugin_services'; +import { coreServices, embeddableService } from '../../../services/kibana_services'; import { placeClonePanel } from '../../panel_placement'; import { DashboardContainer } from '../dashboard_container'; @@ -105,17 +107,13 @@ const duplicateReactEmbeddableInput = async ( }; export async function duplicateDashboardPanel(this: DashboardContainer, idToDuplicate: string) { - const { - notifications: { toasts }, - embeddable: { reactEmbeddableRegistryHasKey }, - } = pluginServices.getServices(); const panelToClone = await this.getDashboardPanelFromId(idToDuplicate); - const duplicatedPanelState = reactEmbeddableRegistryHasKey(panelToClone.type) + const duplicatedPanelState = embeddableService.reactEmbeddableRegistryHasKey(panelToClone.type) ? await duplicateReactEmbeddableInput(this, panelToClone, idToDuplicate) : await duplicateLegacyInput(this, panelToClone, idToDuplicate); - toasts.addSuccess({ + coreServices.notifications.toasts.addSuccess({ title: dashboardClonePanelActionStrings.getSuccessMessage(), 'data-test-subj': 'addObjectToContainerSuccess', }); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/open_settings_flyout.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/api/open_settings_flyout.tsx index 70955ea67d787..867e6ae9d0477 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/open_settings_flyout.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/open_settings_flyout.tsx @@ -11,20 +11,14 @@ import React from 'react'; import { toMountPoint } from '@kbn/react-kibana-mount'; -import { pluginServices } from '../../../services/plugin_services'; -import { DashboardSettings } from '../../component/settings/settings_flyout'; -import { DashboardContext } from '../../../dashboard_api/use_dashboard_api'; import { DashboardApi } from '../../../dashboard_api/types'; +import { DashboardContext } from '../../../dashboard_api/use_dashboard_api'; +import { coreServices } from '../../../services/kibana_services'; +import { DashboardSettings } from '../../component/settings/settings_flyout'; export function openSettingsFlyout(dashboardApi: DashboardApi) { - const { - analytics, - settings: { i18n, theme }, - overlays, - } = pluginServices.getServices(); - dashboardApi.openOverlay( - overlays.openFlyout( + coreServices.overlays.openFlyout( toMountPoint( , - { analytics, i18n, theme } + { analytics: coreServices.analytics, i18n: coreServices.i18n, theme: coreServices.theme } ), { size: 's', diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx index 318dcb71f7f99..681be0ac9bef8 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx @@ -7,14 +7,15 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { i18n } from '@kbn/i18n'; import React, { Fragment, useCallback } from 'react'; + +import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiIconTip, EuiSwitch } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiFormRow, EuiSwitch, EuiIconTip, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { SavedObjectSaveModal } from '@kbn/saved-objects-plugin/public'; +import { savedObjectsTaggingService } from '../../../../services/kibana_services'; import type { DashboardSaveOptions } from '../../../types'; -import { pluginServices } from '../../../../services/plugin_services'; /** * TODO: Portable Dashboard followup, use redux for the state. @@ -79,12 +80,9 @@ export const DashboardSaveModal: React.FC = ({ ); const renderDashboardSaveOptions = useCallback(() => { - const { - savedObjectsTagging: { components }, - } = pluginServices.getServices(); - - const tagSelector = components ? ( - { setSelectedTags(selectedTagIds); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx index 244638fffe90e..7230ff4fcb619 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx @@ -7,6 +7,10 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { cloneDeep } from 'lodash'; +import React from 'react'; +import { batch } from 'react-redux'; + import type { Reference } from '@kbn/content-management-utils'; import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; import { @@ -14,12 +18,10 @@ import { isReferenceOrValueEmbeddable, ViewMode, } from '@kbn/embeddable-plugin/public'; +import { i18n } from '@kbn/i18n'; import { apiHasSerializableState, SerializedPanelState } from '@kbn/presentation-containers'; import { showSaveModal } from '@kbn/saved-objects-plugin/public'; -import { cloneDeep } from 'lodash'; -import React from 'react'; -import { batch } from 'react-redux'; -import { i18n } from '@kbn/i18n'; + import { DashboardContainerInput, DashboardPanelMap, @@ -29,8 +31,14 @@ import { DASHBOARD_CONTENT_ID, SAVED_OBJECT_POST_TIME } from '../../../dashboard import { SaveDashboardReturn, SavedDashboardInput, -} from '../../../services/dashboard_content_management/types'; -import { pluginServices } from '../../../services/plugin_services'; +} from '../../../services/dashboard_content_management_service/types'; +import { getDashboardContentManagementService } from '../../../services/dashboard_content_management_service'; +import { + coreServices, + dataService, + embeddableService, + savedObjectsTaggingService, +} from '../../../services/kibana_services'; import { DashboardSaveOptions, DashboardStateFromSaveModal } from '../../types'; import { DashboardContainer } from '../dashboard_container'; import { extractTitleAndCount } from './lib/extract_title_and_count'; @@ -39,9 +47,6 @@ import { DashboardSaveModal } from './overlays/save_modal'; const serializeAllPanelState = async ( dashboard: DashboardContainer ): Promise<{ panels: DashboardContainerInput['panels']; references: Reference[] }> => { - const { - embeddable: { reactEmbeddableRegistryHasKey }, - } = pluginServices.getServices(); const references: Reference[] = []; const panels = cloneDeep(dashboard.getInput().panels); @@ -49,7 +54,7 @@ const serializeAllPanelState = async ( Promise<{ uuid: string; serialized: SerializedPanelState }> > = []; for (const [uuid, panel] of Object.entries(panels)) { - if (!reactEmbeddableRegistryHasKey(panel.type)) continue; + if (!embeddableService.reactEmbeddableRegistryHasKey(panel.type)) continue; const api = dashboard.children$.value[uuid]; if (api && apiHasSerializableState(api)) { @@ -75,10 +80,6 @@ const serializeAllPanelState = async ( * Save the current state of this dashboard to a saved object without showing any save modal. */ export async function runQuickSave(this: DashboardContainer) { - const { - dashboardContentManagement: { saveDashboardState }, - } = pluginServices.getServices(); - const { explicitInput: currentState, componentState: { lastSavedId, managed }, @@ -98,7 +99,7 @@ export async function runQuickSave(this: DashboardContainer) { stateToSave = { ...stateToSave, controlGroupInput: controlGroupSerializedState }; } - const saveResult = await saveDashboardState({ + const saveResult = await getDashboardContentManagementService().saveDashboardState({ controlGroupReferences, panelReferences: references, currentState: stateToSave, @@ -118,20 +119,11 @@ export async function runQuickSave(this: DashboardContainer) { * accounts for scenarios of cloning elastic managed dashboard into user managed dashboards */ export async function runInteractiveSave(this: DashboardContainer, interactionMode: ViewMode) { - const { - data: { - query: { - timefilter: { timefilter }, - }, - }, - savedObjectsTagging: { hasApi: hasSavedObjectsTagging }, - dashboardContentManagement: { checkForDuplicateDashboardTitle, saveDashboardState }, - } = pluginServices.getServices(); - const { explicitInput: currentState, componentState: { lastSavedId, managed }, } = this.getState(); + const dashboardContentManagementService = getDashboardContentManagementService(); return new Promise((resolve, reject) => { if (interactionMode === ViewMode.EDIT && managed) { @@ -156,7 +148,7 @@ export async function runInteractiveSave(this: DashboardContainer, interactionMo try { if ( - !(await checkForDuplicateDashboardTitle({ + !(await dashboardContentManagementService.checkForDuplicateDashboardTitle({ title: newTitle, onTitleDuplicate, lastSavedTitle: currentState.title, @@ -172,11 +164,13 @@ export async function runInteractiveSave(this: DashboardContainer, interactionMo tags: [] as string[], description: newDescription, timeRestore: newTimeRestore, - timeRange: newTimeRestore ? timefilter.getTime() : undefined, - refreshInterval: newTimeRestore ? timefilter.getRefreshInterval() : undefined, + timeRange: newTimeRestore ? dataService.query.timefilter.timefilter.getTime() : undefined, + refreshInterval: newTimeRestore + ? dataService.query.timefilter.timefilter.getRefreshInterval() + : undefined, }; - if (hasSavedObjectsTagging && newTags) { + if (savedObjectsTaggingService && newTags) { // remove `hasSavedObjectsTagging` once the savedObjectsTagging service is optional stateFromSaveModal.tags = newTags; } @@ -226,7 +220,7 @@ export async function runInteractiveSave(this: DashboardContainer, interactionMo const beforeAddTime = window.performance.now(); - const saveResult = await saveDashboardState({ + const saveResult = await dashboardContentManagementService.saveDashboardState({ controlGroupReferences, panelReferences: references, saveOptions, @@ -240,7 +234,7 @@ export async function runInteractiveSave(this: DashboardContainer, interactionMo const addDuration = window.performance.now() - beforeAddTime; - reportPerformanceMetricEvent(pluginServices.getServices().analytics, { + reportPerformanceMetricEvent(coreServices.analytics, { eventName: SAVED_OBJECT_POST_TIME, duration: addDuration, meta: { @@ -279,7 +273,7 @@ export async function runInteractiveSave(this: DashboardContainer, interactionMo newTitle = `${baseTitle} (${baseCount + 1})`; - await checkForDuplicateDashboardTitle({ + await dashboardContentManagementService.checkForDuplicateDashboardTitle({ title: newTitle, lastSavedTitle: currentState.title, copyOnSave: true, diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts index 7a02b3479a2aa..1ecc06d90e84a 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts @@ -7,34 +7,34 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { EmbeddablePackageState, ViewMode } from '@kbn/embeddable-plugin/public'; import { + CONTACT_CARD_EMBEDDABLE, ContactCardEmbeddable, ContactCardEmbeddableFactory, ContactCardEmbeddableInput, ContactCardEmbeddableOutput, - CONTACT_CARD_EMBEDDABLE, } from '@kbn/embeddable-plugin/public/lib/test_samples'; import { Filter } from '@kbn/es-query'; -import { EmbeddablePackageState, ViewMode } from '@kbn/embeddable-plugin/public'; import { createKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; -import { createDashboard } from './create_dashboard'; -import { getSampleDashboardPanel } from '../../../mocks'; -import { pluginServices } from '../../../services/plugin_services'; -import { DashboardCreationOptions } from '../dashboard_container_factory'; import { DEFAULT_DASHBOARD_INPUT } from '../../../dashboard_constants'; -import { mockControlGroupApi } from '../../../mocks'; +import { getSampleDashboardPanel, mockControlGroupApi } from '../../../mocks'; +import { dataService, embeddableService } from '../../../services/kibana_services'; +import { DashboardCreationOptions } from '../dashboard_container_factory'; +import { createDashboard } from './create_dashboard'; +import { getDashboardContentManagementService } from '../../../services/dashboard_content_management_service'; +import { getDashboardBackupService } from '../../../services/dashboard_backup_service'; + +const dashboardBackupService = getDashboardBackupService(); +const dashboardContentManagementService = getDashboardContentManagementService(); test("doesn't throw error when no data views are available", async () => { - pluginServices.getServices().data.dataViews.defaultDataViewExists = jest - .fn() - .mockReturnValue(false); + dataService.dataViews.defaultDataViewExists = jest.fn().mockReturnValue(false); expect(await createDashboard()).toBeDefined(); // reset get default data view - pluginServices.getServices().data.dataViews.defaultDataViewExists = jest - .fn() - .mockResolvedValue(true); + dataService.dataViews.defaultDataViewExists = jest.fn().mockResolvedValue(true); }); test('throws error when provided validation function returns invalid', async () => { @@ -73,79 +73,63 @@ test('does not get initial input when provided validation function returns redir }); test('pulls state from dashboard saved object when given a saved object id', async () => { - pluginServices.getServices().dashboardContentManagement.loadDashboardState = jest - .fn() - .mockResolvedValue({ - dashboardInput: { - ...DEFAULT_DASHBOARD_INPUT, - description: `wow would you look at that? Wow.`, - }, - }); + dashboardContentManagementService.loadDashboardState = jest.fn().mockResolvedValue({ + dashboardInput: { + ...DEFAULT_DASHBOARD_INPUT, + description: `wow would you look at that? Wow.`, + }, + }); const dashboard = await createDashboard({}, 0, 'wow-such-id'); - expect( - pluginServices.getServices().dashboardContentManagement.loadDashboardState - ).toHaveBeenCalledWith({ id: 'wow-such-id' }); + expect(dashboardContentManagementService.loadDashboardState).toHaveBeenCalledWith({ + id: 'wow-such-id', + }); expect(dashboard).toBeDefined(); expect(dashboard!.getState().explicitInput.description).toBe(`wow would you look at that? Wow.`); }); test('passes managed state from the saved object into the Dashboard component state', async () => { - pluginServices.getServices().dashboardContentManagement.loadDashboardState = jest - .fn() - .mockResolvedValue({ - dashboardInput: { - ...DEFAULT_DASHBOARD_INPUT, - description: 'wow this description is okay', - }, - managed: true, - }); + dashboardContentManagementService.loadDashboardState = jest.fn().mockResolvedValue({ + dashboardInput: { + ...DEFAULT_DASHBOARD_INPUT, + description: 'wow this description is okay', + }, + managed: true, + }); const dashboard = await createDashboard({}, 0, 'what-an-id'); expect(dashboard).toBeDefined(); expect(dashboard!.getState().componentState.managed).toBe(true); }); test('pulls view mode from dashboard backup', async () => { - pluginServices.getServices().dashboardContentManagement.loadDashboardState = jest - .fn() - .mockResolvedValue({ - dashboardInput: DEFAULT_DASHBOARD_INPUT, - }); - pluginServices.getServices().dashboardBackup.getViewMode = jest - .fn() - .mockReturnValue(ViewMode.EDIT); + dashboardContentManagementService.loadDashboardState = jest.fn().mockResolvedValue({ + dashboardInput: DEFAULT_DASHBOARD_INPUT, + }); + dashboardBackupService.getViewMode = jest.fn().mockReturnValue(ViewMode.EDIT); const dashboard = await createDashboard({ useSessionStorageIntegration: true }, 0, 'what-an-id'); expect(dashboard).toBeDefined(); expect(dashboard!.getState().explicitInput.viewMode).toBe(ViewMode.EDIT); }); test('new dashboards start in edit mode', async () => { - pluginServices.getServices().dashboardBackup.getViewMode = jest - .fn() - .mockReturnValue(ViewMode.VIEW); - pluginServices.getServices().dashboardContentManagement.loadDashboardState = jest - .fn() - .mockResolvedValue({ - newDashboardCreated: true, - dashboardInput: { - ...DEFAULT_DASHBOARD_INPUT, - description: 'wow this description is okay', - }, - }); + dashboardBackupService.getViewMode = jest.fn().mockReturnValue(ViewMode.VIEW); + dashboardContentManagementService.loadDashboardState = jest.fn().mockResolvedValue({ + newDashboardCreated: true, + dashboardInput: { + ...DEFAULT_DASHBOARD_INPUT, + description: 'wow this description is okay', + }, + }); const dashboard = await createDashboard({ useSessionStorageIntegration: true }, 0, 'wow-such-id'); expect(dashboard).toBeDefined(); expect(dashboard!.getState().explicitInput.viewMode).toBe(ViewMode.EDIT); }); test('managed dashboards start in view mode', async () => { - pluginServices.getServices().dashboardBackup.getViewMode = jest - .fn() - .mockReturnValue(ViewMode.EDIT); - pluginServices.getServices().dashboardContentManagement.loadDashboardState = jest - .fn() - .mockResolvedValue({ - dashboardInput: DEFAULT_DASHBOARD_INPUT, - managed: true, - }); + dashboardBackupService.getViewMode = jest.fn().mockReturnValue(ViewMode.EDIT); + dashboardContentManagementService.loadDashboardState = jest.fn().mockResolvedValue({ + dashboardInput: DEFAULT_DASHBOARD_INPUT, + managed: true, + }); const dashboard = await createDashboard({}, 0, 'what-an-id'); expect(dashboard).toBeDefined(); expect(dashboard!.getState().componentState.managed).toBe(true); @@ -153,15 +137,13 @@ test('managed dashboards start in view mode', async () => { }); test('pulls state from backup which overrides state from saved object', async () => { - pluginServices.getServices().dashboardContentManagement.loadDashboardState = jest - .fn() - .mockResolvedValue({ - dashboardInput: { - ...DEFAULT_DASHBOARD_INPUT, - description: 'wow this description is okay', - }, - }); - pluginServices.getServices().dashboardBackup.getState = jest + dashboardContentManagementService.loadDashboardState = jest.fn().mockResolvedValue({ + dashboardInput: { + ...DEFAULT_DASHBOARD_INPUT, + description: 'wow this description is okay', + }, + }); + dashboardBackupService.getState = jest .fn() .mockReturnValue({ dashboardState: { description: 'wow this description marginally better' } }); const dashboard = await createDashboard({ useSessionStorageIntegration: true }, 0, 'wow-such-id'); @@ -172,15 +154,13 @@ test('pulls state from backup which overrides state from saved object', async () }); test('pulls state from override input which overrides all other state sources', async () => { - pluginServices.getServices().dashboardContentManagement.loadDashboardState = jest - .fn() - .mockResolvedValue({ - dashboardInput: { - ...DEFAULT_DASHBOARD_INPUT, - description: 'wow this description is okay', - }, - }); - pluginServices.getServices().dashboardBackup.getState = jest + dashboardContentManagementService.loadDashboardState = jest.fn().mockResolvedValue({ + dashboardInput: { + ...DEFAULT_DASHBOARD_INPUT, + description: 'wow this description is okay', + }, + }); + dashboardBackupService.getState = jest .fn() .mockReturnValue({ description: 'wow this description marginally better' }); const dashboard = await createDashboard( @@ -198,35 +178,33 @@ test('pulls state from override input which overrides all other state sources', }); test('pulls panels from override input', async () => { - pluginServices.getServices().embeddable.reactEmbeddableRegistryHasKey = jest + embeddableService.reactEmbeddableRegistryHasKey = jest .fn() .mockImplementation((type: string) => type === 'reactEmbeddable'); - pluginServices.getServices().dashboardContentManagement.loadDashboardState = jest - .fn() - .mockResolvedValue({ - dashboardInput: { - ...DEFAULT_DASHBOARD_INPUT, - panels: { - ...DEFAULT_DASHBOARD_INPUT.panels, - someLegacyPanel: { - type: 'legacy', - gridData: { x: 0, y: 0, w: 0, h: 0, i: 'someLegacyPanel' }, - explicitInput: { - id: 'someLegacyPanel', - title: 'stateFromSavedObject', - }, + dashboardContentManagementService.loadDashboardState = jest.fn().mockResolvedValue({ + dashboardInput: { + ...DEFAULT_DASHBOARD_INPUT, + panels: { + ...DEFAULT_DASHBOARD_INPUT.panels, + someLegacyPanel: { + type: 'legacy', + gridData: { x: 0, y: 0, w: 0, h: 0, i: 'someLegacyPanel' }, + explicitInput: { + id: 'someLegacyPanel', + title: 'stateFromSavedObject', }, - someReactEmbeddablePanel: { - type: 'reactEmbeddable', - gridData: { x: 0, y: 0, w: 0, h: 0, i: 'someReactEmbeddablePanel' }, - explicitInput: { - id: 'someReactEmbeddablePanel', - title: 'stateFromSavedObject', - }, + }, + someReactEmbeddablePanel: { + type: 'reactEmbeddable', + gridData: { x: 0, y: 0, w: 0, h: 0, i: 'someReactEmbeddablePanel' }, + explicitInput: { + id: 'someReactEmbeddablePanel', + title: 'stateFromSavedObject', }, }, }, - }); + }, + }); const dashboard = await createDashboard( { useSessionStorageIntegration: true, @@ -286,10 +264,8 @@ test('applies filters and query from state to query service', async () => { }, getInitialInput: () => ({ filters, query }), }); - expect(pluginServices.getServices().data.query.queryString.setQuery).toHaveBeenCalledWith(query); - expect(pluginServices.getServices().data.query.filterManager.setAppFilters).toHaveBeenCalledWith( - filters - ); + expect(dataService.query.queryString.setQuery).toHaveBeenCalledWith(query); + expect(dataService.query.filterManager.setAppFilters).toHaveBeenCalledWith(filters); }); test('applies time range and refresh interval from initial input to query service if time restore is on', async () => { @@ -302,20 +278,16 @@ test('applies time range and refresh interval from initial input to query servic }, getInitialInput: () => ({ timeRange, refreshInterval, timeRestore: true }), }); - expect( - pluginServices.getServices().data.query.timefilter.timefilter.setTime - ).toHaveBeenCalledWith(timeRange); - expect( - pluginServices.getServices().data.query.timefilter.timefilter.setRefreshInterval - ).toHaveBeenCalledWith(refreshInterval); + expect(dataService.query.timefilter.timefilter.setTime).toHaveBeenCalledWith(timeRange); + expect(dataService.query.timefilter.timefilter.setRefreshInterval).toHaveBeenCalledWith( + refreshInterval + ); }); test('applies time range from query service to initial input if time restore is on but there is an explicit time range in the URL', async () => { const urlTimeRange = { from: new Date().toISOString(), to: new Date().toISOString() }; const savedTimeRange = { from: 'now - 7 days', to: 'now' }; - pluginServices.getServices().data.query.timefilter.timefilter.getTime = jest - .fn() - .mockReturnValue(urlTimeRange); + dataService.query.timefilter.timefilter.getTime = jest.fn().mockReturnValue(urlTimeRange); const kbnUrlStateStorage = createKbnUrlStateStorage(); kbnUrlStateStorage.get = jest.fn().mockReturnValue({ time: urlTimeRange }); @@ -335,9 +307,7 @@ test('applies time range from query service to initial input if time restore is test('applies time range from query service to initial input if time restore is off', async () => { const timeRange = { from: new Date().toISOString(), to: new Date().toISOString() }; - pluginServices.getServices().data.query.timefilter.timefilter.getTime = jest - .fn() - .mockReturnValue(timeRange); + dataService.query.timefilter.timefilter.getTime = jest.fn().mockReturnValue(timeRange); const dashboard = await createDashboard({ useUnifiedSearchIntegration: true, unifiedSearchSettings: { @@ -393,9 +363,7 @@ test('creates new embeddable with incoming embeddable if id does not match exist create: jest.fn().mockReturnValue({ destroy: jest.fn() }), getDefaultInput: jest.fn().mockResolvedValue({}), }; - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(mockContactCardFactory); + embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockContactCardFactory); const dashboard = await createDashboard({ getIncomingEmbeddable: () => incomingEmbeddable, @@ -454,9 +422,7 @@ test('creates new embeddable with specified size if size is provided', async () create: jest.fn().mockReturnValue({ destroy: jest.fn() }), getDefaultInput: jest.fn().mockResolvedValue({}), }; - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(mockContactCardFactory); + embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockContactCardFactory); const dashboard = await createDashboard({ getIncomingEmbeddable: () => incomingEmbeddable, @@ -513,11 +479,9 @@ test('searchSessionId is updated prior to child embeddable parent subscription e }, }), }; - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(embeddableFactory); + embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(embeddableFactory); let sessionCount = 0; - pluginServices.getServices().data.search.session.start = () => { + dataService.search.session.start = () => { sessionCount++; return `searchSessionId${sessionCount}`; }; diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts index 48a9a82838462..2b44abe481b7d 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts @@ -7,13 +7,16 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { cloneDeep, omit } from 'lodash'; +import { Subject } from 'rxjs'; +import { v4 } from 'uuid'; + +import { ContentInsightsClient } from '@kbn/content-management-content-insights-public'; import { GlobalQueryStateFromUrl, syncGlobalQueryStateWithUrl } from '@kbn/data-plugin/public'; import { ViewMode } from '@kbn/embeddable-plugin/public'; import { TimeRange } from '@kbn/es-query'; import { lazyLoadReduxToolsPackage } from '@kbn/presentation-util-plugin/public'; -import { cloneDeep, omit } from 'lodash'; -import { Subject } from 'rxjs'; -import { v4 } from 'uuid'; + import { DashboardContainerInput, DashboardPanelMap, @@ -26,11 +29,17 @@ import { GLOBAL_STATE_STORAGE_KEY, PanelPlacementStrategy, } from '../../../dashboard_constants'; +import { + PANELS_CONTROL_GROUP_KEY, + getDashboardBackupService, +} from '../../../services/dashboard_backup_service'; +import { getDashboardContentManagementService } from '../../../services/dashboard_content_management_service'; import { LoadDashboardReturn, SavedDashboardInput, -} from '../../../services/dashboard_content_management/types'; -import { pluginServices } from '../../../services/plugin_services'; +} from '../../../services/dashboard_content_management_service/types'; +import { coreServices, dataService, embeddableService } from '../../../services/kibana_services'; +import { getDashboardCapabilities } from '../../../utils/get_dashboard_capabilities'; import { runPanelPlacementStrategy } from '../../panel_placement/place_new_panel_strategies'; import { startDiffingDashboardState } from '../../state/diffing/dashboard_diffing_integration'; import { DashboardPublicState, UnsavedPanelState } from '../../types'; @@ -40,7 +49,6 @@ import { startSyncingDashboardDataViews } from './data_views/sync_dashboard_data import { startQueryPerformanceTracking } from './performance/query_performance_tracking'; import { startDashboardSearchSessionIntegration } from './search_sessions/start_dashboard_search_session_integration'; import { syncUnifiedSearchState } from './unified_search/sync_dashboard_unified_search_state'; -import { PANELS_CONTROL_GROUP_KEY } from '../../../services/dashboard_backup/dashboard_backup_service'; /** * Builds a new Dashboard from scratch. @@ -50,11 +58,6 @@ export const createDashboard = async ( dashboardCreationStartTime?: number, savedObjectId?: string ): Promise => { - const { - data: { dataViews }, - dashboardContentManagement: { loadDashboardState }, - } = pluginServices.getServices(); - // -------------------------------------------------------------------------------------- // Create method which allows work to be done on the dashboard container when it's ready. // -------------------------------------------------------------------------------------- @@ -71,8 +74,11 @@ export const createDashboard = async ( // Lazy load required systems and Dashboard saved object. // -------------------------------------------------------------------------------------- const reduxEmbeddablePackagePromise = lazyLoadReduxToolsPackage(); - const defaultDataViewExistsPromise = dataViews.defaultDataViewExists(); - const dashboardSavedObjectPromise = loadDashboardState({ id: savedObjectId }); + const defaultDataViewExistsPromise = dataService.dataViews.defaultDataViewExists(); + const dashboardContentManagementService = getDashboardContentManagementService(); + const dashboardSavedObjectPromise = dashboardContentManagementService.loadDashboardState({ + id: savedObjectId, + }); const [reduxEmbeddablePackage, savedObjectResult] = await Promise.all([ reduxEmbeddablePackagePromise, @@ -140,21 +146,12 @@ export const initializeDashboard = async ({ untilDashboardReady: () => Promise; creationOptions?: DashboardCreationOptions; }) => { - const { - dashboardBackup, - dashboardCapabilities: { showWriteControls }, - embeddable: { reactEmbeddableRegistryHasKey }, - data: { - query: queryService, - search: { session }, - }, - dashboardContentInsights, - } = pluginServices.getServices(); const { queryString, filterManager, timefilter: { timefilter: timefilterService }, - } = queryService; + } = dataService.query; + const dashboardBackupService = getDashboardBackupService(); const { getInitialInput, @@ -179,7 +176,7 @@ export const initializeDashboard = async ({ // -------------------------------------------------------------------------------------- // Combine input from saved object, and session storage // -------------------------------------------------------------------------------------- - const dashboardBackupState = dashboardBackup.getState(loadDashboardReturn.dashboardId); + const dashboardBackupState = dashboardBackupService.getState(loadDashboardReturn.dashboardId); const runtimePanelsToRestore: UnsavedPanelState = useSessionStorageIntegration ? dashboardBackupState?.panels ?? {} : {}; @@ -189,15 +186,16 @@ export const initializeDashboard = async ({ return dashboardBackupState?.dashboardState; })(); const initialViewMode = (() => { - if (loadDashboardReturn.managed || !showWriteControls) return ViewMode.VIEW; + if (loadDashboardReturn.managed || !getDashboardCapabilities().showWriteControls) + return ViewMode.VIEW; if ( loadDashboardReturn.newDashboardCreated || - dashboardBackup.dashboardHasUnsavedEdits(loadDashboardReturn.dashboardId) + dashboardBackupService.dashboardHasUnsavedEdits(loadDashboardReturn.dashboardId) ) { return ViewMode.EDIT; } - return dashboardBackup.getViewMode(); + return dashboardBackupService.getViewMode(); })(); const combinedSessionInput: DashboardContainerInput = { @@ -218,7 +216,7 @@ export const initializeDashboard = async ({ const overridePanels: DashboardPanelMap = {}; for (const panel of Object.values(overrideInput?.panels)) { - if (reactEmbeddableRegistryHasKey(panel.type)) { + if (embeddableService.reactEmbeddableRegistryHasKey(panel.type)) { overridePanels[panel.explicitInput.id] = { ...panel, @@ -263,7 +261,7 @@ export const initializeDashboard = async ({ // Back up any view mode passed in explicitly. if (overrideInput?.viewMode) { - dashboardBackup.storeViewMode(overrideInput?.viewMode); + dashboardBackupService.storeViewMode(overrideInput?.viewMode); } initialDashboardInput.executionContext = { @@ -319,7 +317,7 @@ export const initializeDashboard = async ({ // start syncing global query state with the URL. const { stop: stopSyncingQueryServiceStateWithUrl } = syncGlobalQueryStateWithUrl( - queryService, + dataService.query, kbnUrlStateStorage ); @@ -363,7 +361,7 @@ export const initializeDashboard = async ({ // maintain hide panel titles setting. hidePanelTitles: panelToUpdate.explicitInput.hidePanelTitles, }; - if (reactEmbeddableRegistryHasKey(incomingEmbeddable.type)) { + if (embeddableService.reactEmbeddableRegistryHasKey(incomingEmbeddable.type)) { panelToUpdate.explicitInput = { id: panelToUpdate.explicitInput.id }; runtimePanelsToRestore[incomingEmbeddable.embeddableId] = nextRuntimeState; } else { @@ -399,7 +397,7 @@ export const initializeDashboard = async ({ } ); const newPanelState: DashboardPanelState = (() => { - if (reactEmbeddableRegistryHasKey(incomingEmbeddable.type)) { + if (embeddableService.reactEmbeddableRegistryHasKey(incomingEmbeddable.type)) { runtimePanelsToRestore[embeddableId] = incomingEmbeddable.input; return { explicitInput: { id: embeddableId }, @@ -487,16 +485,18 @@ export const initializeDashboard = async ({ // if this incoming embeddable has a session, continue it. if (incomingEmbeddable?.searchSessionId) { - session.continue(incomingEmbeddable.searchSessionId); + dataService.search.session.continue(incomingEmbeddable.searchSessionId); } if (sessionIdToRestore) { - session.restore(sessionIdToRestore); + dataService.search.session.restore(sessionIdToRestore); } - const existingSession = session.getSessionId(); + const existingSession = dataService.search.session.getSessionId(); initialSearchSessionId = sessionIdToRestore ?? - (existingSession && incomingEmbeddable ? existingSession : session.start()); + (existingSession && incomingEmbeddable + ? existingSession + : dataService.search.session.start()); untilDashboardReady().then(async (container) => { await container.untilContainerInitialized(); @@ -511,7 +511,11 @@ export const initializeDashboard = async ({ // We don't count views when a user is editing a dashboard and is returning from an editor after saving // however, there is an edge case that we now count a new view when a user is editing a dashboard and is returning from an editor by canceling // TODO: this should be revisited by making embeddable transfer support canceling logic https://github.com/elastic/kibana/issues/190485 - dashboardContentInsights.trackDashboardView(loadDashboardReturn.dashboardId); + const contentInsightsClient = new ContentInsightsClient( + { http: coreServices.http }, + { domainId: 'dashboard' } + ); + contentInsightsClient.track(loadDashboardReturn.dashboardId, 'viewed'); } return { input: initialDashboardInput, searchSessionId: initialSearchSessionId }; diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/data_views/sync_dashboard_data_views.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/data_views/sync_dashboard_data_views.ts index 8954155d80939..3060987e296c6 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/data_views/sync_dashboard_data_views.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/data_views/sync_dashboard_data_views.ts @@ -7,19 +7,17 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { uniqBy } from 'lodash'; +import { combineLatest, Observable, of, switchMap } from 'rxjs'; + import { DataView } from '@kbn/data-views-plugin/common'; import { combineCompatibleChildrenApis } from '@kbn/presentation-containers'; import { apiPublishesDataViews, PublishesDataViews } from '@kbn/presentation-publishing'; -import { uniqBy } from 'lodash'; -import { combineLatest, Observable, of, switchMap } from 'rxjs'; -import { pluginServices } from '../../../../services/plugin_services'; + +import { dataService } from '../../../../services/kibana_services'; import { DashboardContainer } from '../../dashboard_container'; export function startSyncingDashboardDataViews(this: DashboardContainer) { - const { - data: { dataViews }, - } = pluginServices.getServices(); - const controlGroupDataViewsPipe: Observable = this.controlGroupApi$.pipe( switchMap((controlGroupApi) => { return controlGroupApi ? controlGroupApi.dataViews : of([]); @@ -42,8 +40,8 @@ export function startSyncingDashboardDataViews(this: DashboardContainer) { ]; if (allDataViews.length === 0) { return (async () => { - const defaultDataViewId = await dataViews.getDefaultId(); - return [await dataViews.get(defaultDataViewId!)]; + const defaultDataViewId = await dataService.dataViews.getDefaultId(); + return [await dataService.dataViews.get(defaultDataViewId!)]; })(); } return of(uniqBy(allDataViews, 'id')); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/performance/query_performance_tracking.test.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/performance/query_performance_tracking.test.ts index 2caf5af31164c..963914bea1c33 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/performance/query_performance_tracking.test.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/performance/query_performance_tracking.test.ts @@ -7,18 +7,18 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import type { CoreStart } from '@kbn/core/public'; import { PerformanceMetricEvent } from '@kbn/ebt-tools'; import { PresentationContainer, TracksQueryPerformance } from '@kbn/presentation-containers'; import { getMockPresentationContainer } from '@kbn/presentation-containers/mocks'; -import { apiPublishesPhaseEvents, PhaseEvent, PhaseEventType } from '@kbn/presentation-publishing'; +import { PhaseEvent, PhaseEventType, apiPublishesPhaseEvents } from '@kbn/presentation-publishing'; import { waitFor } from '@testing-library/react'; import { BehaviorSubject } from 'rxjs'; -import { DashboardAnalyticsService } from '../../../../services/analytics/types'; import { startQueryPerformanceTracking } from './query_performance_tracking'; const mockMetricEvent = jest.fn(); jest.mock('@kbn/ebt-tools', () => ({ - reportPerformanceMetricEvent: (_: DashboardAnalyticsService, args: PerformanceMetricEvent) => { + reportPerformanceMetricEvent: (_: CoreStart['analytics'], args: PerformanceMetricEvent) => { mockMetricEvent(args); }, })); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/performance/query_performance_tracking.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/performance/query_performance_tracking.ts index a8ea06d25effa..ecf990675483a 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/performance/query_performance_tracking.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/performance/query_performance_tracking.ts @@ -7,12 +7,14 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { combineLatest, map, of, pairwise, startWith, switchMap } from 'rxjs'; + import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; import { PresentationContainer, TracksQueryPerformance } from '@kbn/presentation-containers'; -import { apiPublishesPhaseEvents, PublishesPhaseEvents } from '@kbn/presentation-publishing'; -import { combineLatest, map, of, pairwise, startWith, switchMap } from 'rxjs'; +import { PublishesPhaseEvents, apiPublishesPhaseEvents } from '@kbn/presentation-publishing'; + import { DASHBOARD_LOADED_EVENT } from '../../../../dashboard_constants'; -import { pluginServices } from '../../../../services/plugin_services'; +import { coreServices } from '../../../../services/kibana_services'; import { DashboardLoadType } from '../../../types'; let isFirstDashboardLoadOfSession = true; @@ -26,7 +28,6 @@ const loadTypesMapping: { [key in DashboardLoadType]: number } = { export const startQueryPerformanceTracking = ( dashboard: PresentationContainer & TracksQueryPerformance ) => { - const { analytics } = pluginServices.getServices(); const reportPerformanceMetrics = ({ timeToData, panelCount, @@ -41,7 +42,7 @@ export const startQueryPerformanceTracking = ( const duration = loadType === 'dashboardSubsequentLoad' ? timeToData : Math.max(timeToData, totalLoadTime); - reportPerformanceMetricEvent(analytics, { + reportPerformanceMetricEvent(coreServices.analytics, { eventName: DASHBOARD_LOADED_EVENT, duration, key1: 'time_to_data', diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/search_sessions/start_dashboard_search_session_integration.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/search_sessions/start_dashboard_search_session_integration.ts index ee74efbb75d56..8150ee7a72381 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/search_sessions/start_dashboard_search_session_integration.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/search_sessions/start_dashboard_search_session_integration.ts @@ -11,10 +11,11 @@ import { skip } from 'rxjs'; import { noSearchSessionStorageCapabilityMessage } from '@kbn/data-plugin/public'; +import { dataService } from '../../../../services/kibana_services'; import { DashboardContainer } from '../../dashboard_container'; -import { pluginServices } from '../../../../services/plugin_services'; import { DashboardCreationOptions } from '../../dashboard_container_factory'; import { newSession$ } from './new_session'; +import { getDashboardCapabilities } from '../../../../utils/get_dashboard_capabilities'; /** * Enables dashboard search sessions. @@ -25,13 +26,6 @@ export function startDashboardSearchSessionIntegration( ) { if (!searchSessionSettings) return; - const { - data: { - search: { session }, - }, - dashboardCapabilities: { storeSearchSession: canStoreSearchSession }, - } = pluginServices.getServices(); - const { sessionIdUrlChangeObservable, getSearchSessionIdFromURL, @@ -39,9 +33,9 @@ export function startDashboardSearchSessionIntegration( createSessionRestorationDataProvider, } = searchSessionSettings; - session.enableStorage(createSessionRestorationDataProvider(this), { + dataService.search.session.enableStorage(createSessionRestorationDataProvider(this), { isDisabled: () => - canStoreSearchSession + getDashboardCapabilities().storeSearchSession ? { disabled: false } : { disabled: true, @@ -60,15 +54,18 @@ export function startDashboardSearchSessionIntegration( const updatedSearchSessionId: string | undefined = (() => { let searchSessionIdFromURL = getSearchSessionIdFromURL(); if (searchSessionIdFromURL) { - if (session.isRestore() && session.isCurrentSession(searchSessionIdFromURL)) { + if ( + dataService.search.session.isRestore() && + dataService.search.session.isCurrentSession(searchSessionIdFromURL) + ) { // we had previously been in a restored session but have now changed state so remove the session id from the URL. removeSessionIdFromUrl(); searchSessionIdFromURL = undefined; } else { - session.restore(searchSessionIdFromURL); + dataService.search.session.restore(searchSessionIdFromURL); } } - return searchSessionIdFromURL ?? session.start(); + return searchSessionIdFromURL ?? dataService.search.session.start(); })(); if (updatedSearchSessionId && updatedSearchSessionId !== currentSearchSessionId) { diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/unified_search/sync_dashboard_unified_search_state.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/unified_search/sync_dashboard_unified_search_state.ts index 184b97c893a2c..160af8a005b1a 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/unified_search/sync_dashboard_unified_search_state.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/unified_search/sync_dashboard_unified_search_state.ts @@ -21,9 +21,9 @@ import { } from '@kbn/data-plugin/public'; import { DashboardContainer } from '../../dashboard_container'; -import { pluginServices } from '../../../../services/plugin_services'; import { GLOBAL_STATE_STORAGE_KEY } from '../../../../dashboard_constants'; import { areTimesEqual } from '../../../state/diffing/dashboard_diffing_utils'; +import { dataService } from '../../../../services/kibana_services'; /** * Sets up syncing and subscriptions between the filter state from the Data plugin @@ -33,11 +33,7 @@ export function syncUnifiedSearchState( this: DashboardContainer, kbnUrlStateStorage: IKbnUrlStateStorage ) { - const { - data: { query: queryService, search }, - } = pluginServices.getServices(); - const { queryString, timefilter } = queryService; - const { timefilter: timefilterService } = timefilter; + const timefilterService = dataService.query.timefilter.timefilter; // get Observable for when the dashboard's saved filters or query change. const OnFiltersChange$ = new Subject<{ filters: Filter[]; query: Query }>(); @@ -47,7 +43,7 @@ export function syncUnifiedSearchState( } = this.getState(); OnFiltersChange$.next({ filters: filters ?? [], - query: query ?? queryString.getDefaultQuery(), + query: query ?? dataService.query.queryString.getDefaultQuery(), }); }); @@ -56,12 +52,12 @@ export function syncUnifiedSearchState( explicitInput: { filters, query }, } = this.getState(); const intermediateFilterState: { filters: Filter[]; query: Query } = { - query: query ?? queryString.getDefaultQuery(), + query: query ?? dataService.query.queryString.getDefaultQuery(), filters: filters ?? [], }; const stopSyncingAppFilters = connectToQueryState( - queryService, + dataService.query, { get: () => intermediateFilterState, set: ({ filters: newFilters, query: newQuery }) => { @@ -144,7 +140,7 @@ export function syncUnifiedSearchState( }), switchMap((done) => // best way on a dashboard to estimate that panels are updated is to rely on search session service state - waitUntilNextSessionCompletes$(search.session).pipe(finalize(done)) + waitUntilNextSessionCompletes$(dataService.search.session).pipe(finalize(done)) ) ) .subscribe(); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.test.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.test.tsx index eb798049ec48a..83efeab804ba5 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.test.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.test.tsx @@ -9,11 +9,11 @@ import { isErrorEmbeddable, ViewMode } from '@kbn/embeddable-plugin/public'; import { + CONTACT_CARD_EMBEDDABLE, ContactCardEmbeddable, ContactCardEmbeddableFactory, ContactCardEmbeddableInput, ContactCardEmbeddableOutput, - CONTACT_CARD_EMBEDDABLE, EMPTY_EMBEDDABLE, } from '@kbn/embeddable-plugin/public/lib/test_samples/embeddables'; import type { TimeRange } from '@kbn/es-query'; @@ -25,13 +25,11 @@ import { getSampleDashboardPanel, mockControlGroupApi, } from '../../mocks'; -import { pluginServices } from '../../services/plugin_services'; +import { embeddableService } from '../../services/kibana_services'; import { DashboardContainer } from './dashboard_container'; const embeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any); -pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(embeddableFactory); +embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(embeddableFactory); test('DashboardContainer initializes embeddables', (done) => { const container = buildMockDashboard({ diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx index 43f733895f1f5..161b2f93f12a2 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx @@ -7,59 +7,69 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import deepEqual from 'fast-deep-equal'; +import { omit } from 'lodash'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { batch } from 'react-redux'; +import { + BehaviorSubject, + Subject, + Subscription, + distinctUntilChanged, + first, + map, + skipWhile, + switchMap, +} from 'rxjs'; +import { v4 } from 'uuid'; + import { METRIC_TYPE } from '@kbn/analytics'; import type { Reference } from '@kbn/content-management-utils'; -import type { I18nStart, KibanaExecutionContext, OverlayRef } from '@kbn/core/public'; -import { - type PublishingSubject, - apiPublishesPanelTitle, - apiPublishesUnsavedChanges, - getPanelTitle, - PublishesViewMode, - PublishesDataLoading, - apiPublishesDataLoading, -} from '@kbn/presentation-publishing'; +import { ControlGroupApi, ControlGroupSerializedState } from '@kbn/controls-plugin/public'; +import type { KibanaExecutionContext, OverlayRef } from '@kbn/core/public'; import { RefreshInterval } from '@kbn/data-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; import { Container, DefaultEmbeddableApi, EmbeddableFactoryNotFoundError, - embeddableInputToSubject, - isExplicitInputWithAttributes, PanelNotFoundError, ViewMode, + embeddableInputToSubject, + isExplicitInputWithAttributes, type EmbeddableFactory, type EmbeddableInput, type EmbeddableOutput, type IEmbeddable, } from '@kbn/embeddable-plugin/public'; import type { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query'; -import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { HasRuntimeChildState, HasSaveNotification, HasSerializedChildState, + PanelPackage, TrackContentfulRender, TracksQueryPerformance, combineCompatibleChildrenApis, } from '@kbn/presentation-containers'; -import { PanelPackage } from '@kbn/presentation-containers'; +import { PublishesSettings } from '@kbn/presentation-containers/interfaces/publishes_settings'; +import { apiHasSerializableState } from '@kbn/presentation-containers/interfaces/serialized_state'; +import { + PublishesDataLoading, + PublishesViewMode, + apiPublishesDataLoading, + apiPublishesPanelTitle, + apiPublishesUnsavedChanges, + getPanelTitle, + type PublishingSubject, +} from '@kbn/presentation-publishing'; import { ReduxEmbeddableTools, ReduxToolsPackage } from '@kbn/presentation-util-plugin/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { LocatorPublic } from '@kbn/share-plugin/common'; import { ExitFullScreenButtonKibanaProvider } from '@kbn/shared-ux-button-exit-full-screen'; -import deepEqual from 'fast-deep-equal'; -import { omit } from 'lodash'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import { batch } from 'react-redux'; -import { BehaviorSubject, Subject, Subscription, first, skipWhile, switchMap } from 'rxjs'; -import { distinctUntilChanged, map } from 'rxjs'; -import { v4 } from 'uuid'; -import { PublishesSettings } from '@kbn/presentation-containers/interfaces/publishes_settings'; -import { apiHasSerializableState } from '@kbn/presentation-containers/interfaces/serialized_state'; -import { ControlGroupApi, ControlGroupSerializedState } from '@kbn/controls-plugin/public'; -import { DashboardLocatorParams, DASHBOARD_CONTAINER_TYPE, DashboardApi } from '../..'; + +import { DASHBOARD_CONTAINER_TYPE, DashboardApi, DashboardLocatorParams } from '../..'; import { DashboardAttributes, DashboardContainerInput, @@ -70,6 +80,8 @@ import { getReferencesForControls, getReferencesForPanelId, } from '../../../common/dashboard_container/persistable_state/dashboard_container_references'; +import { DashboardContext } from '../../dashboard_api/use_dashboard_api'; +import { getPanelAddedSuccessString } from '../../dashboard_app/_dashboard_app_strings'; import { DASHBOARD_APP_ID, DASHBOARD_UI_METRIC_ID, @@ -77,13 +89,19 @@ import { DEFAULT_PANEL_WIDTH, PanelPlacementStrategy, } from '../../dashboard_constants'; -import { DashboardAnalyticsService } from '../../services/analytics/types'; -import { DashboardCapabilitiesService } from '../../services/dashboard_capabilities/types'; -import { pluginServices } from '../../services/plugin_services'; -import { placePanel } from '../panel_placement'; -import { runPanelPlacementStrategy } from '../panel_placement/place_new_panel_strategies'; +import { PANELS_CONTROL_GROUP_KEY } from '../../services/dashboard_backup_service'; +import { getDashboardContentManagementService } from '../../services/dashboard_content_management_service'; +import { + coreServices, + dataService, + embeddableService, + usageCollectionService, +} from '../../services/kibana_services'; +import { getDashboardCapabilities } from '../../utils/get_dashboard_capabilities'; import { DashboardViewport } from '../component/viewport/dashboard_viewport'; +import { placePanel } from '../panel_placement'; import { getDashboardPanelPlacementSetting } from '../panel_placement/panel_placement_registry'; +import { runPanelPlacementStrategy } from '../panel_placement/place_new_panel_strategies'; import { dashboardContainerReducers } from '../state/dashboard_container_reducers'; import { getDiffingMiddleware } from '../state/diffing/dashboard_diffing_integration'; import { @@ -92,7 +110,7 @@ import { DashboardStateFromSettingsFlyout, UnsavedPanelState, } from '../types'; -import { addFromLibrary, addOrUpdateEmbeddable, runQuickSave, runInteractiveSave } from './api'; +import { addFromLibrary, addOrUpdateEmbeddable, runInteractiveSave, runQuickSave } from './api'; import { duplicateDashboardPanel } from './api/duplicate_dashboard_panel'; import { combineDashboardFiltersWithControlGroupFilters, @@ -104,9 +122,6 @@ import { dashboardTypeDisplayLowercase, dashboardTypeDisplayName, } from './dashboard_container_factory'; -import { getPanelAddedSuccessString } from '../../dashboard_app/_dashboard_app_strings'; -import { PANELS_CONTROL_GROUP_KEY } from '../../services/dashboard_backup/dashboard_backup_service'; -import { DashboardContext } from '../../dashboard_api/use_dashboard_api'; export interface InheritedChildInput { filters: Filter[]; @@ -186,16 +201,11 @@ export class DashboardContainer // Services that are used in the Dashboard container code private creationOptions?: DashboardCreationOptions; - private analyticsService: DashboardAnalyticsService; - private showWriteControls: DashboardCapabilitiesService['showWriteControls']; - private i18n: I18nStart; - private theme; - private chrome; - private customBranding; + private showWriteControls: boolean; public trackContentfulRender() { - if (!this.hadContentfulRender && this.analyticsService) { - this.analyticsService.reportEvent('dashboard_loaded_with_data', {}); + if (!this.hadContentfulRender) { + coreServices.analytics.reportEvent('dashboard_loaded_with_data', {}); } this.hadContentfulRender = true; } @@ -238,37 +248,26 @@ export class DashboardContainer }); } - const { - usageCollection, - embeddable: { getEmbeddableFactory }, - } = pluginServices.getServices(); - super( { ...initialInput, }, { embeddableLoaded: {} }, - getEmbeddableFactory, + embeddableService.getEmbeddableFactory, parent, { untilContainerInitialized } ); + ({ showWriteControls: this.showWriteControls } = getDashboardCapabilities()); + this.controlGroupApi$ = controlGroupApi$; this.untilContainerInitialized = untilContainerInitialized; - this.trackPanelAddMetric = usageCollection.reportUiCounter?.bind( - usageCollection, + this.trackPanelAddMetric = usageCollectionService?.reportUiCounter.bind( + usageCollectionService, DASHBOARD_UI_METRIC_ID ); - ({ - analytics: this.analyticsService, - settings: { theme: this.theme, i18n: this.i18n }, - chrome: this.chrome, - customBranding: this.customBranding, - dashboardCapabilities: { showWriteControls: this.showWriteControls }, - } = pluginServices.getServices()); - this.creationOptions = creationOptions; this.searchSessionId = initialSessionId; this.searchSessionId$.next(initialSessionId); @@ -475,12 +474,12 @@ export class DashboardContainer ReactDOM.render( @@ -610,14 +609,9 @@ export class DashboardContainer panelPackage: PanelPackage, displaySuccessMessage?: boolean ) { - const { - notifications: { toasts }, - embeddable: { getEmbeddableFactory, reactEmbeddableRegistryHasKey }, - } = pluginServices.getServices(); - const onSuccess = (id?: string, title?: string) => { if (!displaySuccessMessage) return; - toasts.addSuccess({ + coreServices.notifications.toasts.addSuccess({ title: getPanelAddedSuccessString(title), 'data-test-subj': 'addEmbeddableToDashboardSuccess', }); @@ -628,10 +622,10 @@ export class DashboardContainer if (this.trackPanelAddMetric) { this.trackPanelAddMetric(METRIC_TYPE.CLICK, panelPackage.panelType); } - if (reactEmbeddableRegistryHasKey(panelPackage.panelType)) { + if (embeddableService.reactEmbeddableRegistryHasKey(panelPackage.panelType)) { const newId = v4(); - const getCustomPlacementSettingFunc = await getDashboardPanelPlacementSetting( + const getCustomPlacementSettingFunc = getDashboardPanelPlacementSetting( panelPackage.panelType ); @@ -671,7 +665,7 @@ export class DashboardContainer return await this.untilReactEmbeddableLoaded(newId); } - const embeddableFactory = getEmbeddableFactory(panelPackage.panelType); + const embeddableFactory = embeddableService.getEmbeddableFactory(panelPackage.panelType); if (!embeddableFactory) { throw new EmbeddableFactoryNotFoundError(panelPackage.panelType); } @@ -709,11 +703,8 @@ export class DashboardContainer } public getDashboardPanelFromId = async (panelId: string) => { - const { - embeddable: { reactEmbeddableRegistryHasKey }, - } = pluginServices.getServices(); const panel = this.getInput().panels[panelId]; - if (reactEmbeddableRegistryHasKey(panel.type)) { + if (embeddableService.reactEmbeddableRegistryHasKey(panel.type)) { const child = this.children$.value[panelId]; if (!child) throw new PanelNotFoundError(); const serialized = apiHasSerializableState(child) @@ -769,13 +760,7 @@ export class DashboardContainer // if we are using the unified search integration, we need to force reset the time picker. if (this.creationOptions?.useUnifiedSearchIntegration && lastSavedTimeRestore) { - const { - data: { - query: { - timefilter: { timefilter: timeFilterService }, - }, - }, - } = pluginServices.getServices(); + const timeFilterService = dataService.query.timefilter.timefilter; if (timeRange) timeFilterService.setTime(timeRange); if (refreshInterval) timeFilterService.setRefreshInterval(refreshInterval); } @@ -790,13 +775,12 @@ export class DashboardContainer this.integrationSubscriptions = new Subscription(); this.stopSyncingWithUnifiedSearch?.(); - const { - dashboardContentManagement: { loadDashboardState }, - } = pluginServices.getServices(); if (newCreationOptions) { this.creationOptions = { ...this.creationOptions, ...newCreationOptions }; } - const loadDashboardReturn = await loadDashboardState({ id: newSavedObjectId }); + const loadDashboardReturn = await getDashboardContentManagementService().loadDashboardState({ + id: newSavedObjectId, + }); const dashboardContainerReady$ = new Subject(); const untilDashboardReady = () => @@ -908,13 +892,10 @@ export class DashboardContainer }; public async getPanelTitles(): Promise { - const { - embeddable: { reactEmbeddableRegistryHasKey }, - } = pluginServices.getServices(); const titles: string[] = []; for (const [id, panel] of Object.entries(this.getInput().panels)) { const title = await (async () => { - if (reactEmbeddableRegistryHasKey(panel.type)) { + if (embeddableService.reactEmbeddableRegistryHasKey(panel.type)) { const child = this.children$.value[id]; return apiPublishesPanelTitle(child) ? getPanelTitle(child) : ''; } @@ -1039,12 +1020,9 @@ export class DashboardContainer }; public removePanel(id: string) { - const { - embeddable: { reactEmbeddableRegistryHasKey }, - } = pluginServices.getServices(); const type = this.getInput().panels[id]?.type; this.removeEmbeddable(id); - if (reactEmbeddableRegistryHasKey(type)) { + if (embeddableService.reactEmbeddableRegistryHasKey(type)) { const { [id]: childToRemove, ...otherChildren } = this.children$.value; this.children$.next(otherChildren); } diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container_factory.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container_factory.tsx index 1a87659370f25..ecccc49a60f12 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container_factory.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container_factory.tsx @@ -29,7 +29,7 @@ import { DEFAULT_DASHBOARD_INPUT } from '../../dashboard_constants'; import { LoadDashboardReturn, SavedDashboardInput, -} from '../../services/dashboard_content_management/types'; +} from '../../services/dashboard_content_management_service/types'; import type { DashboardContainer } from './dashboard_container'; export type DashboardContainerFactory = EmbeddableFactory< diff --git a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx index 6248800cf3740..153324f5a2bf3 100644 --- a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx +++ b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx @@ -7,22 +7,22 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React from 'react'; +import { setStubKibanaServices } from '@kbn/embeddable-plugin/public/mocks'; +import { NotFoundPrompt } from '@kbn/shared-ux-prompt-not-found'; +import { mountWithIntl } from '@kbn/test-jest-helpers'; import { ReactWrapper } from 'enzyme'; +import React from 'react'; import { act } from 'react-dom/test-utils'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { NotFoundPrompt } from '@kbn/shared-ux-prompt-not-found'; -import { setStubKibanaServices } from '@kbn/embeddable-plugin/public/mocks'; +import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/common'; +import { setStubKibanaServices as setPresentationPanelMocks } from '@kbn/presentation-panel-plugin/public/mocks'; +import { BehaviorSubject } from 'rxjs'; import { DashboardContainerFactory } from '..'; import { DASHBOARD_CONTAINER_TYPE } from '../..'; -import { DashboardRenderer } from './dashboard_renderer'; -import { pluginServices } from '../../services/plugin_services'; -import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/common'; +import { embeddableService } from '../../services/kibana_services'; import { DashboardContainer } from '../embeddable/dashboard_container'; import { DashboardCreationOptions } from '../embeddable/dashboard_container_factory'; -import { setStubKibanaServices as setPresentationPanelMocks } from '@kbn/presentation-panel-plugin/public/mocks'; -import { BehaviorSubject } from 'rxjs'; +import { DashboardRenderer } from './dashboard_renderer'; describe('dashboard renderer', () => { let mockDashboardContainer: DashboardContainer; @@ -39,9 +39,7 @@ describe('dashboard renderer', () => { mockDashboardFactory = { create: jest.fn().mockReturnValue(mockDashboardContainer), } as unknown as DashboardContainerFactory; - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(mockDashboardFactory); + embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockDashboardFactory); setPresentationPanelMocks(); }); @@ -49,9 +47,7 @@ describe('dashboard renderer', () => { await act(async () => { mountWithIntl(); }); - expect(pluginServices.getServices().embeddable.getEmbeddableFactory).toHaveBeenCalledWith( - DASHBOARD_CONTAINER_TYPE - ); + expect(embeddableService.getEmbeddableFactory).toHaveBeenCalledWith(DASHBOARD_CONTAINER_TYPE); expect(mockDashboardFactory.create).toHaveBeenCalled(); }); @@ -109,9 +105,7 @@ describe('dashboard renderer', () => { mockDashboardFactory = { create: jest.fn().mockReturnValue(mockErrorEmbeddable), } as unknown as DashboardContainerFactory; - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(mockDashboardFactory); + embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockDashboardFactory); let wrapper: ReactWrapper; await act(async () => { @@ -133,9 +127,7 @@ describe('dashboard renderer', () => { const mockErrorFactory = { create: jest.fn().mockReturnValue(mockErrorEmbeddable), } as unknown as DashboardContainerFactory; - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(mockErrorFactory); + embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockErrorFactory); // render the dashboard - it should run into an error and render the error embeddable. let wrapper: ReactWrapper; @@ -156,9 +148,7 @@ describe('dashboard renderer', () => { const mockSuccessFactory = { create: jest.fn().mockReturnValue(mockSuccessEmbeddable), } as unknown as DashboardContainerFactory; - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(mockSuccessFactory); + embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockSuccessFactory); // update the saved object id to trigger another dashboard load. await act(async () => { @@ -187,9 +177,7 @@ describe('dashboard renderer', () => { const mockErrorFactory = { create: jest.fn().mockReturnValue(mockErrorEmbeddable), } as unknown as DashboardContainerFactory; - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(mockErrorFactory); + embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockErrorFactory); // render the dashboard - it should run into an error and render the error embeddable. let wrapper: ReactWrapper; @@ -252,9 +240,7 @@ describe('dashboard renderer', () => { const mockSuccessFactory = { create: jest.fn().mockReturnValue(mockSuccessEmbeddable), } as unknown as DashboardContainerFactory; - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(mockSuccessFactory); + embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockSuccessFactory); let wrapper: ReactWrapper; await act(async () => { @@ -279,9 +265,7 @@ describe('dashboard renderer', () => { const mockUseMarginFalseFactory = { create: jest.fn().mockReturnValue(mockUseMarginFalseEmbeddable), } as unknown as DashboardContainerFactory; - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(mockUseMarginFalseFactory); + embeddableService.getEmbeddableFactory = jest.fn().mockReturnValue(mockUseMarginFalseFactory); let wrapper: ReactWrapper; await act(async () => { diff --git a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx index 1222b3433877a..e8ef4faef724d 100644 --- a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx +++ b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx @@ -17,11 +17,13 @@ import { v4 as uuidv4 } from 'uuid'; import { EuiLoadingElastic, EuiLoadingSpinner } from '@elastic/eui'; import { ErrorEmbeddable, isErrorEmbeddable } from '@kbn/embeddable-plugin/public'; import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/common'; - -import { LocatorPublic } from '@kbn/share-plugin/common'; import { useStateFromPublishingSubject } from '@kbn/presentation-publishing'; +import { LocatorPublic } from '@kbn/share-plugin/common'; + import { DASHBOARD_CONTAINER_TYPE } from '..'; import { DashboardContainerInput } from '../../../common'; +import { DashboardApi } from '../../dashboard_api/types'; +import { embeddableService, screenshotModeService } from '../../services/kibana_services'; import type { DashboardContainer } from '../embeddable/dashboard_container'; import { DashboardContainerFactory, @@ -30,8 +32,6 @@ import { } from '../embeddable/dashboard_container_factory'; import { DashboardLocatorParams, DashboardRedirect } from '../types'; import { Dashboard404Page } from './dashboard_404'; -import { DashboardApi } from '../../dashboard_api/types'; -import { pluginServices } from '../../services/plugin_services'; export interface DashboardRendererProps { onApiAvailable?: (api: DashboardApi) => void; @@ -57,8 +57,6 @@ export function DashboardRenderer({ const [fatalError, setFatalError] = useState(); const [dashboardMissing, setDashboardMissing] = useState(false); - const { embeddable, screenshotMode } = pluginServices.getServices(); - const id = useMemo(() => uuidv4(), []); useEffect(() => { @@ -93,7 +91,7 @@ export function DashboardRenderer({ (async () => { const creationOptions = await getCreationOptions?.(); - const dashboardFactory = embeddable.getEmbeddableFactory( + const dashboardFactory = embeddableService.getEmbeddableFactory( DASHBOARD_CONTAINER_TYPE ) as DashboardContainerFactory & { create: DashboardContainerFactoryDefinition['create']; @@ -141,7 +139,7 @@ export function DashboardRenderer({ const viewportClasses = classNames( 'dashboardViewport', - { 'dashboardViewport--screenshotMode': screenshotMode }, + { 'dashboardViewport--screenshotMode': screenshotModeService.isScreenshotMode() }, { 'dashboardViewport--loading': loading } ); diff --git a/src/plugins/dashboard/public/dashboard_container/external_api/lazy_dashboard_renderer.tsx b/src/plugins/dashboard/public/dashboard_container/external_api/lazy_dashboard_renderer.tsx index 56c6e5f82ac15..d8e3c6668df38 100644 --- a/src/plugins/dashboard/public/dashboard_container/external_api/lazy_dashboard_renderer.tsx +++ b/src/plugins/dashboard/public/dashboard_container/external_api/lazy_dashboard_renderer.tsx @@ -10,9 +10,13 @@ import React from 'react'; import { dynamic } from '@kbn/shared-ux-utility'; import type { DashboardRendererProps } from './dashboard_renderer'; +import { untilPluginStartServicesReady } from '../../services/kibana_services'; const Component = dynamic(async () => { - const { DashboardRenderer } = await import('./dashboard_renderer'); + const [{ DashboardRenderer }] = await Promise.all([ + import('./dashboard_renderer'), + untilPluginStartServicesReady(), + ]); return { default: DashboardRenderer, }; diff --git a/src/plugins/dashboard/public/dashboard_container/index.ts b/src/plugins/dashboard/public/dashboard_container/index.ts index 815823f74164d..d8103f1e3f9bc 100644 --- a/src/plugins/dashboard/public/dashboard_container/index.ts +++ b/src/plugins/dashboard/public/dashboard_container/index.ts @@ -8,7 +8,7 @@ */ import { LATEST_VERSION } from '../../common/content_management'; -import { convertNumberToDashboardVersion } from '../services/dashboard_content_management/lib/dashboard_versioning'; +import { convertNumberToDashboardVersion } from '../services/dashboard_content_management_service/lib/dashboard_versioning'; export const DASHBOARD_CONTAINER_TYPE = 'dashboard'; diff --git a/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_functions.ts b/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_functions.ts index 72026f2ccd842..2803d9be0e32d 100644 --- a/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_functions.ts +++ b/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_functions.ts @@ -7,10 +7,12 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { compareFilters, COMPARE_ALL_OPTIONS, isFilterPinned } from '@kbn/es-query'; import fastIsEqual from 'fast-deep-equal'; + +import { COMPARE_ALL_OPTIONS, compareFilters, isFilterPinned } from '@kbn/es-query'; + import { DashboardContainerInput } from '../../../../common'; -import { pluginServices } from '../../../services/plugin_services'; +import { embeddableService } from '../../../services/kibana_services'; import { DashboardContainer } from '../../embeddable/dashboard_container'; import { DashboardContainerInputWithoutId } from '../../types'; import { areTimesEqual, getPanelLayoutsAreEqual } from './dashboard_diffing_utils'; @@ -75,11 +77,8 @@ export const unsavedChangesDiffingFunctions: DashboardDiffFunctions = { const explicitInputComparePromises = Object.values(currentValue ?? {}).map( (panel) => new Promise((resolve, reject) => { - const { - embeddable: { reactEmbeddableRegistryHasKey }, - } = pluginServices.getServices(); const embeddableId = panel.explicitInput.id; - if (!embeddableId || reactEmbeddableRegistryHasKey(panel.type)) { + if (!embeddableId || embeddableService.reactEmbeddableRegistryHasKey(panel.type)) { // if this is a new style embeddable, it will handle its own diffing. reject(); return; diff --git a/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts b/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts index b0337ccbb0d38..1bcba571dc24f 100644 --- a/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts +++ b/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts @@ -13,11 +13,13 @@ import { combineLatest, debounceTime, skipWhile, startWith, switchMap } from 'rx import { DashboardContainer, DashboardCreationOptions } from '../..'; import { DashboardContainerInput } from '../../../../common'; import { CHANGE_CHECK_DEBOUNCE } from '../../../dashboard_constants'; -import { pluginServices } from '../../../services/plugin_services'; +import { + PANELS_CONTROL_GROUP_KEY, + getDashboardBackupService, +} from '../../../services/dashboard_backup_service'; import { UnsavedPanelState } from '../../types'; import { dashboardContainerReducers } from '../dashboard_container_reducers'; import { isKeyEqualAsync, unsavedChangesDiffingFunctions } from './dashboard_diffing_functions'; -import { PANELS_CONTROL_GROUP_KEY } from '../../../services/dashboard_backup/dashboard_backup_service'; /** * An array of reducers which cannot cause unsaved changes. Unsaved changes only compares the explicit input @@ -188,10 +190,9 @@ function backupUnsavedChanges( dashboardChanges: Partial, reactEmbeddableChanges: UnsavedPanelState ) { - const { dashboardBackup } = pluginServices.getServices(); const dashboardStateToBackup = omit(dashboardChanges, keysToOmitFromSessionStorage); - dashboardBackup.setState( + getDashboardBackupService().setState( this.getDashboardSavedObjectId(), { ...dashboardStateToBackup, diff --git a/src/plugins/dashboard/public/dashboard_listing/confirm_overlays.tsx b/src/plugins/dashboard/public/dashboard_listing/confirm_overlays.tsx index de1d872f081a8..f3dac2e9bb624 100644 --- a/src/plugins/dashboard/public/dashboard_listing/confirm_overlays.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/confirm_overlays.tsx @@ -10,6 +10,7 @@ import React from 'react'; import { + EUI_MODAL_CANCEL_BUTTON, EuiButton, EuiButtonEmpty, EuiFocusTrap, @@ -19,12 +20,11 @@ import { EuiModalHeaderTitle, EuiOutsideClickDetector, EuiText, - EUI_MODAL_CANCEL_BUTTON, } from '@elastic/eui'; import { ViewMode } from '@kbn/embeddable-plugin/public'; import { toMountPoint } from '@kbn/react-kibana-mount'; -import { pluginServices } from '../services/plugin_services'; +import { coreServices } from '../services/kibana_services'; import { createConfirmStrings, resetConfirmStrings } from './_dashboard_listing_strings'; export type DiscardOrKeepSelection = 'cancel' | 'discard' | 'keep'; @@ -33,21 +33,19 @@ export const confirmDiscardUnsavedChanges = ( discardCallback: () => void, viewMode: ViewMode = ViewMode.EDIT // we want to show the danger modal on the listing page ) => { - const { - overlays: { openConfirm }, - } = pluginServices.getServices(); - - openConfirm(resetConfirmStrings.getResetSubtitle(viewMode), { - confirmButtonText: resetConfirmStrings.getResetConfirmButtonText(), - buttonColor: viewMode === ViewMode.EDIT ? 'danger' : 'primary', - maxWidth: 500, - defaultFocusedButton: EUI_MODAL_CANCEL_BUTTON, - title: resetConfirmStrings.getResetTitle(), - }).then((isConfirmed) => { - if (isConfirmed) { - discardCallback(); - } - }); + coreServices.overlays + .openConfirm(resetConfirmStrings.getResetSubtitle(viewMode), { + confirmButtonText: resetConfirmStrings.getResetConfirmButtonText(), + buttonColor: viewMode === ViewMode.EDIT ? 'danger' : 'primary', + maxWidth: 500, + defaultFocusedButton: EUI_MODAL_CANCEL_BUTTON, + title: resetConfirmStrings.getResetTitle(), + }) + .then((isConfirmed) => { + if (isConfirmed) { + discardCallback(); + } + }); }; export const confirmCreateWithUnsaved = ( @@ -57,13 +55,7 @@ export const confirmCreateWithUnsaved = ( const titleId = 'confirmDiscardOrKeepTitle'; const descriptionId = 'confirmDiscardOrKeepDescription'; - const { - analytics, - settings: { i18n, theme }, - overlays: { openModal }, - } = pluginServices.getServices(); - - const session = openModal( + const session = coreServices.overlays.openModal( toMountPoint( , - { analytics, i18n, theme } + { analytics: coreServices.analytics, i18n: coreServices.i18n, theme: coreServices.theme } ), { 'data-test-subj': 'dashboardCreateConfirmModal', diff --git a/src/plugins/dashboard/public/dashboard_listing/dashboard_listing.test.tsx b/src/plugins/dashboard/public/dashboard_listing/dashboard_listing.test.tsx index c1aabad7eb23f..e17433709b1f1 100644 --- a/src/plugins/dashboard/public/dashboard_listing/dashboard_listing.test.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/dashboard_listing.test.tsx @@ -7,22 +7,22 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { ComponentType, ReactWrapper, mount } from 'enzyme'; import React, { PropsWithChildren } from 'react'; import { act } from 'react-dom/test-utils'; -import { mount, ReactWrapper, ComponentType } from 'enzyme'; -import { I18nProvider } from '@kbn/i18n-react'; - -import { pluginServices } from '../services/plugin_services'; -import { DashboardListing } from './dashboard_listing'; +import { I18nProvider } from '@kbn/i18n-react'; /** * Mock Table List view. This dashboard component is a wrapper around the shared UX table List view. We * need to ensure we're passing down the correct props, but the table list view itself doesn't need to be rendered * in our tests because it is covered in its package. */ import { TableListView } from '@kbn/content-management-table-list-view'; + +import { DashboardListing } from './dashboard_listing'; import { DashboardListingProps } from './types'; -// import { TableListViewKibanaProvider } from '@kbn/content-management-table-list-view'; +import { coreServices } from '../services/kibana_services'; + jest.mock('@kbn/content-management-table-list-view-table', () => { const originalModule = jest.requireActual('@kbn/content-management-table-list-view-table'); return { @@ -65,7 +65,7 @@ function mountWith({ props: incomingProps }: { props?: Partial { - pluginServices.getServices().dashboardCapabilities.showWriteControls = false; + (coreServices.application.capabilities as any).dashboard.showWriteControls = false; let component: ReactWrapper; @@ -80,7 +80,7 @@ test('initial filter is passed through', async () => { }); test('when showWriteControls is true, table list view is passed editing functions', async () => { - pluginServices.getServices().dashboardCapabilities.showWriteControls = true; + (coreServices.application.capabilities as any).dashboard.showWriteControls = true; let component: ReactWrapper; @@ -99,7 +99,7 @@ test('when showWriteControls is true, table list view is passed editing function }); test('when showWriteControls is false, table list view is not passed editing functions', async () => { - pluginServices.getServices().dashboardCapabilities.showWriteControls = false; + (coreServices.application.capabilities as any).dashboard.showWriteControls = false; let component: ReactWrapper; diff --git a/src/plugins/dashboard/public/dashboard_listing/dashboard_listing.tsx b/src/plugins/dashboard/public/dashboard_listing/dashboard_listing.tsx index 96449ed7f3ec8..f6072169e5bda 100644 --- a/src/plugins/dashboard/public/dashboard_listing/dashboard_listing.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/dashboard_listing.tsx @@ -7,26 +7,23 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { FormattedRelative, I18nProvider } from '@kbn/i18n-react'; import React, { useMemo } from 'react'; +import { FavoritesClient } from '@kbn/content-management-favorites-public'; import { TableListView } from '@kbn/content-management-table-list-view'; -import { - type TableListViewKibanaDependencies, - TableListViewKibanaProvider, -} from '@kbn/content-management-table-list-view-table'; - +import { TableListViewKibanaProvider } from '@kbn/content-management-table-list-view-table'; +import { FormattedRelative, I18nProvider } from '@kbn/i18n-react'; import { useExecutionContext } from '@kbn/kibana-react-plugin/public'; -import { pluginServices } from '../services/plugin_services'; - +import { DASHBOARD_APP_ID, DASHBOARD_CONTENT_ID } from '../dashboard_constants'; +import { + coreServices, + savedObjectsTaggingService, + usageCollectionService, +} from '../services/kibana_services'; import { DashboardUnsavedListing } from './dashboard_unsaved_listing'; import { useDashboardListingTable } from './hooks/use_dashboard_listing_table'; -import { - DashboardListingProps, - DashboardSavedObjectUserContent, - TableListViewApplicationService, -} from './types'; +import { DashboardListingProps, DashboardSavedObjectUserContent } from './types'; export const DashboardListing = ({ children, @@ -35,59 +32,38 @@ export const DashboardListing = ({ getDashboardUrl, useSessionStorageIntegration, }: DashboardListingProps) => { - const { - analytics, - application, - notifications, - overlays, - http, - i18n, - chrome: { theme }, - savedObjectsTagging, - coreContext: { executionContext }, - userProfile, - dashboardContentInsights: { contentInsightsClient }, - dashboardFavorites, - } = pluginServices.getServices(); - - useExecutionContext(executionContext, { + useExecutionContext(coreServices.executionContext, { type: 'application', page: 'list', }); - const { unsavedDashboardIds, refreshUnsavedDashboards, tableListViewTableProps } = - useDashboardListingTable({ - goToDashboard, - getDashboardUrl, - useSessionStorageIntegration, - initialFilter, - }); + const { + unsavedDashboardIds, + refreshUnsavedDashboards, + tableListViewTableProps, + contentInsightsClient, + } = useDashboardListingTable({ + goToDashboard, + getDashboardUrl, + useSessionStorageIntegration, + initialFilter, + }); - const savedObjectsTaggingFakePlugin = useMemo(() => { - return savedObjectsTagging.hasApi // TODO: clean up this logic once https://github.com/elastic/kibana/issues/140433 is resolved - ? ({ - ui: savedObjectsTagging, - } as TableListViewKibanaDependencies['savedObjectsTagging']) - : undefined; - }, [savedObjectsTagging]); + const dashboardFavoritesClient = useMemo(() => { + return new FavoritesClient(DASHBOARD_APP_ID, DASHBOARD_CONTENT_ID, { + http: coreServices.http, + usageCollection: usageCollectionService, + }); + }, []); return ( diff --git a/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_empty_prompt.test.tsx b/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_empty_prompt.test.tsx index 92d108231b4fc..a5661238f9ad1 100644 --- a/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_empty_prompt.test.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_empty_prompt.test.tsx @@ -7,18 +7,18 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { ComponentType, ReactWrapper, mount } from 'enzyme'; import React from 'react'; import { act } from 'react-dom/test-utils'; -import { mount, ReactWrapper, ComponentType } from 'enzyme'; import { I18nProvider } from '@kbn/i18n-react'; +import { coreServices } from '../services/kibana_services'; +import { confirmDiscardUnsavedChanges } from './confirm_overlays'; import { DashboardListingEmptyPrompt, DashboardListingEmptyPromptProps, } from './dashboard_listing_empty_prompt'; -import { pluginServices } from '../services/plugin_services'; -import { confirmDiscardUnsavedChanges } from './confirm_overlays'; jest.mock('./confirm_overlays', () => { const originalModule = jest.requireActual('./confirm_overlays'); @@ -56,7 +56,7 @@ function mountWith({ } test('renders readonly empty prompt when showWriteControls is off', async () => { - pluginServices.getServices().dashboardCapabilities.showWriteControls = false; + (coreServices.application.capabilities as any).dashboard.showWriteControls = false; let component: ReactWrapper; await act(async () => { @@ -68,7 +68,7 @@ test('renders readonly empty prompt when showWriteControls is off', async () => }); test('renders empty prompt with link when showWriteControls is on', async () => { - pluginServices.getServices().dashboardCapabilities.showWriteControls = true; + (coreServices.application.capabilities as any).dashboard.showWriteControls = true; let component: ReactWrapper; await act(async () => { @@ -80,7 +80,7 @@ test('renders empty prompt with link when showWriteControls is on', async () => }); test('renders disabled action button when disableCreateDashboardButton is true', async () => { - pluginServices.getServices().dashboardCapabilities.showWriteControls = true; + (coreServices.application.capabilities as any).dashboard.showWriteControls = true; let component: ReactWrapper; await act(async () => { @@ -95,7 +95,7 @@ test('renders disabled action button when disableCreateDashboardButton is true', }); test('renders continue button when no dashboards exist but one is in progress', async () => { - pluginServices.getServices().dashboardCapabilities.showWriteControls = true; + (coreServices.application.capabilities as any).dashboard.showWriteControls = true; let component: ReactWrapper; let props: DashboardListingEmptyPromptProps; await act(async () => { @@ -114,7 +114,7 @@ test('renders continue button when no dashboards exist but one is in progress', }); test('renders discard button when no dashboards exist but one is in progress', async () => { - pluginServices.getServices().dashboardCapabilities.showWriteControls = true; + (coreServices.application.capabilities as any).dashboard.showWriteControls = true; let component: ReactWrapper; await act(async () => { ({ component } = mountWith({ diff --git a/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_empty_prompt.tsx b/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_empty_prompt.tsx index dfb52d579c397..3ddaca1413dc8 100644 --- a/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_empty_prompt.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_empty_prompt.tsx @@ -8,24 +8,28 @@ */ import { - EuiLink, EuiButton, - EuiFlexItem, - EuiFlexGroup, EuiButtonEmpty, EuiEmptyPrompt, + EuiFlexGroup, + EuiFlexItem, + EuiLink, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import React, { useCallback, useMemo } from 'react'; import { - noItemsStrings, - getNewDashboardTitle, + DASHBOARD_PANELS_UNSAVED_ID, + getDashboardBackupService, +} from '../services/dashboard_backup_service'; +import { coreServices } from '../services/kibana_services'; +import { getDashboardCapabilities } from '../utils/get_dashboard_capabilities'; +import { dashboardUnsavedListingStrings, + getNewDashboardTitle, + noItemsStrings, } from './_dashboard_listing_strings'; -import { pluginServices } from '../services/plugin_services'; import { confirmDiscardUnsavedChanges } from './confirm_overlays'; -import { DASHBOARD_PANELS_UNSAVED_ID } from '../services/dashboard_backup/dashboard_backup_service'; import { DashboardListingProps } from './types'; export interface DashboardListingEmptyPromptProps { @@ -45,12 +49,6 @@ export const DashboardListingEmptyPrompt = ({ createItem, disableCreateDashboardButton, }: DashboardListingEmptyPromptProps) => { - const { - application, - dashboardBackup, - dashboardCapabilities: { showWriteControls }, - } = pluginServices.getServices(); - const isEditingFirstDashboard = useMemo( () => useSessionStorageIntegration && unsavedDashboardIds.length === 1, [unsavedDashboardIds.length, useSessionStorageIntegration] @@ -78,8 +76,9 @@ export const DashboardListingEmptyPrompt = ({ color="danger" onClick={() => confirmDiscardUnsavedChanges(() => { - dashboardBackup.clearState(DASHBOARD_PANELS_UNSAVED_ID); - setUnsavedDashboardIds(dashboardBackup.getDashboardIdsWithUnsavedChanges()); + const dashboardBackupService = getDashboardBackupService(); + dashboardBackupService.clearState(DASHBOARD_PANELS_UNSAVED_ID); + setUnsavedDashboardIds(dashboardBackupService.getDashboardIdsWithUnsavedChanges()); }) } data-test-subj="discardDashboardPromptButton" @@ -106,12 +105,11 @@ export const DashboardListingEmptyPrompt = ({ isEditingFirstDashboard, createItem, disableCreateDashboardButton, - dashboardBackup, goToDashboard, setUnsavedDashboardIds, ]); - if (!showWriteControls) { + if (!getDashboardCapabilities().showWriteControls) { return ( - application.navigateToApp('home', { + coreServices.application.navigateToApp('home', { path: '#/tutorial_directory/sampleData', }) } diff --git a/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_table.tsx b/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_table.tsx index 5935b4d861a47..96d9025f822ff 100644 --- a/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_table.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/dashboard_listing_table.tsx @@ -7,26 +7,19 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { FormattedRelative, I18nProvider } from '@kbn/i18n-react'; -import React, { useMemo } from 'react'; +import React from 'react'; import { - type TableListViewKibanaDependencies, TableListViewKibanaProvider, TableListViewTable, } from '@kbn/content-management-table-list-view-table'; - +import { FormattedRelative, I18nProvider } from '@kbn/i18n-react'; import { useExecutionContext } from '@kbn/kibana-react-plugin/public'; -import { pluginServices } from '../services/plugin_services'; - +import { coreServices, savedObjectsTaggingService } from '../services/kibana_services'; import { DashboardUnsavedListing } from './dashboard_unsaved_listing'; import { useDashboardListingTable } from './hooks/use_dashboard_listing_table'; -import { - DashboardListingProps, - DashboardSavedObjectUserContent, - TableListViewApplicationService, -} from './types'; +import { DashboardListingProps, DashboardSavedObjectUserContent } from './types'; export const DashboardListingTable = ({ disableCreateDashboardButton, @@ -37,21 +30,7 @@ export const DashboardListingTable = ({ urlStateEnabled, showCreateDashboardButton = true, }: DashboardListingProps) => { - const { - analytics, - application, - notifications, - overlays, - http, - i18n, - savedObjectsTagging, - coreContext: { executionContext }, - chrome: { theme }, - userProfile, - dashboardContentInsights: { contentInsightsClient }, - } = pluginServices.getServices(); - - useExecutionContext(executionContext, { + useExecutionContext(coreServices.executionContext, { type: 'application', page: 'list', }); @@ -60,6 +39,7 @@ export const DashboardListingTable = ({ unsavedDashboardIds, refreshUnsavedDashboards, tableListViewTableProps: { title: tableCaption, ...tableListViewTable }, + contentInsightsClient, } = useDashboardListingTable({ disableCreateDashboardButton, goToDashboard, @@ -70,35 +50,11 @@ export const DashboardListingTable = ({ showCreateDashboardButton, }); - const savedObjectsTaggingFakePlugin = useMemo( - () => - savedObjectsTagging.hasApi // TODO: clean up this logic once https://github.com/elastic/kibana/issues/140433 is resolved - ? ({ - ui: savedObjectsTagging, - } as TableListViewKibanaDependencies['savedObjectsTagging']) - : undefined, - [savedObjectsTagging] - ); - - const core = useMemo( - () => ({ - analytics, - application: application as TableListViewApplicationService, - notifications, - overlays, - http, - i18n, - theme, - userProfile, - }), - [application, notifications, overlays, http, analytics, i18n, theme, userProfile] - ); - return ( diff --git a/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.test.tsx b/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.test.tsx index e777cc12258ee..74b538d87c207 100644 --- a/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.test.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.test.tsx @@ -7,17 +7,21 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { ComponentType, mount } from 'enzyme'; import React from 'react'; -import { mount, ComponentType } from 'enzyme'; +import { findTestSubject } from '@elastic/eui/lib/test'; +import { ViewMode } from '@kbn/embeddable-plugin/public'; import { I18nProvider } from '@kbn/i18n-react'; import { waitFor } from '@testing-library/react'; -import { findTestSubject } from '@elastic/eui/lib/test'; -import { pluginServices } from '../services/plugin_services'; +import { + DASHBOARD_PANELS_UNSAVED_ID, + getDashboardBackupService, +} from '../services/dashboard_backup_service'; +import { getDashboardContentManagementService } from '../services/dashboard_content_management_service'; +import { coreServices } from '../services/kibana_services'; import { DashboardUnsavedListing, DashboardUnsavedListingProps } from './dashboard_unsaved_listing'; -import { DASHBOARD_PANELS_UNSAVED_ID } from '../services/dashboard_backup/dashboard_backup_service'; -import { ViewMode } from '@kbn/embeddable-plugin/public'; const makeDefaultProps = (): DashboardUnsavedListingProps => ({ goToDashboard: jest.fn(), @@ -39,12 +43,13 @@ function mountWith({ props: incomingProps }: { props?: Partial { + const dashboardBackupService = getDashboardBackupService(); + const dashboardContentManagementService = getDashboardContentManagementService(); + it('Gets information for each unsaved dashboard', async () => { mountWith({}); await waitFor(() => { - expect( - pluginServices.getServices().dashboardContentManagement.findDashboards.findByIds - ).toHaveBeenCalledTimes(1); + expect(dashboardContentManagementService.findDashboards.findByIds).toHaveBeenCalledTimes(1); }); }); @@ -53,9 +58,9 @@ describe('Unsaved listing', () => { props.unsavedDashboardIds = ['dashboardUnsavedOne', DASHBOARD_PANELS_UNSAVED_ID]; mountWith({ props }); await waitFor(() => { - expect( - pluginServices.getServices().dashboardContentManagement.findDashboards.findByIds - ).toHaveBeenCalledWith(['dashboardUnsavedOne']); + expect(dashboardContentManagementService.findDashboards.findByIds).toHaveBeenCalledWith([ + 'dashboardUnsavedOne', + ]); }); }); @@ -94,17 +99,13 @@ describe('Unsaved listing', () => { getDiscardButton().simulate('click'); waitFor(() => { component.update(); - expect(pluginServices.getServices().overlays.openConfirm).toHaveBeenCalled(); - expect(pluginServices.getServices().dashboardBackup.clearState).toHaveBeenCalledWith( - 'dashboardUnsavedOne' - ); + expect(coreServices.overlays.openConfirm).toHaveBeenCalled(); + expect(dashboardBackupService.clearState).toHaveBeenCalledWith('dashboardUnsavedOne'); }); }); it('removes unsaved changes from any dashboard which errors on fetch', async () => { - ( - pluginServices.getServices().dashboardContentManagement.findDashboards.findByIds as jest.Mock - ).mockResolvedValue([ + (dashboardContentManagementService.findDashboards.findByIds as jest.Mock).mockResolvedValue([ { id: 'failCase1', status: 'error', @@ -129,17 +130,11 @@ describe('Unsaved listing', () => { const { component } = mountWith({ props }); waitFor(() => { component.update(); - expect(pluginServices.getServices().dashboardBackup.clearState).toHaveBeenCalledWith( - 'failCase1' - ); - expect(pluginServices.getServices().dashboardBackup.clearState).toHaveBeenCalledWith( - 'failCase2' - ); + expect(dashboardBackupService.clearState).toHaveBeenCalledWith('failCase1'); + expect(dashboardBackupService.clearState).toHaveBeenCalledWith('failCase2'); // clearing panels from dashboard with errors should cause getDashboardIdsWithUnsavedChanges to be called again. - expect( - pluginServices.getServices().dashboardBackup.getDashboardIdsWithUnsavedChanges - ).toHaveBeenCalledTimes(2); + expect(dashboardBackupService.getDashboardIdsWithUnsavedChanges).toHaveBeenCalledTimes(2); }); }); }); diff --git a/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.tsx b/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.tsx index 02f8cb483e717..0e23583801309 100644 --- a/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.tsx @@ -16,15 +16,18 @@ import { EuiSpacer, EuiTitle, } from '@elastic/eui'; -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { ViewMode } from '@kbn/embeddable-plugin/public'; -import { pluginServices } from '../services/plugin_services'; -import { confirmDiscardUnsavedChanges } from './confirm_overlays'; import { DashboardAttributes } from '../../common/content_management'; +import { + DASHBOARD_PANELS_UNSAVED_ID, + getDashboardBackupService, +} from '../services/dashboard_backup_service'; +import { getDashboardContentManagementService } from '../services/dashboard_content_management_service'; import { dashboardUnsavedListingStrings, getNewDashboardTitle } from './_dashboard_listing_strings'; -import { DASHBOARD_PANELS_UNSAVED_ID } from '../services/dashboard_backup/dashboard_backup_service'; +import { confirmDiscardUnsavedChanges } from './confirm_overlays'; const DashboardUnsavedItem = ({ id, @@ -116,12 +119,8 @@ export const DashboardUnsavedListing = ({ unsavedDashboardIds, refreshUnsavedDashboards, }: DashboardUnsavedListingProps) => { - const { - dashboardBackup, - dashboardContentManagement: { findDashboards }, - } = pluginServices.getServices(); - const [items, setItems] = useState({}); + const dashboardBackupService = useMemo(() => getDashboardBackupService(), []); const onOpen = useCallback( (id?: string) => { @@ -133,11 +132,11 @@ export const DashboardUnsavedListing = ({ const onDiscard = useCallback( (id?: string) => { confirmDiscardUnsavedChanges(() => { - dashboardBackup.clearState(id); + dashboardBackupService.clearState(id); refreshUnsavedDashboards(); }); }, - [refreshUnsavedDashboards, dashboardBackup] + [dashboardBackupService, refreshUnsavedDashboards] ); useEffect(() => { @@ -148,37 +147,39 @@ export const DashboardUnsavedListing = ({ const existingDashboardsWithUnsavedChanges = unsavedDashboardIds.filter( (id) => id !== DASHBOARD_PANELS_UNSAVED_ID ); - findDashboards.findByIds(existingDashboardsWithUnsavedChanges).then((results) => { - const dashboardMap = {}; - if (canceled) { - return; - } - let hasError = false; - const newItems = results.reduce((map, result) => { - if (result.status === 'error') { - hasError = true; - if (result.error.statusCode === 404) { - // Save object not found error - dashboardBackup.clearState(result.id); + getDashboardContentManagementService() + .findDashboards.findByIds(existingDashboardsWithUnsavedChanges) + .then((results) => { + const dashboardMap = {}; + if (canceled) { + return; + } + let hasError = false; + const newItems = results.reduce((map, result) => { + if (result.status === 'error') { + hasError = true; + if (result.error.statusCode === 404) { + // Save object not found error + dashboardBackupService.clearState(result.id); + } + return map; } - return map; + return { + ...map, + [result.id || DASHBOARD_PANELS_UNSAVED_ID]: result.attributes, + }; + }, dashboardMap); + if (hasError) { + refreshUnsavedDashboards(); + return; } - return { - ...map, - [result.id || DASHBOARD_PANELS_UNSAVED_ID]: result.attributes, - }; - }, dashboardMap); - if (hasError) { - refreshUnsavedDashboards(); - return; - } - setItems(newItems); - }); + setItems(newItems); + }); return () => { canceled = true; }; - }, [refreshUnsavedDashboards, dashboardBackup, unsavedDashboardIds, findDashboards]); + }, [dashboardBackupService, refreshUnsavedDashboards, unsavedDashboardIds]); return unsavedDashboardIds.length === 0 ? null : ( <> diff --git a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.test.tsx b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.test.tsx index b6f5a736e079f..61b7bf402bc13 100644 --- a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.test.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.test.tsx @@ -9,10 +9,13 @@ import { act, renderHook } from '@testing-library/react-hooks'; -import { useDashboardListingTable } from './use_dashboard_listing_table'; -import { pluginServices } from '../../services/plugin_services'; +import { getDashboardBackupService } from '../../services/dashboard_backup_service'; +import { getDashboardContentManagementService } from '../../services/dashboard_content_management_service'; +import { coreServices } from '../../services/kibana_services'; import { confirmCreateWithUnsaved } from '../confirm_overlays'; import { DashboardSavedObjectUserContent } from '../types'; +import { useDashboardListingTable } from './use_dashboard_listing_table'; + const clearStateMock = jest.fn(); const getDashboardUrl = jest.fn(); const goToDashboard = jest.fn(); @@ -26,7 +29,6 @@ const getUiSettingsMock = jest.fn().mockImplementation((key) => { } return null; }); -const getPluginServices = pluginServices.getServices(); jest.mock('@kbn/ebt-tools', () => ({ reportPerformanceMetricEvent: jest.fn(), @@ -45,20 +47,20 @@ jest.mock('../_dashboard_listing_strings', () => ({ })); describe('useDashboardListingTable', () => { + const dashboardBackupService = getDashboardBackupService(); + const dashboardContentManagementService = getDashboardContentManagementService(); + beforeEach(() => { jest.clearAllMocks(); - getPluginServices.dashboardBackup.dashboardHasUnsavedEdits = jest.fn().mockReturnValue(true); + dashboardBackupService.dashboardHasUnsavedEdits = jest.fn().mockReturnValue(true); - getPluginServices.dashboardBackup.getDashboardIdsWithUnsavedChanges = jest - .fn() - .mockReturnValue([]); + dashboardBackupService.getDashboardIdsWithUnsavedChanges = jest.fn().mockReturnValue([]); - getPluginServices.dashboardBackup.clearState = clearStateMock; - getPluginServices.dashboardCapabilities.showWriteControls = true; - getPluginServices.dashboardContentManagement.deleteDashboards = deleteDashboards; - getPluginServices.settings.uiSettings.get = getUiSettingsMock; - getPluginServices.notifications.toasts.addError = jest.fn(); + dashboardBackupService.clearState = clearStateMock; + dashboardContentManagementService.deleteDashboards = deleteDashboards; + coreServices.uiSettings.get = getUiSettingsMock; + coreServices.notifications.toasts.addError = jest.fn(); }); test('should return the correct initial hasInitialFetchReturned state', () => { @@ -232,8 +234,12 @@ describe('useDashboardListingTable', () => { }); test('createItem should be undefined when showWriteControls equals false', () => { - getPluginServices.dashboardCapabilities.showWriteControls = false; - + coreServices.application.capabilities = { + ...coreServices.application.capabilities, + dashboard: { + showWriteControls: false, + }, + }; const { result } = renderHook(() => useDashboardListingTable({ getDashboardUrl, @@ -245,7 +251,8 @@ describe('useDashboardListingTable', () => { }); test('deleteItems should be undefined when showWriteControls equals false', () => { - getPluginServices.dashboardCapabilities.showWriteControls = false; + (coreServices.application.capabilities as any).dashboard.showWriteControls = false; + const { result } = renderHook(() => useDashboardListingTable({ getDashboardUrl, @@ -257,7 +264,8 @@ describe('useDashboardListingTable', () => { }); test('editItem should be undefined when showWriteControls equals false', () => { - getPluginServices.dashboardCapabilities.showWriteControls = false; + (coreServices.application.capabilities as any).dashboard.showWriteControls = false; + const { result } = renderHook(() => useDashboardListingTable({ getDashboardUrl, diff --git a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx index 81986a7c37a2d..31bfa88120a5e 100644 --- a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx @@ -7,29 +7,34 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React, { useCallback, useState, useMemo } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; -import { ViewMode } from '@kbn/embeddable-plugin/public'; -import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; -import type { SavedObjectsFindOptionsReference } from '@kbn/core/public'; import { OpenContentEditorParams } from '@kbn/content-management-content-editor'; +import { ContentInsightsClient } from '@kbn/content-management-content-insights-public'; import { TableListViewTableProps } from '@kbn/content-management-table-list-view-table'; +import type { SavedObjectsFindOptionsReference } from '@kbn/core/public'; +import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; +import { ViewMode } from '@kbn/embeddable-plugin/public'; +import { DashboardContainerInput } from '../../../common'; +import { DashboardItem } from '../../../common/content_management'; import { DASHBOARD_CONTENT_ID, SAVED_OBJECT_DELETE_TIME, SAVED_OBJECT_LOADED_TIME, } from '../../dashboard_constants'; +import { getDashboardBackupService } from '../../services/dashboard_backup_service'; +import { getDashboardContentManagementService } from '../../services/dashboard_content_management_service'; +import { getDashboardRecentlyAccessedService } from '../../services/dashboard_recently_accessed_service'; +import { coreServices } from '../../services/kibana_services'; +import { getDashboardCapabilities } from '../../utils/get_dashboard_capabilities'; import { dashboardListingErrorStrings, dashboardListingTableStrings, } from '../_dashboard_listing_strings'; -import { DashboardContainerInput } from '../../../common'; -import { DashboardSavedObjectUserContent } from '../types'; import { confirmCreateWithUnsaved } from '../confirm_overlays'; -import { pluginServices } from '../../services/plugin_services'; -import { DashboardItem } from '../../../common/content_management'; import { DashboardListingEmptyPrompt } from '../dashboard_listing_empty_prompt'; +import { DashboardSavedObjectUserContent } from '../types'; type GetDetailViewLink = TableListViewTableProps['getDetailViewLink']; @@ -67,6 +72,7 @@ interface UseDashboardListingTableReturnType { refreshUnsavedDashboards: () => void; tableListViewTableProps: DashboardListingViewTableProps; unsavedDashboardIds: string[]; + contentInsightsClient: ContentInsightsClient; } export const useDashboardListingTable = ({ @@ -90,51 +96,44 @@ export const useDashboardListingTable = ({ useSessionStorageIntegration?: boolean; showCreateDashboardButton?: boolean; }): UseDashboardListingTableReturnType => { - const { - dashboardBackup, - dashboardCapabilities: { showWriteControls }, - settings: { uiSettings }, - dashboardContentManagement: { - findDashboards, - deleteDashboards, - updateDashboardMeta, - checkForDuplicateDashboardTitle, - }, - notifications: { toasts }, - dashboardRecentlyAccessed, - } = pluginServices.getServices(); - const { getEntityName, getTableListTitle, getEntityNamePlural } = dashboardListingTableStrings; const title = getTableListTitle(); const entityName = getEntityName(); const entityNamePlural = getEntityNamePlural(); const [pageDataTestSubject, setPageDataTestSubject] = useState(); const [hasInitialFetchReturned, setHasInitialFetchReturned] = useState(false); + + const dashboardBackupService = useMemo(() => getDashboardBackupService(), []); + const dashboardContentManagementService = useMemo( + () => getDashboardContentManagementService(), + [] + ); + const [unsavedDashboardIds, setUnsavedDashboardIds] = useState( - dashboardBackup.getDashboardIdsWithUnsavedChanges() + dashboardBackupService.getDashboardIdsWithUnsavedChanges() ); - const listingLimit = uiSettings.get(SAVED_OBJECTS_LIMIT_SETTING); - const initialPageSize = uiSettings.get(SAVED_OBJECTS_PER_PAGE_SETTING); + const listingLimit = coreServices.uiSettings.get(SAVED_OBJECTS_LIMIT_SETTING); + const initialPageSize = coreServices.uiSettings.get(SAVED_OBJECTS_PER_PAGE_SETTING); const createItem = useCallback(() => { - if (useSessionStorageIntegration && dashboardBackup.dashboardHasUnsavedEdits()) { + if (useSessionStorageIntegration && dashboardBackupService.dashboardHasUnsavedEdits()) { confirmCreateWithUnsaved(() => { - dashboardBackup.clearState(); + dashboardBackupService.clearState(); goToDashboard(); }, goToDashboard); return; } goToDashboard(); - }, [dashboardBackup, goToDashboard, useSessionStorageIntegration]); + }, [dashboardBackupService, goToDashboard, useSessionStorageIntegration]); const updateItemMeta = useCallback( async (props: Pick) => { - await updateDashboardMeta(props); + await dashboardContentManagementService.updateDashboardMeta(props); - setUnsavedDashboardIds(dashboardBackup.getDashboardIdsWithUnsavedChanges()); + setUnsavedDashboardIds(dashboardBackupService.getDashboardIdsWithUnsavedChanges()); }, - [dashboardBackup, updateDashboardMeta] + [dashboardBackupService, dashboardContentManagementService] ); const contentEditorValidators: OpenContentEditorParams['customValidators'] = useMemo( @@ -145,17 +144,19 @@ export const useDashboardListingTable = ({ fn: async (value: string, id: string) => { if (id) { try { - const [dashboard] = await findDashboards.findByIds([id]); + const [dashboard] = + await dashboardContentManagementService.findDashboards.findByIds([id]); if (dashboard.status === 'error') { return; } - const validTitle = await checkForDuplicateDashboardTitle({ - title: value, - copyOnSave: false, - lastSavedTitle: dashboard.attributes.title, - isTitleDuplicateConfirmed: false, - }); + const validTitle = + await dashboardContentManagementService.checkForDuplicateDashboardTitle({ + title: value, + copyOnSave: false, + lastSavedTitle: dashboard.attributes.title, + isTitleDuplicateConfirmed: false, + }); if (!validTitle) { throw new Error(dashboardListingErrorStrings.getDuplicateTitleWarning(value)); @@ -168,7 +169,7 @@ export const useDashboardListingTable = ({ }, ], }), - [checkForDuplicateDashboardTitle, findDashboards] + [dashboardContentManagementService] ); const emptyPrompt = useMemo( @@ -204,7 +205,7 @@ export const useDashboardListingTable = ({ ) => { const searchStartTime = window.performance.now(); - return findDashboards + return dashboardContentManagementService.findDashboards .search({ search: searchTerm, size: listingLimit, @@ -214,7 +215,7 @@ export const useDashboardListingTable = ({ .then(({ total, hits }) => { const searchEndTime = window.performance.now(); const searchDuration = searchEndTime - searchStartTime; - reportPerformanceMetricEvent(pluginServices.getServices().analytics, { + reportPerformanceMetricEvent(coreServices.analytics, { eventName: SAVED_OBJECT_LOADED_TIME, duration: searchDuration, meta: { @@ -227,7 +228,7 @@ export const useDashboardListingTable = ({ }; }); }, - [findDashboards, listingLimit] + [listingLimit, dashboardContentManagementService] ); const deleteItems = useCallback( @@ -235,15 +236,15 @@ export const useDashboardListingTable = ({ try { const deleteStartTime = window.performance.now(); - await deleteDashboards( + await dashboardContentManagementService.deleteDashboards( dashboardsToDelete.map(({ id }) => { - dashboardBackup.clearState(id); + dashboardBackupService.clearState(id); return id; }) ); const deleteDuration = window.performance.now() - deleteStartTime; - reportPerformanceMetricEvent(pluginServices.getServices().analytics, { + reportPerformanceMetricEvent(coreServices.analytics, { eventName: SAVED_OBJECT_DELETE_TIME, duration: deleteDuration, meta: { @@ -252,14 +253,14 @@ export const useDashboardListingTable = ({ }, }); } catch (error) { - toasts.addError(error, { + coreServices.notifications.toasts.addError(error, { title: dashboardListingErrorStrings.getErrorDeletingDashboardToast(), }); } - setUnsavedDashboardIds(dashboardBackup.getDashboardIdsWithUnsavedChanges()); + setUnsavedDashboardIds(dashboardBackupService.getDashboardIdsWithUnsavedChanges()); }, - [dashboardBackup, deleteDashboards, toasts] + [dashboardBackupService, dashboardContentManagementService] ); const editItem = useCallback( @@ -278,8 +279,9 @@ export const useDashboardListingTable = ({ [getDashboardUrl] ); - const tableListViewTableProps: DashboardListingViewTableProps = useMemo( - () => ({ + const tableListViewTableProps: DashboardListingViewTableProps = useMemo(() => { + const { showWriteControls } = getDashboardCapabilities(); + return { contentEditor: { isReadonly: !showWriteControls, onSave: updateItemMeta, @@ -303,36 +305,38 @@ export const useDashboardListingTable = ({ title, urlStateEnabled, createdByEnabled: true, - recentlyAccessed: dashboardRecentlyAccessed, - }), - [ - contentEditorValidators, - createItem, - dashboardListingId, - deleteItems, - editItem, - emptyPrompt, - entityName, - entityNamePlural, - findItems, - getDetailViewLink, - headingId, - initialFilter, - initialPageSize, - listingLimit, - onFetchSuccess, - showCreateDashboardButton, - showWriteControls, - title, - updateItemMeta, - urlStateEnabled, - dashboardRecentlyAccessed, - ] - ); + recentlyAccessed: getDashboardRecentlyAccessedService(), + }; + }, [ + contentEditorValidators, + createItem, + dashboardListingId, + deleteItems, + editItem, + emptyPrompt, + entityName, + entityNamePlural, + findItems, + getDetailViewLink, + headingId, + initialFilter, + initialPageSize, + listingLimit, + onFetchSuccess, + showCreateDashboardButton, + title, + updateItemMeta, + urlStateEnabled, + ]); const refreshUnsavedDashboards = useCallback( - () => setUnsavedDashboardIds(dashboardBackup.getDashboardIdsWithUnsavedChanges()), - [dashboardBackup] + () => setUnsavedDashboardIds(getDashboardBackupService().getDashboardIdsWithUnsavedChanges()), + [] + ); + + const contentInsightsClient = useMemo( + () => new ContentInsightsClient({ http: coreServices.http }, { domainId: 'dashboard' }), + [] ); return { @@ -341,5 +345,6 @@ export const useDashboardListingTable = ({ refreshUnsavedDashboards, tableListViewTableProps, unsavedDashboardIds, + contentInsightsClient, }; }; diff --git a/src/plugins/dashboard/public/dashboard_listing/types.ts b/src/plugins/dashboard/public/dashboard_listing/types.ts index c5788868b5535..0f5e245366242 100644 --- a/src/plugins/dashboard/public/dashboard_listing/types.ts +++ b/src/plugins/dashboard/public/dashboard_listing/types.ts @@ -10,7 +10,6 @@ import type { PropsWithChildren } from 'react'; import type { UserContentCommonSchema } from '@kbn/content-management-table-list-view-common'; import type { ViewMode } from '@kbn/embeddable-plugin/public'; -import type { DashboardApplicationService } from '../services/application/types'; export type DashboardListingProps = PropsWithChildren<{ disableCreateDashboardButton?: boolean; @@ -22,12 +21,6 @@ export type DashboardListingProps = PropsWithChildren<{ showCreateDashboardButton?: boolean; }>; -// because the type of `application.capabilities.advancedSettings` is so generic, the provider -// requiring the `save` key to be part of it is causing type issues - so, creating a custom type -export type TableListViewApplicationService = DashboardApplicationService & { - capabilities: { advancedSettings: { save: boolean } }; -}; - export interface DashboardSavedObjectUserContent extends UserContentCommonSchema { managed?: boolean; attributes: { diff --git a/src/plugins/dashboard/public/dashboard_top_nav/index.tsx b/src/plugins/dashboard/public/dashboard_top_nav/index.tsx index c8c02abae950d..18c0b69cd9b57 100644 --- a/src/plugins/dashboard/public/dashboard_top_nav/index.tsx +++ b/src/plugins/dashboard/public/dashboard_top_nav/index.tsx @@ -8,13 +8,13 @@ */ import React, { Suspense } from 'react'; -import { servicesReady } from '../plugin'; import { DashboardTopNavProps } from './dashboard_top_nav_with_context'; +import { untilPluginStartServicesReady } from '../services/kibana_services'; const LazyDashboardTopNav = React.lazy(() => (async () => { const modulePromise = import('./dashboard_top_nav_with_context'); - const [module] = await Promise.all([modulePromise, servicesReady]); + const [module] = await Promise.all([modulePromise, untilPluginStartServicesReady()]); return { default: module.DashboardTopNavWithContext, diff --git a/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.test.tsx b/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.test.tsx index 4114b7ab06d06..8cf7f36918ddc 100644 --- a/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.test.tsx +++ b/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.test.tsx @@ -12,10 +12,10 @@ import { render } from '@testing-library/react'; import { buildMockDashboard } from '../mocks'; import { InternalDashboardTopNav } from './internal_dashboard_top_nav'; import { setMockedPresentationUtilServices } from '@kbn/presentation-util-plugin/public/mocks'; -import { pluginServices } from '../services/plugin_services'; import { TopNavMenuProps } from '@kbn/navigation-plugin/public'; import { DashboardContext } from '../dashboard_api/use_dashboard_api'; import { DashboardApi } from '../dashboard_api/types'; +import { dataService, navigationService } from '../services/kibana_services'; describe('Internal dashboard top nav', () => { const mockTopNav = (badges: TopNavMenuProps['badges'] | undefined[]) => { @@ -32,13 +32,10 @@ describe('Internal dashboard top nav', () => { beforeEach(() => { setMockedPresentationUtilServices(); - pluginServices.getServices().data.query.filterManager.getFilters = jest - .fn() - .mockReturnValue([]); + dataService.query.filterManager.getFilters = jest.fn().mockReturnValue([]); // topNavMenu is mocked as a jest.fn() so we want to mock it with a component // @ts-ignore type issue with the mockTopNav for this test suite - pluginServices.getServices().navigation.TopNavMenu = ({ badges }: TopNavMenuProps) => - mockTopNav(badges); + navigationService.ui.TopNavMenu = ({ badges }: TopNavMenuProps) => mockTopNav(badges); }); it('should not render the managed badge by default', async () => { diff --git a/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx b/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx index 02cbaa7d90100..bcfcf2e98dddf 100644 --- a/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx +++ b/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx @@ -7,48 +7,57 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import UseUnmount from 'react-use/lib/useUnmount'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import UseUnmount from 'react-use/lib/useUnmount'; import { - withSuspense, - LazyLabsFlyout, - getContextProvider as getPresentationUtilContextProvider, -} from '@kbn/presentation-util-plugin/public'; -import { TopNavMenuBadgeProps, TopNavMenuProps } from '@kbn/navigation-plugin/public'; -import { + EuiBadge, EuiBreadcrumb, EuiHorizontalRule, EuiIcon, - EuiToolTipProps, - EuiPopover, - EuiBadge, EuiLink, + EuiPopover, + EuiToolTipProps, } from '@elastic/eui'; import { MountPoint } from '@kbn/core/public'; -import { getManagedContentBadge } from '@kbn/managed-content-badge'; +import { Query } from '@kbn/es-query'; import { FormattedMessage } from '@kbn/i18n-react'; +import { getManagedContentBadge } from '@kbn/managed-content-badge'; +import { TopNavMenuBadgeProps, TopNavMenuProps } from '@kbn/navigation-plugin/public'; import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing'; -import { Query } from '@kbn/es-query'; import { + LazyLabsFlyout, + getContextProvider as getPresentationUtilContextProvider, + withSuspense, +} from '@kbn/presentation-util-plugin/public'; + +import { UI_SETTINGS } from '../../common'; +import { useDashboardApi } from '../dashboard_api/use_dashboard_api'; +import { + dashboardManagedBadge, + getDashboardBreadcrumb, getDashboardTitle, leaveConfirmStrings, - getDashboardBreadcrumb, unsavedChangesBadgeStrings, - dashboardManagedBadge, } from '../dashboard_app/_dashboard_app_strings'; -import { UI_SETTINGS } from '../../common'; -import { pluginServices } from '../services/plugin_services'; +import { useDashboardMountContext } from '../dashboard_app/hooks/dashboard_mount_context'; +import { DashboardEditingToolbar } from '../dashboard_app/top_nav/dashboard_editing_toolbar'; import { useDashboardMenuItems } from '../dashboard_app/top_nav/use_dashboard_menu_items'; import { DashboardEmbedSettings } from '../dashboard_app/types'; -import { DashboardEditingToolbar } from '../dashboard_app/top_nav/dashboard_editing_toolbar'; -import { useDashboardMountContext } from '../dashboard_app/hooks/dashboard_mount_context'; -import { getFullEditPath, LEGACY_DASHBOARD_APP_ID } from '../dashboard_constants'; -import './_dashboard_top_nav.scss'; -import { DashboardRedirect } from '../dashboard_container/types'; -import { SaveDashboardReturn } from '../services/dashboard_content_management/types'; -import { useDashboardApi } from '../dashboard_api/use_dashboard_api'; +import { LEGACY_DASHBOARD_APP_ID, getFullEditPath } from '../dashboard_constants'; import { openSettingsFlyout } from '../dashboard_container/embeddable/api'; +import { DashboardRedirect } from '../dashboard_container/types'; +import { SaveDashboardReturn } from '../services/dashboard_content_management_service/types'; +import { getDashboardRecentlyAccessedService } from '../services/dashboard_recently_accessed_service'; +import { + coreServices, + dataService, + embeddableService, + navigationService, + serverlessService, +} from '../services/kibana_services'; +import { getDashboardCapabilities } from '../utils/get_dashboard_capabilities'; +import './_dashboard_top_nav.scss'; export interface InternalDashboardTopNavProps { customLeadingBreadCrumbs?: EuiBreadcrumb[]; @@ -75,28 +84,7 @@ export function InternalDashboardTopNav({ const [isLabsShown, setIsLabsShown] = useState(false); const dashboardTitleRef = useRef(null); - /** - * Unpack dashboard services - */ - const { - data: { - query: { filterManager }, - }, - chrome: { - setBreadcrumbs, - setIsVisible: setChromeVisibility, - getIsVisible$: getChromeIsVisible$, - recentlyAccessed: chromeRecentlyAccessed, - }, - serverless, - settings: { uiSettings }, - navigation: { TopNavMenu }, - embeddable: { getStateTransfer }, - initializerContext: { allowByValueEmbeddables }, - dashboardCapabilities: { saveQuery: allowSaveQuery, showWriteControls }, - dashboardRecentlyAccessed, - } = pluginServices.getServices(); - const isLabsEnabled = uiSettings.get(UI_SETTINGS.ENABLE_LABS_UI); + const isLabsEnabled = useMemo(() => coreServices.uiSettings.get(UI_SETTINGS.ENABLE_LABS_UI), []); const { setHeaderActionMenu, onAppLeave } = useDashboardMountContext(); const dashboardApi = useDashboardApi(); @@ -144,36 +132,24 @@ export function InternalDashboardTopNav({ * Manage chrome visibility when dashboard is embedded. */ useEffect(() => { - if (!embedSettings) setChromeVisibility(viewMode !== 'print'); - }, [embedSettings, setChromeVisibility, viewMode]); + if (!embedSettings) coreServices.chrome.setIsVisible(viewMode !== 'print'); + }, [embedSettings, viewMode]); /** * populate recently accessed, and set is chrome visible. */ useEffect(() => { - const subscription = getChromeIsVisible$().subscribe((visible) => setIsChromeVisible(visible)); + const subscription = coreServices.chrome + .getIsVisible$() + .subscribe((visible) => setIsChromeVisible(visible)); + if (lastSavedId && title) { - chromeRecentlyAccessed.add( - getFullEditPath(lastSavedId, viewMode === 'edit'), - title, - lastSavedId - ); - dashboardRecentlyAccessed.add( - getFullEditPath(lastSavedId, viewMode === 'edit'), - title, - lastSavedId - ); + const fullEditPath = getFullEditPath(lastSavedId, viewMode === 'edit'); + coreServices.chrome.recentlyAccessed.add(fullEditPath, title, lastSavedId); + getDashboardRecentlyAccessedService().add(fullEditPath, title, lastSavedId); // used to sort the listing table } return () => subscription.unsubscribe(); - }, [ - allowByValueEmbeddables, - chromeRecentlyAccessed, - getChromeIsVisible$, - lastSavedId, - viewMode, - title, - dashboardRecentlyAccessed, - ]); + }, [lastSavedId, viewMode, title]); /** * Set breadcrumbs to dashboard title when dashboard's title or view mode changes @@ -198,17 +174,17 @@ export function InternalDashboardTopNav({ }, ]; - if (serverless?.setBreadcrumbs) { + if (serverlessService) { // set serverless breadcrumbs if available, // set only the dashboardTitleBreadcrumbs because the main breadcrumbs automatically come as part of the navigation config - serverless.setBreadcrumbs(dashboardTitleBreadcrumbs); + serverlessService.setBreadcrumbs(dashboardTitleBreadcrumbs); } else { /** * non-serverless regular breadcrumbs * Dashboard embedded in other plugins (e.g. SecuritySolution) * will have custom leading breadcrumbs for back to their app. **/ - setBreadcrumbs( + coreServices.chrome.setBreadcrumbs( customLeadingBreadCrumbs.concat([ { text: getDashboardBreadcrumb(), @@ -221,22 +197,18 @@ export function InternalDashboardTopNav({ ]) ); } - }, [ - setBreadcrumbs, - redirectTo, - dashboardTitle, - dashboardApi, - viewMode, - serverless, - customLeadingBreadCrumbs, - ]); + }, [redirectTo, dashboardTitle, dashboardApi, viewMode, customLeadingBreadCrumbs]); /** * Build app leave handler whenever hasUnsavedChanges changes */ useEffect(() => { onAppLeave((actions) => { - if (viewMode === 'edit' && hasUnsavedChanges && !getStateTransfer().isTransferInProgress) { + if ( + viewMode === 'edit' && + hasUnsavedChanges && + !embeddableService.getStateTransfer().isTransferInProgress + ) { return actions.confirm( leaveConfirmStrings.getLeaveSubtitle(), leaveConfirmStrings.getLeaveTitle() @@ -248,13 +220,13 @@ export function InternalDashboardTopNav({ // reset on app leave handler so leaving from the listing page doesn't trigger a confirmation onAppLeave((actions) => actions.default()); }; - }, [onAppLeave, getStateTransfer, hasUnsavedChanges, viewMode]); + }, [onAppLeave, hasUnsavedChanges, viewMode]); const visibilityProps = useMemo(() => { const shouldShowNavBarComponent = (forceShow: boolean): boolean => (forceShow || isChromeVisible) && !fullScreenMode; const shouldShowFilterBar = (forceHide: boolean): boolean => - !forceHide && (filterManager.getFilters().length > 0 || !fullScreenMode); + !forceHide && (dataService.query.filterManager.getFilters().length > 0 || !fullScreenMode); const showTopNavMenu = shouldShowNavBarComponent(Boolean(embedSettings?.forceShowTopNavMenu)); const showQueryInput = Boolean(forceHideUnifiedSearch) @@ -275,14 +247,7 @@ export function InternalDashboardTopNav({ showQueryInput, showDatePicker, }; - }, [ - embedSettings, - filterManager, - forceHideUnifiedSearch, - fullScreenMode, - isChromeVisible, - viewMode, - ]); + }, [embedSettings, forceHideUnifiedSearch, fullScreenMode, isChromeVisible, viewMode]); const maybeRedirect = useCallback( (result?: SaveDashboardReturn) => { @@ -338,6 +303,8 @@ export function InternalDashboardTopNav({ } as EuiToolTipProps, }); } + + const { showWriteControls } = getDashboardCapabilities(); if (showWriteControls && managed) { const badgeProps = { ...getManagedContentBadge(dashboardManagedBadge.getBadgeAriaLabel()), @@ -390,7 +357,6 @@ export function InternalDashboardTopNav({ hasUnsavedChanges, viewMode, hasRunMigrations, - showWriteControls, managed, isPopoverOpen, dashboardApi, @@ -405,7 +371,7 @@ export function InternalDashboardTopNav({ ref={dashboardTitleRef} tabIndex={-1} >{`${getDashboardBreadcrumb()} - ${dashboardTitle}`} - { - return pluginServices.getServices(); -}; export type Start = jest.Mocked; diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index 33f9115fa6763..c46dcbc3e4139 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -7,75 +7,78 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { i18n } from '@kbn/i18n'; -import { BehaviorSubject } from 'rxjs'; -import { filter, map } from 'rxjs'; +import { BehaviorSubject, filter, map } from 'rxjs'; +import type { + ContentManagementPublicSetup, + ContentManagementPublicStart, +} from '@kbn/content-management-plugin/public'; +import { CustomBrandingStart } from '@kbn/core-custom-branding-browser'; import { + APP_WRAPPER_CLASS, App, - Plugin, + AppMountParameters, AppUpdater, + DEFAULT_APP_CATEGORIES, + Plugin, + PluginInitializerContext, ScopedHistory, type CoreSetup, type CoreStart, - AppMountParameters, - DEFAULT_APP_CATEGORIES, - PluginInitializerContext, } from '@kbn/core/public'; -import type { - ScreenshotModePluginSetup, - ScreenshotModePluginStart, -} from '@kbn/screenshot-mode-plugin/public'; -import type { - UsageCollectionSetup, - UsageCollectionStart, -} from '@kbn/usage-collection-plugin/public'; -import { APP_WRAPPER_CLASS } from '@kbn/core/public'; -import { type UiActionsSetup, type UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; +import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; +import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; +import { FieldFormatsStart } from '@kbn/field-formats-plugin/public/plugin'; import type { HomePublicPluginSetup } from '@kbn/home-plugin/public'; +import { i18n } from '@kbn/i18n'; +import type { Start as InspectorStartContract } from '@kbn/inspector-plugin/public'; import { replaceUrlHashQuery } from '@kbn/kibana-utils-plugin/common'; import { createKbnUrlTracker } from '@kbn/kibana-utils-plugin/public'; -import type { VisualizationsStart } from '@kbn/visualizations-plugin/public'; -import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; -import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; -import type { Start as InspectorStartContract } from '@kbn/inspector-plugin/public'; -import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; -import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; -import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; -import type { - ContentManagementPublicSetup, - ContentManagementPublicStart, -} from '@kbn/content-management-plugin/public'; -import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; -import type { UrlForwardingSetup, UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; -import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; -import type { ServerlessPluginStart } from '@kbn/serverless/public'; import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; import type { ObservabilityAIAssistantPublicSetup, ObservabilityAIAssistantPublicStart, } from '@kbn/observability-ai-assistant-plugin/public'; +import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; +import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; +import type { + ScreenshotModePluginSetup, + ScreenshotModePluginStart, +} from '@kbn/screenshot-mode-plugin/public'; +import type { ServerlessPluginStart } from '@kbn/serverless/public'; +import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; +import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; +import { type UiActionsSetup, type UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; +import type { UrlForwardingSetup, UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; +import type { + UsageCollectionSetup, + UsageCollectionStart, +} from '@kbn/usage-collection-plugin/public'; +import type { VisualizationsStart } from '@kbn/visualizations-plugin/public'; -import { CustomBrandingStart } from '@kbn/core-custom-branding-browser'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; -import { DashboardContainerFactoryDefinition } from './dashboard_container/embeddable/dashboard_container_factory'; -import { registerDashboardPanelPlacementSetting } from './dashboard_container/panel_placement'; +import { CONTENT_ID, LATEST_VERSION } from '../common/content_management'; import { - type DashboardAppLocator, DashboardAppLocatorDefinition, + type DashboardAppLocator, } from './dashboard_app/locator/locator'; +import { DashboardMountContextProps } from './dashboard_app/types'; import { DASHBOARD_APP_ID, LANDING_PAGE_PATH, LEGACY_DASHBOARD_APP_ID, SEARCH_SESSION_ID, } from './dashboard_constants'; -import { DashboardMountContextProps } from './dashboard_app/types'; -import type { FindDashboardsService } from './services/dashboard_content_management/types'; -import { CONTENT_ID, LATEST_VERSION } from '../common/content_management'; -import { GetPanelPlacementSettings } from './dashboard_container/panel_placement'; +import { DashboardContainerFactoryDefinition } from './dashboard_container/embeddable/dashboard_container_factory'; +import { + GetPanelPlacementSettings, + registerDashboardPanelPlacementSetting, +} from './dashboard_container/panel_placement'; +import type { FindDashboardsService } from './services/dashboard_content_management_service/types'; +import { setKibanaServices, untilPluginStartServicesReady } from './services/kibana_services'; export interface DashboardFeatureFlagConfig { allowByValueEmbeddables: boolean; @@ -99,6 +102,7 @@ export interface DashboardStartDependencies { data: DataPublicPluginStart; dataViewEditor: DataViewEditorStart; embeddable: EmbeddableStart; + fieldFormats: FieldFormatsStart; inspector: InspectorStartContract; navigation: NavigationPublicPluginStart; presentationUtil: PresentationUtilPluginStart; @@ -148,27 +152,9 @@ export class DashboardPlugin private dashboardFeatureFlagConfig?: DashboardFeatureFlagConfig; private locator?: DashboardAppLocator; - private async startDashboardKibanaServices( - coreStart: CoreStart, - startPlugins: DashboardStartDependencies, - initContext: PluginInitializerContext - ) { - const { registry, pluginServices } = await import('./services/plugin_services'); - pluginServices.setRegistry(registry.start({ coreStart, startPlugins, initContext })); - resolveServicesReady(); - } - public setup( core: CoreSetup, - { - share, - embeddable, - home, - urlForwarding, - data, - contentManagement, - uiActions, - }: DashboardSetupDependencies + { share, embeddable, home, urlForwarding, data, contentManagement }: DashboardSetupDependencies ): DashboardSetup { this.dashboardFeatureFlagConfig = this.initializerContext.config.get(); @@ -183,11 +169,14 @@ export class DashboardPlugin new DashboardAppLocatorDefinition({ useHashedUrl: core.uiSettings.get('state:storeInSessionStorage'), getDashboardFilterFields: async (dashboardId: string) => { - const { pluginServices } = await import('./services/plugin_services'); - const { - dashboardContentManagement: { loadDashboardState }, - } = pluginServices.getServices(); - return (await loadDashboardState({ id: dashboardId })).dashboardInput?.filters ?? []; + const [{ getDashboardContentManagementService }] = await Promise.all([ + import('./services/dashboard_content_management_service'), + untilPluginStartServicesReady(), + ]); + return ( + (await getDashboardContentManagementService().loadDashboardState({ id: dashboardId })) + .dashboardInput?.filters ?? [] + ); }, }) ); @@ -262,6 +251,7 @@ export class DashboardPlugin mount: async (params: AppMountParameters) => { this.currentHistory = params.history; params.element.classList.add(APP_WRAPPER_CLASS); + await untilPluginStartServicesReady(); const { mountApp } = await import('./dashboard_app/dashboard_router'); appMounted(); @@ -340,25 +330,26 @@ export class DashboardPlugin } public start(core: CoreStart, plugins: DashboardStartDependencies): DashboardStart { - this.startDashboardKibanaServices(core, plugins, this.initializerContext).then(async () => { - const { buildAllDashboardActions } = await import('./dashboard_actions'); - buildAllDashboardActions({ - core, - plugins, - allowByValueEmbeddables: this.dashboardFeatureFlagConfig?.allowByValueEmbeddables, - }); - }); + setKibanaServices(core, plugins); + + Promise.all([import('./dashboard_actions'), untilPluginStartServicesReady()]).then( + ([{ buildAllDashboardActions }]) => { + buildAllDashboardActions({ + plugins, + allowByValueEmbeddables: this.dashboardFeatureFlagConfig?.allowByValueEmbeddables, + }); + } + ); return { locator: this.locator, dashboardFeatureFlagConfig: this.dashboardFeatureFlagConfig!, registerDashboardPanelPlacementSetting, findDashboardsService: async () => { - const { pluginServices } = await import('./services/plugin_services'); - const { - dashboardContentManagement: { findDashboards }, - } = pluginServices.getServices(); - return findDashboards; + const { getDashboardContentManagementService } = await import( + './services/dashboard_content_management_service' + ); + return getDashboardContentManagementService().findDashboards; }, }; } diff --git a/src/plugins/dashboard/public/services/analytics/analytics.stub.ts b/src/plugins/dashboard/public/services/analytics/analytics.stub.ts deleted file mode 100644 index a5baa963a276c..0000000000000 --- a/src/plugins/dashboard/public/services/analytics/analytics.stub.ts +++ /dev/null @@ -1,22 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardAnalyticsService } from './types'; - -type AnalyticsServiceFactory = PluginServiceFactory; - -export const analyticsServiceFactory: AnalyticsServiceFactory = () => { - const pluginMock = analyticsServiceMock.createAnalyticsServiceStart(); - - return { - reportEvent: pluginMock.reportEvent, - }; -}; diff --git a/src/plugins/dashboard/public/services/analytics/analytics_service.ts b/src/plugins/dashboard/public/services/analytics/analytics_service.ts deleted file mode 100644 index f027963d30cda..0000000000000 --- a/src/plugins/dashboard/public/services/analytics/analytics_service.ts +++ /dev/null @@ -1,27 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardAnalyticsService } from './types'; - -export type AnalyticsServiceFactory = KibanaPluginServiceFactory< - DashboardAnalyticsService, - DashboardStartDependencies ->; - -export const analyticsServiceFactory: AnalyticsServiceFactory = ({ coreStart }) => { - const { - analytics: { reportEvent }, - } = coreStart; - - return { - reportEvent, - }; -}; diff --git a/src/plugins/dashboard/public/services/analytics/types.ts b/src/plugins/dashboard/public/services/analytics/types.ts deleted file mode 100644 index fb0423229709f..0000000000000 --- a/src/plugins/dashboard/public/services/analytics/types.ts +++ /dev/null @@ -1,14 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CoreStart } from '@kbn/core/public'; - -export interface DashboardAnalyticsService { - reportEvent: CoreStart['analytics']['reportEvent']; -} diff --git a/src/plugins/dashboard/public/services/application/application.stub.ts b/src/plugins/dashboard/public/services/application/application.stub.ts deleted file mode 100644 index 83565a9302a96..0000000000000 --- a/src/plugins/dashboard/public/services/application/application.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { applicationServiceMock } from '@kbn/core-application-browser-mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardApplicationService } from './types'; - -type ApplicationServiceFactory = PluginServiceFactory; - -export const applicationServiceFactory: ApplicationServiceFactory = () => { - const pluginMock = applicationServiceMock.createStartContract(); - - return { - currentAppId$: pluginMock.currentAppId$, - navigateToApp: pluginMock.navigateToApp, - navigateToUrl: pluginMock.navigateToUrl, - getUrlForApp: pluginMock.getUrlForApp, - capabilities: { - advancedSettings: pluginMock.capabilities.advancedSettings, - maps: pluginMock.capabilities.maps, - navLinks: pluginMock.capabilities.navLinks, - visualize: pluginMock.capabilities.visualize, - }, - }; -}; diff --git a/src/plugins/dashboard/public/services/application/application_service.ts b/src/plugins/dashboard/public/services/application/application_service.ts deleted file mode 100644 index bf4af0719c2ad..0000000000000 --- a/src/plugins/dashboard/public/services/application/application_service.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardApplicationService } from './types'; - -export type ApplicationServiceFactory = KibanaPluginServiceFactory< - DashboardApplicationService, - DashboardStartDependencies ->; - -export const applicationServiceFactory: ApplicationServiceFactory = ({ coreStart }) => { - const { - application: { - currentAppId$, - navigateToApp, - navigateToUrl, - getUrlForApp, - capabilities: { advancedSettings, maps, navLinks, visualize }, - }, - } = coreStart; - - return { - currentAppId$, - navigateToApp, - navigateToUrl, - getUrlForApp, - capabilities: { - advancedSettings, - maps, - navLinks, - visualize, - }, - }; -}; diff --git a/src/plugins/dashboard/public/services/application/types.ts b/src/plugins/dashboard/public/services/application/types.ts deleted file mode 100644 index 16041562257bf..0000000000000 --- a/src/plugins/dashboard/public/services/application/types.ts +++ /dev/null @@ -1,23 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CoreStart } from '@kbn/core/public'; - -export interface DashboardApplicationService { - currentAppId$: CoreStart['application']['currentAppId$']; - navigateToApp: CoreStart['application']['navigateToApp']; - navigateToUrl: CoreStart['application']['navigateToUrl']; - getUrlForApp: CoreStart['application']['getUrlForApp']; - capabilities: { - advancedSettings: CoreStart['application']['capabilities']['advancedSettings']; - maps: CoreStart['application']['capabilities']['maps']; // only used in `add_to_library_action` - navLinks: CoreStart['application']['capabilities']['navLinks']; - visualize: CoreStart['application']['capabilities']['visualize']; // only used in `add_to_library_action` - }; -} diff --git a/src/plugins/dashboard/public/services/chrome/chrome.stub.ts b/src/plugins/dashboard/public/services/chrome/chrome.stub.ts deleted file mode 100644 index 70a2635f3a8b5..0000000000000 --- a/src/plugins/dashboard/public/services/chrome/chrome.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { coreMock, chromeServiceMock } from '@kbn/core/public/mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardChromeService } from './types'; - -type ChromeServiceFactory = PluginServiceFactory; - -export const chromeServiceFactory: ChromeServiceFactory = () => { - const pluginMock = chromeServiceMock.createStartContract(); - - return { - docTitle: pluginMock.docTitle, - setBadge: pluginMock.setBadge, - getIsVisible$: pluginMock.getIsVisible$, - recentlyAccessed: pluginMock.recentlyAccessed, - setBreadcrumbs: pluginMock.setBreadcrumbs, - setHelpExtension: pluginMock.setHelpExtension, - setIsVisible: pluginMock.setIsVisible, - theme: coreMock.createStart().theme, - }; -}; diff --git a/src/plugins/dashboard/public/services/chrome/chrome_service.ts b/src/plugins/dashboard/public/services/chrome/chrome_service.ts deleted file mode 100644 index 43458bd71cd06..0000000000000 --- a/src/plugins/dashboard/public/services/chrome/chrome_service.ts +++ /dev/null @@ -1,43 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardChromeService } from './types'; - -export type ChromeServiceFactory = KibanaPluginServiceFactory< - DashboardChromeService, - DashboardStartDependencies ->; - -export const chromeServiceFactory: ChromeServiceFactory = ({ coreStart }) => { - const { - chrome: { - docTitle, - setBadge, - getIsVisible$, - recentlyAccessed, - setBreadcrumbs, - setHelpExtension, - setIsVisible, - }, - theme, - } = coreStart; - - return { - docTitle, - setBadge, - getIsVisible$, - recentlyAccessed, - setBreadcrumbs, - setHelpExtension, - setIsVisible, - theme, - }; -}; diff --git a/src/plugins/dashboard/public/services/chrome/types.ts b/src/plugins/dashboard/public/services/chrome/types.ts deleted file mode 100644 index 983073aab75f9..0000000000000 --- a/src/plugins/dashboard/public/services/chrome/types.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CoreStart } from '@kbn/core/public'; - -export interface DashboardChromeService { - docTitle: CoreStart['chrome']['docTitle']; - setBadge: CoreStart['chrome']['setBadge']; - getIsVisible$: CoreStart['chrome']['getIsVisible$']; - recentlyAccessed: CoreStart['chrome']['recentlyAccessed']; - setBreadcrumbs: CoreStart['chrome']['setBreadcrumbs']; - setHelpExtension: CoreStart['chrome']['setHelpExtension']; - setIsVisible: CoreStart['chrome']['setIsVisible']; - theme: CoreStart['theme']; -} diff --git a/src/plugins/dashboard/public/services/content_management/content_management_service.stub.ts b/src/plugins/dashboard/public/services/content_management/content_management_service.stub.ts deleted file mode 100644 index 21bf785fb611c..0000000000000 --- a/src/plugins/dashboard/public/services/content_management/content_management_service.stub.ts +++ /dev/null @@ -1,18 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; -import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; - -export type ContentManagementServiceFactory = PluginServiceFactory; - -export const contentManagementServiceFactory: ContentManagementServiceFactory = () => { - return contentManagementMock.createStartContract(); -}; diff --git a/src/plugins/dashboard/public/services/content_management/content_management_service.ts b/src/plugins/dashboard/public/services/content_management/content_management_service.ts deleted file mode 100644 index c5c94ef91a31c..0000000000000 --- a/src/plugins/dashboard/public/services/content_management/content_management_service.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; -import { DashboardStartDependencies } from '../../plugin'; - -export type ContentManagementServiceFactory = KibanaPluginServiceFactory< - ContentManagementPublicStart, - DashboardStartDependencies ->; - -export const contentManagementServiceFactory: ContentManagementServiceFactory = ({ - startPlugins, -}) => { - const { contentManagement } = startPlugins; - - return contentManagement; -}; diff --git a/src/plugins/dashboard/public/services/core_context/core_context.stub.ts b/src/plugins/dashboard/public/services/core_context/core_context.stub.ts deleted file mode 100644 index 36d1f19b7cd30..0000000000000 --- a/src/plugins/dashboard/public/services/core_context/core_context.stub.ts +++ /dev/null @@ -1,22 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { coreMock } from '@kbn/core/public/mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardCoreContextService } from './types'; - -type CoreContextServiceFactory = PluginServiceFactory; - -export const coreContextServiceFactory: CoreContextServiceFactory = () => { - const pluginMock = coreMock.createStart(); - return { - executionContext: pluginMock.executionContext, - i18nContext: pluginMock.i18n.Context, - }; -}; diff --git a/src/plugins/dashboard/public/services/core_context/core_context_service.ts b/src/plugins/dashboard/public/services/core_context/core_context_service.ts deleted file mode 100644 index 38b8834455ce9..0000000000000 --- a/src/plugins/dashboard/public/services/core_context/core_context_service.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardCoreContextService } from './types'; - -export type CoreContextServiceFactory = KibanaPluginServiceFactory< - DashboardCoreContextService, - DashboardStartDependencies ->; - -export const coreContextServiceFactory: CoreContextServiceFactory = ({ coreStart }) => { - const { - executionContext, - i18n: { Context }, - } = coreStart; - - return { - executionContext, - i18nContext: Context, - }; -}; diff --git a/src/plugins/dashboard/public/services/core_context/types.ts b/src/plugins/dashboard/public/services/core_context/types.ts deleted file mode 100644 index 23f3fc7b5a7c3..0000000000000 --- a/src/plugins/dashboard/public/services/core_context/types.ts +++ /dev/null @@ -1,15 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CoreStart } from '@kbn/core/public'; - -export interface DashboardCoreContextService { - executionContext: CoreStart['executionContext']; - i18nContext: CoreStart['i18n']['Context']; -} diff --git a/src/plugins/dashboard/public/services/custom_branding/custom_branding.stub.ts b/src/plugins/dashboard/public/services/custom_branding/custom_branding.stub.ts deleted file mode 100644 index 6bcb0ba4172b2..0000000000000 --- a/src/plugins/dashboard/public/services/custom_branding/custom_branding.stub.ts +++ /dev/null @@ -1,22 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { coreMock } from '@kbn/core/public/mocks'; -import { DashboardCustomBrandingService } from './types'; - -type CustomBrandingServiceFactory = PluginServiceFactory; - -export const customBrandingServiceFactory: CustomBrandingServiceFactory = () => { - const pluginMock = coreMock.createStart(); - return { - hasCustomBranding$: pluginMock.customBranding.hasCustomBranding$, - customBranding$: pluginMock.customBranding.customBranding$, - }; -}; diff --git a/src/plugins/dashboard/public/services/custom_branding/custom_branding_service.ts b/src/plugins/dashboard/public/services/custom_branding/custom_branding_service.ts deleted file mode 100644 index bed7d1ac229fc..0000000000000 --- a/src/plugins/dashboard/public/services/custom_branding/custom_branding_service.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardStartDependencies } from '../../plugin'; -import { DashboardCustomBrandingService } from './types'; - -export type CustomBrandingServiceFactory = KibanaPluginServiceFactory< - DashboardCustomBrandingService, - DashboardStartDependencies ->; - -export const customBrandingServiceFactory: CustomBrandingServiceFactory = ({ coreStart }) => { - const { customBranding } = coreStart; - return { - hasCustomBranding$: customBranding.hasCustomBranding$, - customBranding$: customBranding.customBranding$, - }; -}; diff --git a/src/plugins/dashboard/public/services/custom_branding/types.ts b/src/plugins/dashboard/public/services/custom_branding/types.ts deleted file mode 100644 index f2cd986b2db1c..0000000000000 --- a/src/plugins/dashboard/public/services/custom_branding/types.ts +++ /dev/null @@ -1,15 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CustomBrandingStart } from '@kbn/core-custom-branding-browser'; - -export interface DashboardCustomBrandingService { - hasCustomBranding$: CustomBrandingStart['hasCustomBranding$']; - customBranding$: CustomBrandingStart['customBranding$']; -} diff --git a/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup.stub.ts b/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup.stub.ts deleted file mode 100644 index 4c80fcff9e828..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup.stub.ts +++ /dev/null @@ -1,27 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardBackupServiceType } from './types'; - -type DashboardBackupServiceFactory = PluginServiceFactory; - -export const dashboardBackupServiceFactory: DashboardBackupServiceFactory = () => { - return { - clearState: jest.fn(), - getState: jest.fn().mockReturnValue(undefined), - setState: jest.fn(), - getViewMode: jest.fn(), - storeViewMode: jest.fn(), - getDashboardIdsWithUnsavedChanges: jest - .fn() - .mockReturnValue(['dashboardUnsavedOne', 'dashboardUnsavedTwo']), - dashboardHasUnsavedEdits: jest.fn(), - }; -}; diff --git a/src/plugins/dashboard/public/services/dashboard_backup/types.ts b/src/plugins/dashboard/public/services/dashboard_backup/types.ts deleted file mode 100644 index d7b7416d5810d..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_backup/types.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ViewMode } from '@kbn/embeddable-plugin/public'; -import { UnsavedPanelState } from '../../dashboard_container/types'; -import { SavedDashboardInput } from '../dashboard_content_management/types'; - -export interface DashboardBackupServiceType { - clearState: (id?: string) => void; - getState: (id: string | undefined) => - | { - dashboardState?: Partial; - panels?: UnsavedPanelState; - } - | undefined; - setState: ( - id: string | undefined, - dashboardState: Partial, - panels: UnsavedPanelState - ) => void; - getViewMode: () => ViewMode; - storeViewMode: (viewMode: ViewMode) => void; - getDashboardIdsWithUnsavedChanges: () => string[]; - dashboardHasUnsavedEdits: (id?: string) => boolean; -} diff --git a/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts b/src/plugins/dashboard/public/services/dashboard_backup_service.ts similarity index 78% rename from src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts rename to src/plugins/dashboard/public/services/dashboard_backup_service.ts index ea56cd8ed5d5e..5ffff35ff3d77 100644 --- a/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts +++ b/src/plugins/dashboard/public/services/dashboard_backup_service.ts @@ -7,21 +7,18 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { firstValueFrom } from 'rxjs'; import { isEqual } from 'lodash'; +import { firstValueFrom } from 'rxjs'; -import { set } from '@kbn/safer-lodash-set'; import { ViewMode } from '@kbn/embeddable-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; +import { set } from '@kbn/safer-lodash-set'; -import { DashboardSpacesService } from '../spaces/types'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardBackupServiceType } from './types'; -import type { DashboardContainerInput } from '../../../common'; -import { DashboardNotificationsService } from '../notifications/types'; -import { backupServiceStrings } from '../../dashboard_container/_dashboard_container_strings'; -import { UnsavedPanelState } from '../../dashboard_container/types'; +import type { DashboardContainerInput } from '../../common'; +import { backupServiceStrings } from '../dashboard_container/_dashboard_container_strings'; +import { UnsavedPanelState } from '../dashboard_container/types'; +import { coreServices, spacesService } from './kibana_services'; +import { SavedDashboardInput } from './dashboard_content_management_service/types'; export const DASHBOARD_PANELS_UNSAVED_ID = 'unsavedDashboard'; export const PANELS_CONTROL_GROUP_KEY = 'controlGroup'; @@ -31,34 +28,39 @@ const DASHBOARD_VIEWMODE_LOCAL_KEY = 'dashboardViewMode'; // this key is named `panels` for BWC reasons, but actually contains the entire dashboard state const DASHBOARD_STATE_SESSION_KEY = 'dashboardStateManagerPanels'; -interface DashboardBackupRequiredServices { - notifications: DashboardNotificationsService; - spaces: DashboardSpacesService; +interface DashboardBackupServiceType { + clearState: (id?: string) => void; + getState: (id: string | undefined) => + | { + dashboardState?: Partial; + panels?: UnsavedPanelState; + } + | undefined; + setState: ( + id: string | undefined, + dashboardState: Partial, + panels: UnsavedPanelState + ) => void; + getViewMode: () => ViewMode; + storeViewMode: (viewMode: ViewMode) => void; + getDashboardIdsWithUnsavedChanges: () => string[]; + dashboardHasUnsavedEdits: (id?: string) => boolean; } -export type DashboardBackupServiceFactory = KibanaPluginServiceFactory< - DashboardBackupServiceType, - DashboardStartDependencies, - DashboardBackupRequiredServices ->; - class DashboardBackupService implements DashboardBackupServiceType { private activeSpaceId: string; private sessionStorage: Storage; private localStorage: Storage; - private notifications: DashboardNotificationsService; - private spaces: DashboardSpacesService; private oldDashboardsWithUnsavedChanges: string[] = []; - constructor(requiredServices: DashboardBackupRequiredServices) { - ({ notifications: this.notifications, spaces: this.spaces } = requiredServices); + constructor() { this.sessionStorage = new Storage(sessionStorage); this.localStorage = new Storage(localStorage); this.activeSpaceId = 'default'; - if (this.spaces.getActiveSpace$) { - firstValueFrom(this.spaces.getActiveSpace$()).then((space) => { + if (spacesService) { + firstValueFrom(spacesService.getActiveSpace$()).then((space) => { this.activeSpaceId = space.id; }); } @@ -72,7 +74,7 @@ class DashboardBackupService implements DashboardBackupServiceType { try { this.localStorage.set(DASHBOARD_VIEWMODE_LOCAL_KEY, viewMode); } catch (e) { - this.notifications.toasts.addDanger({ + coreServices.notifications.toasts.addDanger({ title: backupServiceStrings.viewModeStorageError(e.message), 'data-test-subj': 'dashboardViewmodeBackupFailure', }); @@ -99,7 +101,7 @@ class DashboardBackupService implements DashboardBackupServiceType { }); } } catch (e) { - this.notifications.toasts.addDanger({ + coreServices.notifications.toasts.addDanger({ title: backupServiceStrings.getPanelsClearError(e.message), 'data-test-subj': 'dashboardPanelsClearFailure', }); @@ -117,7 +119,7 @@ class DashboardBackupService implements DashboardBackupServiceType { return { dashboardState, panels }; } catch (e) { - this.notifications.toasts.addDanger({ + coreServices.notifications.toasts.addDanger({ title: backupServiceStrings.getPanelsGetError(e.message), 'data-test-subj': 'dashboardPanelsGetFailure', }); @@ -138,7 +140,7 @@ class DashboardBackupService implements DashboardBackupServiceType { set(panelsStorage, [this.activeSpaceId, id], unsavedPanels); this.sessionStorage.set(DASHBOARD_PANELS_SESSION_KEY, panelsStorage, true); } catch (e) { - this.notifications.toasts.addDanger({ + coreServices.notifications.toasts.addDanger({ title: backupServiceStrings.getPanelsSetError(e.message), 'data-test-subj': 'dashboardPanelsSetFailure', }); @@ -178,7 +180,7 @@ class DashboardBackupService implements DashboardBackupServiceType { return this.oldDashboardsWithUnsavedChanges; } catch (e) { - this.notifications.toasts.addDanger({ + coreServices.notifications.toasts.addDanger({ title: backupServiceStrings.getPanelsGetError(e.message), 'data-test-subj': 'dashboardPanelsGetFailure', }); @@ -191,9 +193,11 @@ class DashboardBackupService implements DashboardBackupServiceType { } } -export const dashboardBackupServiceFactory: DashboardBackupServiceFactory = ( - core, - requiredServices -) => { - return new DashboardBackupService(requiredServices); +let dashboardBackupService: DashboardBackupService; + +export const getDashboardBackupService = () => { + if (!dashboardBackupService) { + dashboardBackupService = new DashboardBackupService(); + } + return dashboardBackupService; }; diff --git a/src/plugins/dashboard/public/services/dashboard_capabilities/dashboard_capabilities.stub.ts b/src/plugins/dashboard/public/services/dashboard_capabilities/dashboard_capabilities.stub.ts deleted file mode 100644 index 118f649d7030b..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_capabilities/dashboard_capabilities.stub.ts +++ /dev/null @@ -1,30 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardCapabilitiesService } from './types'; - -const defaultDashboardCapabilities: DashboardCapabilitiesService = { - show: true, - createNew: true, - saveQuery: true, - createShortUrl: true, - showWriteControls: true, - storeSearchSession: true, - mapsCapabilities: { save: true }, - visualizeCapabilities: { save: true }, -}; - -type DashboardCapabilitiesServiceFactory = PluginServiceFactory; - -export const dashboardCapabilitiesServiceFactory: DashboardCapabilitiesServiceFactory = () => { - return { - ...defaultDashboardCapabilities, - }; -}; diff --git a/src/plugins/dashboard/public/services/dashboard_capabilities/types.ts b/src/plugins/dashboard/public/services/dashboard_capabilities/types.ts deleted file mode 100644 index 4f78fa8ad38b9..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_capabilities/types.ts +++ /dev/null @@ -1,19 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export interface DashboardCapabilitiesService { - show: boolean; - saveQuery: boolean; - createNew: boolean; - mapsCapabilities: { save: boolean }; - createShortUrl: boolean; - showWriteControls: boolean; - visualizeCapabilities: { save: boolean }; - storeSearchSession: boolean; -} diff --git a/src/plugins/dashboard/public/services/dashboard_content_insights/dashboard_content_insights.stub.ts b/src/plugins/dashboard/public/services/dashboard_content_insights/dashboard_content_insights.stub.ts deleted file mode 100644 index 83ddf74df0a8a..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_content_insights/dashboard_content_insights.stub.ts +++ /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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardContentInsightsService } from './types'; - -type DashboardContentInsightsServiceFactory = PluginServiceFactory; - -export const dashboardContentInsightsServiceFactory: DashboardContentInsightsServiceFactory = - () => { - return { - trackDashboardView: jest.fn(), - contentInsightsClient: { - track: jest.fn(), - getStats: jest.fn(), - }, - }; - }; diff --git a/src/plugins/dashboard/public/services/dashboard_content_insights/dashboard_content_insights_service.ts b/src/plugins/dashboard/public/services/dashboard_content_insights/dashboard_content_insights_service.ts deleted file mode 100644 index 349d78bb2abb3..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_content_insights/dashboard_content_insights_service.ts +++ /dev/null @@ -1,34 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { ContentInsightsClient } from '@kbn/content-management-content-insights-public'; -import { DashboardStartDependencies } from '../../plugin'; -import { DashboardContentInsightsService } from './types'; - -export type DashboardContentInsightsServiceFactory = KibanaPluginServiceFactory< - DashboardContentInsightsService, - DashboardStartDependencies ->; - -export const dashboardContentInsightsServiceFactory: DashboardContentInsightsServiceFactory = ( - params -) => { - const contentInsightsClient = new ContentInsightsClient( - { http: params.coreStart.http }, - { domainId: 'dashboard' } - ); - - return { - trackDashboardView: (dashboardId: string) => { - contentInsightsClient.track(dashboardId, 'viewed'); - }, - contentInsightsClient, - }; -}; diff --git a/src/plugins/dashboard/public/services/dashboard_content_insights/types.ts b/src/plugins/dashboard/public/services/dashboard_content_insights/types.ts deleted file mode 100644 index 848f51b920270..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_content_insights/types.ts +++ /dev/null @@ -1,15 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { ContentInsightsClientPublic } from '@kbn/content-management-content-insights-public'; - -export interface DashboardContentInsightsService { - trackDashboardView: (dashboardId: string) => void; - contentInsightsClient: ContentInsightsClientPublic; -} diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management.stub.ts b/src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management.stub.ts deleted file mode 100644 index 04adeb88c3b94..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management.stub.ts +++ /dev/null @@ -1,80 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { DashboardContentManagementService, LoadDashboardReturn } from './types'; -import { DashboardAttributes } from '../../../common/content_management'; -import { SearchDashboardsResponse } from './lib/find_dashboards'; - -export type DashboardContentManagementServiceFactory = - PluginServiceFactory; - -export const dashboardContentManagementServiceFactory: DashboardContentManagementServiceFactory = - () => { - return { - loadDashboardState: jest.fn().mockImplementation(() => - Promise.resolve({ - dashboardInput: {}, - } as LoadDashboardReturn) - ), - saveDashboardState: jest.fn(), - findDashboards: { - search: jest.fn().mockImplementation(({ search, size }) => { - const sizeToUse = size ?? 10; - const hits: SearchDashboardsResponse['hits'] = []; - for (let i = 0; i < sizeToUse; i++) { - hits.push({ - type: 'dashboard', - id: `dashboard${i}`, - attributes: { - description: `dashboard${i} desc`, - title: `dashboard${i} - ${search} - title`, - }, - references: [] as SearchDashboardsResponse['hits'][0]['references'], - } as SearchDashboardsResponse['hits'][0]); - } - return Promise.resolve({ - total: sizeToUse, - hits, - }); - }), - findById: jest.fn(), - findByIds: jest.fn().mockImplementation(() => - Promise.resolve([ - { - id: `dashboardUnsavedOne`, - status: 'success', - attributes: { - title: `Dashboard Unsaved One`, - } as unknown as DashboardAttributes, - }, - { - id: `dashboardUnsavedTwo`, - status: 'success', - attributes: { - title: `Dashboard Unsaved Two`, - } as unknown as DashboardAttributes, - }, - { - id: `dashboardUnsavedThree`, - status: 'success', - attributes: { - title: `Dashboard Unsaved Three`, - } as unknown as DashboardAttributes, - }, - ]) - ), - findByTitle: jest.fn(), - }, - deleteDashboards: jest.fn(), - checkForDuplicateDashboardTitle: jest.fn(), - updateDashboardMeta: jest.fn(), - }; - }; diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management_service.ts b/src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management_service.ts deleted file mode 100644 index 5ab0f97d3b147..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management_service.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import type { DashboardStartDependencies } from '../../plugin'; -import { checkForDuplicateDashboardTitle } from './lib/check_for_duplicate_dashboard_title'; - -import { - searchDashboards, - findDashboardById, - findDashboardsByIds, - findDashboardIdByTitle, -} from './lib/find_dashboards'; -import { saveDashboardState } from './lib/save_dashboard_state'; -import type { - DashboardContentManagementRequiredServices, - DashboardContentManagementService, -} from './types'; -import { deleteDashboards } from './lib/delete_dashboards'; -import { loadDashboardState } from './lib/load_dashboard_state'; -import { updateDashboardMeta } from './lib/update_dashboard_meta'; -import { DashboardContentManagementCache } from './dashboard_content_management_cache'; - -export type DashboardContentManagementServiceFactory = KibanaPluginServiceFactory< - DashboardContentManagementService, - DashboardStartDependencies, - DashboardContentManagementRequiredServices ->; - -export const dashboardContentManagementCache = new DashboardContentManagementCache(); - -export const dashboardContentManagementServiceFactory: DashboardContentManagementServiceFactory = ( - { startPlugins: { contentManagement } }, - requiredServices -) => { - const { - data, - embeddable, - notifications, - dashboardBackup, - initializerContext, - savedObjectsTagging, - } = requiredServices; - return { - loadDashboardState: ({ id }) => - loadDashboardState({ - id, - data, - embeddable, - contentManagement, - savedObjectsTagging, - }), - saveDashboardState: ({ - controlGroupReferences, - currentState, - saveOptions, - lastSavedId, - panelReferences, - }) => - saveDashboardState({ - controlGroupReferences, - data, - embeddable, - saveOptions, - lastSavedId, - currentState, - notifications, - panelReferences, - dashboardBackup, - contentManagement, - initializerContext, - savedObjectsTagging, - }), - findDashboards: { - search: ({ hasReference, hasNoReference, search, size, options }) => - searchDashboards({ - contentManagement, - hasNoReference, - hasReference, - options, - search, - size, - }), - findById: (id) => findDashboardById(contentManagement, id), - findByIds: (ids) => findDashboardsByIds(contentManagement, ids), - findByTitle: (title) => findDashboardIdByTitle(contentManagement, title), - }, - checkForDuplicateDashboardTitle: (props) => - checkForDuplicateDashboardTitle(props, contentManagement), - deleteDashboards: (ids) => deleteDashboards(ids, contentManagement), - updateDashboardMeta: (props) => - updateDashboardMeta(props, { contentManagement, savedObjectsTagging, embeddable }), - }; -}; diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management_cache.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/dashboard_content_management_cache.ts similarity index 100% rename from src/plugins/dashboard/public/services/dashboard_content_management/dashboard_content_management_cache.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/dashboard_content_management_cache.ts diff --git a/src/plugins/dashboard/public/services/dashboard_content_management_service/index.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/index.ts new file mode 100644 index 0000000000000..ebc5a414f9f64 --- /dev/null +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/index.ts @@ -0,0 +1,45 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { DashboardContentManagementCache } from './dashboard_content_management_cache'; +import { checkForDuplicateDashboardTitle } from './lib/check_for_duplicate_dashboard_title'; +import { deleteDashboards } from './lib/delete_dashboards'; +import { + findDashboardById, + findDashboardIdByTitle, + findDashboardsByIds, + searchDashboards, +} from './lib/find_dashboards'; +import { loadDashboardState } from './lib/load_dashboard_state'; +import { saveDashboardState } from './lib/save_dashboard_state'; +import { updateDashboardMeta } from './lib/update_dashboard_meta'; + +let dashboardContentManagementCache: DashboardContentManagementCache; + +export const getDashboardContentManagementCache = () => { + if (!dashboardContentManagementCache) + dashboardContentManagementCache = new DashboardContentManagementCache(); + return dashboardContentManagementCache; +}; + +export const getDashboardContentManagementService = () => { + return { + loadDashboardState, + saveDashboardState, + findDashboards: { + search: searchDashboards, + findById: findDashboardById, + findByIds: findDashboardsByIds, + findByTitle: findDashboardIdByTitle, + }, + checkForDuplicateDashboardTitle, + deleteDashboards, + updateDashboardMeta, + }; +}; diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.test.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/check_for_duplicate_dashboard_title.test.ts similarity index 64% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.test.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/check_for_duplicate_dashboard_title.test.ts index 68de161325771..c20ba72d41472 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.test.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/check_for_duplicate_dashboard_title.test.ts @@ -7,17 +7,11 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { ContentClient } from '@kbn/content-management-plugin/public'; import { checkForDuplicateDashboardTitle } from './check_for_duplicate_dashboard_title'; import { extractTitleAndCount } from '../../../dashboard_container/embeddable/api/lib/extract_title_and_count'; - -type ContentManagementStart = Parameters[1]; +import { contentManagementService } from '../../kibana_services'; describe('checkForDuplicateDashboardTitle', () => { - const mockedContentManagementClient = { - search: jest.fn(), - } as unknown as ContentClient; - const newTitle = 'Shiny dashboard (1)'; afterEach(() => { @@ -35,9 +29,7 @@ describe('checkForDuplicateDashboardTitle', () => { }, ]; - ( - mockedContentManagementClient.search as jest.MockedFunction - ).mockImplementationOnce(() => + contentManagementService.client.search = jest.fn().mockImplementationOnce(() => Promise.resolve({ hits: pageResults, pagination: { @@ -46,17 +38,14 @@ describe('checkForDuplicateDashboardTitle', () => { }) ); - await checkForDuplicateDashboardTitle( - { - title: newTitle, - lastSavedTitle: baseDashboardName, - copyOnSave: true, - isTitleDuplicateConfirmed: false, - }, - { client: mockedContentManagementClient } as ContentManagementStart - ); + await checkForDuplicateDashboardTitle({ + title: newTitle, + lastSavedTitle: baseDashboardName, + copyOnSave: true, + isTitleDuplicateConfirmed: false, + }); - expect(mockedContentManagementClient.search).toHaveBeenCalledWith( + expect(contentManagementService.client.search).toHaveBeenCalledWith( expect.objectContaining({ query: expect.objectContaining({ text: `${baseDashboardName}*`, @@ -86,9 +75,7 @@ describe('checkForDuplicateDashboardTitle', () => { const onTitleDuplicate = jest.fn(); - ( - mockedContentManagementClient.search as jest.MockedFunction - ).mockImplementationOnce(() => + contentManagementService.client.search = jest.fn().mockImplementationOnce(() => Promise.resolve({ hits: pageResults, pagination: { @@ -97,18 +84,15 @@ describe('checkForDuplicateDashboardTitle', () => { }) ); - await checkForDuplicateDashboardTitle( - { - title: userTitleInput, - lastSavedTitle: baseDashboardName, - copyOnSave: true, - isTitleDuplicateConfirmed: false, - onTitleDuplicate, - }, - { client: mockedContentManagementClient } as ContentManagementStart - ); + await checkForDuplicateDashboardTitle({ + title: userTitleInput, + lastSavedTitle: baseDashboardName, + copyOnSave: true, + isTitleDuplicateConfirmed: false, + onTitleDuplicate, + }); - expect(mockedContentManagementClient.search).toHaveBeenCalledWith( + expect(contentManagementService.client.search).toHaveBeenCalledWith( expect.objectContaining({ query: expect.objectContaining({ text: 'Shiny dashboard*', diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/check_for_duplicate_dashboard_title.ts similarity index 86% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/check_for_duplicate_dashboard_title.ts index 2d5a4f7742e9d..0d12cb446129b 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/check_for_duplicate_dashboard_title.ts @@ -7,10 +7,10 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { DashboardStartDependencies } from '../../../plugin'; import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; import { DashboardCrudTypes } from '../../../../common/content_management'; import { extractTitleAndCount } from '../../../dashboard_container/embeddable/api/lib/extract_title_and_count'; +import { contentManagementService } from '../../kibana_services'; export interface DashboardDuplicateTitleCheckProps { title: string; @@ -28,16 +28,13 @@ export interface DashboardDuplicateTitleCheckProps { * returns Promise when there is no duplicate, or runs the provided onTitleDuplicate * function when the title already exists */ -export async function checkForDuplicateDashboardTitle( - { - title, - copyOnSave, - lastSavedTitle, - onTitleDuplicate, - isTitleDuplicateConfirmed, - }: DashboardDuplicateTitleCheckProps, - contentManagement: DashboardStartDependencies['contentManagement'] -): Promise { +export async function checkForDuplicateDashboardTitle({ + title, + copyOnSave, + lastSavedTitle, + onTitleDuplicate, + isTitleDuplicateConfirmed, +}: DashboardDuplicateTitleCheckProps): Promise { // Don't check if the title is an empty string if (!title) { return true; @@ -56,7 +53,7 @@ export async function checkForDuplicateDashboardTitle( const [baseDashboardName] = extractTitleAndCount(title); - const { hits } = await contentManagement.client.search< + const { hits } = await contentManagementService.client.search< DashboardCrudTypes['SearchIn'], DashboardCrudTypes['SearchOut'] >({ diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/dashboard_versioning.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/dashboard_versioning.ts similarity index 100% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/dashboard_versioning.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/dashboard_versioning.ts diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/delete_dashboards.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/delete_dashboards.ts similarity index 68% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/delete_dashboards.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/delete_dashboards.ts index dbafbe7382124..0be9355ddb606 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/delete_dashboards.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/delete_dashboards.ts @@ -7,18 +7,15 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { DashboardStartDependencies } from '../../../plugin'; -import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; +import { getDashboardContentManagementCache } from '..'; import { DashboardCrudTypes } from '../../../../common/content_management'; -import { dashboardContentManagementCache } from '../dashboard_content_management_service'; +import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; +import { contentManagementService } from '../../kibana_services'; -export const deleteDashboards = async ( - ids: string[], - contentManagement: DashboardStartDependencies['contentManagement'] -) => { +export const deleteDashboards = async (ids: string[]) => { const deletePromises = ids.map((id) => { - dashboardContentManagementCache.deleteDashboard(id); - return contentManagement.client.delete< + getDashboardContentManagementCache().deleteDashboard(id); + return contentManagementService.client.delete< DashboardCrudTypes['DeleteIn'], DashboardCrudTypes['DeleteOut'] >({ diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/find_dashboards.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/find_dashboards.ts similarity index 78% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/find_dashboards.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/find_dashboards.ts index eef3e9e142040..2f9a2c2e9a033 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/find_dashboards.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/find_dashboards.ts @@ -10,17 +10,16 @@ import type { Reference } from '@kbn/content-management-utils'; import { SavedObjectError, SavedObjectsFindOptionsReference } from '@kbn/core/public'; +import { getDashboardContentManagementCache } from '..'; import { DashboardAttributes, DashboardCrudTypes, DashboardItem, } from '../../../../common/content_management'; import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; -import { DashboardStartDependencies } from '../../../plugin'; -import { dashboardContentManagementCache } from '../dashboard_content_management_service'; +import { contentManagementService } from '../../kibana_services'; export interface SearchDashboardsArgs { - contentManagement: DashboardStartDependencies['contentManagement']; options?: DashboardCrudTypes['SearchIn']['options']; hasNoReference?: SavedObjectsFindOptionsReference[]; hasReference?: SavedObjectsFindOptionsReference[]; @@ -34,7 +33,6 @@ export interface SearchDashboardsResponse { } export async function searchDashboards({ - contentManagement, hasNoReference, hasReference, options, @@ -44,7 +42,7 @@ export async function searchDashboards({ const { hits, pagination: { total }, - } = await contentManagement.client.search< + } = await contentManagementService.client.search< DashboardCrudTypes['SearchIn'], DashboardCrudTypes['SearchOut'] >({ @@ -70,10 +68,9 @@ export type FindDashboardsByIdResponse = { id: string } & ( | { status: 'error'; error: SavedObjectError } ); -export async function findDashboardById( - contentManagement: DashboardStartDependencies['contentManagement'], - id: string -): Promise { +export async function findDashboardById(id: string): Promise { + const dashboardContentManagementCache = getDashboardContentManagementCache(); + /** If the dashboard exists in the cache, then return the result from that */ const cachedDashboard = dashboardContentManagementCache.fetchDashboard(id); if (cachedDashboard) { @@ -87,7 +84,7 @@ export async function findDashboardById( /** Otherwise, fetch the dashboard from the content management client, add it to the cache, and return the result */ try { - const response = await contentManagement.client.get< + const response = await contentManagementService.client.get< DashboardCrudTypes['GetIn'], DashboardCrudTypes['GetOut'] >({ @@ -114,20 +111,14 @@ export async function findDashboardById( } } -export async function findDashboardsByIds( - contentManagement: DashboardStartDependencies['contentManagement'], - ids: string[] -): Promise { - const findPromises = ids.map((id) => findDashboardById(contentManagement, id)); +export async function findDashboardsByIds(ids: string[]): Promise { + const findPromises = ids.map((id) => findDashboardById(id)); const results = await Promise.all(findPromises); return results as FindDashboardsByIdResponse[]; } -export async function findDashboardIdByTitle( - contentManagement: DashboardStartDependencies['contentManagement'], - title: string -): Promise<{ id: string } | undefined> { - const { hits } = await contentManagement.client.search< +export async function findDashboardIdByTitle(title: string): Promise<{ id: string } | undefined> { + const { hits } = await contentManagementService.client.search< DashboardCrudTypes['SearchIn'], DashboardCrudTypes['SearchOut'] >({ diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/load_dashboard_state.test.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/load_dashboard_state.test.ts similarity index 76% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/load_dashboard_state.test.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/load_dashboard_state.test.ts index 0f6880cb76e8a..e03a078e0df45 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/load_dashboard_state.test.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/load_dashboard_state.test.ts @@ -7,23 +7,14 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { registry } from '../../plugin_services.stub'; -import { pluginServices } from '../../plugin_services'; +import { getDashboardContentManagementCache } from '..'; import { getSampleDashboardInput } from '../../../mocks'; +import { contentManagementService } from '../../kibana_services'; import { loadDashboardState } from './load_dashboard_state'; -import { dashboardContentManagementCache } from '../dashboard_content_management_service'; - -pluginServices.setRegistry(registry.start({})); -const { data, embeddable, contentManagement, savedObjectsTagging } = pluginServices.getServices(); - -const allServices = { - data, - embeddable, - contentManagement, - savedObjectsTagging, -}; describe('Load dashboard state', () => { + const dashboardContentManagementCache = getDashboardContentManagementCache(); + it('should return cached result if available', async () => { dashboardContentManagementCache.fetchDashboard = jest.fn().mockImplementation((id: string) => { return { @@ -40,17 +31,16 @@ describe('Load dashboard state', () => { meta: {}, }; }); + contentManagementService.client.get = jest.fn(); dashboardContentManagementCache.addDashboard = jest.fn(); - contentManagement.client.get = jest.fn(); const { id } = getSampleDashboardInput(); const result = await loadDashboardState({ id, - ...allServices, }); expect(dashboardContentManagementCache.fetchDashboard).toBeCalled(); expect(dashboardContentManagementCache.addDashboard).not.toBeCalled(); - expect(contentManagement.client.get).not.toBeCalled(); + expect(contentManagementService.client.get).not.toBeCalled(); expect(result).toMatchObject({ dashboardId: id, dashboardFound: true, @@ -63,7 +53,7 @@ describe('Load dashboard state', () => { it('should not add to cache for alias redirect result', async () => { dashboardContentManagementCache.fetchDashboard = jest.fn().mockImplementation(() => undefined); dashboardContentManagementCache.addDashboard = jest.fn(); - contentManagement.client.get = jest.fn().mockImplementation(({ id }) => { + contentManagementService.client.get = jest.fn().mockImplementation(({ id }) => { return Promise.resolve({ item: { id }, meta: { @@ -74,7 +64,6 @@ describe('Load dashboard state', () => { const { id } = getSampleDashboardInput(); await loadDashboardState({ id, - ...allServices, }); expect(dashboardContentManagementCache.fetchDashboard).toBeCalled(); expect(dashboardContentManagementCache.addDashboard).not.toBeCalled(); diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/load_dashboard_state.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/load_dashboard_state.ts similarity index 84% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/load_dashboard_state.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/load_dashboard_state.ts index 2f78325e083f5..17102e2fe7d0a 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/load_dashboard_state.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/load_dashboard_state.ts @@ -7,26 +7,32 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { v4 as uuidv4 } from 'uuid'; import { has } from 'lodash'; +import { v4 as uuidv4 } from 'uuid'; -import { Filter, Query } from '@kbn/es-query'; +import { injectSearchSourceReferences, parseSearchSourceJSON } from '@kbn/data-plugin/public'; import { ViewMode } from '@kbn/embeddable-plugin/public'; +import { Filter, Query } from '@kbn/es-query'; import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/public'; import { cleanFiltersForSerialize } from '@kbn/presentation-util-plugin/public'; -import { parseSearchSourceJSON, injectSearchSourceReferences } from '@kbn/data-plugin/public'; +import { getDashboardContentManagementCache } from '..'; import { + convertSavedPanelsToPanelMap, injectReferences, type DashboardOptions, - convertSavedPanelsToPanelMap, } from '../../../../common'; -import { migrateDashboardInput } from './migrate_dashboard_input'; -import { convertNumberToDashboardVersion } from './dashboard_versioning'; import { DashboardCrudTypes } from '../../../../common/content_management'; -import type { LoadDashboardFromSavedObjectProps, LoadDashboardReturn } from '../types'; -import { dashboardContentManagementCache } from '../dashboard_content_management_service'; import { DASHBOARD_CONTENT_ID, DEFAULT_DASHBOARD_INPUT } from '../../../dashboard_constants'; +import { + contentManagementService, + dataService, + embeddableService, + savedObjectsTaggingService, +} from '../../kibana_services'; +import type { LoadDashboardFromSavedObjectProps, LoadDashboardReturn } from '../types'; +import { convertNumberToDashboardVersion } from './dashboard_versioning'; +import { migrateDashboardInput } from './migrate_dashboard_input'; export function migrateLegacyQuery(query: Query | { [key: string]: any } | string): Query { // Lucene was the only option before, so language-less queries are all lucene @@ -39,15 +45,12 @@ export function migrateLegacyQuery(query: Query | { [key: string]: any } | strin export const loadDashboardState = async ({ id, - data, - embeddable, - contentManagement, - savedObjectsTagging, }: LoadDashboardFromSavedObjectProps): Promise => { const { search: dataSearchService, query: { queryString }, - } = data; + } = dataService; + const dashboardContentManagementCache = getDashboardContentManagementCache(); const savedObjectId = id; const embeddableId = uuidv4(); @@ -78,7 +81,7 @@ export const loadDashboardState = async ({ ({ item: rawDashboardContent, meta: resolveMeta } = cachedDashboard); } else { /** Otherwise, fetch and load the dashboard from the content management client, and add it to the cache */ - const result = await contentManagement.client + const result = await contentManagementService.client .get({ contentTypeId: DASHBOARD_CONTENT_ID, id, @@ -116,7 +119,7 @@ export const loadDashboardState = async ({ return injectReferences( { references, attributes: rawAttributes }, { - embeddablePersistableStateService: embeddable, + embeddablePersistableStateService: embeddableService, } ); })(); @@ -170,30 +173,27 @@ export const loadDashboardState = async ({ const options: DashboardOptions = optionsJSON ? JSON.parse(optionsJSON) : undefined; const panels = convertSavedPanelsToPanelMap(panelsJSON ? JSON.parse(panelsJSON) : []); - const { dashboardInput, anyMigrationRun } = migrateDashboardInput( - { - ...DEFAULT_DASHBOARD_INPUT, - ...options, - - id: embeddableId, - refreshInterval, - timeRestore, - description, - timeRange, - filters, - panels, - query, - title, - - viewMode: ViewMode.VIEW, // dashboards loaded from saved object default to view mode. If it was edited recently, the view mode from session storage will override this. - tags: savedObjectsTagging.getTagIdsFromReferences?.(references) ?? [], - - controlGroupInput: attributes.controlGroupInput, - - version: convertNumberToDashboardVersion(version), - }, - embeddable - ); + const { dashboardInput, anyMigrationRun } = migrateDashboardInput({ + ...DEFAULT_DASHBOARD_INPUT, + ...options, + + id: embeddableId, + refreshInterval, + timeRestore, + description, + timeRange, + filters, + panels, + query, + title, + + viewMode: ViewMode.VIEW, // dashboards loaded from saved object default to view mode. If it was edited recently, the view mode from session storage will override this. + tags: savedObjectsTaggingService?.getTaggingApi()?.ui.getTagIdsFromReferences(references) ?? [], + + controlGroupInput: attributes.controlGroupInput, + + version: convertNumberToDashboardVersion(version), + }); return { managed, diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/migrate_dashboard_input.test.ts similarity index 84% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/migrate_dashboard_input.test.ts index 4b84d67a4bcaf..ad0a5cc386b26 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.test.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/migrate_dashboard_input.test.ts @@ -8,7 +8,7 @@ */ import { getSampleDashboardInput, getSampleDashboardPanel } from '../../../mocks'; -import { DashboardEmbeddableService } from '../../embeddable/types'; +import { embeddableService } from '../../kibana_services'; import { SavedDashboardInput } from '../types'; import { migrateDashboardInput } from './migrate_dashboard_input'; @@ -31,14 +31,12 @@ describe('Migrate dashboard input', () => { panel4: getSampleDashboardPanel({ type: 'ultraDiscover', explicitInput: { id: 'panel4' } }), }; - const embeddableService: DashboardEmbeddableService = { - getEmbeddableFactory: jest.fn(() => ({ - latestVersion: '1.0.0', - migrations: {}, - })), - } as unknown as DashboardEmbeddableService; + embeddableService.getEmbeddableFactory = jest.fn(() => ({ + latestVersion: '1.0.0', + migrations: {}, + })) as unknown as typeof embeddableService.getEmbeddableFactory; - const result = migrateDashboardInput(dashboardInput, embeddableService); + const result = migrateDashboardInput(dashboardInput); // migration run should be true because the runEmbeddableFactoryMigrations mock above returns true. expect(result.anyMigrationRun).toBe(true); diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/migrate_dashboard_input.ts similarity index 83% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/migrate_dashboard_input.ts index cfae6b1fa809a..b0cfac9f97ce4 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/migrate_dashboard_input.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/migrate_dashboard_input.ts @@ -12,8 +12,7 @@ import { runEmbeddableFactoryMigrations, } from '@kbn/embeddable-plugin/public'; import { DashboardContainerInput, DashboardPanelState } from '../../../../common'; -import { type DashboardEmbeddableService } from '../../embeddable/types'; -import { pluginServices } from '../../plugin_services'; +import { embeddableService } from '../../kibana_services'; import { SavedDashboardInput } from '../types'; /** @@ -22,25 +21,19 @@ import { SavedDashboardInput } from '../types'; * This prevents the reset button from un-migrating the panels on the Dashboard. This also means that the migrations may * get skipped at Embeddable create time - unless states with older versions are saved in the URL or session storage. */ -export const migrateDashboardInput = ( - dashboardInput: SavedDashboardInput, - embeddable: DashboardEmbeddableService -) => { - const { - embeddable: { reactEmbeddableRegistryHasKey }, - } = pluginServices.getServices(); +export const migrateDashboardInput = (dashboardInput: SavedDashboardInput) => { let anyMigrationRun = false; if (!dashboardInput) return dashboardInput; const migratedPanels: DashboardContainerInput['panels'] = {}; for (const [id, panel] of Object.entries(dashboardInput.panels)) { // if the panel type is registered in the new embeddable system, we do not need to run migrations for it. - if (reactEmbeddableRegistryHasKey(panel.type)) { + if (embeddableService.reactEmbeddableRegistryHasKey(panel.type)) { migratedPanels[id] = panel; continue; } - const factory = embeddable.getEmbeddableFactory(panel.type); + const factory = embeddableService.getEmbeddableFactory(panel.type); if (!factory) throw new EmbeddableFactoryNotFoundError(panel.type); // run last saved migrations for by value panels only. if (!panel.explicitInput.savedObjectId) { diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/save_dashboard_state.test.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.test.ts similarity index 75% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/save_dashboard_state.test.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.test.ts index 342dd0bf6f8de..8327397a66068 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/save_dashboard_state.test.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.test.ts @@ -7,24 +7,17 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { registry } from '../../plugin_services.stub'; -import { pluginServices } from '../../plugin_services'; +import { DashboardContainerInput } from '../../../../common'; import { getSampleDashboardInput } from '../../../mocks'; +import { + contentManagementService, + coreServices, + dataService, + embeddableService, +} from '../../kibana_services'; import { saveDashboardState } from './save_dashboard_state'; -import { DashboardContainerInput } from '../../../../common'; -pluginServices.setRegistry(registry.start({})); -const { - data, - embeddable, - notifications, - dashboardBackup, - contentManagement, - initializerContext, - savedObjectsTagging, -} = pluginServices.getServices(); - -contentManagement.client.create = jest.fn().mockImplementation(({ options }) => { +contentManagementService.client.create = jest.fn().mockImplementation(({ options }) => { if (options.id === undefined) { return { item: { id: 'newlyGeneratedId' } }; } @@ -32,24 +25,18 @@ contentManagement.client.create = jest.fn().mockImplementation(({ options }) => throw new Error('Update should be used when id is provided'); }); -contentManagement.client.update = jest.fn().mockImplementation(({ id }) => { +contentManagementService.client.update = jest.fn().mockImplementation(({ id }) => { if (id === undefined) { throw new Error('Update needs an id'); } return { item: { id } }; }); -const allServices = { - data, - embeddable, - notifications, - dashboardBackup, - contentManagement, - initializerContext, - savedObjectsTagging, -}; -data.query.timefilter.timefilter.getTime = jest.fn().mockReturnValue({ from: 'then', to: 'now' }); -embeddable.extract = jest +dataService.query.timefilter.timefilter.getTime = jest + .fn() + .mockReturnValue({ from: 'then', to: 'now' }); + +embeddableService.extract = jest .fn() .mockImplementation((attributes) => ({ state: attributes, references: [] })); @@ -66,14 +53,13 @@ describe('Save dashboard state', () => { } as unknown as DashboardContainerInput, lastSavedId: 'Boogaloo', saveOptions: {}, - ...allServices, }); expect(result.id).toBe('Boogaloo'); - expect(allServices.contentManagement.client.update).toHaveBeenCalledWith( + expect(contentManagementService.client.update).toHaveBeenCalledWith( expect.objectContaining({ id: 'Boogaloo' }) ); - expect(allServices.notifications.toasts.addSuccess).toHaveBeenCalledWith({ + expect(coreServices.notifications.toasts.addSuccess).toHaveBeenCalledWith({ title: `Dashboard 'BOO' was saved`, className: 'eui-textBreakWord', 'data-test-subj': 'saveDashboardSuccess', @@ -88,17 +74,16 @@ describe('Save dashboard state', () => { } as unknown as DashboardContainerInput, lastSavedId: 'Boogaloonie', saveOptions: { saveAsCopy: true }, - ...allServices, }); expect(result.id).toBe('newlyGeneratedId'); expect(result.redirectRequired).toBe(true); - expect(allServices.contentManagement.client.create).toHaveBeenCalledWith( + expect(contentManagementService.client.create).toHaveBeenCalledWith( expect.objectContaining({ options: { references: [] }, }) ); - expect(allServices.notifications.toasts.addSuccess).toHaveBeenCalledWith({ + expect(coreServices.notifications.toasts.addSuccess).toHaveBeenCalledWith({ title: `Dashboard 'BooToo' was saved`, className: 'eui-textBreakWord', 'data-test-subj': 'saveDashboardSuccess', @@ -114,12 +99,11 @@ describe('Save dashboard state', () => { } as unknown as DashboardContainerInput, lastSavedId: 'Boogatoonie', saveOptions: { saveAsCopy: true }, - ...allServices, }); expect(result.id).toBe('newlyGeneratedId'); - expect(allServices.contentManagement.client.create).toHaveBeenCalledWith( + expect(contentManagementService.client.create).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ panelsJSON: expect.not.stringContaining('neverGonnaGetThisId'), @@ -138,11 +122,10 @@ describe('Save dashboard state', () => { panelReferences: [{ name: 'idOne:panel_idOne', type: 'boop', id: 'idOne' }], lastSavedId: 'Boogatoonie', saveOptions: { saveAsCopy: true }, - ...allServices, }); expect(result.id).toBe('newlyGeneratedId'); - expect(allServices.contentManagement.client.create).toHaveBeenCalledWith( + expect(contentManagementService.client.create).toHaveBeenCalledWith( expect.objectContaining({ options: expect.objectContaining({ references: expect.arrayContaining([ @@ -157,7 +140,7 @@ describe('Save dashboard state', () => { }); it('should return an error when the save fails.', async () => { - contentManagement.client.create = jest.fn().mockRejectedValue('Whoops'); + contentManagementService.client.create = jest.fn().mockRejectedValue('Whoops'); const result = await saveDashboardState({ currentState: { ...getSampleDashboardInput(), @@ -166,7 +149,6 @@ describe('Save dashboard state', () => { } as unknown as DashboardContainerInput, lastSavedId: 'Boogatoonie', saveOptions: { saveAsCopy: true }, - ...allServices, }); expect(result.id).toBeUndefined(); diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/save_dashboard_state.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.ts similarity index 82% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/save_dashboard_state.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.ts index b9285b208c14d..283ed5eed7f5b 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/save_dashboard_state.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.ts @@ -13,20 +13,23 @@ import moment, { Moment } from 'moment'; import { extractSearchSourceReferences, RefreshInterval } from '@kbn/data-plugin/public'; import { isFilterPinned } from '@kbn/es-query'; +import { getDashboardContentManagementCache } from '..'; import { convertPanelMapToSavedPanels, extractReferences } from '../../../../common'; import { DashboardAttributes, DashboardCrudTypes } from '../../../../common/content_management'; +import { generateNewPanelIds } from '../../../../common/lib/dashboard_panel_converters'; import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; import { LATEST_DASHBOARD_CONTAINER_VERSION } from '../../../dashboard_container'; import { dashboardSaveToastStrings } from '../../../dashboard_container/_dashboard_container_strings'; -import { DashboardStartDependencies } from '../../../plugin'; -import { dashboardContentManagementCache } from '../dashboard_content_management_service'; +import { getDashboardBackupService } from '../../dashboard_backup_service'; import { - DashboardContentManagementRequiredServices, - SaveDashboardProps, - SaveDashboardReturn, -} from '../types'; + contentManagementService, + coreServices, + dataService, + embeddableService, + savedObjectsTaggingService, +} from '../../kibana_services'; +import { SaveDashboardProps, SaveDashboardReturn } from '../types'; import { convertDashboardVersionToNumber } from './dashboard_versioning'; -import { generateNewPanelIds } from '../../../../common/lib/dashboard_panel_converters'; export const convertTimeToUTCString = (time?: string | Moment): undefined | string => { if (moment(time).isValid()) { @@ -38,35 +41,20 @@ export const convertTimeToUTCString = (time?: string | Moment): undefined | stri } }; -type SaveDashboardStateProps = SaveDashboardProps & { - data: DashboardContentManagementRequiredServices['data']; - contentManagement: DashboardStartDependencies['contentManagement']; - embeddable: DashboardContentManagementRequiredServices['embeddable']; - notifications: DashboardContentManagementRequiredServices['notifications']; - dashboardBackup: DashboardContentManagementRequiredServices['dashboardBackup']; - initializerContext: DashboardContentManagementRequiredServices['initializerContext']; - savedObjectsTagging: DashboardContentManagementRequiredServices['savedObjectsTagging']; -}; - export const saveDashboardState = async ({ controlGroupReferences, - data, - embeddable, lastSavedId, saveOptions, currentState, panelReferences, - dashboardBackup, - contentManagement, - savedObjectsTagging, - notifications: { toasts }, -}: SaveDashboardStateProps): Promise => { +}: SaveDashboardProps): Promise => { const { search: dataSearchService, query: { timefilter: { timefilter }, }, - } = data; + } = dataService; + const dashboardContentManagementCache = getDashboardContentManagementCache(); const { tags, @@ -165,11 +153,12 @@ export const saveDashboardState = async ({ attributes: rawDashboardAttributes, references: searchSourceReferences, }, - { embeddablePersistableStateService: embeddable } + { embeddablePersistableStateService: embeddableService } ); - const references = savedObjectsTagging.updateTagsReferences - ? savedObjectsTagging.updateTagsReferences(dashboardReferences, tags) + const savedObjectsTaggingApi = savedObjectsTaggingService?.getTaggingApi(); + const references = savedObjectsTaggingApi?.ui.updateTagsReferences + ? savedObjectsTaggingApi?.ui.updateTagsReferences(dashboardReferences, tags) : dashboardReferences; const allReferences = [ @@ -185,7 +174,7 @@ export const saveDashboardState = async ({ try { const result = idToSaveTo - ? await contentManagement.client.update< + ? await contentManagementService.client.update< DashboardCrudTypes['UpdateIn'], DashboardCrudTypes['UpdateOut'] >({ @@ -198,7 +187,7 @@ export const saveDashboardState = async ({ mergeAttributes: false, }, }) - : await contentManagement.client.create< + : await contentManagementService.client.create< DashboardCrudTypes['CreateIn'], DashboardCrudTypes['CreateOut'] >({ @@ -208,11 +197,10 @@ export const saveDashboardState = async ({ references: allReferences, }, }); - const newId = result.item.id; if (newId) { - toasts.addSuccess({ + coreServices.notifications.toasts.addSuccess({ title: dashboardSaveToastStrings.getSuccessString(currentState.title), className: 'eui-textBreakWord', 'data-test-subj': 'saveDashboardSuccess', @@ -222,7 +210,7 @@ export const saveDashboardState = async ({ * If the dashboard id has been changed, redirect to the new ID to keep the url param in sync. */ if (newId !== lastSavedId) { - dashboardBackup.clearState(lastSavedId); + getDashboardBackupService().clearState(lastSavedId); return { redirectRequired: true, id: newId, references: allReferences }; } else { dashboardContentManagementCache.deleteDashboard(newId); // something changed in an existing dashboard, so delete it from the cache so that it can be re-fetched @@ -230,7 +218,7 @@ export const saveDashboardState = async ({ } return { id: newId, references: allReferences }; } catch (error) { - toasts.addDanger({ + coreServices.notifications.toasts.addDanger({ title: dashboardSaveToastStrings.getFailureString(currentState.title, error.message), 'data-test-subj': 'saveDashboardFailure', }); diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/update_dashboard_meta.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/update_dashboard_meta.ts similarity index 56% rename from src/plugins/dashboard/public/services/dashboard_content_management/lib/update_dashboard_meta.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/lib/update_dashboard_meta.ts index 60da204fcb073..2fd57738f17aa 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/update_dashboard_meta.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/update_dashboard_meta.ts @@ -8,37 +8,34 @@ */ import { DashboardContainerInput } from '../../../../common'; -import { DashboardStartDependencies } from '../../../plugin'; import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; import { DashboardCrudTypes } from '../../../../common/content_management'; import { findDashboardsByIds } from './find_dashboards'; -import { DashboardContentManagementRequiredServices } from '../types'; +import { contentManagementService, savedObjectsTaggingService } from '../../kibana_services'; type UpdateDashboardMetaProps = Pick< DashboardContainerInput, 'id' | 'title' | 'description' | 'tags' >; -interface UpdateDashboardMetaDependencies { - contentManagement: DashboardStartDependencies['contentManagement']; - savedObjectsTagging: DashboardContentManagementRequiredServices['savedObjectsTagging']; - embeddable: DashboardContentManagementRequiredServices['embeddable']; -} -export const updateDashboardMeta = async ( - { id, title, description = '', tags }: UpdateDashboardMetaProps, - { contentManagement, savedObjectsTagging, embeddable }: UpdateDashboardMetaDependencies -) => { - const [dashboard] = await findDashboardsByIds(contentManagement, [id]); +export const updateDashboardMeta = async ({ + id, + title, + description = '', + tags, +}: UpdateDashboardMetaProps) => { + const [dashboard] = await findDashboardsByIds([id]); if (dashboard.status === 'error') { return; } + const savedObjectsTaggingApi = savedObjectsTaggingService?.getTaggingApi(); const references = - savedObjectsTagging.updateTagsReferences && tags.length - ? savedObjectsTagging.updateTagsReferences(dashboard.references, tags) + savedObjectsTaggingApi?.ui.updateTagsReferences && tags.length + ? savedObjectsTaggingApi.ui.updateTagsReferences(dashboard.references, tags) : dashboard.references; - await contentManagement.client.update< + await contentManagementService.client.update< DashboardCrudTypes['UpdateIn'], DashboardCrudTypes['UpdateOut'] >({ diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/types.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/types.ts similarity index 72% rename from src/plugins/dashboard/public/services/dashboard_content_management/types.ts rename to src/plugins/dashboard/public/services/dashboard_content_management_service/types.ts index 19ddfac9e1199..3294bb06c0d42 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/types.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/types.ts @@ -8,20 +8,11 @@ */ import type { Reference } from '@kbn/content-management-utils'; +import { ControlGroupRuntimeState } from '@kbn/controls-plugin/public'; import { SavedObjectSaveOpts } from '@kbn/saved-objects-plugin/public'; -import { ControlGroupRuntimeState } from '@kbn/controls-plugin/public'; import { DashboardContainerInput } from '../../../common'; import { DashboardAttributes, DashboardCrudTypes } from '../../../common/content_management'; -import { DashboardStartDependencies } from '../../plugin'; -import { DashboardBackupServiceType } from '../dashboard_backup/types'; -import { DashboardDataService } from '../data/types'; -import { DashboardEmbeddableService } from '../embeddable/types'; -import { DashboardInitializerContextService } from '../initializer_context/types'; -import { DashboardNotificationsService } from '../notifications/types'; -import { DashboardSavedObjectsTaggingService } from '../saved_objects_tagging/types'; -import { DashboardScreenshotModeService } from '../screenshot_mode/types'; -import { DashboardSpacesService } from '../spaces/types'; import { DashboardDuplicateTitleCheckProps } from './lib/check_for_duplicate_dashboard_title'; import { FindDashboardsByIdResponse, @@ -29,17 +20,6 @@ import { SearchDashboardsResponse, } from './lib/find_dashboards'; -export interface DashboardContentManagementRequiredServices { - data: DashboardDataService; - spaces: DashboardSpacesService; - embeddable: DashboardEmbeddableService; - notifications: DashboardNotificationsService; - dashboardBackup: DashboardBackupServiceType; - screenshotMode: DashboardScreenshotModeService; - initializerContext: DashboardInitializerContextService; - savedObjectsTagging: DashboardSavedObjectsTaggingService; -} - export interface DashboardContentManagementService { findDashboards: FindDashboardsService; deleteDashboards: (ids: string[]) => Promise; @@ -56,10 +36,6 @@ export interface DashboardContentManagementService { */ export interface LoadDashboardFromSavedObjectProps { id?: string; - data: DashboardContentManagementRequiredServices['data']; - contentManagement: DashboardStartDependencies['contentManagement']; - embeddable: DashboardContentManagementRequiredServices['embeddable']; - savedObjectsTagging: DashboardContentManagementRequiredServices['savedObjectsTagging']; } type DashboardResolveMeta = DashboardCrudTypes['GetOut']['meta']; diff --git a/src/plugins/dashboard/public/services/dashboard_favorites/dashboard_favorites_service.stub.ts b/src/plugins/dashboard/public/services/dashboard_favorites/dashboard_favorites_service.stub.ts deleted file mode 100644 index 9e06c0b06483d..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_favorites/dashboard_favorites_service.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { FavoritesClient } from '@kbn/content-management-favorites-public'; -import { httpServiceMock } from '@kbn/core-http-browser-mocks'; -import { DashboardFavoritesService } from './types'; - -export type DashboardFavoritesServiceFactory = PluginServiceFactory; - -export const dashboardFavoritesServiceFactory: DashboardFavoritesServiceFactory = () => { - return new FavoritesClient('dashboards', 'dashboard', { - http: httpServiceMock.createStartContract(), - }); -}; diff --git a/src/plugins/dashboard/public/services/dashboard_favorites/dashboard_favorites_service.ts b/src/plugins/dashboard/public/services/dashboard_favorites/dashboard_favorites_service.ts deleted file mode 100644 index 503f90c11e549..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_favorites/dashboard_favorites_service.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FavoritesClient } from '@kbn/content-management-favorites-public'; -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardStartDependencies } from '../../plugin'; -import { DashboardFavoritesService } from './types'; -import { DASHBOARD_APP_ID, DASHBOARD_CONTENT_ID } from '../../dashboard_constants'; - -export type DashboardFavoritesServiceFactory = KibanaPluginServiceFactory< - DashboardFavoritesService, - DashboardStartDependencies ->; - -export const dashboardFavoritesServiceFactory: DashboardFavoritesServiceFactory = ({ - coreStart, - startPlugins, -}) => { - return new FavoritesClient(DASHBOARD_APP_ID, DASHBOARD_CONTENT_ID, { - http: coreStart.http, - usageCollection: startPlugins.usageCollection, - }); -}; diff --git a/src/plugins/dashboard/public/services/dashboard_favorites/types.ts b/src/plugins/dashboard/public/services/dashboard_favorites/types.ts deleted file mode 100644 index 3ed4b88f48941..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_favorites/types.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { FavoritesClientPublic } from '@kbn/content-management-favorites-public'; - -export type DashboardFavoritesService = FavoritesClientPublic; diff --git a/src/plugins/dashboard/public/services/dashboard_recently_accessed/dashboard_recently_accessed.stub.ts b/src/plugins/dashboard/public/services/dashboard_recently_accessed/dashboard_recently_accessed.stub.ts deleted file mode 100644 index 8932b3210f0ae..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_recently_accessed/dashboard_recently_accessed.stub.ts +++ /dev/null @@ -1,23 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardRecentlyAccessedService } from './types'; - -type DashboardRecentlyAccessedServiceFactory = - PluginServiceFactory; - -export const dashboardRecentlyAccessedServiceFactory: DashboardRecentlyAccessedServiceFactory = - () => { - return { - add: jest.fn(), - get: jest.fn(), - get$: jest.fn(), - }; - }; diff --git a/src/plugins/dashboard/public/services/dashboard_recently_accessed/dashboard_recently_accessed.ts b/src/plugins/dashboard/public/services/dashboard_recently_accessed/dashboard_recently_accessed.ts deleted file mode 100644 index bdfe42e9988bd..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_recently_accessed/dashboard_recently_accessed.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { RecentlyAccessedService } from '@kbn/recently-accessed'; -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { DashboardHTTPService } from '../http/types'; -import { DashboardStartDependencies } from '../../plugin'; -import { DashboardRecentlyAccessedService } from './types'; - -interface DashboardRecentlyAccessedRequiredServices { - http: DashboardHTTPService; -} - -export type DashboardBackupServiceFactory = KibanaPluginServiceFactory< - DashboardRecentlyAccessedService, - DashboardStartDependencies, - DashboardRecentlyAccessedRequiredServices ->; - -export const dashboardRecentlyAccessedFactory: DashboardBackupServiceFactory = ( - core, - requiredServices -) => { - const { http } = requiredServices; - return new RecentlyAccessedService().start({ http, key: 'dashboardRecentlyAccessed' }); -}; diff --git a/src/plugins/dashboard/public/services/dashboard_recently_accessed/types.ts b/src/plugins/dashboard/public/services/dashboard_recently_accessed/types.ts deleted file mode 100644 index 96f1772bb8ee3..0000000000000 --- a/src/plugins/dashboard/public/services/dashboard_recently_accessed/types.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { RecentlyAccessed } from '@kbn/recently-accessed'; - -export type DashboardRecentlyAccessedService = RecentlyAccessed; diff --git a/src/plugins/dashboard/public/services/i18n/i18n.stub.ts b/src/plugins/dashboard/public/services/dashboard_recently_accessed_service.ts similarity index 50% rename from src/plugins/dashboard/public/services/i18n/i18n.stub.ts rename to src/plugins/dashboard/public/services/dashboard_recently_accessed_service.ts index d756f2632aaac..06ab02857c30a 100644 --- a/src/plugins/dashboard/public/services/i18n/i18n.stub.ts +++ b/src/plugins/dashboard/public/services/dashboard_recently_accessed_service.ts @@ -7,14 +7,17 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { coreMock } from '@kbn/core/public/mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardI18nService } from './types'; +import { RecentlyAccessed, RecentlyAccessedService } from '@kbn/recently-accessed'; +import { coreServices } from './kibana_services'; -type I18nServiceFactory = PluginServiceFactory; +let dashboardRecentlyAccessed: RecentlyAccessed; -export const i18nServiceFactory: I18nServiceFactory = () => { - const { i18n } = coreMock.createStart(); - - return i18n; +export const getDashboardRecentlyAccessedService = () => { + if (!dashboardRecentlyAccessed) { + dashboardRecentlyAccessed = new RecentlyAccessedService().start({ + http: coreServices.http, + key: 'dashboardRecentlyAccessed', + }); + } + return dashboardRecentlyAccessed; }; diff --git a/src/plugins/dashboard/public/services/data/data.stub.ts b/src/plugins/dashboard/public/services/data/data.stub.ts deleted file mode 100644 index 9f688f4cd5dd1..0000000000000 --- a/src/plugins/dashboard/public/services/data/data.stub.ts +++ /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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -// import { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; -import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardDataService } from './types'; - -type DataServiceFactory = PluginServiceFactory; - -export const dataServiceFactory: DataServiceFactory = () => ({ - ...dataPluginMock.createStartContract(), - dataViews: { - ...dataViewPluginMocks.createStartContract(), - defaultDataViewExists: async () => true, - }, -}); diff --git a/src/plugins/dashboard/public/services/data/data_service.ts b/src/plugins/dashboard/public/services/data/data_service.ts deleted file mode 100644 index 7e464c2609c19..0000000000000 --- a/src/plugins/dashboard/public/services/data/data_service.ts +++ /dev/null @@ -1,30 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardDataService } from './types'; - -export type DataServiceFactory = KibanaPluginServiceFactory< - DashboardDataService, - DashboardStartDependencies ->; - -export const dataServiceFactory: DataServiceFactory = ({ startPlugins }) => { - const { - data: { dataViews, fieldFormats, query, search }, - } = startPlugins; - - return { - dataViews, - fieldFormats, - query, - search, - }; -}; diff --git a/src/plugins/dashboard/public/services/data/types.ts b/src/plugins/dashboard/public/services/data/types.ts deleted file mode 100644 index 81e42a455095d..0000000000000 --- a/src/plugins/dashboard/public/services/data/types.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; - -export interface DashboardDataService { - dataViews: DataPublicPluginStart['dataViews']; - fieldFormats: DataPublicPluginStart['fieldFormats']; - query: DataPublicPluginStart['query']; - search: DataPublicPluginStart['search']; -} diff --git a/src/plugins/dashboard/public/services/data_view_editor/data_view_editor.stub.ts b/src/plugins/dashboard/public/services/data_view_editor/data_view_editor.stub.ts deleted file mode 100644 index b5d15dafbad43..0000000000000 --- a/src/plugins/dashboard/public/services/data_view_editor/data_view_editor.stub.ts +++ /dev/null @@ -1,23 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { indexPatternEditorPluginMock as dataViewEditorPluginMock } from '@kbn/data-view-editor-plugin/public/mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardDataViewEditorService } from './types'; - -type DataViewEditorServiceFactory = PluginServiceFactory; - -export const dataViewEditorServiceFactory: DataViewEditorServiceFactory = () => { - const dataViewEditorMock = dataViewEditorPluginMock.createStartContract(); - - return { - openEditor: dataViewEditorMock.openEditor, - userPermissions: dataViewEditorMock.userPermissions, - }; -}; diff --git a/src/plugins/dashboard/public/services/data_view_editor/data_view_editor_service.ts b/src/plugins/dashboard/public/services/data_view_editor/data_view_editor_service.ts deleted file mode 100644 index d64eba5d32821..0000000000000 --- a/src/plugins/dashboard/public/services/data_view_editor/data_view_editor_service.ts +++ /dev/null @@ -1,28 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardDataViewEditorService } from './types'; - -export type DataViewEditorServiceFactory = KibanaPluginServiceFactory< - DashboardDataViewEditorService, - DashboardStartDependencies ->; - -export const dataViewEditorServiceFactory: DataViewEditorServiceFactory = ({ startPlugins }) => { - const { - dataViewEditor: { openEditor, userPermissions }, - } = startPlugins; - - return { - openEditor, - userPermissions, - }; -}; diff --git a/src/plugins/dashboard/public/services/data_view_editor/types.ts b/src/plugins/dashboard/public/services/data_view_editor/types.ts deleted file mode 100644 index 3e5e7977f2119..0000000000000 --- a/src/plugins/dashboard/public/services/data_view_editor/types.ts +++ /dev/null @@ -1,14 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; -export interface DashboardDataViewEditorService { - openEditor: DataViewEditorStart['openEditor']; - userPermissions: DataViewEditorStart['userPermissions']; -} diff --git a/src/plugins/dashboard/public/services/documentation_links/documentation_links.stub.ts b/src/plugins/dashboard/public/services/documentation_links/documentation_links.stub.ts deleted file mode 100644 index e7d7a0f0c091d..0000000000000 --- a/src/plugins/dashboard/public/services/documentation_links/documentation_links.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { coreMock } from '@kbn/core/public/mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardDocumentationLinksService } from './types'; - -type DocumentationLinksServiceFactory = PluginServiceFactory; - -export const documentationLinksServiceFactory: DocumentationLinksServiceFactory = () => { - const corePluginMock = coreMock.createStart(); - - return { - indexPatternsDocLink: corePluginMock.docLinks.links.indexPatterns.introduction, - kibanaGuideDocLink: corePluginMock.docLinks.links.kibana.guide, - dashboardDocLink: corePluginMock.docLinks.links.dashboard.guide, - esqlDocLink: corePluginMock.docLinks.links.query.queryESQL, - }; -}; diff --git a/src/plugins/dashboard/public/services/documentation_links/documentation_links_service.ts b/src/plugins/dashboard/public/services/documentation_links/documentation_links_service.ts deleted file mode 100644 index 9dbe6a57aea0a..0000000000000 --- a/src/plugins/dashboard/public/services/documentation_links/documentation_links_service.ts +++ /dev/null @@ -1,39 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardDocumentationLinksService } from './types'; - -export type DocumentationLinksServiceFactory = KibanaPluginServiceFactory< - DashboardDocumentationLinksService, - DashboardStartDependencies ->; - -export const documentationLinksServiceFactory: DocumentationLinksServiceFactory = ({ - coreStart, -}) => { - const { - docLinks: { - links: { - kibana, - indexPatterns: { introduction }, - dashboard, - query: { queryESQL }, - }, - }, - } = coreStart; - - return { - indexPatternsDocLink: introduction, - kibanaGuideDocLink: kibana.guide, - dashboardDocLink: dashboard.guide, - esqlDocLink: queryESQL, - }; -}; diff --git a/src/plugins/dashboard/public/services/documentation_links/types.ts b/src/plugins/dashboard/public/services/documentation_links/types.ts deleted file mode 100644 index d79c95fc43aff..0000000000000 --- a/src/plugins/dashboard/public/services/documentation_links/types.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { CoreStart } from '@kbn/core/public'; - -export interface DashboardDocumentationLinksService { - indexPatternsDocLink: CoreStart['docLinks']['links']['indexPatterns']['introduction']; - kibanaGuideDocLink: CoreStart['docLinks']['links']['kibana']['guide']; - dashboardDocLink: CoreStart['docLinks']['links']['dashboard']['guide']; - esqlDocLink: CoreStart['docLinks']['links']['query']['queryESQL']; -} diff --git a/src/plugins/dashboard/public/services/embeddable/embeddable.stub.ts b/src/plugins/dashboard/public/services/embeddable/embeddable.stub.ts deleted file mode 100644 index 078f6b8cfe813..0000000000000 --- a/src/plugins/dashboard/public/services/embeddable/embeddable.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; -import type { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardEmbeddableService } from './types'; - -export type EmbeddableServiceFactory = PluginServiceFactory; - -export const embeddableServiceFactory: EmbeddableServiceFactory = () => { - const pluginMock = embeddablePluginMock.createStartContract(); - - return { - reactEmbeddableRegistryHasKey: pluginMock.reactEmbeddableRegistryHasKey, - getEmbeddableFactories: pluginMock.getEmbeddableFactories, - getEmbeddableFactory: pluginMock.getEmbeddableFactory, - getStateTransfer: pluginMock.getStateTransfer, - getAllMigrations: pluginMock.getAllMigrations, - telemetry: pluginMock.telemetry, - extract: pluginMock.extract, - inject: pluginMock.inject, - }; -}; diff --git a/src/plugins/dashboard/public/services/embeddable/embeddable_service.ts b/src/plugins/dashboard/public/services/embeddable/embeddable_service.ts deleted file mode 100644 index 6cce6426343a8..0000000000000 --- a/src/plugins/dashboard/public/services/embeddable/embeddable_service.ts +++ /dev/null @@ -1,34 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pick } from 'lodash'; - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardEmbeddableService } from './types'; - -export type EmbeddableServiceFactory = KibanaPluginServiceFactory< - DashboardEmbeddableService, - DashboardStartDependencies ->; -export const embeddableServiceFactory: EmbeddableServiceFactory = ({ startPlugins }) => { - const { embeddable } = startPlugins; - - return pick(embeddable, [ - 'reactEmbeddableRegistryHasKey', - 'getEmbeddableFactory', - 'getEmbeddableFactories', - 'getStateTransfer', - 'getAllMigrations', - 'telemetry', - 'extract', - 'inject', - ]); -}; diff --git a/src/plugins/dashboard/public/services/embeddable/types.ts b/src/plugins/dashboard/public/services/embeddable/types.ts deleted file mode 100644 index 8b293a75fc823..0000000000000 --- a/src/plugins/dashboard/public/services/embeddable/types.ts +++ /dev/null @@ -1,22 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { EmbeddableStart } from '@kbn/embeddable-plugin/public'; - -export type DashboardEmbeddableService = Pick< - EmbeddableStart, - | 'reactEmbeddableRegistryHasKey' - | 'getEmbeddableFactories' - | 'getEmbeddableFactory' - | 'getAllMigrations' - | 'getStateTransfer' - | 'telemetry' - | 'extract' - | 'inject' ->; diff --git a/src/plugins/dashboard/public/services/http/http.stub.ts b/src/plugins/dashboard/public/services/http/http.stub.ts deleted file mode 100644 index f66ffa40e1098..0000000000000 --- a/src/plugins/dashboard/public/services/http/http.stub.ts +++ /dev/null @@ -1,23 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { coreMock } from '@kbn/core/public/mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardHTTPService } from './types'; - -type HttpServiceFactory = PluginServiceFactory; - -export const httpServiceFactory: HttpServiceFactory = () => { - const serviceMock = coreMock.createStart(); - - return { - basePath: serviceMock.http.basePath, - get: serviceMock.http.get, - }; -}; diff --git a/src/plugins/dashboard/public/services/http/http_service.ts b/src/plugins/dashboard/public/services/http/http_service.ts deleted file mode 100644 index d06b7d718153f..0000000000000 --- a/src/plugins/dashboard/public/services/http/http_service.ts +++ /dev/null @@ -1,27 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardHTTPService } from './types'; - -export type HttpServiceFactory = KibanaPluginServiceFactory< - DashboardHTTPService, - DashboardStartDependencies ->; -export const httpServiceFactory: HttpServiceFactory = ({ coreStart }) => { - const { - http: { basePath, get }, - } = coreStart; - - return { - basePath, - get, - }; -}; diff --git a/src/plugins/dashboard/public/services/http/types.ts b/src/plugins/dashboard/public/services/http/types.ts deleted file mode 100644 index 532d9bb907f9d..0000000000000 --- a/src/plugins/dashboard/public/services/http/types.ts +++ /dev/null @@ -1,15 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CoreStart } from '@kbn/core/public'; - -export interface DashboardHTTPService { - basePath: CoreStart['http']['basePath']; - get: CoreStart['http']['get']; -} diff --git a/src/plugins/dashboard/public/services/i18n/i18n_service.ts b/src/plugins/dashboard/public/services/i18n/i18n_service.ts deleted file mode 100644 index e0ef2a3e36137..0000000000000 --- a/src/plugins/dashboard/public/services/i18n/i18n_service.ts +++ /dev/null @@ -1,22 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardI18nService } from './types'; - -export type I18nServiceFactory = KibanaPluginServiceFactory< - DashboardI18nService, - DashboardStartDependencies ->; -export const i18nServiceFactory: I18nServiceFactory = ({ coreStart }) => { - const { i18n } = coreStart; - - return i18n; -}; diff --git a/src/plugins/dashboard/public/services/i18n/types.ts b/src/plugins/dashboard/public/services/i18n/types.ts deleted file mode 100644 index 353ceab072034..0000000000000 --- a/src/plugins/dashboard/public/services/i18n/types.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CoreStart } from '@kbn/core/public'; - -export type DashboardI18nService = CoreStart['i18n']; diff --git a/src/plugins/dashboard/public/services/initializer_context/initializer_context.stub.ts b/src/plugins/dashboard/public/services/initializer_context/initializer_context.stub.ts deleted file mode 100644 index 9296d6cba94ee..0000000000000 --- a/src/plugins/dashboard/public/services/initializer_context/initializer_context.stub.ts +++ /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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardInitializerContextService } from './types'; - -const defaultDashboardInitializerContext: DashboardInitializerContextService = { - kibanaVersion: 'test.kibana.version', - allowByValueEmbeddables: true, -}; - -type InitializerContextServiceFactory = PluginServiceFactory; - -export const initializerContextServiceFactory: InitializerContextServiceFactory = () => { - return { - ...defaultDashboardInitializerContext, - }; -}; diff --git a/src/plugins/dashboard/public/services/initializer_context/initializer_context_service.ts b/src/plugins/dashboard/public/services/initializer_context/initializer_context_service.ts deleted file mode 100644 index 90b4ad2f953e1..0000000000000 --- a/src/plugins/dashboard/public/services/initializer_context/initializer_context_service.ts +++ /dev/null @@ -1,32 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DashboardFeatureFlagConfig } from '../..'; -import { DashboardPluginServiceParams } from '../types'; -import { DashboardInitializerContextService } from './types'; - -export type InitializerContextServiceFactory = ( - params: DashboardPluginServiceParams -) => DashboardInitializerContextService; - -export const initializerContextServiceFactory: InitializerContextServiceFactory = ({ - initContext, -}) => { - const { - env: { - packageInfo: { version }, - }, - config: { get }, - } = initContext; - - return { - kibanaVersion: version, - allowByValueEmbeddables: get().allowByValueEmbeddables, - }; -}; diff --git a/src/plugins/dashboard/public/services/initializer_context/types.ts b/src/plugins/dashboard/public/services/initializer_context/types.ts deleted file mode 100644 index cd8ea8cd41e0b..0000000000000 --- a/src/plugins/dashboard/public/services/initializer_context/types.ts +++ /dev/null @@ -1,13 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export interface DashboardInitializerContextService { - kibanaVersion: string; - allowByValueEmbeddables: boolean; -} diff --git a/src/plugins/dashboard/public/services/kibana_services.ts b/src/plugins/dashboard/public/services/kibana_services.ts new file mode 100644 index 0000000000000..e8b164d47b413 --- /dev/null +++ b/src/plugins/dashboard/public/services/kibana_services.ts @@ -0,0 +1,90 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { BehaviorSubject } from 'rxjs'; + +import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; +import type { CoreStart } from '@kbn/core/public'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; +import type { EmbeddableStart } from '@kbn/embeddable-plugin/public/plugin'; +import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public/plugin'; +import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; +import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; +import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public'; +import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; +import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; +import type { ScreenshotModePluginStart } from '@kbn/screenshot-mode-plugin/public'; +import type { ServerlessPluginStart } from '@kbn/serverless/public'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import type { SpacesApi } from '@kbn/spaces-plugin/public'; +import type { UiActionsPublicStart } from '@kbn/ui-actions-plugin/public/plugin'; +import type { UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; +import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; +import type { VisualizationsStart } from '@kbn/visualizations-plugin/public'; + +import type { DashboardStartDependencies } from '../plugin'; + +export let coreServices: CoreStart; +export let contentManagementService: ContentManagementPublicStart; +export let dataService: DataPublicPluginStart; +export let dataViewEditorService: DataViewEditorStart; +export let embeddableService: EmbeddableStart; +export let fieldFormatService: FieldFormatsStart; +export let navigationService: NavigationPublicPluginStart; +export let noDataPageService: NoDataPagePluginStart | undefined; +export let observabilityAssistantService: ObservabilityAIAssistantPublicStart | undefined; +export let presentationUtilService: PresentationUtilPluginStart; +export let savedObjectsTaggingService: SavedObjectTaggingOssPluginStart | undefined; +export let screenshotModeService: ScreenshotModePluginStart; +export let serverlessService: ServerlessPluginStart | undefined; +export let shareService: SharePluginStart | undefined; +export let spacesService: SpacesApi | undefined; +export let uiActionsService: UiActionsPublicStart; +export let urlForwardingService: UrlForwardingStart; +export let usageCollectionService: UsageCollectionStart | undefined; +export let visualizationsService: VisualizationsStart; + +const servicesReady$ = new BehaviorSubject(false); + +export const setKibanaServices = (kibanaCore: CoreStart, deps: DashboardStartDependencies) => { + coreServices = kibanaCore; + contentManagementService = deps.contentManagement; + dataService = deps.data; + dataViewEditorService = deps.dataViewEditor; + embeddableService = deps.embeddable; + fieldFormatService = deps.fieldFormats; + navigationService = deps.navigation; + noDataPageService = deps.noDataPage; + observabilityAssistantService = deps.observabilityAIAssistant; + presentationUtilService = deps.presentationUtil; + savedObjectsTaggingService = deps.savedObjectsTaggingOss; + serverlessService = deps.serverless; + screenshotModeService = deps.screenshotMode; + shareService = deps.share; + spacesService = deps.spaces; + uiActionsService = deps.uiActions; + urlForwardingService = deps.urlForwarding; + usageCollectionService = deps.usageCollection; + visualizationsService = deps.visualizations; + + servicesReady$.next(true); +}; + +export const untilPluginStartServicesReady = () => { + if (servicesReady$.value) return Promise.resolve(); + return new Promise((resolve) => { + const subscription = servicesReady$.subscribe((isInitialized) => { + if (isInitialized) { + subscription.unsubscribe(); + resolve(); + } + }); + }); +}; diff --git a/src/plugins/dashboard/public/services/mocks.ts b/src/plugins/dashboard/public/services/mocks.ts index a4126962432c6..61132c2fc264e 100644 --- a/src/plugins/dashboard/public/services/mocks.ts +++ b/src/plugins/dashboard/public/services/mocks.ts @@ -7,11 +7,148 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { pluginServices } from './plugin_services'; -import { registry } from './plugin_services.stub'; +import { serverlessMock } from '@kbn/serverless/public/mocks'; +import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; +import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; +import { usageCollectionPluginMock } from '@kbn/usage-collection-plugin/public/mocks'; +import { coreMock } from '@kbn/core/public/mocks'; +import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; +import { customBrandingServiceMock } from '@kbn/core-custom-branding-browser-mocks'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; +import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; +import { indexPatternEditorPluginMock } from '@kbn/data-view-editor-plugin/public/mocks'; +import { inspectorPluginMock } from '@kbn/inspector-plugin/public/mocks'; +import { navigationPluginMock } from '@kbn/navigation-plugin/public/mocks'; +import { noDataPagePublicMock } from '@kbn/no-data-page-plugin/public/mocks'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; +import { presentationUtilPluginMock } from '@kbn/presentation-util-plugin/public/mocks'; +import { savedObjectsManagementPluginMock } from '@kbn/saved-objects-management-plugin/public/mocks'; +import { screenshotModePluginMock } from '@kbn/screenshot-mode-plugin/public/mocks'; +import { savedObjectTaggingOssPluginMock } from '@kbn/saved-objects-tagging-oss-plugin/public/mocks'; +import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; +import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks'; +import { urlForwardingPluginMock } from '@kbn/url-forwarding-plugin/public/mocks'; +import { visualizationsPluginMock } from '@kbn/visualizations-plugin/public/mocks'; -export function setStubDashboardServices() { - pluginServices.setRegistry(registry.start({})); -} +import { setKibanaServices } from './kibana_services'; +import { DashboardAttributes, DashboardCapabilities } from '../../common'; +import { LoadDashboardReturn } from './dashboard_content_management_service/types'; +import { SearchDashboardsResponse } from './dashboard_content_management_service/lib/find_dashboards'; -setStubDashboardServices(); +const defaultDashboardCapabilities: DashboardCapabilities = { + show: true, + createNew: true, + saveQuery: true, + createShortUrl: true, + showWriteControls: true, + storeSearchSession: true, +}; + +export const setStubKibanaServices = () => { + const core = coreMock.createStart(); + (core.application.capabilities as any).dashboard = defaultDashboardCapabilities; + + setKibanaServices(core, { + contentManagement: contentManagementMock.createStartContract(), + customBranding: customBrandingServiceMock.createStartContract(), + data: dataPluginMock.createStartContract(), + dataViewEditor: indexPatternEditorPluginMock.createStartContract(), + embeddable: embeddablePluginMock.createStartContract(), + fieldFormats: fieldFormatsServiceMock.createStartContract(), + inspector: inspectorPluginMock.createStartContract(), + navigation: navigationPluginMock.createStartContract(), + noDataPage: noDataPagePublicMock.createStart(), + observabilityAIAssistant: observabilityAIAssistantPluginMock.createStartContract(), + presentationUtil: presentationUtilPluginMock.createStartContract(core), + savedObjectsManagement: savedObjectsManagementPluginMock.createStartContract(), + savedObjectsTaggingOss: savedObjectTaggingOssPluginMock.createStart(), + screenshotMode: screenshotModePluginMock.createStartContract(), + serverless: serverlessMock.createStart(), + share: sharePluginMock.createStartContract(), + spaces: spacesPluginMock.createStartContract(), + uiActions: uiActionsPluginMock.createStartContract(), + unifiedSearch: unifiedSearchPluginMock.createStartContract(), + urlForwarding: urlForwardingPluginMock.createStartContract(), + usageCollection: usageCollectionPluginMock.createSetupContract(), + visualizations: visualizationsPluginMock.createStartContract(), + }); +}; + +export const mockDashboardContentManagementService = { + loadDashboardState: jest.fn().mockImplementation(() => + Promise.resolve({ + dashboardInput: {}, + } as LoadDashboardReturn) + ), + saveDashboardState: jest.fn(), + findDashboards: { + search: jest.fn().mockImplementation(({ search, size }) => { + const sizeToUse = size ?? 10; + const hits: SearchDashboardsResponse['hits'] = []; + for (let i = 0; i < sizeToUse; i++) { + hits.push({ + type: 'dashboard', + id: `dashboard${i}`, + attributes: { + description: `dashboard${i} desc`, + title: `dashboard${i} - ${search} - title`, + }, + references: [] as SearchDashboardsResponse['hits'][0]['references'], + } as SearchDashboardsResponse['hits'][0]); + } + return Promise.resolve({ + total: sizeToUse, + hits, + }); + }), + findById: jest.fn(), + findByIds: jest.fn().mockImplementation(() => + Promise.resolve([ + { + id: `dashboardUnsavedOne`, + status: 'success', + attributes: { + title: `Dashboard Unsaved One`, + } as unknown as DashboardAttributes, + }, + { + id: `dashboardUnsavedTwo`, + status: 'success', + attributes: { + title: `Dashboard Unsaved Two`, + } as unknown as DashboardAttributes, + }, + { + id: `dashboardUnsavedThree`, + status: 'success', + attributes: { + title: `Dashboard Unsaved Three`, + } as unknown as DashboardAttributes, + }, + ]) + ), + findByTitle: jest.fn(), + }, + deleteDashboards: jest.fn(), + checkForDuplicateDashboardTitle: jest.fn(), + updateDashboardMeta: jest.fn(), +}; + +export const mockDashboardBackupService = { + clearState: jest.fn(), + getState: jest.fn().mockReturnValue(undefined), + setState: jest.fn(), + getViewMode: jest.fn(), + storeViewMode: jest.fn(), + getDashboardIdsWithUnsavedChanges: jest + .fn() + .mockReturnValue(['dashboardUnsavedOne', 'dashboardUnsavedTwo']), + dashboardHasUnsavedEdits: jest.fn(), +}; + +export const mockDashboardContentManagementCache = { + fetchDashboard: jest.fn(), + addDashboard: jest.fn(), + deleteDashboard: jest.fn(), +}; diff --git a/src/plugins/dashboard/public/services/navigation/navigation.stub.ts b/src/plugins/dashboard/public/services/navigation/navigation.stub.ts deleted file mode 100644 index 81b5c0734574d..0000000000000 --- a/src/plugins/dashboard/public/services/navigation/navigation.stub.ts +++ /dev/null @@ -1,22 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { navigationPluginMock } from '@kbn/navigation-plugin/public/mocks'; -import { DashboardNavigationService } from './types'; - -type NavigationServiceFactory = PluginServiceFactory; - -export const navigationServiceFactory: NavigationServiceFactory = () => { - const pluginMock = navigationPluginMock.createStartContract(); - - return { - TopNavMenu: pluginMock.ui.TopNavMenu, - }; -}; diff --git a/src/plugins/dashboard/public/services/navigation/navigation_service.ts b/src/plugins/dashboard/public/services/navigation/navigation_service.ts deleted file mode 100644 index 7bb3f97220fc3..0000000000000 --- a/src/plugins/dashboard/public/services/navigation/navigation_service.ts +++ /dev/null @@ -1,28 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardNavigationService } from './types'; - -export type NavigationServiceFactory = KibanaPluginServiceFactory< - DashboardNavigationService, - DashboardStartDependencies ->; -export const navigationServiceFactory: NavigationServiceFactory = ({ startPlugins }) => { - const { - navigation: { - ui: { TopNavMenu }, - }, - } = startPlugins; - - return { - TopNavMenu, - }; -}; diff --git a/src/plugins/dashboard/public/services/navigation/types.ts b/src/plugins/dashboard/public/services/navigation/types.ts deleted file mode 100644 index e407e8e77b769..0000000000000 --- a/src/plugins/dashboard/public/services/navigation/types.ts +++ /dev/null @@ -1,14 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; - -export interface DashboardNavigationService { - TopNavMenu: NavigationPublicPluginStart['ui']['TopNavMenu']; -} diff --git a/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.stub.ts b/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.stub.ts deleted file mode 100644 index 6797d5ef9e7d8..0000000000000 --- a/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { noDataPagePublicMock } from '@kbn/no-data-page-plugin/public/mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { NoDataPageService } from './types'; - -export type NoDataPageServiceFactory = PluginServiceFactory; - -export const noDataPageServiceFactory: NoDataPageServiceFactory = () => - noDataPagePublicMock.createSetup(); diff --git a/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.ts b/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.ts deleted file mode 100644 index 13000ca2cdddb..0000000000000 --- a/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardStartDependencies } from '../../plugin'; -import { NoDataPageService } from './types'; - -export type NoDataPageServiceFactory = KibanaPluginServiceFactory< - NoDataPageService, - DashboardStartDependencies ->; - -export const noDataPageServiceFactory: NoDataPageServiceFactory = ({ startPlugins }) => { - const { noDataPage } = startPlugins; - - return { - getAnalyticsNoDataPageFlavor: noDataPage?.getAnalyticsNoDataPageFlavor ?? (() => 'kibana'), - }; -}; diff --git a/src/plugins/dashboard/public/services/no_data_page/types.ts b/src/plugins/dashboard/public/services/no_data_page/types.ts deleted file mode 100644 index 81700402db72d..0000000000000 --- a/src/plugins/dashboard/public/services/no_data_page/types.ts +++ /dev/null @@ -1,14 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; - -export interface NoDataPageService { - getAnalyticsNoDataPageFlavor: NoDataPagePluginStart['getAnalyticsNoDataPageFlavor']; -} diff --git a/src/plugins/dashboard/public/services/notifications/notifications.stub.ts b/src/plugins/dashboard/public/services/notifications/notifications.stub.ts deleted file mode 100644 index 0be8056dd604b..0000000000000 --- a/src/plugins/dashboard/public/services/notifications/notifications.stub.ts +++ /dev/null @@ -1,23 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardNotificationsService } from './types'; - -type NotificationsServiceFactory = PluginServiceFactory; - -export const notificationsServiceFactory: NotificationsServiceFactory = () => { - const pluginMock = notificationServiceMock.createStartContract(); - - return { - toasts: pluginMock.toasts, - showErrorDialog: pluginMock.showErrorDialog, - }; -}; diff --git a/src/plugins/dashboard/public/services/notifications/notifications_service.ts b/src/plugins/dashboard/public/services/notifications/notifications_service.ts deleted file mode 100644 index c2acd02891492..0000000000000 --- a/src/plugins/dashboard/public/services/notifications/notifications_service.ts +++ /dev/null @@ -1,28 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardNotificationsService } from './types'; - -export type NotificationsServiceFactory = KibanaPluginServiceFactory< - DashboardNotificationsService, - DashboardStartDependencies ->; - -export const notificationsServiceFactory: NotificationsServiceFactory = ({ coreStart }) => { - const { - notifications: { toasts, showErrorDialog }, - } = coreStart; - - return { - toasts, - showErrorDialog, - }; -}; diff --git a/src/plugins/dashboard/public/services/notifications/types.ts b/src/plugins/dashboard/public/services/notifications/types.ts deleted file mode 100644 index f31420238f175..0000000000000 --- a/src/plugins/dashboard/public/services/notifications/types.ts +++ /dev/null @@ -1,15 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CoreStart } from '@kbn/core/public'; - -export interface DashboardNotificationsService { - toasts: CoreStart['notifications']['toasts']; - showErrorDialog: CoreStart['notifications']['showErrorDialog']; -} diff --git a/src/plugins/dashboard/public/services/observability_ai_assistant/observability_ai_assistant_service.stub.ts b/src/plugins/dashboard/public/services/observability_ai_assistant/observability_ai_assistant_service.stub.ts deleted file mode 100644 index d33491f0024f3..0000000000000 --- a/src/plugins/dashboard/public/services/observability_ai_assistant/observability_ai_assistant_service.stub.ts +++ /dev/null @@ -1,22 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; -import { ObservabilityAIAssistantService } from './types'; - -type ObservabilityAIAssistantServiceFactory = PluginServiceFactory; - -export const observabilityAIAssistantServiceStubFactory: ObservabilityAIAssistantServiceFactory = - () => { - const pluginMock = observabilityAIAssistantPluginMock.createStartContract(); - return { - start: pluginMock, - }; - }; diff --git a/src/plugins/dashboard/public/services/observability_ai_assistant/observability_ai_assistant_service.ts b/src/plugins/dashboard/public/services/observability_ai_assistant/observability_ai_assistant_service.ts deleted file mode 100644 index 5b3b08f148f1a..0000000000000 --- a/src/plugins/dashboard/public/services/observability_ai_assistant/observability_ai_assistant_service.ts +++ /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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { ObservabilityAIAssistantService } from './types'; - -export type ObservabilityAIAssistantServiceFactory = KibanaPluginServiceFactory< - ObservabilityAIAssistantService, - DashboardStartDependencies ->; -export const observabilityAIAssistantServiceFactory: ObservabilityAIAssistantServiceFactory = ({ - startPlugins, -}) => { - return startPlugins.observabilityAIAssistant - ? { start: startPlugins.observabilityAIAssistant } - : {}; -}; diff --git a/src/plugins/dashboard/public/services/observability_ai_assistant/types.ts b/src/plugins/dashboard/public/services/observability_ai_assistant/types.ts deleted file mode 100644 index 6cb252910219a..0000000000000 --- a/src/plugins/dashboard/public/services/observability_ai_assistant/types.ts +++ /dev/null @@ -1,14 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public'; - -export interface ObservabilityAIAssistantService { - start?: ObservabilityAIAssistantPublicStart; -} diff --git a/src/plugins/dashboard/public/services/overlays/overlays.stub.ts b/src/plugins/dashboard/public/services/overlays/overlays.stub.ts deleted file mode 100644 index 0fc7d90fa13fd..0000000000000 --- a/src/plugins/dashboard/public/services/overlays/overlays.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { overlayServiceMock } from '@kbn/core-overlays-browser-mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardOverlaysService } from './types'; - -type OverlaysServiceFactory = PluginServiceFactory; - -export const overlaysServiceFactory: OverlaysServiceFactory = () => { - const pluginMock = overlayServiceMock.createStartContract(); - - return { - banners: pluginMock.banners, - openConfirm: pluginMock.openConfirm, - openFlyout: pluginMock.openFlyout, - openModal: pluginMock.openModal, - }; -}; diff --git a/src/plugins/dashboard/public/services/overlays/overlays_service.ts b/src/plugins/dashboard/public/services/overlays/overlays_service.ts deleted file mode 100644 index aca127b116697..0000000000000 --- a/src/plugins/dashboard/public/services/overlays/overlays_service.ts +++ /dev/null @@ -1,30 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardOverlaysService } from './types'; - -export type OverlaysServiceFactory = KibanaPluginServiceFactory< - DashboardOverlaysService, - DashboardStartDependencies ->; - -export const overlaysServiceFactory: OverlaysServiceFactory = ({ coreStart }) => { - const { - overlays: { banners, openConfirm, openFlyout, openModal }, - } = coreStart; - - return { - banners, - openConfirm, - openFlyout, - openModal, - }; -}; diff --git a/src/plugins/dashboard/public/services/overlays/types.ts b/src/plugins/dashboard/public/services/overlays/types.ts deleted file mode 100644 index f2a2dd8feb509..0000000000000 --- a/src/plugins/dashboard/public/services/overlays/types.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CoreStart } from '@kbn/core/public'; - -export interface DashboardOverlaysService { - banners: CoreStart['overlays']['banners']; - openConfirm: CoreStart['overlays']['openConfirm']; - openFlyout: CoreStart['overlays']['openFlyout']; - openModal: CoreStart['overlays']['openModal']; -} diff --git a/src/plugins/dashboard/public/services/plugin_services.stub.ts b/src/plugins/dashboard/public/services/plugin_services.stub.ts deleted file mode 100644 index a9334c001c2c0..0000000000000 --- a/src/plugins/dashboard/public/services/plugin_services.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - PluginServiceProviders, - PluginServiceProvider, - PluginServiceRegistry, -} from '@kbn/presentation-util-plugin/public'; - -import { DashboardServices } from './types'; - -import { analyticsServiceFactory } from './analytics/analytics.stub'; -import { applicationServiceFactory } from './application/application.stub'; -import { chromeServiceFactory } from './chrome/chrome.stub'; -import { coreContextServiceFactory } from './core_context/core_context.stub'; -import { dashboardCapabilitiesServiceFactory } from './dashboard_capabilities/dashboard_capabilities.stub'; -import { dashboardBackupServiceFactory } from './dashboard_backup/dashboard_backup.stub'; -import { dataServiceFactory } from './data/data.stub'; -import { dataViewEditorServiceFactory } from './data_view_editor/data_view_editor.stub'; -import { documentationLinksServiceFactory } from './documentation_links/documentation_links.stub'; -import { embeddableServiceFactory } from './embeddable/embeddable.stub'; -import { httpServiceFactory } from './http/http.stub'; -import { i18nServiceFactory } from './i18n/i18n.stub'; -import { initializerContextServiceFactory } from './initializer_context/initializer_context.stub'; -import { navigationServiceFactory } from './navigation/navigation.stub'; -import { notificationsServiceFactory } from './notifications/notifications.stub'; -import { overlaysServiceFactory } from './overlays/overlays.stub'; -import { savedObjectsTaggingServiceFactory } from './saved_objects_tagging/saved_objects_tagging.stub'; -import { screenshotModeServiceFactory } from './screenshot_mode/screenshot_mode.stub'; -import { settingsServiceFactory } from './settings/settings.stub'; -import { shareServiceFactory } from './share/share.stub'; -import { usageCollectionServiceFactory } from './usage_collection/usage_collection.stub'; -import { spacesServiceFactory } from './spaces/spaces.stub'; -import { urlForwardingServiceFactory } from './url_forwarding/url_fowarding.stub'; -import { visualizationsServiceFactory } from './visualizations/visualizations.stub'; -import { dashboardContentManagementServiceFactory } from './dashboard_content_management/dashboard_content_management.stub'; -import { customBrandingServiceFactory } from './custom_branding/custom_branding.stub'; -import { savedObjectsManagementServiceFactory } from './saved_objects_management/saved_objects_management_service.stub'; -import { contentManagementServiceFactory } from './content_management/content_management_service.stub'; -import { serverlessServiceFactory } from './serverless/serverless_service.stub'; -import { userProfileServiceFactory } from './user_profile/user_profile_service.stub'; -import { observabilityAIAssistantServiceStubFactory } from './observability_ai_assistant/observability_ai_assistant_service.stub'; -import { noDataPageServiceFactory } from './no_data_page/no_data_page_service.stub'; -import { uiActionsServiceFactory } from './ui_actions/ui_actions_service.stub'; -import { dashboardRecentlyAccessedServiceFactory } from './dashboard_recently_accessed/dashboard_recently_accessed.stub'; -import { dashboardFavoritesServiceFactory } from './dashboard_favorites/dashboard_favorites_service.stub'; -import { dashboardContentInsightsServiceFactory } from './dashboard_content_insights/dashboard_content_insights.stub'; - -export const providers: PluginServiceProviders = { - dashboardContentManagement: new PluginServiceProvider(dashboardContentManagementServiceFactory), - analytics: new PluginServiceProvider(analyticsServiceFactory), - application: new PluginServiceProvider(applicationServiceFactory), - chrome: new PluginServiceProvider(chromeServiceFactory), - coreContext: new PluginServiceProvider(coreContextServiceFactory), - dashboardCapabilities: new PluginServiceProvider(dashboardCapabilitiesServiceFactory), - dashboardBackup: new PluginServiceProvider(dashboardBackupServiceFactory), - data: new PluginServiceProvider(dataServiceFactory), - dataViewEditor: new PluginServiceProvider(dataViewEditorServiceFactory), - documentationLinks: new PluginServiceProvider(documentationLinksServiceFactory), - embeddable: new PluginServiceProvider(embeddableServiceFactory), - http: new PluginServiceProvider(httpServiceFactory), - i18n: new PluginServiceProvider(i18nServiceFactory), - initializerContext: new PluginServiceProvider(initializerContextServiceFactory), - navigation: new PluginServiceProvider(navigationServiceFactory), - notifications: new PluginServiceProvider(notificationsServiceFactory), - overlays: new PluginServiceProvider(overlaysServiceFactory), - savedObjectsTagging: new PluginServiceProvider(savedObjectsTaggingServiceFactory), - screenshotMode: new PluginServiceProvider(screenshotModeServiceFactory), - settings: new PluginServiceProvider(settingsServiceFactory), - share: new PluginServiceProvider(shareServiceFactory), - spaces: new PluginServiceProvider(spacesServiceFactory), - urlForwarding: new PluginServiceProvider(urlForwardingServiceFactory), - usageCollection: new PluginServiceProvider(usageCollectionServiceFactory), - visualizations: new PluginServiceProvider(visualizationsServiceFactory), - customBranding: new PluginServiceProvider(customBrandingServiceFactory), - savedObjectsManagement: new PluginServiceProvider(savedObjectsManagementServiceFactory), - contentManagement: new PluginServiceProvider(contentManagementServiceFactory), - serverless: new PluginServiceProvider(serverlessServiceFactory), - noDataPage: new PluginServiceProvider(noDataPageServiceFactory), - uiActions: new PluginServiceProvider(uiActionsServiceFactory), - userProfile: new PluginServiceProvider(userProfileServiceFactory), - observabilityAIAssistant: new PluginServiceProvider(observabilityAIAssistantServiceStubFactory), - dashboardRecentlyAccessed: new PluginServiceProvider(dashboardRecentlyAccessedServiceFactory), - dashboardContentInsights: new PluginServiceProvider(dashboardContentInsightsServiceFactory), - dashboardFavorites: new PluginServiceProvider(dashboardFavoritesServiceFactory), -}; - -export const registry = new PluginServiceRegistry(providers); diff --git a/src/plugins/dashboard/public/services/plugin_services.ts b/src/plugins/dashboard/public/services/plugin_services.ts deleted file mode 100644 index a3b826bfe5632..0000000000000 --- a/src/plugins/dashboard/public/services/plugin_services.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - PluginServiceProviders, - PluginServiceProvider, - PluginServiceRegistry, - PluginServices, -} from '@kbn/presentation-util-plugin/public'; - -import { DashboardPluginServiceParams, DashboardServices } from './types'; - -import { applicationServiceFactory } from './application/application_service'; -import { chromeServiceFactory } from './chrome/chrome_service'; -import { coreContextServiceFactory } from './core_context/core_context_service'; -import { dashboardCapabilitiesServiceFactory } from './dashboard_capabilities/dashboard_capabilities_service'; -import { dashboardBackupServiceFactory } from './dashboard_backup/dashboard_backup_service'; -import { dataServiceFactory } from './data/data_service'; -import { dataViewEditorServiceFactory } from './data_view_editor/data_view_editor_service'; -import { documentationLinksServiceFactory } from './documentation_links/documentation_links_service'; -import { embeddableServiceFactory } from './embeddable/embeddable_service'; -import { httpServiceFactory } from './http/http_service'; -import { i18nServiceFactory } from './i18n/i18n_service'; -import { initializerContextServiceFactory } from './initializer_context/initializer_context_service'; -import { navigationServiceFactory } from './navigation/navigation_service'; -import { notificationsServiceFactory } from './notifications/notifications_service'; -import { overlaysServiceFactory } from './overlays/overlays_service'; -import { screenshotModeServiceFactory } from './screenshot_mode/screenshot_mode_service'; -import { savedObjectsTaggingServiceFactory } from './saved_objects_tagging/saved_objects_tagging_service'; -import { settingsServiceFactory } from './settings/settings_service'; -import { shareServiceFactory } from './share/share_services'; -import { spacesServiceFactory } from './spaces/spaces_service'; -import { urlForwardingServiceFactory } from './url_forwarding/url_forwarding_service'; -import { visualizationsServiceFactory } from './visualizations/visualizations_service'; -import { usageCollectionServiceFactory } from './usage_collection/usage_collection_service'; -import { analyticsServiceFactory } from './analytics/analytics_service'; -import { customBrandingServiceFactory } from './custom_branding/custom_branding_service'; -import { savedObjectsManagementServiceFactory } from './saved_objects_management/saved_objects_management_service'; -import { dashboardContentManagementServiceFactory } from './dashboard_content_management/dashboard_content_management_service'; -import { contentManagementServiceFactory } from './content_management/content_management_service'; -import { serverlessServiceFactory } from './serverless/serverless_service'; -import { noDataPageServiceFactory } from './no_data_page/no_data_page_service'; -import { uiActionsServiceFactory } from './ui_actions/ui_actions_service'; -import { observabilityAIAssistantServiceFactory } from './observability_ai_assistant/observability_ai_assistant_service'; -import { userProfileServiceFactory } from './user_profile/user_profile_service'; -import { dashboardRecentlyAccessedFactory } from './dashboard_recently_accessed/dashboard_recently_accessed'; -import { dashboardFavoritesServiceFactory } from './dashboard_favorites/dashboard_favorites_service'; -import { dashboardContentInsightsServiceFactory } from './dashboard_content_insights/dashboard_content_insights_service'; - -const providers: PluginServiceProviders = { - dashboardContentManagement: new PluginServiceProvider(dashboardContentManagementServiceFactory, [ - 'savedObjectsTagging', - 'initializerContext', - 'dashboardBackup', - 'screenshotMode', - 'notifications', - 'embeddable', - 'spaces', - 'data', - ]), - dashboardBackup: new PluginServiceProvider(dashboardBackupServiceFactory, [ - 'notifications', - 'spaces', - ]), - - analytics: new PluginServiceProvider(analyticsServiceFactory), - application: new PluginServiceProvider(applicationServiceFactory), - chrome: new PluginServiceProvider(chromeServiceFactory), - coreContext: new PluginServiceProvider(coreContextServiceFactory), - dashboardCapabilities: new PluginServiceProvider(dashboardCapabilitiesServiceFactory), - data: new PluginServiceProvider(dataServiceFactory), - dataViewEditor: new PluginServiceProvider(dataViewEditorServiceFactory), - documentationLinks: new PluginServiceProvider(documentationLinksServiceFactory), - embeddable: new PluginServiceProvider(embeddableServiceFactory), - http: new PluginServiceProvider(httpServiceFactory), - i18n: new PluginServiceProvider(i18nServiceFactory), - initializerContext: new PluginServiceProvider(initializerContextServiceFactory), - navigation: new PluginServiceProvider(navigationServiceFactory), - notifications: new PluginServiceProvider(notificationsServiceFactory), - overlays: new PluginServiceProvider(overlaysServiceFactory), - savedObjectsTagging: new PluginServiceProvider(savedObjectsTaggingServiceFactory), - screenshotMode: new PluginServiceProvider(screenshotModeServiceFactory), - settings: new PluginServiceProvider(settingsServiceFactory), - share: new PluginServiceProvider(shareServiceFactory), - spaces: new PluginServiceProvider(spacesServiceFactory), - urlForwarding: new PluginServiceProvider(urlForwardingServiceFactory), - usageCollection: new PluginServiceProvider(usageCollectionServiceFactory), - visualizations: new PluginServiceProvider(visualizationsServiceFactory), - customBranding: new PluginServiceProvider(customBrandingServiceFactory), - savedObjectsManagement: new PluginServiceProvider(savedObjectsManagementServiceFactory), - contentManagement: new PluginServiceProvider(contentManagementServiceFactory), - serverless: new PluginServiceProvider(serverlessServiceFactory), - noDataPage: new PluginServiceProvider(noDataPageServiceFactory), - uiActions: new PluginServiceProvider(uiActionsServiceFactory), - observabilityAIAssistant: new PluginServiceProvider(observabilityAIAssistantServiceFactory), - userProfile: new PluginServiceProvider(userProfileServiceFactory), - dashboardRecentlyAccessed: new PluginServiceProvider(dashboardRecentlyAccessedFactory, ['http']), - dashboardContentInsights: new PluginServiceProvider(dashboardContentInsightsServiceFactory), - dashboardFavorites: new PluginServiceProvider(dashboardFavoritesServiceFactory), -}; - -export const pluginServices = new PluginServices(); - -export const registry = new PluginServiceRegistry( - providers -); diff --git a/src/plugins/dashboard/public/services/saved_objects_management/saved_objects_management_service.stub.ts b/src/plugins/dashboard/public/services/saved_objects_management/saved_objects_management_service.stub.ts deleted file mode 100644 index 085387b25eaf7..0000000000000 --- a/src/plugins/dashboard/public/services/saved_objects_management/saved_objects_management_service.stub.ts +++ /dev/null @@ -1,18 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; -import { savedObjectsManagementPluginMock } from '@kbn/saved-objects-management-plugin/public/mocks'; - -type SavedObjectsManagementServiceFactory = PluginServiceFactory; - -export const savedObjectsManagementServiceFactory: SavedObjectsManagementServiceFactory = () => { - return savedObjectsManagementPluginMock.createStartContract(); -}; diff --git a/src/plugins/dashboard/public/services/saved_objects_management/saved_objects_management_service.ts b/src/plugins/dashboard/public/services/saved_objects_management/saved_objects_management_service.ts deleted file mode 100644 index 3f471b0f12d47..0000000000000 --- a/src/plugins/dashboard/public/services/saved_objects_management/saved_objects_management_service.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; -import { DashboardStartDependencies } from '../../plugin'; - -export type SavedObjectsManagementServiceFactory = KibanaPluginServiceFactory< - SavedObjectsManagementPluginStart, - DashboardStartDependencies ->; - -export const savedObjectsManagementServiceFactory: SavedObjectsManagementServiceFactory = ({ - startPlugins, -}) => { - const { savedObjectsManagement } = startPlugins; - - return savedObjectsManagement; -}; diff --git a/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging.stub.ts b/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging.stub.ts deleted file mode 100644 index ed8e4e5486dad..0000000000000 --- a/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { taggingApiMock } from '@kbn/saved-objects-tagging-oss-plugin/public/mocks'; -import { DashboardSavedObjectsTaggingService } from './types'; - -type SavedObjectsTaggingServiceFactory = PluginServiceFactory; - -export const savedObjectsTaggingServiceFactory: SavedObjectsTaggingServiceFactory = () => { - const pluginMock = taggingApiMock.createUi(); - - return { - hasApi: true, - - // I'm not defining components so that I don't have to update the snapshot of `save_modal.test` - // However, if it's ever necessary, it can be done via: `components: pluginMock.components`, - parseSearchQuery: pluginMock.parseSearchQuery, - getSearchBarFilter: pluginMock.getSearchBarFilter, - getTagIdsFromReferences: pluginMock.getTagIdsFromReferences, - getTableColumnDefinition: pluginMock.getTableColumnDefinition, - }; -}; diff --git a/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging_service.ts b/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging_service.ts deleted file mode 100644 index 4440ee069d2bc..0000000000000 --- a/src/plugins/dashboard/public/services/saved_objects_tagging/saved_objects_tagging_service.ts +++ /dev/null @@ -1,51 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardSavedObjectsTaggingService } from './types'; - -export type SavedObjectsTaggingServiceFactory = KibanaPluginServiceFactory< - DashboardSavedObjectsTaggingService, - DashboardStartDependencies ->; -export const savedObjectsTaggingServiceFactory: SavedObjectsTaggingServiceFactory = ({ - startPlugins, -}) => { - const { savedObjectsTaggingOss } = startPlugins; - if (!savedObjectsTaggingOss) return { hasApi: false }; - - const { getTaggingApi } = savedObjectsTaggingOss; - const taggingApi = getTaggingApi(); - if (!taggingApi) return { hasApi: false }; - - const { - ui: { - components, - parseSearchQuery, - getSearchBarFilter, - updateTagsReferences, - getTagIdsFromReferences, - getTableColumnDefinition, - getTagList, - }, - } = taggingApi; - - return { - hasApi: true, - api: taggingApi, - components, - parseSearchQuery, - getSearchBarFilter, - updateTagsReferences, - getTagIdsFromReferences, - getTableColumnDefinition, - getTagList, - }; -}; diff --git a/src/plugins/dashboard/public/services/saved_objects_tagging/types.ts b/src/plugins/dashboard/public/services/saved_objects_tagging/types.ts deleted file mode 100644 index f08aa7c6c28f2..0000000000000 --- a/src/plugins/dashboard/public/services/saved_objects_tagging/types.ts +++ /dev/null @@ -1,22 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public'; - -export interface DashboardSavedObjectsTaggingService { - hasApi: boolean; // remove this once the entire service is optional - api?: SavedObjectsTaggingApi; - components?: SavedObjectsTaggingApi['ui']['components']; - parseSearchQuery?: SavedObjectsTaggingApi['ui']['parseSearchQuery']; - getSearchBarFilter?: SavedObjectsTaggingApi['ui']['getSearchBarFilter']; - updateTagsReferences?: SavedObjectsTaggingApi['ui']['updateTagsReferences']; - getTagIdsFromReferences?: SavedObjectsTaggingApi['ui']['getTagIdsFromReferences']; - getTableColumnDefinition?: SavedObjectsTaggingApi['ui']['getTableColumnDefinition']; - getTagList?: SavedObjectsTaggingApi['ui']['getTagList']; -} diff --git a/src/plugins/dashboard/public/services/screenshot_mode/screenshot_mode.stub.ts b/src/plugins/dashboard/public/services/screenshot_mode/screenshot_mode.stub.ts deleted file mode 100644 index ef7c6760b03f8..0000000000000 --- a/src/plugins/dashboard/public/services/screenshot_mode/screenshot_mode.stub.ts +++ /dev/null @@ -1,23 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { screenshotModePluginMock } from '@kbn/screenshot-mode-plugin/public/mocks'; -import { DashboardScreenshotModeService } from './types'; - -type ScreenshotModeServiceFactory = PluginServiceFactory; - -export const screenshotModeServiceFactory: ScreenshotModeServiceFactory = () => { - const pluginMock = screenshotModePluginMock.createStartContract(); - - return { - isScreenshotMode: pluginMock.isScreenshotMode, - getScreenshotContext: pluginMock.getScreenshotContext, - }; -}; diff --git a/src/plugins/dashboard/public/services/screenshot_mode/screenshot_mode_service.ts b/src/plugins/dashboard/public/services/screenshot_mode/screenshot_mode_service.ts deleted file mode 100644 index 2e7e160ce93fc..0000000000000 --- a/src/plugins/dashboard/public/services/screenshot_mode/screenshot_mode_service.ts +++ /dev/null @@ -1,27 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardScreenshotModeService } from './types'; - -export type ScreenshotModeServiceFactory = KibanaPluginServiceFactory< - DashboardScreenshotModeService, - DashboardStartDependencies ->; -export const screenshotModeServiceFactory: ScreenshotModeServiceFactory = ({ startPlugins }) => { - const { - screenshotMode: { isScreenshotMode, getScreenshotContext }, - } = startPlugins; - - return { - isScreenshotMode, - getScreenshotContext, - }; -}; diff --git a/src/plugins/dashboard/public/services/screenshot_mode/types.ts b/src/plugins/dashboard/public/services/screenshot_mode/types.ts deleted file mode 100644 index 464ca9134960a..0000000000000 --- a/src/plugins/dashboard/public/services/screenshot_mode/types.ts +++ /dev/null @@ -1,15 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { ScreenshotModePluginStart } from '@kbn/screenshot-mode-plugin/public'; - -export interface DashboardScreenshotModeService { - isScreenshotMode: ScreenshotModePluginStart['isScreenshotMode']; - getScreenshotContext: ScreenshotModePluginStart['getScreenshotContext']; -} diff --git a/src/plugins/dashboard/public/services/serverless/serverless_service.stub.ts b/src/plugins/dashboard/public/services/serverless/serverless_service.stub.ts deleted file mode 100644 index 09b8fea6e9c14..0000000000000 --- a/src/plugins/dashboard/public/services/serverless/serverless_service.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardServerlessService } from './types'; - -export type ServerlessServiceFactory = PluginServiceFactory; - -export const serverlessServiceFactory: ServerlessServiceFactory = () => { - return {}; -}; diff --git a/src/plugins/dashboard/public/services/serverless/serverless_service.ts b/src/plugins/dashboard/public/services/serverless/serverless_service.ts deleted file mode 100644 index c9991f1b7cfdc..0000000000000 --- a/src/plugins/dashboard/public/services/serverless/serverless_service.ts +++ /dev/null @@ -1,23 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardStartDependencies } from '../../plugin'; -import { DashboardServerlessService } from './types'; - -export type ServerlessServiceFactory = KibanaPluginServiceFactory< - DashboardServerlessService, - DashboardStartDependencies ->; - -export const serverlessServiceFactory: ServerlessServiceFactory = ({ startPlugins }) => { - const { serverless } = startPlugins; - - return { setBreadcrumbs: serverless?.setBreadcrumbs }; -}; diff --git a/src/plugins/dashboard/public/services/serverless/types.ts b/src/plugins/dashboard/public/services/serverless/types.ts deleted file mode 100644 index 8d6223fd0b46d..0000000000000 --- a/src/plugins/dashboard/public/services/serverless/types.ts +++ /dev/null @@ -1,14 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { ServerlessPluginStart } from '@kbn/serverless/public'; - -export interface DashboardServerlessService { - setBreadcrumbs?: ServerlessPluginStart['setBreadcrumbs']; -} diff --git a/src/plugins/dashboard/public/services/settings/settings.stub.ts b/src/plugins/dashboard/public/services/settings/settings.stub.ts deleted file mode 100644 index e71f83662aefa..0000000000000 --- a/src/plugins/dashboard/public/services/settings/settings.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; -import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; -import { DashboardSettingsService } from './types'; - -type SettingsServiceFactory = PluginServiceFactory; - -export const settingsServiceFactory: SettingsServiceFactory = () => { - return { - i18n: i18nServiceMock.createStartContract(), - uiSettings: uiSettingsServiceMock.createStartContract(), - theme: themeServiceMock.createStartContract(), - isProjectEnabledInLabs: jest.fn().mockReturnValue(true), - }; -}; diff --git a/src/plugins/dashboard/public/services/settings/settings_service.ts b/src/plugins/dashboard/public/services/settings/settings_service.ts deleted file mode 100644 index c21a9a4baec0b..0000000000000 --- a/src/plugins/dashboard/public/services/settings/settings_service.ts +++ /dev/null @@ -1,34 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardSettingsService } from './types'; - -export type SettingsServiceFactory = KibanaPluginServiceFactory< - DashboardSettingsService, - DashboardStartDependencies ->; - -export const settingsServiceFactory: SettingsServiceFactory = ({ coreStart, startPlugins }) => { - const { i18n, uiSettings, theme } = coreStart; - - const { - presentationUtil: { - labsService: { isProjectEnabled }, - }, - } = startPlugins; - - return { - i18n, - uiSettings, - theme, - isProjectEnabledInLabs: isProjectEnabled, - }; -}; diff --git a/src/plugins/dashboard/public/services/settings/types.ts b/src/plugins/dashboard/public/services/settings/types.ts deleted file mode 100644 index 475687988f880..0000000000000 --- a/src/plugins/dashboard/public/services/settings/types.ts +++ /dev/null @@ -1,18 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CoreStart } from '@kbn/core/public'; -import type { PresentationLabsService } from '@kbn/presentation-util-plugin/public'; - -export interface DashboardSettingsService { - uiSettings: CoreStart['uiSettings']; - i18n: CoreStart['i18n']; - theme: CoreStart['theme']; - isProjectEnabledInLabs: PresentationLabsService['isProjectEnabled']; -} diff --git a/src/plugins/dashboard/public/services/share/share.stub.ts b/src/plugins/dashboard/public/services/share/share.stub.ts deleted file mode 100644 index 3189e7cfd933a..0000000000000 --- a/src/plugins/dashboard/public/services/share/share.stub.ts +++ /dev/null @@ -1,23 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardShareService } from './types'; - -type ShareServiceFactory = PluginServiceFactory; - -export const shareServiceFactory: ShareServiceFactory = () => { - const pluginMock = sharePluginMock.createStartContract(); - - return { - url: pluginMock.url, - toggleShareContextMenu: pluginMock.toggleShareContextMenu, - }; -}; diff --git a/src/plugins/dashboard/public/services/share/share_services.ts b/src/plugins/dashboard/public/services/share/share_services.ts deleted file mode 100644 index 0e280c9ae8077..0000000000000 --- a/src/plugins/dashboard/public/services/share/share_services.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardShareService } from './types'; - -export type ShareServiceFactory = KibanaPluginServiceFactory< - DashboardShareService, - DashboardStartDependencies ->; - -export const shareServiceFactory: ShareServiceFactory = ({ startPlugins }) => { - const { share } = startPlugins; - if (!share) return {}; - - const { toggleShareContextMenu, url } = share; - - return { - url, - toggleShareContextMenu, - }; -}; diff --git a/src/plugins/dashboard/public/services/share/types.ts b/src/plugins/dashboard/public/services/share/types.ts deleted file mode 100644 index 8b21c741c1868..0000000000000 --- a/src/plugins/dashboard/public/services/share/types.ts +++ /dev/null @@ -1,15 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SharePluginStart } from '@kbn/share-plugin/public'; - -export interface DashboardShareService { - url?: SharePluginStart['url']; - toggleShareContextMenu?: SharePluginStart['toggleShareContextMenu']; -} diff --git a/src/plugins/dashboard/public/services/spaces/spaces.stub.ts b/src/plugins/dashboard/public/services/spaces/spaces.stub.ts deleted file mode 100644 index 6c85c6158dfe5..0000000000000 --- a/src/plugins/dashboard/public/services/spaces/spaces.stub.ts +++ /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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; -import { DashboardSpacesService } from './types'; - -type SpacesServiceFactory = PluginServiceFactory; - -export const spacesServiceFactory: SpacesServiceFactory = () => { - const pluginMock = spacesPluginMock.createStartContract(); - - return { - getActiveSpace$: pluginMock.getActiveSpace$, - getLegacyUrlConflict: pluginMock.ui.components.getLegacyUrlConflict, - redirectLegacyUrl: pluginMock.ui.redirectLegacyUrl, - }; -}; diff --git a/src/plugins/dashboard/public/services/spaces/spaces_service.ts b/src/plugins/dashboard/public/services/spaces/spaces_service.ts deleted file mode 100644 index 33df8d1db87d0..0000000000000 --- a/src/plugins/dashboard/public/services/spaces/spaces_service.ts +++ /dev/null @@ -1,34 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardSpacesService } from './types'; - -export type SpacesServiceFactory = KibanaPluginServiceFactory< - DashboardSpacesService, - DashboardStartDependencies ->; -export const spacesServiceFactory: SpacesServiceFactory = ({ startPlugins }) => { - const { spaces } = startPlugins; - if (!spaces || !spaces.ui) return {}; - - const { - getActiveSpace$, - ui: { - components: { getLegacyUrlConflict }, - redirectLegacyUrl, - }, - } = spaces; - return { - getActiveSpace$, - getLegacyUrlConflict, - redirectLegacyUrl, - }; -}; diff --git a/src/plugins/dashboard/public/services/spaces/types.ts b/src/plugins/dashboard/public/services/spaces/types.ts deleted file mode 100644 index 26330e6824339..0000000000000 --- a/src/plugins/dashboard/public/services/spaces/types.ts +++ /dev/null @@ -1,16 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; - -export interface DashboardSpacesService { - getActiveSpace$?: SpacesPluginStart['getActiveSpace$']; - getLegacyUrlConflict?: SpacesPluginStart['ui']['components']['getLegacyUrlConflict']; - redirectLegacyUrl?: SpacesPluginStart['ui']['redirectLegacyUrl']; -} diff --git a/src/plugins/dashboard/public/services/types.ts b/src/plugins/dashboard/public/services/types.ts deleted file mode 100644 index abfa5942d7a62..0000000000000 --- a/src/plugins/dashboard/public/services/types.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginInitializerContext } from '@kbn/core/public'; -import { KibanaPluginServiceParams } from '@kbn/presentation-util-plugin/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; -import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; - -import { DashboardStartDependencies } from '../plugin'; -import { DashboardAnalyticsService } from './analytics/types'; -import { DashboardApplicationService } from './application/types'; -import { DashboardChromeService } from './chrome/types'; -import { DashboardCoreContextService } from './core_context/types'; -import { DashboardCustomBrandingService } from './custom_branding/types'; -import { DashboardCapabilitiesService } from './dashboard_capabilities/types'; -import { DashboardContentManagementService } from './dashboard_content_management/types'; -import { DashboardBackupServiceType } from './dashboard_backup/types'; -import { DashboardDataService } from './data/types'; -import { DashboardDataViewEditorService } from './data_view_editor/types'; -import { DashboardDocumentationLinksService } from './documentation_links/types'; -import { DashboardEmbeddableService } from './embeddable/types'; -import { DashboardHTTPService } from './http/types'; -import { DashboardI18nService } from './i18n/types'; -import { DashboardInitializerContextService } from './initializer_context/types'; -import { DashboardNavigationService } from './navigation/types'; -import { DashboardNotificationsService } from './notifications/types'; -import { DashboardOverlaysService } from './overlays/types'; -import { DashboardSavedObjectsTaggingService } from './saved_objects_tagging/types'; -import { DashboardScreenshotModeService } from './screenshot_mode/types'; -import { DashboardSettingsService } from './settings/types'; -import { DashboardShareService } from './share/types'; -import { DashboardSpacesService } from './spaces/types'; -import { DashboardUrlForwardingService } from './url_forwarding/types'; -import { DashboardUsageCollectionService } from './usage_collection/types'; -import { DashboardVisualizationsService } from './visualizations/types'; -import { DashboardServerlessService } from './serverless/types'; -import { NoDataPageService } from './no_data_page/types'; -import { DashboardUiActionsService } from './ui_actions/types'; -import { ObservabilityAIAssistantService } from './observability_ai_assistant/types'; -import { DashboardUserProfileService } from './user_profile/types'; -import { DashboardRecentlyAccessedService } from './dashboard_recently_accessed/types'; -import { DashboardContentInsightsService } from './dashboard_content_insights/types'; -import { DashboardFavoritesService } from './dashboard_favorites/types'; - -export type DashboardPluginServiceParams = KibanaPluginServiceParams & { - initContext: PluginInitializerContext; // need a custom type so that initContext is a required parameter for initializerContext -}; -export interface DashboardServices { - dashboardBackup: DashboardBackupServiceType; - dashboardContentManagement: DashboardContentManagementService; - - analytics: DashboardAnalyticsService; - application: DashboardApplicationService; - chrome: DashboardChromeService; - coreContext: DashboardCoreContextService; - dashboardCapabilities: DashboardCapabilitiesService; - data: DashboardDataService; - dataViewEditor: DashboardDataViewEditorService; // this service is used only for the no data state - documentationLinks: DashboardDocumentationLinksService; - embeddable: DashboardEmbeddableService; - http: DashboardHTTPService; - i18n: DashboardI18nService; - initializerContext: DashboardInitializerContextService; - navigation: DashboardNavigationService; - notifications: DashboardNotificationsService; - overlays: DashboardOverlaysService; - savedObjectsTagging: DashboardSavedObjectsTaggingService; // TODO: make this optional in follow up - screenshotMode: DashboardScreenshotModeService; - settings: DashboardSettingsService; - share: DashboardShareService; // TODO: make this optional in follow up - spaces: DashboardSpacesService; // TODO: make this optional in follow up - urlForwarding: DashboardUrlForwardingService; - usageCollection: DashboardUsageCollectionService; // TODO: make this optional in follow up - visualizations: DashboardVisualizationsService; - customBranding: DashboardCustomBrandingService; - savedObjectsManagement: SavedObjectsManagementPluginStart; - contentManagement: ContentManagementPublicStart; - serverless: DashboardServerlessService; // TODO: make this optional in follow up - noDataPage: NoDataPageService; - uiActions: DashboardUiActionsService; - observabilityAIAssistant: ObservabilityAIAssistantService; // TODO: make this optional in follow up - userProfile: DashboardUserProfileService; - dashboardRecentlyAccessed: DashboardRecentlyAccessedService; - dashboardContentInsights: DashboardContentInsightsService; - dashboardFavorites: DashboardFavoritesService; -} diff --git a/src/plugins/dashboard/public/services/ui_actions/types.ts b/src/plugins/dashboard/public/services/ui_actions/types.ts deleted file mode 100644 index 94f931ba9fc1d..0000000000000 --- a/src/plugins/dashboard/public/services/ui_actions/types.ts +++ /dev/null @@ -1,14 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; - -export interface DashboardUiActionsService { - getTriggerCompatibleActions?: UiActionsStart['getTriggerCompatibleActions']; -} diff --git a/src/plugins/dashboard/public/services/ui_actions/ui_actions_service.stub.ts b/src/plugins/dashboard/public/services/ui_actions/ui_actions_service.stub.ts deleted file mode 100644 index 971b143933610..0000000000000 --- a/src/plugins/dashboard/public/services/ui_actions/ui_actions_service.stub.ts +++ /dev/null @@ -1,19 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardUiActionsService } from './types'; - -export type UIActionsServiceFactory = PluginServiceFactory; - -export const uiActionsServiceFactory: UIActionsServiceFactory = () => { - const pluginMock = uiActionsPluginMock.createStartContract(); - return { getTriggerCompatibleActions: pluginMock.getTriggerCompatibleActions }; -}; diff --git a/src/plugins/dashboard/public/services/ui_actions/ui_actions_service.ts b/src/plugins/dashboard/public/services/ui_actions/ui_actions_service.ts deleted file mode 100644 index 363082473df94..0000000000000 --- a/src/plugins/dashboard/public/services/ui_actions/ui_actions_service.ts +++ /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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardUiActionsService } from './types'; - -export type UsageCollectionServiceFactory = KibanaPluginServiceFactory< - DashboardUiActionsService, - DashboardStartDependencies ->; -export const uiActionsServiceFactory: UsageCollectionServiceFactory = ({ startPlugins }) => { - const { uiActions } = startPlugins; - if (!uiActions) return {}; - - const { getTriggerCompatibleActions } = uiActions; - return { - getTriggerCompatibleActions, - }; -}; diff --git a/src/plugins/dashboard/public/services/url_forwarding/types.ts b/src/plugins/dashboard/public/services/url_forwarding/types.ts deleted file mode 100644 index af032a10643a8..0000000000000 --- a/src/plugins/dashboard/public/services/url_forwarding/types.ts +++ /dev/null @@ -1,14 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; - -export interface DashboardUrlForwardingService { - navigateToLegacyKibanaUrl: UrlForwardingStart['navigateToLegacyKibanaUrl']; -} diff --git a/src/plugins/dashboard/public/services/url_forwarding/url_forwarding_service.ts b/src/plugins/dashboard/public/services/url_forwarding/url_forwarding_service.ts deleted file mode 100644 index 7ddc92b29c9e6..0000000000000 --- a/src/plugins/dashboard/public/services/url_forwarding/url_forwarding_service.ts +++ /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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardUrlForwardingService } from './types'; - -export type UrlForwardingServiceFactory = KibanaPluginServiceFactory< - DashboardUrlForwardingService, - DashboardStartDependencies ->; -export const urlForwardingServiceFactory: UrlForwardingServiceFactory = ({ startPlugins }) => { - const { - urlForwarding: { navigateToLegacyKibanaUrl }, - } = startPlugins; - - return { - navigateToLegacyKibanaUrl, - }; -}; diff --git a/src/plugins/dashboard/public/services/url_forwarding/url_fowarding.stub.ts b/src/plugins/dashboard/public/services/url_forwarding/url_fowarding.stub.ts deleted file mode 100644 index 29792e40fd27b..0000000000000 --- a/src/plugins/dashboard/public/services/url_forwarding/url_fowarding.stub.ts +++ /dev/null @@ -1,22 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { urlForwardingPluginMock } from '@kbn/url-forwarding-plugin/public/mocks'; -import { DashboardUrlForwardingService } from './types'; - -type UrlForwardingServiceFactory = PluginServiceFactory; - -export const urlForwardingServiceFactory: UrlForwardingServiceFactory = () => { - const pluginMock = urlForwardingPluginMock.createStartContract(); - - return { - navigateToLegacyKibanaUrl: pluginMock.navigateToLegacyKibanaUrl, - }; -}; diff --git a/src/plugins/dashboard/public/services/usage_collection/types.ts b/src/plugins/dashboard/public/services/usage_collection/types.ts deleted file mode 100644 index 3aaaccbe9d8a2..0000000000000 --- a/src/plugins/dashboard/public/services/usage_collection/types.ts +++ /dev/null @@ -1,14 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; - -export interface DashboardUsageCollectionService { - reportUiCounter?: UsageCollectionStart['reportUiCounter']; -} diff --git a/src/plugins/dashboard/public/services/usage_collection/usage_collection.stub.ts b/src/plugins/dashboard/public/services/usage_collection/usage_collection.stub.ts deleted file mode 100644 index 1d3a3d119a7f2..0000000000000 --- a/src/plugins/dashboard/public/services/usage_collection/usage_collection.stub.ts +++ /dev/null @@ -1,22 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { usageCollectionPluginMock } from '@kbn/usage-collection-plugin/public/mocks'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardUsageCollectionService } from './types'; - -type UsageCollectionServiceFactory = PluginServiceFactory; - -export const usageCollectionServiceFactory: UsageCollectionServiceFactory = () => { - const pluginMock = usageCollectionPluginMock.createSetupContract(); - - return { - reportUiCounter: pluginMock.reportUiCounter, - }; -}; diff --git a/src/plugins/dashboard/public/services/usage_collection/usage_collection_service.ts b/src/plugins/dashboard/public/services/usage_collection/usage_collection_service.ts deleted file mode 100644 index 1d95aa3c2c4b9..0000000000000 --- a/src/plugins/dashboard/public/services/usage_collection/usage_collection_service.ts +++ /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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardUsageCollectionService } from './types'; - -export type UsageCollectionServiceFactory = KibanaPluginServiceFactory< - DashboardUsageCollectionService, - DashboardStartDependencies ->; -export const usageCollectionServiceFactory: UsageCollectionServiceFactory = ({ startPlugins }) => { - const { usageCollection } = startPlugins; - if (!usageCollection) return {}; - - const { reportUiCounter } = usageCollection; - return { - reportUiCounter, - }; -}; diff --git a/src/plugins/dashboard/public/services/user_profile/types.ts b/src/plugins/dashboard/public/services/user_profile/types.ts deleted file mode 100644 index 0de4bed4479eb..0000000000000 --- a/src/plugins/dashboard/public/services/user_profile/types.ts +++ /dev/null @@ -1,14 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { CoreStart } from '@kbn/core/public'; - -export interface DashboardUserProfileService { - bulkGet: CoreStart['userProfile']['bulkGet']; -} diff --git a/src/plugins/dashboard/public/services/user_profile/user_profile_service.stub.ts b/src/plugins/dashboard/public/services/user_profile/user_profile_service.stub.ts deleted file mode 100644 index 37c20141deb62..0000000000000 --- a/src/plugins/dashboard/public/services/user_profile/user_profile_service.stub.ts +++ /dev/null @@ -1,18 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { userProfileServiceMock } from '@kbn/core-user-profile-browser-mocks'; -import { DashboardUserProfileService } from './types'; - -export type UserProfileServiceFactory = PluginServiceFactory; - -export const userProfileServiceFactory: UserProfileServiceFactory = () => { - return userProfileServiceMock.createStart(); -}; diff --git a/src/plugins/dashboard/public/services/user_profile/user_profile_service.ts b/src/plugins/dashboard/public/services/user_profile/user_profile_service.ts deleted file mode 100644 index d0585ff37d22f..0000000000000 --- a/src/plugins/dashboard/public/services/user_profile/user_profile_service.ts +++ /dev/null @@ -1,23 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { DashboardStartDependencies } from '../../plugin'; -import { DashboardUserProfileService } from './types'; - -export type UserProfileServiceFactory = KibanaPluginServiceFactory< - DashboardUserProfileService, - DashboardStartDependencies ->; - -export const userProfileServiceFactory: UserProfileServiceFactory = ({ coreStart }) => { - const { userProfile } = coreStart; - - return userProfile; -}; diff --git a/src/plugins/dashboard/public/services/visualizations/types.ts b/src/plugins/dashboard/public/services/visualizations/types.ts deleted file mode 100644 index 32a96c2cd183f..0000000000000 --- a/src/plugins/dashboard/public/services/visualizations/types.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { VisualizationsStart } from '@kbn/visualizations-plugin/public'; - -export interface DashboardVisualizationsService { - get: VisualizationsStart['get']; - getAliases: VisualizationsStart['getAliases']; - getByGroup: VisualizationsStart['getByGroup']; - showNewVisModal: VisualizationsStart['showNewVisModal']; -} diff --git a/src/plugins/dashboard/public/services/visualizations/visualizations.stub.ts b/src/plugins/dashboard/public/services/visualizations/visualizations.stub.ts deleted file mode 100644 index a149080963fa5..0000000000000 --- a/src/plugins/dashboard/public/services/visualizations/visualizations.stub.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { visualizationsPluginMock } from '@kbn/visualizations-plugin/public/mocks'; -import { DashboardVisualizationsService } from './types'; - -type HttpServiceFactory = PluginServiceFactory; - -export const visualizationsServiceFactory: HttpServiceFactory = () => { - const pluginMock = visualizationsPluginMock.createStartContract(); - - return { - get: pluginMock.get, - getAliases: pluginMock.getAliases, - getByGroup: pluginMock.getByGroup, - showNewVisModal: pluginMock.showNewVisModal, - }; -}; diff --git a/src/plugins/dashboard/public/services/visualizations/visualizations_service.ts b/src/plugins/dashboard/public/services/visualizations/visualizations_service.ts deleted file mode 100644 index c9aa8ed64f9c0..0000000000000 --- a/src/plugins/dashboard/public/services/visualizations/visualizations_service.ts +++ /dev/null @@ -1,30 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardVisualizationsService } from './types'; - -export type VisualizationsServiceFactory = KibanaPluginServiceFactory< - DashboardVisualizationsService, - DashboardStartDependencies ->; - -export const visualizationsServiceFactory: VisualizationsServiceFactory = ({ startPlugins }) => { - const { - visualizations: { get, getAliases, getByGroup, showNewVisModal }, - } = startPlugins; - - return { - get, - getAliases, - getByGroup, - showNewVisModal, - }; -}; diff --git a/src/plugins/dashboard/public/services/dashboard_capabilities/dashboard_capabilities_service.ts b/src/plugins/dashboard/public/utils/get_dashboard_capabilities.ts similarity index 56% rename from src/plugins/dashboard/public/services/dashboard_capabilities/dashboard_capabilities_service.ts rename to src/plugins/dashboard/public/utils/get_dashboard_capabilities.ts index 3909f839acb2f..083ca2fea43af 100644 --- a/src/plugins/dashboard/public/services/dashboard_capabilities/dashboard_capabilities_service.ts +++ b/src/plugins/dashboard/public/utils/get_dashboard_capabilities.ts @@ -7,31 +7,22 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import type { DashboardStartDependencies } from '../../plugin'; -import type { DashboardCapabilitiesService } from './types'; +import { DashboardCapabilities } from '../../common'; +import { coreServices } from '../services/kibana_services'; -export type DashboardCapabilitiesServiceFactory = KibanaPluginServiceFactory< - DashboardCapabilitiesService, - DashboardStartDependencies ->; -export const dashboardCapabilitiesServiceFactory: DashboardCapabilitiesServiceFactory = ({ - coreStart, -}) => { +export const getDashboardCapabilities = (): DashboardCapabilities => { const { application: { - capabilities: { dashboard, maps, visualize }, + capabilities: { dashboard }, }, - } = coreStart; + } = coreServices; return { show: Boolean(dashboard.show), saveQuery: Boolean(dashboard.saveQuery), createNew: Boolean(dashboard.createNew), - mapsCapabilities: { save: Boolean(maps?.save) }, createShortUrl: Boolean(dashboard.createShortUrl), showWriteControls: Boolean(dashboard.showWriteControls), - visualizeCapabilities: { save: Boolean(visualize?.save) }, storeSearchSession: Boolean(dashboard.storeSearchSession), }; }; diff --git a/src/plugins/dashboard/tsconfig.json b/src/plugins/dashboard/tsconfig.json index f289f4f725fe5..0f4059edfb0bf 100644 --- a/src/plugins/dashboard/tsconfig.json +++ b/src/plugins/dashboard/tsconfig.json @@ -41,14 +41,8 @@ "@kbn/core-application-browser", "@kbn/ebt-tools", "@kbn/shared-ux-button-exit-full-screen", - "@kbn/core-analytics-browser-mocks", - "@kbn/core-application-browser-mocks", "@kbn/analytics", "@kbn/safer-lodash-set", - "@kbn/core-notifications-browser-mocks", - "@kbn/core-overlays-browser-mocks", - "@kbn/core-theme-browser-mocks", - "@kbn/core-ui-settings-browser-mocks", "@kbn/task-manager-plugin", "@kbn/core-execution-context-common", "@kbn/core-custom-branding-browser", @@ -66,7 +60,6 @@ "@kbn/serverless", "@kbn/no-data-page-plugin", "@kbn/react-kibana-mount", - "@kbn/core-lifecycle-browser", "@kbn/logging", "@kbn/presentation-publishing", "@kbn/presentation-containers", @@ -75,9 +68,7 @@ "@kbn/shared-ux-utility", "@kbn/core-test-helpers-model-versions", "@kbn/deeplinks-analytics", - "@kbn/core-user-profile-browser-mocks", "@kbn/react-kibana-context-render", - "@kbn/core-i18n-browser-mocks", "@kbn/observability-ai-assistant-plugin", "@kbn/esql-utils", "@kbn/lens-embeddable-utils", @@ -87,7 +78,7 @@ "@kbn/content-management-content-insights-server", "@kbn/managed-content-badge", "@kbn/content-management-favorites-public", - "@kbn/core-http-browser-mocks", + "@kbn/core-custom-branding-browser-mocks", ], "exclude": ["target/**/*"] } diff --git a/src/plugins/links/jest_setup.ts b/src/plugins/links/jest_setup.ts index d573139bd6964..998abc0e9d9b7 100644 --- a/src/plugins/links/jest_setup.ts +++ b/src/plugins/links/jest_setup.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { setStubDashboardServices } from '@kbn/dashboard-plugin/public/services/mocks'; +import { setStubKibanaServices as setStubDashboardServices } from '@kbn/dashboard-plugin/public/services/mocks'; import { setStubKibanaServices } from './public/mocks'; setStubKibanaServices(); diff --git a/x-pack/plugins/observability_solution/apm/public/hooks/use_dashboards_fetcher.ts b/x-pack/plugins/observability_solution/apm/public/hooks/use_dashboards_fetcher.ts index c463d07276a3a..8b1ccf301ae38 100644 --- a/x-pack/plugins/observability_solution/apm/public/hooks/use_dashboards_fetcher.ts +++ b/x-pack/plugins/observability_solution/apm/public/hooks/use_dashboards_fetcher.ts @@ -7,7 +7,7 @@ import { useState, useEffect } from 'react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { SearchDashboardsResponse } from '@kbn/dashboard-plugin/public/services/dashboard_content_management/lib/find_dashboards'; +import { SearchDashboardsResponse } from '@kbn/dashboard-plugin/public'; import { ApmPluginStartDeps } from '../plugin'; import { FETCH_STATUS } from './use_fetcher'; diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_dashboards_fetcher.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_dashboards_fetcher.ts index 0035fbc0a5889..c6be0f59efd05 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_dashboards_fetcher.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_dashboards_fetcher.ts @@ -6,7 +6,7 @@ */ import { useState, useEffect } from 'react'; -import type { SearchDashboardsResponse } from '@kbn/dashboard-plugin/public/services/dashboard_content_management/lib/find_dashboards'; +import type { SearchDashboardsResponse } from '@kbn/dashboard-plugin/public'; import { i18n } from '@kbn/i18n'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { FETCH_STATUS } from '../../../hooks/use_fetcher'; From 1c0ec85b740789ba99c30f09a5b56bc66a9de897 Mon Sep 17 00:00:00 2001 From: Garrett Spong Date: Thu, 26 Sep 2024 12:17:50 -0600 Subject: [PATCH 2/4] [Security Assistant] Add support for manually entering eval datasets (#194072) ## Summary On cloud environments we don't send the LangSmith credentials through the `GET /evaluate` route which returns available datasets for selection, so the datasets are never populated. Since the Dataset field didn't allow custom options, this means you couldn't perform evals in cloud environments. This PR updates the Dataset field to take custom options so that you can manually enter the dataset name in cloud environments:

To test, enable the below feature flag to show the evaluation tab under settings: ``` xpack.securitySolution.enableExperimental: - "assistantModelEvaluation" ``` --- .../evaluation_settings/evaluation_settings.tsx | 15 +++++++++++++++ .../settings/evaluation_settings/translations.ts | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx index 319ee812a3cf3..cefc008eba992 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx @@ -95,6 +95,20 @@ export const EvaluationSettings: React.FC = React.memo(() => { }, [setSelectedDatasetOptions] ); + const onDatasetCreateOption = useCallback( + (searchValue: string) => { + const normalizedSearchValue = searchValue.trim().toLowerCase(); + if (!normalizedSearchValue) { + return; + } + const newOption = { + label: searchValue, + }; + + setSelectedDatasetOptions([newOption]); + }, + [setSelectedDatasetOptions] + ); // Predictions // Connectors / Models @@ -244,6 +258,7 @@ export const EvaluationSettings: React.FC = React.memo(() => { options={datasetOptions} selectedOptions={selectedDatasetOptions} onChange={onDatasetOptionsChange} + onCreateOption={onDatasetCreateOption} compressed={true} /> diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts index b1adb6296b2a1..62902d0f14095 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts @@ -163,7 +163,8 @@ export const EVALUATOR_DATASET_LABEL = i18n.translate( export const LANGSMITH_DATASET_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langsmithDatasetDescription', { - defaultMessage: 'Name of dataset hosted on LangSmith to evaluate.', + defaultMessage: + 'Name of dataset hosted on LangSmith to evaluate. Must manually enter on cloud environments.', } ); From 4591aa28e54110359e2e67dbafd5e78253c76932 Mon Sep 17 00:00:00 2001 From: Jon Date: Thu, 26 Sep 2024 13:25:40 -0500 Subject: [PATCH 3/4] Reapply "[workflows] Add condition to if backport:skip event (#194158)" (#194192) This reverts commit 1992a394438da98f4295c3dc07cd30af9aa74746. Reapply's #194158 without the extraneous semicolon. Tested at https://github.com/jbudz/test-github-actions/actions/runs/11056774576 --- .github/workflows/on-merge.yml | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/.github/workflows/on-merge.yml b/.github/workflows/on-merge.yml index 14f94571d551f..b41d04bf85174 100644 --- a/.github/workflows/on-merge.yml +++ b/.github/workflows/on-merge.yml @@ -10,21 +10,23 @@ jobs: name: 'Label and Backport' runs-on: ubuntu-latest if: | - github.event.pull_request.merged == true - && ( - ( - github.event.action == 'labeled' && ( - github.event.label.name == 'backport:prev-minor' - || github.event.label.name == 'backport:prev-major' - || github.event.label.name == 'backport:current-major' - || github.event.label.name == 'backport:all-open' - || github.event.label.name == 'backport:version' - || github.event.label.name == 'auto-backport' - ) - ) - || (github.event.action == 'unlabeled' && github.event.label.name == 'backport:skip') - || (github.event.action == 'closed') - ) + github.event.pull_request.merged == true && + (github.event.action == 'closed' || + (github.event.action == 'labeled' && + (github.event.label.name == 'backport:prev-minor' || + github.event.label.name == 'backport:prev-major' || + github.event.label.name == 'backport:current-major' || + github.event.label.name == 'backport:all-open' || + github.event.label.name == 'backport:version' || + github.event.label.name == 'auto-backport')) || + (github.event.action == 'unlabeled' && + github.event.label.name == 'backport:skip' && + (contains(github.event.pull_request.labels.*.name, 'backport:prev-minor') || + contains(github.event.pull_request.labels.*.name, 'backport:prev-major') || + contains(github.event.pull_request.labels.*.name, 'backport:current-major') || + contains(github.event.pull_request.labels.*.name, 'backport:all-open') || + contains(github.event.pull_request.labels.*.name, 'backport:version') || + contains(github.event.pull_request.labels.*.name, 'auto-backport')))) steps: - name: Checkout Actions uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 From f8416b892744ced1864404670a51e501237446c3 Mon Sep 17 00:00:00 2001 From: Elena Shostak <165678770+elena-shostak@users.noreply.github.com> Date: Thu, 26 Sep 2024 20:44:11 +0200 Subject: [PATCH 4/4] [Spaces] Filtering out features that do not have space scope (#194157) ## Summary Filtering out features that do not have space scope in `create_space_page` ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios __Fixes: https://github.com/elastic/kibana/issues/194134__ ## Release Note Filtering out features that do not have space scope in `create_space_page` --- .../create_space/create_space_page.test.tsx | 58 +++++++++++++++++++ .../create_space/create_space_page.tsx | 11 +++- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/spaces/public/management/create_space/create_space_page.test.tsx b/x-pack/plugins/spaces/public/management/create_space/create_space_page.test.tsx index 4c8617ff007b8..757e882bf741c 100644 --- a/x-pack/plugins/spaces/public/management/create_space/create_space_page.test.tsx +++ b/x-pack/plugins/spaces/public/management/create_space/create_space_page.test.tsx @@ -14,6 +14,7 @@ import { act } from 'react-dom/test-utils'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public'; import { notificationServiceMock, scopedHistoryMock } from '@kbn/core/public/mocks'; +import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import { KibanaFeature } from '@kbn/features-plugin/public'; import { featuresPluginMock } from '@kbn/features-plugin/public/mocks'; import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers'; @@ -48,6 +49,15 @@ featuresStart.getFeatures.mockResolvedValue([ app: [], category: DEFAULT_APP_CATEGORIES.kibana, privileges: null, + scope: [KibanaFeatureScope.Spaces, KibanaFeatureScope.Security], + }), + new KibanaFeature({ + id: 'feature-2', + name: 'feature 2', + app: [], + category: DEFAULT_APP_CATEGORIES.kibana, + privileges: null, + scope: [KibanaFeatureScope.Security], }), ]); @@ -641,6 +651,54 @@ describe('ManageSpacePage', () => { expect(spacesManager.updateSpace).toHaveBeenCalledTimes(1); }); + + it('shows only features with space scope', async () => { + const spacesManager = spacesManagerMock.create(); + spacesManager.getSpace = jest.fn().mockResolvedValue({ + id: 'my-space', + name: 'Existing Space', + description: 'hey an existing space', + color: '#aabbcc', + initials: 'AB', + disabledFeatures: [], + }); + spacesManager.getActiveSpace = jest.fn().mockResolvedValue(space); + + const wrapper = mountWithIntl( + + ); + + await waitFor(() => { + wrapper.update(); + expect(spacesManager.getSpace).toHaveBeenCalledWith('my-space'); + }); + + expect(wrapper.state('features')).toEqual([ + new KibanaFeature({ + id: 'feature-1', + name: 'feature 1', + app: [], + category: DEFAULT_APP_CATEGORIES.kibana, + privileges: null, + scope: [KibanaFeatureScope.Spaces, KibanaFeatureScope.Security], + }), + ]); + }); }); function updateSpace( diff --git a/x-pack/plugins/spaces/public/management/create_space/create_space_page.tsx b/x-pack/plugins/spaces/public/management/create_space/create_space_page.tsx index e8204a53fe345..ed0e52edd6c4b 100644 --- a/x-pack/plugins/spaces/public/management/create_space/create_space_page.tsx +++ b/x-pack/plugins/spaces/public/management/create_space/create_space_page.tsx @@ -22,6 +22,7 @@ import React, { Component } from 'react'; import type { Capabilities, NotificationsStart, ScopedHistory } from '@kbn/core/public'; import { SectionLoading } from '@kbn/es-ui-shared-plugin/public'; +import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import type { FeaturesPluginStart, KibanaFeature } from '@kbn/features-plugin/public'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -91,6 +92,10 @@ export class CreateSpacePage extends Component { }; } + private filterSpaceFeatures = (features: KibanaFeature[]) => { + return features.filter((feature) => feature.scope?.includes(KibanaFeatureScope.Spaces)); + }; + public async componentDidMount() { if (!this.props.capabilities.spaces.manage) { return; @@ -103,7 +108,8 @@ export class CreateSpacePage extends Component { await this.loadSpace(spaceId, getFeatures()); } else { const features = await getFeatures(); - this.setState({ isLoading: false, features }); + + this.setState({ isLoading: false, features: this.filterSpaceFeatures(features) }); } } catch (e) { notifications.toasts.addError(e, { @@ -410,6 +416,7 @@ export class CreateSpacePage extends Component { spacesManager.getSpace(spaceId), featuresPromise, ]); + if (space) { if (onLoadSpace) { onLoadSpace(space); @@ -426,7 +433,7 @@ export class CreateSpacePage extends Component { !!space.initials && getSpaceInitials({ name: space.name }) !== space.initials, customAvatarColor: !!space.color && getSpaceColor({ name: space.name }) !== space.color, }, - features, + features: this.filterSpaceFeatures(features), originalSpace: space, isLoading: false, });