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 ""