diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 911bfb5161dc0..6189270654c7b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -517,6 +517,7 @@ x-pack/plugins/monitoring @elastic/infra-monitoring-ui src/plugins/navigation @elastic/appex-sharedux src/plugins/newsfeed @elastic/kibana-core test/common/plugins/newsfeed @elastic/kibana-core +src/plugins/no_data_page @elastic/appex-sharedux x-pack/plugins/notifications @elastic/appex-sharedux packages/kbn-object-versioning @elastic/appex-sharedux x-pack/plugins/observability_ai_assistant @elastic/obs-ai-assistant diff --git a/config/serverless.es.yml b/config/serverless.es.yml index 8ee07c718cce0..7a1da782855bd 100644 --- a/config/serverless.es.yml +++ b/config/serverless.es.yml @@ -32,3 +32,6 @@ telemetry.labels.serverless: search # Alerts config xpack.actions.enabledActionTypes: ['.email', '.index', '.slack', '.jira', '.webhook', '.teams'] + +# Customize empty page state for analytics apps +no_data_page.analyticsNoDataPageFlavor: 'serverless_search' diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index e8c008af6e0e8..41aecaccf554c 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -254,6 +254,10 @@ It also provides a stateful version of it on the start contract. Content is fetched from the remote (https://feeds.elastic.co) once a day, with periodic checks if the content needs to be refreshed. All newsfeed content is hosted remotely. +|{kib-repo}blob/{branch}/src/plugins/no_data_page/README.md[noDataPage] +|Helps to globally configure the no data page components + + |{kib-repo}blob/{branch}/src/plugins/presentation_util/README.mdx[presentationUtil] |The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). diff --git a/package.json b/package.json index a1c0e7d000ed9..657329a4bb6a8 100644 --- a/package.json +++ b/package.json @@ -535,6 +535,7 @@ "@kbn/navigation-plugin": "link:src/plugins/navigation", "@kbn/newsfeed-plugin": "link:src/plugins/newsfeed", "@kbn/newsfeed-test-plugin": "link:test/common/plugins/newsfeed", + "@kbn/no-data-page-plugin": "link:src/plugins/no_data_page", "@kbn/notifications-plugin": "link:x-pack/plugins/notifications", "@kbn/object-versioning": "link:packages/kbn-object-versioning", "@kbn/observability-ai-assistant-plugin": "link:x-pack/plugins/observability_ai_assistant", diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 536b3f883cac6..dc07f316c5244 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -96,6 +96,7 @@ pageLoadAssetSize: monitoring: 80000 navigation: 37269 newsfeed: 42228 + noDataPage: 5000 observability: 115443 observabilityAIAssistant: 25000 observabilityOnboarding: 19573 diff --git a/packages/shared-ux/card/no_data/impl/src/no_data_card.tsx b/packages/shared-ux/card/no_data/impl/src/no_data_card.tsx index 22126c6b335e0..2fd29d42224ee 100644 --- a/packages/shared-ux/card/no_data/impl/src/no_data_card.tsx +++ b/packages/shared-ux/card/no_data/impl/src/no_data_card.tsx @@ -35,7 +35,9 @@ export const NoDataCard = ({ href: srcHref, category, description, ...props }: P return ( - + ); }; diff --git a/packages/shared-ux/card/no_data/types/index.d.ts b/packages/shared-ux/card/no_data/types/index.d.ts index 5b2a0b090ffe2..e52843b160639 100644 --- a/packages/shared-ux/card/no_data/types/index.d.ts +++ b/packages/shared-ux/card/no_data/types/index.d.ts @@ -79,4 +79,4 @@ export type NoDataCardComponentProps = Partial< /** * Props for the `NoDataCard` sevice-connected component. */ -export type NoDataCardProps = Omit; +export type NoDataCardProps = NoDataCardComponentProps; diff --git a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.test.tsx b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.test.tsx index 1f657f642fc47..4e16dd6c38bc0 100644 --- a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.test.tsx +++ b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.test.tsx @@ -10,7 +10,10 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { mountWithIntl } from '@kbn/test-jest-helpers'; +import { I18nProvider } from '@kbn/i18n-react'; + import { KibanaNoDataPage } from '@kbn/shared-ux-page-kibana-no-data'; +import { render, screen } from '@testing-library/react'; import { AnalyticsNoDataPage } from './analytics_no_data_page.component'; import { AnalyticsNoDataPageProvider } from './services'; @@ -28,6 +31,7 @@ describe('AnalyticsNoDataPageComponent', () => { onDataViewCreated={onDataViewCreated} kibanaGuideDocLink={'http://www.test.com'} showPlainSpinner={false} + prependBasePath={(path: string) => path} /> ); @@ -52,6 +56,7 @@ describe('AnalyticsNoDataPageComponent', () => { kibanaGuideDocLink={'http://www.test.com'} allowAdHocDataView={true} showPlainSpinner={false} + prependBasePath={(path: string) => path} /> ); @@ -61,4 +66,86 @@ describe('AnalyticsNoDataPageComponent', () => { expect(component.find(KibanaNoDataPage).length).toBe(1); expect(component.find(KibanaNoDataPage).props().allowAdHocDataView).toBe(true); }); + + describe('no data state', () => { + describe('kibana flavor', () => { + it('renders add integrations card', async () => { + render( + + false }}> + path} + /> + + + ); + + await screen.findByTestId('kbnOverviewAddIntegrations'); + await screen.getAllByText('Add integrations'); + }); + + it('renders disabled add integrations card when fleet is not available', async () => { + render( + + false, canAccessFleet: false }} + > + path} + /> + + + ); + + await screen.findByTestId('kbnOverviewAddIntegrations'); + await screen.getByText('Contact your administrator'); + }); + }); + + describe('serverless_search flavor', () => { + it('renders getting started card', async () => { + render( + + false }}> + path} + /> + + + ); + + await screen.findByTestId('kbnOverviewElasticsearchGettingStarted'); + }); + + it('renders the same getting started card when fleet is not available', async () => { + render( + + false, canAccessFleet: false }} + > + path} + pageFlavor={'serverless_search'} + /> + + + ); + + await screen.findByTestId('kbnOverviewElasticsearchGettingStarted'); + }); + }); + }); }); diff --git a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.tsx b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.tsx index d67cb082f5539..4c22a0acb2475 100644 --- a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.tsx +++ b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.component.tsx @@ -8,6 +8,8 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { KibanaNoDataPage } from '@kbn/shared-ux-page-kibana-no-data'; +import { KibanaNoDataPageProps } from '@kbn/shared-ux-page-kibana-no-data-types'; +import { AnalyticsNoDataPageFlavor } from '@kbn/shared-ux-page-analytics-no-data-types'; /** * Props for the pure component. @@ -21,26 +23,63 @@ export interface Props { allowAdHocDataView?: boolean; /** if the kibana instance is customly branded */ showPlainSpinner: boolean; + /** The flavor of the empty page to use. */ + pageFlavor?: AnalyticsNoDataPageFlavor; + prependBasePath: (path: string) => string; } -const solution = i18n.translate('sharedUXPackages.noDataConfig.analytics', { - defaultMessage: 'Analytics', -}); - -const pageTitle = i18n.translate('sharedUXPackages.noDataConfig.analyticsPageTitle', { - defaultMessage: 'Welcome to Analytics!', -}); - -const addIntegrationsTitle = i18n.translate('sharedUXPackages.noDataConfig.addIntegrationsTitle', { - defaultMessage: 'Add integrations', -}); - -const addIntegrationsDescription = i18n.translate( - 'sharedUXPackages.noDataConfig.addIntegrationsDescription', - { - defaultMessage: 'Use Elastic Agent to collect data and build out Analytics solutions.', - } -); +const flavors: { + [K in AnalyticsNoDataPageFlavor]: (deps: { + kibanaGuideDocLink: string; + prependBasePath: (path: string) => string; + }) => KibanaNoDataPageProps['noDataConfig']; +} = { + kibana: ({ kibanaGuideDocLink }) => ({ + solution: i18n.translate('sharedUXPackages.noDataConfig.analytics', { + defaultMessage: 'Analytics', + }), + pageTitle: i18n.translate('sharedUXPackages.noDataConfig.analyticsPageTitle', { + defaultMessage: 'Welcome to Analytics!', + }), + logo: 'logoKibana', + action: { + elasticAgent: { + title: i18n.translate('sharedUXPackages.noDataConfig.addIntegrationsTitle', { + defaultMessage: 'Add integrations', + }), + description: i18n.translate('sharedUXPackages.noDataConfig.addIntegrationsDescription', { + defaultMessage: 'Use Elastic Agent to collect data and build out Analytics solutions.', + }), + 'data-test-subj': 'kbnOverviewAddIntegrations', + }, + }, + docsLink: kibanaGuideDocLink, + }), + serverless_search: ({ prependBasePath }) => ({ + solution: i18n.translate('sharedUXPackages.noDataConfig.elasticsearch', { + defaultMessage: 'Elasticsearch', + }), + pageTitle: i18n.translate('sharedUXPackages.noDataConfig.elasticsearchPageTitle', { + defaultMessage: 'Welcome to Elasticsearch!', + }), + logo: 'logoElasticsearch', + action: { + elasticsearch: { + title: i18n.translate('sharedUXPackages.noDataConfig.elasticsearchTitle', { + defaultMessage: 'Get started', + }), + description: i18n.translate('sharedUXPackages.noDataConfig.elasticsearchDescription', { + defaultMessage: + 'Set up your programming language client, ingest some data, and start searching.', + }), + 'data-test-subj': 'kbnOverviewElasticsearchGettingStarted', + href: prependBasePath('/app/elasticsearch/'), + /** force the no data card to be shown **/ + canAccessFleet: true, + }, + }, + }), +}; /** * A pure component of an entire page that can be displayed when Kibana "has no data", specifically for Analytics. @@ -50,20 +89,13 @@ export const AnalyticsNoDataPage = ({ onDataViewCreated, allowAdHocDataView, showPlainSpinner, + prependBasePath, + pageFlavor = 'kibana', }: Props) => { - const noDataConfig = { - solution, - pageTitle, - logo: 'logoKibana', - action: { - elasticAgent: { - title: addIntegrationsTitle, - description: addIntegrationsDescription, - 'data-test-subj': 'kbnOverviewAddIntegrations', - }, - }, - docsLink: kibanaGuideDocLink, - }; + const noDataConfig: KibanaNoDataPageProps['noDataConfig'] = flavors[pageFlavor]({ + kibanaGuideDocLink, + prependBasePath, + }); return ( { expect(component.find(Component).props().kibanaGuideDocLink).toBe(services.kibanaGuideDocLink); expect(component.find(Component).props().onDataViewCreated).toBe(onDataViewCreated); expect(component.find(Component).props().allowAdHocDataView).toBe(true); + expect(component.find(Component).props().prependBasePath).toBe(services.prependBasePath); + expect(component.find(Component).props().pageFlavor).toBe(services.pageFlavor); }); it('passes correct boolean value to showPlainSpinner', () => { diff --git a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.tsx b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.tsx index 9b600c374dd02..e9d3ee318d3fd 100644 --- a/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.tsx +++ b/packages/shared-ux/page/analytics_no_data/impl/src/analytics_no_data_page.tsx @@ -21,7 +21,7 @@ export const AnalyticsNoDataPage = ({ allowAdHocDataView, }: AnalyticsNoDataPageProps) => { const services = useServices(); - const { kibanaGuideDocLink, customBranding } = services; + const { kibanaGuideDocLink, customBranding, prependBasePath, pageFlavor } = services; const { hasCustomBranding$ } = customBranding; const showPlainSpinner = useObservable(hasCustomBranding$) ?? false; @@ -32,6 +32,8 @@ export const AnalyticsNoDataPage = ({ allowAdHocDataView, kibanaGuideDocLink, showPlainSpinner, + prependBasePath, + pageFlavor, }} /> ); diff --git a/packages/shared-ux/page/analytics_no_data/impl/src/services.tsx b/packages/shared-ux/page/analytics_no_data/impl/src/services.tsx index 991893aeca501..4d514ba032ec9 100644 --- a/packages/shared-ux/page/analytics_no_data/impl/src/services.tsx +++ b/packages/shared-ux/page/analytics_no_data/impl/src/services.tsx @@ -27,10 +27,10 @@ export const AnalyticsNoDataPageProvider: FC = ({ children, ...services }) => { - const { kibanaGuideDocLink, customBranding } = services; + const { kibanaGuideDocLink, customBranding, prependBasePath, pageFlavor } = services; return ( - + {children} ); @@ -48,6 +48,8 @@ export const AnalyticsNoDataPageKibanaProvider: FC diff --git a/packages/shared-ux/page/analytics_no_data/impl/tsconfig.json b/packages/shared-ux/page/analytics_no_data/impl/tsconfig.json index 6a78f24dff0f7..4b9192a9fd714 100644 --- a/packages/shared-ux/page/analytics_no_data/impl/tsconfig.json +++ b/packages/shared-ux/page/analytics_no_data/impl/tsconfig.json @@ -19,6 +19,8 @@ "@kbn/shared-ux-page-analytics-no-data-types", "@kbn/test-jest-helpers", "@kbn/shared-ux-page-analytics-no-data-mocks", + "@kbn/shared-ux-page-kibana-no-data-types", + "@kbn/i18n-react", ], "exclude": [ "target/**/*", diff --git a/packages/shared-ux/page/analytics_no_data/mocks/src/jest.ts b/packages/shared-ux/page/analytics_no_data/mocks/src/jest.ts index 98885d55ba47d..f45d0f72ffed9 100644 --- a/packages/shared-ux/page/analytics_no_data/mocks/src/jest.ts +++ b/packages/shared-ux/page/analytics_no_data/mocks/src/jest.ts @@ -15,6 +15,8 @@ export const getServicesMock = () => { ...getKibanaNoDataPageServicesMock(), kibanaGuideDocLink: 'Kibana guide', customBranding: { hasCustomBranding$: of(false) }, + prependBasePath: (path) => path, + pageFlavor: 'kibana', }; return services; @@ -26,6 +28,8 @@ export const getServicesMockCustomBranding = () => { // this mock will have custom branding set to true customBranding: { hasCustomBranding$: of(true) }, kibanaGuideDocLink: 'Kibana guide', + prependBasePath: (path) => path, + pageFlavor: 'kibana', }; return services; diff --git a/packages/shared-ux/page/analytics_no_data/mocks/src/storybook.ts b/packages/shared-ux/page/analytics_no_data/mocks/src/storybook.ts index 86bf25dbde9e9..6bb3f07e34a87 100644 --- a/packages/shared-ux/page/analytics_no_data/mocks/src/storybook.ts +++ b/packages/shared-ux/page/analytics_no_data/mocks/src/storybook.ts @@ -51,6 +51,8 @@ export class StorybookMock extends AbstractStorybookMock< customBranding: { hasCustomBranding$: of(false), }, + pageFlavor: 'kibana', + prependBasePath: (path) => path, ...kibanaNoDataMock.getServices(params), }; } diff --git a/packages/shared-ux/page/analytics_no_data/types/index.d.ts b/packages/shared-ux/page/analytics_no_data/types/index.d.ts index 4e54315f071dd..f292e297b6fdc 100644 --- a/packages/shared-ux/page/analytics_no_data/types/index.d.ts +++ b/packages/shared-ux/page/analytics_no_data/types/index.d.ts @@ -17,6 +17,8 @@ import { Observable } from 'rxjs'; export interface Services { kibanaGuideDocLink: string; customBranding: { hasCustomBranding$: Observable }; + prependBasePath: (path: string) => string; + pageFlavor: AnalyticsNoDataPageFlavor; } /** @@ -24,6 +26,8 @@ export interface Services { */ export type AnalyticsNoDataPageServices = Services & KibanaNoDataPageServices; +export type AnalyticsNoDataPageFlavor = 'kibana' | 'serverless_search'; + export interface KibanaDependencies { coreStart: { docLinks: { @@ -36,6 +40,14 @@ export interface KibanaDependencies { customBranding: { hasCustomBranding$: Observable; }; + http: { + basePath: { + prepend: (path: string) => string; + }; + }; + }; + noDataPage?: { + getAnalyticsNoDataPageFlavor: () => AnalyticsNoDataPageFlavor; }; } diff --git a/packages/shared-ux/page/no_data/impl/src/no_data_page.tsx b/packages/shared-ux/page/no_data/impl/src/no_data_page.tsx index 1ba9b18049e87..5aec81d942de6 100644 --- a/packages/shared-ux/page/no_data/impl/src/no_data_page.tsx +++ b/packages/shared-ux/page/no_data/impl/src/no_data_page.tsx @@ -33,13 +33,13 @@ export const NoDataPage = ({ values: { solution }, }); - const link = ( + const link = docsLink ? ( - ); + ) : null; - const message = ( + const message = link ? ( + ) : ( + ); return ( diff --git a/packages/shared-ux/page/no_data/types/index.d.ts b/packages/shared-ux/page/no_data/types/index.d.ts index 3db9e80c950c9..6f29e5ab08d7a 100644 --- a/packages/shared-ux/page/no_data/types/index.d.ts +++ b/packages/shared-ux/page/no_data/types/index.d.ts @@ -31,9 +31,9 @@ export interface NoDataPageProps extends CommonProps, ActionCardProps { */ solution: string; /** - * Required to set the docs link for the whole solution + * Required in "kibana" flavor to set the docs link for the whole solution, otherwise optional */ - docsLink: string; + docsLink?: string; /** * Optionally replace the auto-generated logo */ diff --git a/src/plugins/dashboard/kibana.jsonc b/src/plugins/dashboard/kibana.jsonc index c22d68173deb6..0f8601cb96c5d 100644 --- a/src/plugins/dashboard/kibana.jsonc +++ b/src/plugins/dashboard/kibana.jsonc @@ -34,7 +34,8 @@ "screenshotMode", "usageCollection", "taskManager", - "serverless" + "serverless", + "noDataPage" ], "requiredBundles": ["kibanaReact", "kibanaUtils", "presentationUtil"] } 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 fb04a3187c72c..8580ae2f168d3 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 @@ -26,6 +26,7 @@ export const DashboardAppNoDataPage = ({ http: { basePath }, documentationLinks: { indexPatternsDocLink, kibanaGuideDocLink }, customBranding, + noDataPage, } = pluginServices.getServices(); const analyticsServices = { @@ -44,6 +45,7 @@ export const DashboardAppNoDataPage = ({ }, dataViews, dataViewEditor, + noDataPage, }; return ( diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index a28dbe9c45ae7..d2802a8ef3b6d 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -52,6 +52,7 @@ import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plu import type { UrlForwardingSetup, UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; +import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; import { CustomBrandingStart } from '@kbn/core-custom-branding-browser'; import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; @@ -108,6 +109,7 @@ export interface DashboardStartDependencies { visualizations: VisualizationsStart; customBranding: CustomBrandingStart; serverless?: ServerlessPluginStart; + noDataPage?: NoDataPagePluginStart; } export interface DashboardSetup { diff --git a/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.stub.ts b/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.stub.ts new file mode 100644 index 0000000000000..c1af1452176a8 --- /dev/null +++ b/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.stub.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; +import { NoDataPageService } from './types'; + +export type NoDataPageServiceFactory = PluginServiceFactory; + +export const noDataPageServiceFactory: NoDataPageServiceFactory = () => { + return { getAnalyticsNoDataPageFlavor: () => 'kibana' }; +}; diff --git a/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.ts b/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.ts new file mode 100644 index 0000000000000..f1dded3f12ff3 --- /dev/null +++ b/src/plugins/dashboard/public/services/no_data_page/no_data_page_service.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; +import { DashboardStartDependencies } from '../../plugin'; +import { NoDataPageService } from './types'; + +export type NoDataPageServiceFactory = KibanaPluginServiceFactory< + NoDataPageService, + DashboardStartDependencies +>; + +export const noDataPageServiceFactory: NoDataPageServiceFactory = ({ startPlugins }) => { + const { noDataPage } = startPlugins; + + return { + getAnalyticsNoDataPageFlavor: noDataPage?.getAnalyticsNoDataPageFlavor ?? (() => 'kibana'), + }; +}; diff --git a/src/plugins/dashboard/public/services/no_data_page/types.ts b/src/plugins/dashboard/public/services/no_data_page/types.ts new file mode 100644 index 0000000000000..7e87f1586db33 --- /dev/null +++ b/src/plugins/dashboard/public/services/no_data_page/types.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; + +export interface NoDataPageService { + getAnalyticsNoDataPageFlavor: NoDataPagePluginStart['getAnalyticsNoDataPageFlavor']; +} diff --git a/src/plugins/dashboard/public/services/plugin_services.stub.ts b/src/plugins/dashboard/public/services/plugin_services.stub.ts index 0ae4159ed2128..8ba55d486d75b 100644 --- a/src/plugins/dashboard/public/services/plugin_services.stub.ts +++ b/src/plugins/dashboard/public/services/plugin_services.stub.ts @@ -42,6 +42,7 @@ import { customBrandingServiceFactory } from './custom_branding/custom_branding. import { savedObjectsManagementServiceFactory } from './saved_objects_management/saved_objects_management_service.stub'; import { contentManagementServiceFactory } from './content_management/content_management_service.stub'; import { serverlessServiceFactory } from './serverless/serverless_service.stub'; +import { noDataPageServiceFactory } from './no_data_page/no_data_page_service.stub'; export const providers: PluginServiceProviders = { dashboardContentManagement: new PluginServiceProvider(dashboardContentManagementServiceFactory), @@ -72,6 +73,7 @@ export const providers: PluginServiceProviders = { savedObjectsManagement: new PluginServiceProvider(savedObjectsManagementServiceFactory), contentManagement: new PluginServiceProvider(contentManagementServiceFactory), serverless: new PluginServiceProvider(serverlessServiceFactory), + noDataPage: new PluginServiceProvider(noDataPageServiceFactory), }; export const registry = new PluginServiceRegistry(providers); diff --git a/src/plugins/dashboard/public/services/plugin_services.ts b/src/plugins/dashboard/public/services/plugin_services.ts index d84b55d0ff4a1..f16b4c8f34b0e 100644 --- a/src/plugins/dashboard/public/services/plugin_services.ts +++ b/src/plugins/dashboard/public/services/plugin_services.ts @@ -43,6 +43,7 @@ import { savedObjectsManagementServiceFactory } from './saved_objects_management import { dashboardContentManagementServiceFactory } from './dashboard_content_management/dashboard_content_management_service'; import { contentManagementServiceFactory } from './content_management/content_management_service'; import { serverlessServiceFactory } from './serverless/serverless_service'; +import { noDataPageServiceFactory } from './no_data_page/no_data_page_service'; const providers: PluginServiceProviders = { dashboardContentManagement: new PluginServiceProvider(dashboardContentManagementServiceFactory, [ @@ -86,6 +87,7 @@ const providers: PluginServiceProviders(); diff --git a/src/plugins/dashboard/public/services/types.ts b/src/plugins/dashboard/public/services/types.ts index 13adaf6098070..5ad3aab951121 100644 --- a/src/plugins/dashboard/public/services/types.ts +++ b/src/plugins/dashboard/public/services/types.ts @@ -38,6 +38,7 @@ import { DashboardUrlForwardingService } from './url_forwarding/types'; import { DashboardUsageCollectionService } from './usage_collection/types'; import { DashboardVisualizationsService } from './visualizations/types'; import { DashboardServerlessService } from './serverless/types'; +import { NoDataPageService } from './no_data_page/types'; export type DashboardPluginServiceParams = KibanaPluginServiceParams & { initContext: PluginInitializerContext; // need a custom type so that initContext is a required parameter for initializerContext @@ -72,4 +73,5 @@ export interface DashboardServices { savedObjectsManagement: SavedObjectsManagementPluginStart; contentManagement: ContentManagementPublicStart; serverless: DashboardServerlessService; // TODO: make this optional in follow up + noDataPage: NoDataPageService; } diff --git a/src/plugins/dashboard/tsconfig.json b/src/plugins/dashboard/tsconfig.json index 9d5dafa47c88a..31cc2b1aab236 100644 --- a/src/plugins/dashboard/tsconfig.json +++ b/src/plugins/dashboard/tsconfig.json @@ -64,7 +64,8 @@ "@kbn/content-management-table-list-view-table", "@kbn/shared-ux-prompt-not-found", "@kbn/content-management-content-editor", - "@kbn/serverless" + "@kbn/serverless", + "@kbn/no-data-page-plugin" ], "exclude": ["target/**/*"] } diff --git a/src/plugins/discover/kibana.jsonc b/src/plugins/discover/kibana.jsonc index 1c6ffaae833cb..3da4912dd5661 100644 --- a/src/plugins/discover/kibana.jsonc +++ b/src/plugins/discover/kibana.jsonc @@ -26,7 +26,7 @@ "expressions", "unifiedSearch", "unifiedHistogram", - "contentManagement", + "contentManagement" ], "optionalPlugins": [ "home", @@ -36,7 +36,8 @@ "triggersActionsUi", "savedObjectsTaggingOss", "lens", - "serverless" + "serverless", + "noDataPage" ], "requiredBundles": ["kibanaUtils", "kibanaReact", "unifiedSearch"], "extraPublicDirs": ["common"] diff --git a/src/plugins/discover/public/application/main/discover_main_route.tsx b/src/plugins/discover/public/application/main/discover_main_route.tsx index cf62f96ca7d1a..febda09ebb939 100644 --- a/src/plugins/discover/public/application/main/discover_main_route.tsx +++ b/src/plugins/discover/public/application/main/discover_main_route.tsx @@ -48,11 +48,7 @@ export interface MainRouteProps { mode?: DiscoverDisplayMode; } -export function DiscoverMainRoute({ - customizationCallbacks, - isDev, - mode = 'standalone', -}: MainRouteProps) { +export function DiscoverMainRoute({ customizationCallbacks, mode = 'standalone' }: MainRouteProps) { const history = useHistory(); const services = useDiscoverServices(); const { @@ -109,7 +105,7 @@ export function DiscoverMainRoute({ const hasUserDataViewValue = await data.dataViews.hasData .hasUserDataView() .catch(() => false); - const hasESDataValue = isDev || (await data.dataViews.hasData.hasESData().catch(() => false)); + const hasESDataValue = await data.dataViews.hasData.hasESData().catch(() => false); setHasUserDataView(hasUserDataViewValue); setHasESData(hasESDataValue); @@ -134,7 +130,7 @@ export function DiscoverMainRoute({ setError(e); return false; } - }, [data.dataViews, isDev, savedSearchId]); + }, [data.dataViews, savedSearchId]); const loadSavedSearch = useCallback( async (nextDataView?: DataView) => { @@ -256,11 +252,12 @@ export function DiscoverMainRoute({ // We've already called this, so we can optimize the analytics services to // use the already-retrieved data to avoid a double-call. - hasESData: () => Promise.resolve(isDev ? true : hasESData), + hasESData: () => Promise.resolve(hasESData), hasUserDataView: () => Promise.resolve(hasUserDataView), }, }, dataViewEditor, + noDataPage: services.noDataPage, }; return ( diff --git a/src/plugins/discover/public/build_services.ts b/src/plugins/discover/public/build_services.ts index 254292e6d07e6..65cd9c06e84c7 100644 --- a/src/plugins/discover/public/build_services.ts +++ b/src/plugins/discover/public/build_services.ts @@ -53,6 +53,7 @@ import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { SettingsStart } from '@kbn/core-ui-settings-browser'; import type { ContentClient } from '@kbn/content-management-plugin/public'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; +import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; import { getHistory } from './kibana_services'; import { DiscoverStartPlugins } from './plugin'; import { DiscoverContextAppLocator } from './application/context/services/locator'; @@ -111,6 +112,7 @@ export interface DiscoverServices { uiActions: UiActionsStart; contentClient: ContentClient; serverless?: ServerlessPluginStart; + noDataPage?: NoDataPagePluginStart; } export const buildServices = memoize(function ( @@ -171,5 +173,6 @@ export const buildServices = memoize(function ( uiActions: plugins.uiActions, contentClient: plugins.contentManagement.client, serverless: plugins.serverless, + noDataPage: plugins.noDataPage, }; }); diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index 6db46f53c35fb..c3b92275d3956 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -46,6 +46,7 @@ import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; import { DOC_TABLE_LEGACY, TRUNCATE_MAX_HEIGHT } from '@kbn/discover-utils'; +import { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; import { PLUGIN_ID } from '../common'; import { DocViewInput, DocViewInputFn } from './services/doc_views/doc_views_types'; import { DocViewsRegistry } from './services/doc_views/doc_views_registry'; @@ -213,6 +214,7 @@ export interface DiscoverStartPlugins { lens: LensPublicStart; contentManagement: ContentManagementPublicStart; serverless?: ServerlessPluginStart; + noDataPage?: NoDataPagePluginStart; } /** diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index df92ba4c9070c..8e93218385709 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -70,7 +70,8 @@ "@kbn/content-management-plugin", "@kbn/serverless", "@kbn/react-kibana-mount", - "@kbn/react-kibana-context-render" + "@kbn/react-kibana-context-render", + "@kbn/no-data-page-plugin" ], "exclude": [ "target/**/*" diff --git a/src/plugins/no_data_page/README.md b/src/plugins/no_data_page/README.md new file mode 100755 index 0000000000000..a516e3274ff3f --- /dev/null +++ b/src/plugins/no_data_page/README.md @@ -0,0 +1,3 @@ +# No Data Page + +Helps to globally configure the no data page components diff --git a/src/plugins/no_data_page/config.ts b/src/plugins/no_data_page/config.ts new file mode 100644 index 0000000000000..8fae1aad10aaa --- /dev/null +++ b/src/plugins/no_data_page/config.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema, TypeOf, offeringBasedSchema } from '@kbn/config-schema'; + +export const configSchema = schema.object({ + analyticsNoDataPageFlavor: offeringBasedSchema({ + serverless: schema.oneOf( + [schema.oneOf([schema.literal('kibana'), schema.literal('serverless_search')])], + { defaultValue: 'kibana' as const } + ), + }), +}); +export type NoDataPageConfig = TypeOf; diff --git a/src/plugins/no_data_page/jest.config.js b/src/plugins/no_data_page/jest.config.js new file mode 100644 index 0000000000000..546031bc12414 --- /dev/null +++ b/src/plugins/no_data_page/jest.config.js @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/src/plugins/no_data_page'], + coverageDirectory: '/target/kibana-coverage/jest/src/plugins/no_data_page', + coverageReporters: ['text', 'html'], + collectCoverageFrom: ['/src/plugins/no_data_page/{common,public,server}/**/*.{ts,tsx}'], +}; diff --git a/src/plugins/no_data_page/kibana.jsonc b/src/plugins/no_data_page/kibana.jsonc new file mode 100644 index 0000000000000..202917173b7a4 --- /dev/null +++ b/src/plugins/no_data_page/kibana.jsonc @@ -0,0 +1,10 @@ +{ + "type": "plugin", + "id": "@kbn/no-data-page-plugin", + "owner": "@elastic/appex-sharedux", + "plugin": { + "id": "noDataPage", + "server": true, + "browser": true + } +} diff --git a/src/plugins/no_data_page/public/index.ts b/src/plugins/no_data_page/public/index.ts new file mode 100644 index 0000000000000..28dfcd6044403 --- /dev/null +++ b/src/plugins/no_data_page/public/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PluginInitializerContext } from '@kbn/core-plugins-browser'; +import { NoDataPagePlugin } from './plugin'; + +export function plugin(ctx: PluginInitializerContext) { + return new NoDataPagePlugin(ctx); +} + +export type { NoDataPagePluginSetup, NoDataPagePluginStart } from './types'; diff --git a/src/plugins/no_data_page/public/plugin.ts b/src/plugins/no_data_page/public/plugin.ts new file mode 100644 index 0000000000000..740f796f4f395 --- /dev/null +++ b/src/plugins/no_data_page/public/plugin.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; +import type { NoDataPagePluginSetup, NoDataPagePluginStart } from './types'; +import type { NoDataPageConfig } from '../config'; + +export class NoDataPagePlugin implements Plugin { + constructor(private initializerContext: PluginInitializerContext) {} + + public setup(core: CoreSetup): NoDataPagePluginSetup { + return { + getAnalyticsNoDataPageFlavor: () => { + return this.initializerContext.config.get().analyticsNoDataPageFlavor; + }, + }; + } + + public start(core: CoreStart): NoDataPagePluginStart { + return { + getAnalyticsNoDataPageFlavor: () => { + return this.initializerContext.config.get().analyticsNoDataPageFlavor; + }, + }; + } +} diff --git a/src/plugins/no_data_page/public/types.ts b/src/plugins/no_data_page/public/types.ts new file mode 100644 index 0000000000000..c9523f7fcd93a --- /dev/null +++ b/src/plugins/no_data_page/public/types.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export interface NoDataPagePluginSetup { + getAnalyticsNoDataPageFlavor: () => 'kibana' | 'serverless_search'; +} + +export type NoDataPagePluginStart = NoDataPagePluginSetup; diff --git a/src/plugins/no_data_page/server/index.ts b/src/plugins/no_data_page/server/index.ts new file mode 100644 index 0000000000000..ba02a016a9676 --- /dev/null +++ b/src/plugins/no_data_page/server/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PluginConfigDescriptor } from '@kbn/core-plugins-server'; + +import { configSchema, NoDataPageConfig } from '../config'; + +export const config: PluginConfigDescriptor = { + exposeToBrowser: { + analyticsNoDataPageFlavor: true, + }, + schema: configSchema, +}; + +export function plugin() { + return new (class NoDataPagePlugin { + setup() {} + start() {} + })(); +} diff --git a/src/plugins/no_data_page/tsconfig.json b/src/plugins/no_data_page/tsconfig.json new file mode 100644 index 0000000000000..bab1c8c23edfb --- /dev/null +++ b/src/plugins/no_data_page/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": ["common/**/*", "public/**/*", "server/**/*", "config.ts"], + "kbn_references": [ + "@kbn/core", + "@kbn/core-plugins-browser", + "@kbn/core-plugins-server", + "@kbn/config-schema", + ], + "exclude": ["target/**/*"] +} diff --git a/src/plugins/visualizations/kibana.jsonc b/src/plugins/visualizations/kibana.jsonc index 22c6bd9dd32b2..69caa82b50030 100644 --- a/src/plugins/visualizations/kibana.jsonc +++ b/src/plugins/visualizations/kibana.jsonc @@ -34,7 +34,8 @@ "share", "spaces", "savedObjectsTaggingOss", - "serverless" + "serverless", + "noDataPage" ], "requiredBundles": [ "kibanaUtils", diff --git a/src/plugins/visualizations/public/plugin.ts b/src/plugins/visualizations/public/plugin.ts index 3ca1672159f24..d2805b43ed468 100644 --- a/src/plugins/visualizations/public/plugin.ts +++ b/src/plugins/visualizations/public/plugin.ts @@ -64,6 +64,7 @@ import { ContentManagementPublicSetup, ContentManagementPublicStart, } from '@kbn/content-management-plugin/public'; +import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; import type { TypesSetup, TypesStart } from './vis_types'; import type { VisualizeServices } from './visualize_app/types'; import { @@ -166,6 +167,7 @@ export interface VisualizationsStartDeps { savedObjectsManagement: SavedObjectsManagementPluginStart; contentManagement: ContentManagementPublicStart; serverless?: ServerlessPluginStart; + noDataPage?: NoDataPagePluginStart; } /** @@ -330,6 +332,7 @@ export class VisualizationsPlugin listingViewRegistry, unifiedSearch: pluginsStart.unifiedSearch, serverless: pluginsStart.serverless, + noDataPage: pluginsStart.noDataPage, }; params.element.classList.add('visAppWrapper'); diff --git a/src/plugins/visualizations/public/visualize_app/app.tsx b/src/plugins/visualizations/public/visualize_app/app.tsx index 70dd288fccaec..c7c73893eb438 100644 --- a/src/plugins/visualizations/public/visualize_app/app.tsx +++ b/src/plugins/visualizations/public/visualize_app/app.tsx @@ -14,6 +14,7 @@ import { EuiLoadingSpinner } from '@elastic/eui'; import { AppMountParameters, CoreStart } from '@kbn/core/public'; import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import { syncGlobalQueryStateWithUrl } from '@kbn/data-plugin/public'; +import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { AnalyticsNoDataPageKibanaProvider, @@ -38,6 +39,7 @@ interface NoDataComponentProps { dataViews: DataViewsContract; dataViewEditor: DataViewEditorStart; onDataViewCreated: (dataView: unknown) => void; + noDataPage?: NoDataPagePluginStart; } const NoDataComponent = ({ @@ -45,11 +47,13 @@ const NoDataComponent = ({ dataViews, dataViewEditor, onDataViewCreated, + noDataPage, }: NoDataComponentProps) => { const analyticsServices = { coreStart: core, dataViews, dataViewEditor, + noDataPage, }; return ( @@ -65,6 +69,7 @@ export const VisualizeApp = ({ onAppLeave }: VisualizeAppProps) => { core, kbnUrlStateStorage, dataViewEditor, + noDataPage, }, } = useKibana(); const { pathname } = useLocation(); @@ -125,6 +130,7 @@ export const VisualizeApp = ({ onAppLeave }: VisualizeAppProps) => { dataViewEditor={dataViewEditor} dataViews={dataViews} onDataViewCreated={onDataViewCreated} + noDataPage={noDataPage} /> ); } diff --git a/src/plugins/visualizations/public/visualize_app/types.ts b/src/plugins/visualizations/public/visualize_app/types.ts index 90806f138f9b6..77f743aaeef77 100644 --- a/src/plugins/visualizations/public/visualize_app/types.ts +++ b/src/plugins/visualizations/public/visualize_app/types.ts @@ -41,6 +41,7 @@ import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public'; import type { SavedSearch, SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; +import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; import type { Vis, VisualizeEmbeddableContract, @@ -117,6 +118,7 @@ export interface VisualizeServices extends CoreStart { listingViewRegistry: ListingViewRegistry; unifiedSearch: UnifiedSearchPublicPluginStart; serverless?: ServerlessPluginStart; + noDataPage?: NoDataPagePluginStart; } export interface VisInstance { diff --git a/src/plugins/visualizations/tsconfig.json b/src/plugins/visualizations/tsconfig.json index c72d4fd24d7ea..e643d9fa1fd61 100644 --- a/src/plugins/visualizations/tsconfig.json +++ b/src/plugins/visualizations/tsconfig.json @@ -62,7 +62,8 @@ "@kbn/content-management-tabbed-table-list-view", "@kbn/content-management-table-list-view", "@kbn/content-management-utils", - "@kbn/serverless" + "@kbn/serverless", + "@kbn/no-data-page-plugin" ], "exclude": [ "target/**/*", diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 6e0c4be2faaec..03928a378f6f3 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -145,6 +145,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'newsfeed.mainInterval (duration)', 'newsfeed.service.pathTemplate (string)', 'newsfeed.service.urlRoot (string)', + 'no_data_page.analyticsNoDataPageFlavor (any)', // It's a string (any because schema.conditional) 'telemetry.allowChangingOptInStatus (boolean)', 'telemetry.appendServerlessChannelsSuffix (any)', // It's a boolean (any because schema.conditional) 'telemetry.banner (boolean)', diff --git a/tsconfig.base.json b/tsconfig.base.json index cf7d73b7a5a9c..2efdd91c53d3b 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1028,6 +1028,8 @@ "@kbn/newsfeed-plugin/*": ["src/plugins/newsfeed/*"], "@kbn/newsfeed-test-plugin": ["test/common/plugins/newsfeed"], "@kbn/newsfeed-test-plugin/*": ["test/common/plugins/newsfeed/*"], + "@kbn/no-data-page-plugin": ["src/plugins/no_data_page"], + "@kbn/no-data-page-plugin/*": ["src/plugins/no_data_page/*"], "@kbn/notifications-plugin": ["x-pack/plugins/notifications"], "@kbn/notifications-plugin/*": ["x-pack/plugins/notifications/*"], "@kbn/object-versioning": ["packages/kbn-object-versioning"], diff --git a/x-pack/test_serverless/functional/test_suites/search/empty_page.ts b/x-pack/test_serverless/functional/test_suites/search/empty_page.ts new file mode 100644 index 0000000000000..9808bb69bbeb6 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/empty_page.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getPageObject, getService }: FtrProviderContext) { + const svlSearchNavigation = getService('svlSearchNavigation'); + const testSubjects = getService('testSubjects'); + const svlCommonNavigation = getPageObject('svlCommonNavigation'); + + describe('empty pages', function () { + before(async () => { + await svlSearchNavigation.navigateToLandingPage(); + }); + + it('should show search specific empty page in discover', async () => { + await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'discover' }); + await testSubjects.existOrFail('kbnOverviewElasticsearchGettingStarted'); + await testSubjects.click('kbnOverviewElasticsearchGettingStarted'); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Getting started' }); + }); + + it('should show search specific empty page in visualize', async () => { + await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'visualize' }); + await testSubjects.existOrFail('kbnOverviewElasticsearchGettingStarted'); + await testSubjects.click('kbnOverviewElasticsearchGettingStarted'); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Getting started' }); + }); + + it('should show search specific empty page in dashboards', async () => { + await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'dashboards' }); + await testSubjects.existOrFail('kbnOverviewElasticsearchGettingStarted'); + await testSubjects.click('kbnOverviewElasticsearchGettingStarted'); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Getting started' }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/search/index.ts b/x-pack/test_serverless/functional/test_suites/search/index.ts index 9a3f5de27f16c..e4e3021ef8143 100644 --- a/x-pack/test_serverless/functional/test_suites/search/index.ts +++ b/x-pack/test_serverless/functional/test_suites/search/index.ts @@ -10,6 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('serverless search UI', function () { loadTestFile(require.resolve('./landing_page')); + loadTestFile(require.resolve('./empty_page')); loadTestFile(require.resolve('./navigation')); loadTestFile(require.resolve('./cases/attachment_framework')); }); diff --git a/yarn.lock b/yarn.lock index 774ec13a90362..b3a342acb0eef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4962,6 +4962,10 @@ version "0.0.0" uid "" +"@kbn/no-data-page-plugin@link:src/plugins/no_data_page": + version "0.0.0" + uid "" + "@kbn/notifications-plugin@link:x-pack/plugins/notifications": version "0.0.0" uid ""