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
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,
});