diff --git a/package.json b/package.json index 0cf2676cdc172..510dcfaf8081a 100644 --- a/package.json +++ b/package.json @@ -211,6 +211,7 @@ "@kbn/shared-ux-avatar-solution": "link:bazel-bin/packages/shared-ux/avatar/solution", "@kbn/shared-ux-button-exit-full-screen": "link:bazel-bin/packages/shared-ux/button/exit_full_screen", "@kbn/shared-ux-button-toolbar": "link:bazel-bin/packages/shared-ux/button_toolbar", + "@kbn/shared-ux-card-no-data": "link:bazel-bin/packages/shared-ux/card/no_data", "@kbn/shared-ux-components": "link:bazel-bin/packages/kbn-shared-ux-components", "@kbn/shared-ux-link-redirect-app": "link:bazel-bin/packages/shared-ux/link/redirect_app", "@kbn/shared-ux-page-analytics-no-data": "link:bazel-bin/packages/shared-ux/page/analytics_no_data", @@ -751,6 +752,7 @@ "@types/kbn__shared-ux-avatar-solution": "link:bazel-bin/packages/shared-ux/avatar/solution/npm_module_types", "@types/kbn__shared-ux-button-exit-full-screen": "link:bazel-bin/packages/shared-ux/button/exit_full_screen/npm_module_types", "@types/kbn__shared-ux-button-toolbar": "link:bazel-bin/packages/shared-ux/button_toolbar/npm_module_types", + "@types/kbn__shared-ux-card-no-data": "link:bazel-bin/packages/shared-ux/card/no_data/npm_module_types", "@types/kbn__shared-ux-components": "link:bazel-bin/packages/kbn-shared-ux-components/npm_module_types", "@types/kbn__shared-ux-link-redirect-app": "link:bazel-bin/packages/shared-ux/link/redirect_app/npm_module_types", "@types/kbn__shared-ux-page-analytics-no-data": "link:bazel-bin/packages/shared-ux/page/analytics_no_data/npm_module_types", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index cc5c0e13dcccf..6c65af1a97e91 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -146,6 +146,7 @@ filegroup( "//packages/shared-ux/avatar/solution:build", "//packages/shared-ux/button_toolbar:build", "//packages/shared-ux/button/exit_full_screen:build", + "//packages/shared-ux/card/no_data:build", "//packages/shared-ux/link/redirect_app:build", "//packages/shared-ux/page/analytics_no_data:build", "//packages/shared-ux/page/kibana_no_data:build", @@ -279,6 +280,7 @@ filegroup( "//packages/shared-ux/avatar/solution:build_types", "//packages/shared-ux/button_toolbar:build_types", "//packages/shared-ux/button/exit_full_screen:build_types", + "//packages/shared-ux/card/no_data:build_types", "//packages/shared-ux/link/redirect_app:build_types", "//packages/shared-ux/page/analytics_no_data:build_types", "//packages/shared-ux/page/kibana_no_data:build_types", diff --git a/packages/kbn-shared-ux-components/BUILD.bazel b/packages/kbn-shared-ux-components/BUILD.bazel index 1a4a7100ded72..20d71557fef9a 100644 --- a/packages/kbn-shared-ux-components/BUILD.bazel +++ b/packages/kbn-shared-ux-components/BUILD.bazel @@ -45,6 +45,7 @@ RUNTIME_DEPS = [ "//packages/shared-ux/avatar/solution", "//packages/shared-ux/link/redirect_app", "//packages/shared-ux/prompt/no_data_views", + "//packages/shared-ux/card/no_data", "//packages/kbn-shared-ux-services", "//packages/kbn-shared-ux-storybook", "//packages/kbn-shared-ux-utility", @@ -74,6 +75,7 @@ TYPES_DEPS = [ "//packages/shared-ux/avatar/solution:npm_module_types", "//packages/shared-ux/link/redirect_app:npm_module_types", "//packages/shared-ux/prompt/no_data_views:npm_module_types", + "//packages/shared-ux/card/no_data:npm_module_types", "//packages/kbn-shared-ux-services:npm_module_types", "//packages/kbn-shared-ux-storybook:npm_module_types", "//packages/kbn-shared-ux-utility:npm_module_types", diff --git a/packages/kbn-shared-ux-components/src/page_template/index.ts b/packages/kbn-shared-ux-components/src/page_template/index.ts index 671f720972fc9..cd7d6232d9a8b 100644 --- a/packages/kbn-shared-ux-components/src/page_template/index.ts +++ b/packages/kbn-shared-ux-components/src/page_template/index.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -export { NoDataCard, ElasticAgentCard, NoDataPage, NoDataConfigPage } from './no_data_page'; +export { NoDataPage, NoDataConfigPage } from './no_data_page'; export { KibanaPageTemplate } from './page_template'; export type { KibanaPageTemplateProps } from './types'; export type { NoDataPageProps } from './no_data_page'; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/__snapshots__/no_data_page.test.tsx.snap b/packages/kbn-shared-ux-components/src/page_template/no_data_page/__snapshots__/no_data_page.test.tsx.snap deleted file mode 100644 index 5fd29bc57b331..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/__snapshots__/no_data_page.test.tsx.snap +++ /dev/null @@ -1,55 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`NoDataPage render 1`] = ` -
- - - -

- Welcome to Elastic Analytics! -

- -

- - - , - "solution": "Analytics", - } - } - /> -

-
-
- - -
-`; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/index.ts b/packages/kbn-shared-ux-components/src/page_template/no_data_page/index.ts index 894097727cd1f..a6f8c91f7614c 100644 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/index.ts +++ b/packages/kbn-shared-ux-components/src/page_template/no_data_page/index.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -export { NoDataCard, ElasticAgentCard } from './no_data_card'; export { NoDataPage } from './no_data_page'; export type { NoDataPageProps } from './types'; export { NoDataConfigPage, NoDataConfigPageWithSolutionNavBar } from './no_data_config_page'; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.component.test.tsx.snap b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.component.test.tsx.snap deleted file mode 100644 index c871196b92282..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.component.test.tsx.snap +++ /dev/null @@ -1,104 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ElasticAgentCardComponent props button 1`] = ` - - } - title="Add Elastic Agent" -/> -`; - -exports[`ElasticAgentCardComponent props href 1`] = ` - - } - title="Add Elastic Agent" -/> -`; - -exports[`ElasticAgentCardComponent renders 1`] = ` - - } - title="Add Elastic Agent" -/> -`; - -exports[`ElasticAgentCardComponent renders with canAccessFleet false 1`] = ` - - This integration is not yet enabled. Your administrator has the required permissions to turn it on. - - } - image={ - - } - isDisabled={true} - title={ - - Contact your administrator - - } -/> -`; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap deleted file mode 100644 index dbdb652a10c1f..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap +++ /dev/null @@ -1,75 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ElasticAgentCard renders 1`] = ` -
-
-
-
-
- -
-
-
-
- - - - Add Elastic Agent - - - -
-

- Use Elastic Agent for a simple, unified way to collect data from your machines. -

-
-
- -
-
-`; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/__snapshots__/no_data_card.test.tsx.snap b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/__snapshots__/no_data_card.test.tsx.snap deleted file mode 100644 index 0028d505e9187..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/__snapshots__/no_data_card.test.tsx.snap +++ /dev/null @@ -1,231 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`NoDataCard props button 1`] = ` -
-
- - - Card title - - -
-

- Description -

-
-
- -
-`; - -exports[`NoDataCard props extends EuiCardProps 1`] = ` -
-
- - - Card title - - -
-

- Description -

-
-
- -
-`; - -exports[`NoDataCard props href 1`] = ` -
-
- - - - Card title - - - -
-

- Description -

-
-
- -
-`; - -exports[`NoDataCard props isDisabled 1`] = ` -
-
- - - -
-

- Description -

-
-
-
-`; - -exports[`NoDataCard renders 1`] = ` -
-
- - - Card title - - -
-

- Description -

-
-
- -
-`; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.component.test.tsx b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.component.test.tsx deleted file mode 100644 index 367fcd10b96a9..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.component.test.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { shallow } from 'enzyme'; -import React from 'react'; -import { ElasticAgentCardComponent } from './elastic_agent_card.component'; -import { NoDataCard } from './no_data_card'; - -describe('ElasticAgentCardComponent', () => { - test('renders', () => { - const component = shallow(); - expect(component).toMatchSnapshot(); - }); - - test('renders with canAccessFleet false', () => { - const component = shallow(); - expect(component.find(NoDataCard).props().isDisabled).toBe(true); - expect(component).toMatchSnapshot(); - }); - - describe('props', () => { - test('button', () => { - const component = shallow( - - ); - expect(component.find(NoDataCard).props().button).toBe('Button'); - expect(component).toMatchSnapshot(); - }); - - test('href', () => { - const component = shallow( - - ); - expect(component.find(NoDataCard).props().href).toBe('some path'); - expect(component).toMatchSnapshot(); - }); - }); -}); diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.component.tsx b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.component.tsx deleted file mode 100644 index 31d0aad7cc631..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.component.tsx +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { FunctionComponent } from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiImage, EuiTextColor } from '@elastic/eui'; -import { ElasticAgentCardProps } from './types'; -import { NoDataCard } from './no_data_card'; -import ElasticAgentCardIllustration from './assets/elastic_agent_card.svg'; - -export type ElasticAgentCardComponentProps = ElasticAgentCardProps & { - canAccessFleet: boolean; -}; - -const noPermissionTitle = i18n.translate( - 'sharedUXComponents.noDataPage.elasticAgentCard.noPermission.title', - { - defaultMessage: `Contact your administrator`, - } -); - -const noPermissionDescription = i18n.translate( - 'sharedUXComponents.noDataPage.elasticAgentCard.noPermission.description', - { - defaultMessage: `This integration is not yet enabled. Your administrator has the required permissions to turn it on.`, - } -); - -const elasticAgentCardTitle = i18n.translate( - 'sharedUXComponents.noDataPage.elasticAgentCard.title', - { - defaultMessage: 'Add Elastic Agent', - } -); - -const elasticAgentCardDescription = i18n.translate( - 'sharedUXComponents.noDataPage.elasticAgentCard.description', - { - defaultMessage: `Use Elastic Agent for a simple, unified way to collect data from your machines.`, - } -); - -/** - * Creates a specific NoDataCard pointing users to Integrations when `canAccessFleet` - */ -export const ElasticAgentCardComponent: FunctionComponent = ({ - canAccessFleet, - title = elasticAgentCardTitle, - description, - ...cardRest -}) => { - const props = canAccessFleet - ? { - title, - description: description || elasticAgentCardDescription, - } - : { - title: {noPermissionTitle}, - description: {noPermissionDescription}, - isDisabled: true, - }; - - const image = ( - - ); - - return ; -}; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.stories.tsx b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.stories.tsx deleted file mode 100644 index a87da6ff9ca0e..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.stories.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 React from 'react'; - -import { - ElasticAgentCardComponent as Component, - ElasticAgentCardComponentProps as ComponentProps, -} from './elastic_agent_card.component'; - -import { ElasticAgentCard } from './elastic_agent_card'; - -export default { - title: 'Page Template/No Data/Elastic Agent Data Card', - description: 'A solution-specific wrapper around NoDataCard, to be used on NoData page', -}; - -type Params = Pick; - -export const PureComponent = (params: Params) => { - return ; -}; - -PureComponent.argTypes = { - canAccessFleet: { - control: 'boolean', - defaultValue: true, - }, - description: { - control: 'text', - defaultValue: '', - }, -}; - -export const ConnectedComponent = () => { - return ; -}; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.test.tsx b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.test.tsx deleted file mode 100644 index ed0b4471fa32c..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.test.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { ReactWrapper } from 'enzyme'; -import React from 'react'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { - SharedUxServicesProvider, - SharedUxServices, - mockServicesFactory, -} from '@kbn/shared-ux-services'; - -import { ElasticAgentCard } from './elastic_agent_card'; -import { ElasticAgentCardComponent } from './elastic_agent_card.component'; - -describe('ElasticAgentCard', () => { - let services: SharedUxServices; - let mount: (element: JSX.Element) => ReactWrapper; - - beforeEach(() => { - services = mockServicesFactory(); - mount = (element: JSX.Element) => - mountWithIntl({element}); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - test('renders', () => { - const component = mount(); - expect(component.render()).toMatchSnapshot(); - }); - - describe('href', () => { - test('returns href if href is given', () => { - const component = mount(); - expect(component.find(ElasticAgentCardComponent).props().href).toBe('/take/me/somewhere'); - }); - - test('returns prefix + category if href is not given', () => { - const component = mount(); - expect(component.find(ElasticAgentCardComponent).props().href).toBe( - '/app/integrations/browse/solutions' - ); - }); - - test('returns prefix if nor category nor href are given', () => { - const component = mount(); - expect(component.find(ElasticAgentCardComponent).props().href).toBe( - '/app/integrations/browse' - ); - }); - }); - - describe('description', () => { - test('renders custom description if provided', () => { - const component = mount( - - ); - expect(component.find(ElasticAgentCardComponent).props().description).toBe( - 'Build seamless search experiences faster.' - ); - }); - }); - - describe('canAccessFleet', () => { - test('passes in the right parameter', () => { - const component = mount(); - expect(component.find(ElasticAgentCardComponent).props().canAccessFleet).toBe(true); - }); - }); -}); diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.tsx b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.tsx deleted file mode 100644 index a4025f33616ed..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/elastic_agent_card.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { useMemo } from 'react'; -import { useApplication, useHttp, usePermissions } from '@kbn/shared-ux-services'; -import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; -import useObservable from 'react-use/lib/useObservable'; - -import { ElasticAgentCardProps } from './types'; -import { ElasticAgentCardComponent } from './elastic_agent_card.component'; - -export const ElasticAgentCard = (props: ElasticAgentCardProps) => { - const { canAccessFleet } = usePermissions(); - const { addBasePath } = useHttp(); - const { navigateToUrl, currentAppId$ } = useApplication(); - const currentAppId = useObservable(currentAppId$); - - const { href: srcHref, category, description } = props; - - const href = useMemo(() => { - if (srcHref) { - return srcHref; - } - - // TODO: get this URL from a locator - const prefix = '/app/integrations/browse'; - - if (category) { - return addBasePath(`${prefix}/${category}`); - } - - return addBasePath(prefix); - }, [addBasePath, srcHref, category]); - - return ( - - - - ); -}; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/no_data_card.stories.tsx b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/no_data_card.stories.tsx deleted file mode 100644 index 9c1b2d0322074..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/no_data_card.stories.tsx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { NoDataCard } from './no_data_card'; -import type { NoDataCardProps } from './types'; - -export default { - title: 'Page Template/No Data/No Data Card', - description: 'A wrapper around EuiCard, to be used on NoData page', -}; - -type Params = Pick; - -export const PureComponent = (params: Params) => { - return ; -}; - -PureComponent.argTypes = { - button: { - control: { - type: 'text', - }, - defaultValue: 'Button text', - }, - description: { - control: { - type: 'text', - }, - defaultValue: 'This is a description', - }, -}; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/no_data_card.tsx b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/no_data_card.tsx deleted file mode 100644 index 508d03d5028b8..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/no_data_card.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { i18n } from '@kbn/i18n'; -import React, { FunctionComponent } from 'react'; -import { EuiButton, EuiCard, EuiScreenReaderOnly } from '@elastic/eui'; - -import type { NoDataCardProps } from './types'; -import { NoDataCardStyles } from './no_data_card.styles'; - -const defaultDescription = i18n.translate( - 'sharedUXComponents.pageTemplate.noDataCard.description', - { - defaultMessage: `Proceed without collecting data`, - } -); - -export const NoDataCard: FunctionComponent = ({ - title: titleProp, - button, - description, - isDisabled, - ...cardRest -}) => { - const styles = NoDataCardStyles(); - - const footer = () => { - // Don't render the footer action if disabled - if (isDisabled) { - return; - } - // Render a custom footer action if the button is not a simple string - if (button && typeof button !== 'string') { - return button; - } - // Default footer action is a button with the provided or default string - return {button || titleProp}; - }; - - const cardDescription = description || defaultDescription; - - // Fix the need for an a11y title even though the button exists by setting to screen reader only - const title = titleProp ? ( - - {titleProp} - - ) : null; - - return ( - - ); -}; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/types.ts b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/types.ts deleted file mode 100644 index fef4f654ce970..0000000000000 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/types.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { EuiCardProps } from '@elastic/eui'; -import { MouseEventHandler, ReactNode } from 'react'; - -export type NoDataCardProps = Partial> & { - /** - * Provide just a string for the button's label, or a whole component; - * The button will be hidden completely if `isDisabled=true` - */ - button?: string | ReactNode; - /** - * Remapping `onClick` to any element - */ - onClick?: MouseEventHandler; - /** - * Description for the card; - * If not provided, the default will be used - */ - description?: string | ReactNode; -}; - -export type ElasticAgentCardProps = NoDataCardProps & { - /** - * Category to auto-select within Fleet - */ - category?: string; -}; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_page.test.tsx b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_page.test.tsx index c84dea27552aa..b9474285469e1 100644 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_page.test.tsx +++ b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_page.test.tsx @@ -7,24 +7,27 @@ */ import React from 'react'; +import { mountWithIntl } from '@kbn/test-jest-helpers'; +import { NoDataCard } from '@kbn/shared-ux-card-no-data'; +import { SharedUxServicesProvider, mockServicesFactory } from '@kbn/shared-ux-services'; + import { NoDataPage } from './no_data_page'; -import { shallowWithIntl } from '@kbn/test-jest-helpers'; -import { ElasticAgentCard } from './no_data_card'; describe('NoDataPage', () => { test('render', () => { - const component = shallowWithIntl( - + const component = mountWithIntl( + + + ); - expect(component).toMatchSnapshot(); expect(component.find('h1').html()).toContain('Welcome to Elastic Analytics!'); - expect(component.find(ElasticAgentCard).length).toBe(1); + expect(component.find(NoDataCard).length).toBe(1); }); }); diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_page.tsx b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_page.tsx index 093a76d17759f..724570d4baccd 100644 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_page.tsx +++ b/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_page.tsx @@ -7,6 +7,7 @@ */ import React, { useMemo, FunctionComponent } from 'react'; +import useObservable from 'react-use/lib/useObservable'; import classNames from 'classnames'; import { EuiLink, EuiSpacer, EuiText, EuiTextColor } from '@elastic/eui'; @@ -14,7 +15,8 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { KibanaSolutionAvatar } from '@kbn/shared-ux-avatar-solution'; -import { ElasticAgentCard } from './no_data_card'; +import { useSharedUxServices } from '@kbn/shared-ux-services'; +import { NoDataCard, NoDataCardProvider } from '@kbn/shared-ux-card-no-data'; import { NoDataPageProps } from './types'; export const NoDataPage: FunctionComponent = ({ @@ -25,6 +27,19 @@ export const NoDataPage: FunctionComponent = ({ pageTitle, ...rest }) => { + const services = useSharedUxServices(); + + // TODO: clintandrewhall - including the `NoDataCardProvider` here is a temporary solution + // to consumers using this context to populate the NoDataPage. This will likely be removed soon, + // when NoDataPage is moved to its own package. + const currentAppId = useObservable(services.application.currentAppId$); + const noDataCardServices = { + currentAppId, + addBasePath: services.http.addBasePath, + canAccessFleet: services.permissions.canAccessFleet, + navigateToUrl: services.application.navigateToUrl, + }; + const actionKeys = Object.keys(action); const actionCard = useMemo(() => { @@ -34,7 +49,7 @@ export const NoDataPage: FunctionComponent = ({ const actionKey = actionKeys[0]; const key = actionKey === 'elasticAgent' ? 'empty-page-agent-action' : `empty-page-${actionKey}-action`; - return ; + return ; }, [action, actionKeys]); const title = @@ -74,7 +89,7 @@ export const NoDataPage: FunctionComponent = ({ - {actionCard} + {actionCard} ); }; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/types.ts b/packages/kbn-shared-ux-components/src/page_template/no_data_page/types.ts index b304a1462a278..e22f7a7b81a77 100644 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/types.ts +++ b/packages/kbn-shared-ux-components/src/page_template/no_data_page/types.ts @@ -7,9 +7,9 @@ */ import { CommonProps } from '@elastic/eui'; -import { ElasticAgentCardProps } from './no_data_card'; +import { NoDataCardProps } from '@kbn/shared-ux-card-no-data'; -export type NoDataPageActions = ElasticAgentCardProps; +export type NoDataPageActions = NoDataCardProps; export interface NoDataPageProps extends CommonProps { /** diff --git a/packages/kbn-shared-ux-storybook/src/config/main.ts b/packages/kbn-shared-ux-storybook/src/config/main.ts index ccd0d1e73cba8..6e57ca8ad5e72 100644 --- a/packages/kbn-shared-ux-storybook/src/config/main.ts +++ b/packages/kbn-shared-ux-storybook/src/config/main.ts @@ -15,4 +15,7 @@ module.exports = { '../../../kbn-shared-ux*/**/*.stories.+(tsx|mdx)', '../../../../src/plugins/shared_ux/**/*.stories.+(tsx|mdx)', ], + reactOptions: { + strictMode: true, + }, }; diff --git a/packages/shared-ux/card/no_data/BUILD.bazel b/packages/shared-ux/card/no_data/BUILD.bazel new file mode 100644 index 0000000000000..ae3e21ba55247 --- /dev/null +++ b/packages/shared-ux/card/no_data/BUILD.bazel @@ -0,0 +1,143 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "no_data" +PKG_REQUIRE_NAME = "@kbn/shared-ux-card-no-data" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.mdx", + "src/**/*.svg", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +# In this array place runtime dependencies, including other packages and NPM packages +# which must be available for this code to run. +# +# To reference other packages use: +# "//repo/relative/path/to/package" +# eg. "//packages/kbn-utils" +# +# To reference a NPM package use: +# "@npm//name-of-package" +# eg. "@npm//lodash" +RUNTIME_DEPS = [ + "@npm//@elastic/eui", + "@npm//@storybook/addon-actions", + "@npm//enzyme", + "@npm//react", + "//packages/kbn-i18n-react", + "//packages/kbn-i18n", + "//packages/shared-ux/link/redirect_app", +] + +# In this array place dependencies necessary to build the types, which will include the +# :npm_module_types target of other packages and packages from NPM, including @types/* +# packages. +# +# To reference the types for another package use: +# "//repo/relative/path/to/package:npm_module_types" +# eg. "//packages/kbn-utils:npm_module_types" +# +# References to NPM packages work the same as RUNTIME_DEPS +TYPES_DEPS = [ + "@npm//@elastic/eui", + "@npm//@storybook/addon-actions", + "@npm//@types/enzyme", + "@npm//@types/jest", + "@npm//@types/node", + "@npm//@types/react", + "//packages/kbn-ambient-ui-types", + "//packages/kbn-i18n-react:npm_module_types", + "//packages/kbn-i18n:npm_module_types", + "//packages/shared-ux/link/redirect_app:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, + additional_args = [ + "--copy-files", + "--quiet" + ], +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/shared-ux/card/no_data/README.mdx b/packages/shared-ux/card/no_data/README.mdx new file mode 100644 index 0000000000000..e2b044c27ac44 --- /dev/null +++ b/packages/shared-ux/card/no_data/README.mdx @@ -0,0 +1,29 @@ +--- +id: sharedUX/Components/NoDataCard +slug: /shared-ux/components/no-data-card +title: No Data Card +summary: A card displayed when no data is available is available in Kibana. +tags: ['shared-ux', 'component'] +date: 2022-06-15 +--- + +## Description + +A wrapper around `EuiCard` tailored for use in Kibana solutions when no data is available. + +## Usage + +All of the `EuiCard` props are available with the exception of `layout`. A default `description` and `button` are provided, but can be overridden in specific use cases. + +The `NoDataCard` connected component uses: + +- `navLinks.integrations` from `coreStart.application.capabilities` to determine if the user has access to the Integrations page. +- `addBasePath` from `coreStart` to navigate to the Integrations page. + +## API +| Export | Description | +|---|---| +| `NoDataCardProvider` | Provides contextual services to `NoDataCard`. | +| `NoDataCardKibanaProvider` | Maps Kibana dependencies to provide contextual services to `NoDataCard`. | +| `NoDataCard` | Uses a `Provider` to access contextual services to populate props on the `NoDataCardComponent`. | +| `NoDataCardComponent` | The pure component, a pre-configured **EuiCard**. | \ No newline at end of file diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/index.ts b/packages/shared-ux/card/no_data/jest.config.js similarity index 67% rename from packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/index.ts rename to packages/shared-ux/card/no_data/jest.config.js index e4cdeb401584f..47ce28115535f 100644 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/index.ts +++ b/packages/shared-ux/card/no_data/jest.config.js @@ -5,6 +5,9 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -export { NoDataCard } from './no_data_card'; -export { ElasticAgentCard } from './elastic_agent_card'; -export type { NoDataCardProps, ElasticAgentCardProps } from './types'; + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/packages/shared-ux/card/no_data'], +}; diff --git a/packages/shared-ux/card/no_data/package.json b/packages/shared-ux/card/no_data/package.json new file mode 100644 index 0000000000000..a1d3efd5a6985 --- /dev/null +++ b/packages/shared-ux/card/no_data/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/shared-ux-card-no-data", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/shared-ux/card/no_data/src/__snapshots__/no_data_card.component.test.tsx.snap b/packages/shared-ux/card/no_data/src/__snapshots__/no_data_card.component.test.tsx.snap new file mode 100644 index 0000000000000..17eb4ef8804cd --- /dev/null +++ b/packages/shared-ux/card/no_data/src/__snapshots__/no_data_card.component.test.tsx.snap @@ -0,0 +1,117 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NoDataCardComponent props button 1`] = ` + + Button + + } + image={} + isDisabled={false} + paddingSize="l" + title={ + + + Add Elastic Agent + + + } +/> +`; + +exports[`NoDataCardComponent props href 1`] = ` + + Add Elastic Agent + + } + href="some path" + image={} + isDisabled={false} + paddingSize="l" + title={ + + + Add Elastic Agent + + + } +/> +`; + +exports[`NoDataCardComponent renders 1`] = ` + + Add Elastic Agent + + } + image={} + isDisabled={false} + paddingSize="l" + title={ + + + Add Elastic Agent + + + } +/> +`; + +exports[`NoDataCardComponent renders with canAccessFleet false 1`] = ` + + This integration is not yet enabled. Your administrator has the required permissions to turn it on. + + } + image={} + isDisabled={true} + paddingSize="l" + title={ + + Contact your administrator + + } +/> +`; diff --git a/packages/shared-ux/card/no_data/src/__snapshots__/no_data_card.test.tsx.snap b/packages/shared-ux/card/no_data/src/__snapshots__/no_data_card.test.tsx.snap new file mode 100644 index 0000000000000..1f4277ffd139f --- /dev/null +++ b/packages/shared-ux/card/no_data/src/__snapshots__/no_data_card.test.tsx.snap @@ -0,0 +1,356 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NoDataCard props button 1`] = ` +
+
+
+
+
+ +
+
+
+
+ + + + Card title + + + +
+

+ Description +

+
+
+ +
+
+`; + +exports[`NoDataCard props extends EuiCardProps 1`] = ` +
+
+
+
+
+ +
+
+
+
+ + + + Card title + + + +
+

+ Description +

+
+
+ +
+
+`; + +exports[`NoDataCard props href 1`] = ` +
+
+
+
+
+ +
+
+
+
+ + + + Card title + + + +
+

+ Description +

+
+
+ +
+
+`; + +exports[`NoDataCard props no access to Fleet 1`] = ` +
+
+
+
+
+ +
+
+
+
+ + + +
+

+ + This integration is not yet enabled. Your administrator has the required permissions to turn it on. + +

+
+
+
+
+`; + +exports[`NoDataCard renders 1`] = ` +
+
+
+
+
+ +
+
+
+
+ + + + Card title + + + +
+

+ Description +

+
+
+ +
+
+`; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/assets/elastic_agent_card.svg b/packages/shared-ux/card/no_data/src/assets/elastic_agent_card.svg similarity index 100% rename from packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/assets/elastic_agent_card.svg rename to packages/shared-ux/card/no_data/src/assets/elastic_agent_card.svg diff --git a/packages/shared-ux/card/no_data/src/index.ts b/packages/shared-ux/card/no_data/src/index.ts new file mode 100644 index 0000000000000..24463007b5a8c --- /dev/null +++ b/packages/shared-ux/card/no_data/src/index.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. + */ + +export { NoDataCard } from './no_data_card'; +export type { Props as NoDataCardProps } from './no_data_card'; + +export { NoDataCardKibanaProvider, NoDataCardProvider } from './services'; +export type { NoDataCardKibanaDependencies, NoDataCardServices } from './services'; + +export { + getMockServices as getNoDataCardMockServices, + getStoryArgTypes as getNoDataCardStoryArgTypes, + getStoryServices as getNoDataCardStoryServices, +} from './mocks'; diff --git a/packages/shared-ux/card/no_data/src/mocks.ts b/packages/shared-ux/card/no_data/src/mocks.ts new file mode 100644 index 0000000000000..d5ec849e1456b --- /dev/null +++ b/packages/shared-ux/card/no_data/src/mocks.ts @@ -0,0 +1,88 @@ +/* + * 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 { action } from '@storybook/addon-actions'; +import { + getRedirectAppLinksMockServices, + getRedirectAppLinksStoryArgTypes, + getRedirectAppLinksStoryServices, +} from '@kbn/shared-ux-link-redirect-app'; + +import { NoDataCardServices } from './services'; + +/** + * Parameters drawn from the Storybook arguments collection that customize a component story. + */ +export type Params = Record, any>; + +/** + * Returns Storybook-compatible service abstractions for the `NoDataCard` Provider. + */ +export const getStoryServices = (params: Params) => { + const services: NoDataCardServices = { + ...getRedirectAppLinksStoryServices(), + ...params, + addBasePath: (path) => { + action('addBasePath')(path); + return path; + }, + }; + + return services; +}; + +/** + * Returns the Storybook arguments for `NoDataCard`, for its stories and for + * consuming component stories. + */ +export const getStoryArgTypes = () => ({ + ...getRedirectAppLinksStoryArgTypes(), + canAccessFleet: { + control: 'boolean', + defaultValue: true, + }, + category: { + control: { + type: 'text', + }, + defaultValue: '', + }, + title: { + control: { + type: 'text', + }, + defaultValue: '', + }, + description: { + control: { + type: 'text', + }, + defaultValue: '', + }, + button: { + control: { + type: 'text', + }, + defaultValue: '', + }, +}); + +/** + * Returns the Jest-compatible service abstractions for the `NoDataCard` Provider. + */ +export const getMockServices = (params?: Params) => { + const { canAccessFleet } = params || { canAccessFleet: true }; + + const services: NoDataCardServices = { + ...getRedirectAppLinksMockServices(), + canAccessFleet, + addBasePath: (path) => path, + }; + + return services; +}; diff --git a/packages/shared-ux/card/no_data/src/no_data_card.component.test.tsx b/packages/shared-ux/card/no_data/src/no_data_card.component.test.tsx new file mode 100644 index 0000000000000..72d179602e6d5 --- /dev/null +++ b/packages/shared-ux/card/no_data/src/no_data_card.component.test.tsx @@ -0,0 +1,36 @@ +/* + * 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 React from 'react'; +import { shallow } from 'enzyme'; + +import { NoDataCard } from './no_data_card.component'; + +describe('NoDataCardComponent', () => { + test('renders', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); + + test('renders with canAccessFleet false', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); + + describe('props', () => { + test('button', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); + + test('href', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/shared-ux/card/no_data/src/no_data_card.component.tsx b/packages/shared-ux/card/no_data/src/no_data_card.component.tsx new file mode 100644 index 0000000000000..43c4e9cd3a4af --- /dev/null +++ b/packages/shared-ux/card/no_data/src/no_data_card.component.tsx @@ -0,0 +1,136 @@ +/* + * 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 React, { MouseEventHandler, ReactNode } from 'react'; +import { + EuiButton, + EuiCard, + EuiScreenReaderOnly, + EuiTextColor, + EuiCardProps, + EuiImage, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { NoDataCardStyles } from './no_data_card.styles'; +import ElasticAgentCardIllustration from './assets/elastic_agent_card.svg'; + +export type Props = Partial< + Omit +> & { + /** + * Provide just a string for the button's label, or a whole component; + * The button will be hidden completely if `isDisabled=true` + */ + button?: string | ReactNode; + /** Remapping `onClick` to any element */ + onClick?: MouseEventHandler; + /** + * Description for the card; + * If not provided, the default will be used + */ + description?: string | ReactNode; + /** Category to auto-select within Fleet */ + category?: string; + /** True if the person has permission to access Fleet, false otherwise */ + canAccessFleet?: boolean; +}; + +const noPermissionTitle = i18n.translate('sharedUXPackages.card.noData.noPermission.title', { + defaultMessage: `Contact your administrator`, +}); + +const noPermissionDescription = i18n.translate( + 'sharedUXPackages.card.noData.noPermission.description', + { + defaultMessage: `This integration is not yet enabled. Your administrator has the required permissions to turn it on.`, + } +); + +const defaultTitle = i18n.translate('sharedUXPackages.card.noData.title', { + defaultMessage: 'Add Elastic Agent', +}); + +const defaultDescription = i18n.translate('sharedUXPackages.card.noData.description', { + defaultMessage: `Use Elastic Agent for a simple, unified way to collect data from your machines.`, +}); + +const Image = () => ( + +); + +/** + * Creates a specific NoDataCard pointing users to Integrations when `canAccessFleet` + */ +export const NoDataCard = ({ + title: titleProp, + description: descriptionProp, + canAccessFleet, + button, + ...props +}: Props) => { + const styles = NoDataCardStyles(); + + const footer = () => { + // Don't render the footer action if disabled + if (!canAccessFleet) { + return; + } + + // Render a custom footer action if the button is not a simple string + if (button && typeof button !== 'string') { + return button; + } + + // Default footer action is a button with the provided or default string + return {button || titleProp || defaultTitle}; + }; + + const title = () => { + if (!canAccessFleet) { + return {noPermissionTitle}; + } + + return ( + + {titleProp || defaultTitle} + + ); + }; + + const description = () => { + if (!canAccessFleet) { + return {noPermissionDescription}; + } + + return descriptionProp || defaultDescription; + }; + + return ( + } + {...props} + /> + ); +}; diff --git a/packages/shared-ux/card/no_data/src/no_data_card.stories.tsx b/packages/shared-ux/card/no_data/src/no_data_card.stories.tsx new file mode 100644 index 0000000000000..38f299d3d3d35 --- /dev/null +++ b/packages/shared-ux/card/no_data/src/no_data_card.stories.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 React from 'react'; + +import { Params, getStoryArgTypes, getStoryServices } from './mocks'; + +import { NoDataCard as Component } from './no_data_card.component'; +import { NoDataCard as ConnectedComponent } from './no_data_card'; +import { NoDataCardProvider } from './services'; + +import mdx from '../README.mdx'; + +export default { + title: 'No Data/Card', + description: 'A solution-specific wrapper around `EuiCard`, to be used on `NoData` page', + parameters: { + docs: { + page: mdx, + }, + }, +}; + +const argTypes = getStoryArgTypes(); + +export const NoDataCard = (params: Params) => { + return ( + + + + ); +}; + +NoDataCard.argTypes = argTypes; + +export const NoDataCardComponent = (params: Params) => { + return ; +}; + +NoDataCardComponent.argTypes = argTypes; diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/no_data_card.styles.ts b/packages/shared-ux/card/no_data/src/no_data_card.styles.ts similarity index 100% rename from packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/no_data_card.styles.ts rename to packages/shared-ux/card/no_data/src/no_data_card.styles.ts diff --git a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/no_data_card.test.tsx b/packages/shared-ux/card/no_data/src/no_data_card.test.tsx similarity index 73% rename from packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/no_data_card.test.tsx rename to packages/shared-ux/card/no_data/src/no_data_card.test.tsx index 6bbed463f23ed..0f659ad7a7f50 100644 --- a/packages/kbn-shared-ux-components/src/page_template/no_data_page/no_data_card/no_data_card.test.tsx +++ b/packages/shared-ux/card/no_data/src/no_data_card.test.tsx @@ -6,11 +6,23 @@ * Side Public License, v 1. */ -import { render } from 'enzyme'; +import { render as enzymeRender } from 'enzyme'; import React from 'react'; + import { NoDataCard } from './no_data_card'; +import { NoDataCardProvider } from './services'; + +const services = { + addBasePath: (path: string) => path, + navigateToUrl: () => {}, +}; describe('NoDataCard', () => { + const render = (element: React.ReactElement, canAccessFleet: boolean = true) => + enzymeRender( + {element} + ); + test('renders', () => { const component = render(); expect(component).toMatchSnapshot(); @@ -31,14 +43,10 @@ describe('NoDataCard', () => { expect(component).toMatchSnapshot(); }); - test('isDisabled', () => { + test('no access to Fleet', () => { const component = render( - + , + false ); expect(component).toMatchSnapshot(); }); diff --git a/packages/shared-ux/card/no_data/src/no_data_card.tsx b/packages/shared-ux/card/no_data/src/no_data_card.tsx new file mode 100644 index 0000000000000..a58ee5bc9d08b --- /dev/null +++ b/packages/shared-ux/card/no_data/src/no_data_card.tsx @@ -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 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 React, { useMemo } from 'react'; +import { RedirectAppLinksContainer } from '@kbn/shared-ux-link-redirect-app'; + +import { NoDataCard as Component, Props as ComponentProps } from './no_data_card.component'; + +import { useServices } from './services'; + +export type Props = Omit; + +export const NoDataCard = ({ href: srcHref, category, description, ...props }: Props) => { + const { canAccessFleet, addBasePath } = useServices(); + + const href = useMemo(() => { + if (srcHref) { + return srcHref; + } + + // TODO: get this URL from a locator + const prefix = '/app/integrations/browse'; + + if (category) { + return addBasePath(`${prefix}/${category}`); + } + + return addBasePath(prefix); + }, [addBasePath, srcHref, category]); + + return ( + + + + ); +}; diff --git a/packages/shared-ux/card/no_data/src/services.tsx b/packages/shared-ux/card/no_data/src/services.tsx new file mode 100644 index 0000000000000..c4937a6d21da9 --- /dev/null +++ b/packages/shared-ux/card/no_data/src/services.tsx @@ -0,0 +1,97 @@ +/* + * 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 React, { FC, useContext } from 'react'; +import { + RedirectAppLinksServices, + RedirectAppLinksKibanaDependencies, + RedirectAppLinksProvider, + RedirectAppLinksKibanaProvider, +} from '@kbn/shared-ux-link-redirect-app'; + +/** + * A list of services that are consumed by this component. + */ +interface Services { + addBasePath: (path: string) => string; + canAccessFleet: boolean; +} + +const Context = React.createContext(null); + +/** + * Services that are consumed by this component and its dependencies. + */ +export type NoDataCardServices = Services & RedirectAppLinksServices; + +/** + * A Context Provider that provides services to the component and its dependencies. + */ +export const NoDataCardProvider: FC = ({ children, ...services }) => { + const { addBasePath, canAccessFleet } = services; + + return ( + + {children} + + ); +}; + +interface KibanaDependencies { + coreStart: { + http: { + basePath: { + prepend: (path: string) => string; + }; + }; + application: { + capabilities: { + navLinks: Record; + }; + }; + }; +} +/** + * An interface containing a collection of Kibana plugins and services required to + * render this component as well as its dependencies. + */ +export type NoDataCardKibanaDependencies = KibanaDependencies & RedirectAppLinksKibanaDependencies; + +/** + * Kibana-specific Provider that maps dependencies to services. + */ +export const NoDataCardKibanaProvider: FC = ({ + children, + ...dependencies +}) => { + const value: Services = { + addBasePath: dependencies.coreStart.http.basePath.prepend, + canAccessFleet: dependencies.coreStart.application.capabilities.navLinks.integrations, + }; + + return ( + + {children} + + ); +}; + +/** + * React hook for accessing pre-wired services. + */ +export function useServices() { + const context = useContext(Context); + + if (!context) { + throw new Error( + 'NoDataCard Context is missing. Ensure your component or React root is wrapped with NoDataCardContext.' + ); + } + + return context; +} diff --git a/packages/shared-ux/card/no_data/tsconfig.json b/packages/shared-ux/card/no_data/tsconfig.json new file mode 100644 index 0000000000000..44b240540718d --- /dev/null +++ b/packages/shared-ux/card/no_data/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node", + "react", + "@emotion/react/types/css-prop", + "@kbn/ambient-ui-types" + ] + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/shared-ux/link/redirect_app/src/index.tsx b/packages/shared-ux/link/redirect_app/src/index.tsx index 09317ebab59f7..0d1c61242edb3 100644 --- a/packages/shared-ux/link/redirect_app/src/index.tsx +++ b/packages/shared-ux/link/redirect_app/src/index.tsx @@ -10,16 +10,27 @@ export { RedirectAppLinks as RedirectAppLinksContainer } from './redirect_app_li export { RedirectAppLinks as RedirectAppLinksComponent } from './redirect_app_links.component'; export { RedirectAppLinksKibanaProvider, RedirectAppLinksProvider } from './services'; +export type { + Services as RedirectAppLinksServices, + KibanaDependencies as RedirectAppLinksKibanaDependencies, +} from './services'; + +export { + getMockServices as getRedirectAppLinksMockServices, + getStoryArgTypes as getRedirectAppLinksStoryArgTypes, + getStoryServices as getRedirectAppLinksStoryServices, +} from './mocks'; + import React, { FC } from 'react'; import { RedirectAppLinks as RedirectAppLinksContainer } from './redirect_app_links'; import { Services, - KibanaServices, + KibanaDependencies, RedirectAppLinksKibanaProvider, RedirectAppLinksProvider, } from './services'; -const isKibanaContract = (services: any): services is KibanaServices => { +const isKibanaContract = (services: any): services is KibanaDependencies => { return typeof services.coreStart !== 'undefined'; }; @@ -28,12 +39,22 @@ const isKibanaContract = (services: any): services is KibanaServices => { * `RedirectAppLinksKibanaProvider` based on the services provided, creating a single component * with which consumers can wrap their components or solutions. */ -export const RedirectAppLinks: FC = ({ children, ...services }) => { +export const RedirectAppLinks: FC = ({ children, ...services }) => { const container = {children}; - return isKibanaContract(services) ? ( - {container} - ) : ( - {container} + if (isKibanaContract(services)) { + const { coreStart } = services; + return ( + + {container} + + ); + } + + const { navigateToUrl, currentAppId } = services; + return ( + + {container} + ); }; diff --git a/packages/shared-ux/link/redirect_app/src/mocks.ts b/packages/shared-ux/link/redirect_app/src/mocks.ts new file mode 100644 index 0000000000000..4b5519dd646bb --- /dev/null +++ b/packages/shared-ux/link/redirect_app/src/mocks.ts @@ -0,0 +1,46 @@ +/* + * 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 { action } from '@storybook/addon-actions'; + +import { Services } from './services'; + +/** + * Parameters drawn from the Storybook arguments collection that customize a component story. + */ +export type Params = Record, any>; + +/** + * Returns Storybook-compatible service abstractions for the `NoDataCard` Provider. + */ +export const getStoryServices = () => { + const services: Services = { + navigateToUrl: action('navigateToUrl'), + currentAppId: 'currentAppId', + }; + + return services; +}; + +/** + * Returns the Storybook arguments for `NoDataCard`, for its stories and for + * consuming component stories. + */ +export const getStoryArgTypes = () => ({}); + +/** + * Returns the Jest-compatible service abstractions for the `NoDataCard` Provider. + */ +export const getMockServices = () => { + const services: Services = { + navigateToUrl: jest.fn(), + currentAppId: 'currentAppId', + }; + + return services; +}; diff --git a/packages/shared-ux/link/redirect_app/src/redirect_app_links.component.tsx b/packages/shared-ux/link/redirect_app/src/redirect_app_links.component.tsx index 477471fe71824..f0da5b307fbd1 100644 --- a/packages/shared-ux/link/redirect_app/src/redirect_app_links.component.tsx +++ b/packages/shared-ux/link/redirect_app/src/redirect_app_links.component.tsx @@ -29,12 +29,7 @@ export interface Props extends DetailedHTMLProps, * * ``` */ -export const RedirectAppLinks: FC = ({ - children, - navigateToUrl, - currentAppId, - ...otherProps -}) => { +export const RedirectAppLinks: FC = ({ children, navigateToUrl, currentAppId }) => { const containerRef = useRef(null); const handleClick: MouseEventHandler = useCallback( @@ -50,7 +45,7 @@ export const RedirectAppLinks: FC = ({ return ( // eslint-disable-next-line jsx-a11y/click-events-have-key-events -
+
{children}
); diff --git a/packages/shared-ux/link/redirect_app/src/redirect_app_links.stories.tsx b/packages/shared-ux/link/redirect_app/src/redirect_app_links.stories.tsx index 9bb3d0d9782d4..1b77f7148964e 100644 --- a/packages/shared-ux/link/redirect_app/src/redirect_app_links.stories.tsx +++ b/packages/shared-ux/link/redirect_app/src/redirect_app_links.stories.tsx @@ -10,11 +10,12 @@ import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; import { action } from '@storybook/addon-actions'; -import { RedirectAppLinks } from '.'; +import { RedirectAppLinks as Component } from '.'; +import { getStoryArgTypes, getStoryServices } from './mocks'; import mdx from '../README.mdx'; export default { - title: 'Redirect App Links', + title: 'Link', description: 'An "area of effect" component which intercepts clicks on anchor elements and redirects them to Kibana solutions without a page refresh.', parameters: { @@ -24,16 +25,10 @@ export default { }, }; -export const Component = () => { - const navigateToUrl = async (url: string) => { - action('navigateToUrl')(url); - }; - - const currentAppId = 'abc123'; - +export const RedirectAppLinks = () => { return ( <> - + { - + { ); }; + +RedirectAppLinks.argTypes = getStoryArgTypes(); diff --git a/packages/shared-ux/link/redirect_app/src/redirect_app_links.tsx b/packages/shared-ux/link/redirect_app/src/redirect_app_links.tsx index 1e805ad4475b6..9a069881b2128 100644 --- a/packages/shared-ux/link/redirect_app/src/redirect_app_links.tsx +++ b/packages/shared-ux/link/redirect_app/src/redirect_app_links.tsx @@ -6,15 +6,10 @@ * Side Public License, v 1. */ -import React from 'react'; +import React, { FC } from 'react'; import { useServices } from './services'; -import { - RedirectAppLinks as Component, - Props as ComponentProps, -} from './redirect_app_links.component'; - -type Props = Omit; +import { RedirectAppLinks as Component } from './redirect_app_links.component'; /** * A service-enabled component that provides Kibana-specific functionality to the `RedirectAppLinks` @@ -27,4 +22,6 @@ type Props = Omit; * * ``` */ -export const RedirectAppLinks = (props: Props) => ; +export const RedirectAppLinks: FC<{}> = ({ children }) => ( + {children} +); diff --git a/packages/shared-ux/link/redirect_app/src/services.tsx b/packages/shared-ux/link/redirect_app/src/services.tsx index 22bc5a5cd0c55..b29d82f8eea13 100644 --- a/packages/shared-ux/link/redirect_app/src/services.tsx +++ b/packages/shared-ux/link/redirect_app/src/services.tsx @@ -25,8 +25,9 @@ const RedirectAppLinksContext = React.createContext(null); * Contextual services Provider. */ export const RedirectAppLinksProvider: FC = ({ children, ...services }) => { + const { navigateToUrl, currentAppId } = services; return ( - + {children} ); @@ -35,7 +36,7 @@ export const RedirectAppLinksProvider: FC = ({ children, ...services } /** * Kibana-specific contextual services to be adapted for this component. */ -export interface KibanaServices { +export interface KibanaDependencies { coreStart: { application: { currentAppId$: Observable; @@ -47,7 +48,7 @@ export interface KibanaServices { /** * Kibana-specific contextual services Provider. */ -export const RedirectAppLinksKibanaProvider: FC = ({ children, coreStart }) => { +export const RedirectAppLinksKibanaProvider: FC = ({ children, coreStart }) => { const { navigateToUrl, currentAppId$ } = coreStart.application; const currentAppId = useObservable(currentAppId$, undefined); diff --git a/packages/shared-ux/page/analytics_no_data/src/analytics_no_data_page.stories.tsx b/packages/shared-ux/page/analytics_no_data/src/analytics_no_data_page.stories.tsx index d5d82d801fc8d..8cb9b3aaa5f7e 100644 --- a/packages/shared-ux/page/analytics_no_data/src/analytics_no_data_page.stories.tsx +++ b/packages/shared-ux/page/analytics_no_data/src/analytics_no_data_page.stories.tsx @@ -16,7 +16,7 @@ import mdx from '../README.mdx'; import { Params, getStoryArgTypes, getStoryServices } from './mocks'; export default { - title: 'No Data/Analytics', + title: 'No Data/Analytics Page', description: 'An Analytics-specific version of KibanaNoDataPage.', parameters: { docs: { diff --git a/packages/shared-ux/page/kibana_no_data/src/kibana_no_data_page.stories.tsx b/packages/shared-ux/page/kibana_no_data/src/kibana_no_data_page.stories.tsx index 206b958e64771..c18adc20e4af0 100644 --- a/packages/shared-ux/page/kibana_no_data/src/kibana_no_data_page.stories.tsx +++ b/packages/shared-ux/page/kibana_no_data/src/kibana_no_data_page.stories.tsx @@ -16,7 +16,7 @@ import { KibanaNoDataPageProvider } from './services'; import mdx from '../README.mdx'; export default { - title: 'No Data/Kibana', + title: 'No Data/Kibana Page', description: 'A component to display when there is no data available', parameters: { docs: { diff --git a/packages/shared-ux/page/kibana_no_data/src/mocks.ts b/packages/shared-ux/page/kibana_no_data/src/mocks.ts index e88097c933849..d91949ddc6c32 100644 --- a/packages/shared-ux/page/kibana_no_data/src/mocks.ts +++ b/packages/shared-ux/page/kibana_no_data/src/mocks.ts @@ -14,6 +14,12 @@ import { getNoDataViewsPromptMockServices, } from '@kbn/shared-ux-prompt-no-data-views'; +import { + getNoDataCardMockServices, + getNoDataCardStoryArgTypes, + getNoDataCardStoryServices, +} from '@kbn/shared-ux-card-no-data'; + import { KibanaNoDataPageServices } from './services'; // TODO: clintandrewhall - this looks (and is) a bit complicated because the No Data View @@ -32,6 +38,8 @@ export const getStoryServices = (params: StoryParams) => { const { canCreateNewDataView, dataViewsDocLink, openDataViewEditor } = getNoDataViewsPromptStorybookServices(params); + const { addBasePath, canAccessFleet } = getNoDataCardStoryServices(params); + // Workaround to leverage the services package. const { application, data, docLinks, editors, http, permissions, platform } = servicesFactory(params); @@ -47,6 +55,8 @@ export const getStoryServices = (params: StoryParams) => { canCreateNewDataView, dataViewsDocLink, openDataViewEditor, + addBasePath, + canAccessFleet, }; return services; @@ -75,6 +85,7 @@ export const getStoryArgTypes = () => ({ defaultValue: false, }, ...getNoDataViewsPromptStoryArgTypes(), + ...getNoDataCardStoryArgTypes(), }); /** @@ -84,6 +95,8 @@ export const getMockServices = (params?: MockServicesFactoryParams) => { const { canCreateNewDataView, dataViewsDocLink, openDataViewEditor } = getNoDataViewsPromptMockServices(); + const { addBasePath, canAccessFleet } = getNoDataCardMockServices(); + const { application, data, docLinks, editors, http, permissions, platform } = mockServicesFactory(params); @@ -98,6 +111,8 @@ export const getMockServices = (params?: MockServicesFactoryParams) => { canCreateNewDataView, dataViewsDocLink, openDataViewEditor, + addBasePath, + canAccessFleet, }; return services; diff --git a/packages/shared-ux/page/kibana_no_data/src/services.tsx b/packages/shared-ux/page/kibana_no_data/src/services.tsx index 07b5787ae8b72..47f6b9c3690f9 100644 --- a/packages/shared-ux/page/kibana_no_data/src/services.tsx +++ b/packages/shared-ux/page/kibana_no_data/src/services.tsx @@ -13,6 +13,8 @@ import { NoDataViewsPromptKibanaProvider, } from '@kbn/shared-ux-prompt-no-data-views'; +import { NoDataCardProvider, NoDataCardKibanaProvider } from '@kbn/shared-ux-card-no-data'; + import { LegacyServicesProvider, getLegacyServices } from './legacy_services'; /** @@ -85,7 +87,9 @@ export const KibanaNoDataPageProvider: FC = ({ }) => ( - {children} + + {children} + ); @@ -159,7 +163,9 @@ export const KibanaNoDataPageKibanaProvider: FC - {children} + + {children} + ); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 3c492c1443bf7..5877421bf5d1b 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -5338,11 +5338,10 @@ "share.urlService.redirect.RedirectManager.missingParamLocator": "ID du localisateur non spécifié. Spécifiez le paramètre de recherche \"l\" dans l'URL ; ce devrait être un ID de localisateur existant.", "share.urlService.redirect.RedirectManager.missingParamParams": "Paramètres du localisateur non spécifiés. Spécifiez le paramètre de recherche \"p\" dans l'URL ; ce devrait être un objet sérialisé JSON des paramètres du localisateur.", "share.urlService.redirect.RedirectManager.missingParamVersion": "Version des paramètres du localisateur non spécifiée. Spécifiez le paramètre de recherche \"v\" dans l'URL ; ce devrait être la version de Kibana au moment de la génération des paramètres du localisateur.", - "sharedUXComponents.noDataPage.elasticAgentCard.description": "Utilisez Elastic Agent pour collecter de manière simple et unifiée les données de vos machines.", - "sharedUXComponents.noDataPage.elasticAgentCard.noPermission.description": "Cette intégration n'est pas encore activée. Votre administrateur possède les autorisations requises pour l’activer.", - "sharedUXComponents.noDataPage.elasticAgentCard.noPermission.title": "Contactez votre administrateur", - "sharedUXComponents.noDataPage.elasticAgentCard.title": "Ajouter Elastic Agent", - "sharedUXComponents.pageTemplate.noDataCard.description": "Continuer sans collecter de données", + "sharedUXPackages.card.noData.description": "Utilisez Elastic Agent pour collecter de manière simple et unifiée les données de vos machines.", + "sharedUXPackages.card.noData.noPermission.description": "Cette intégration n'est pas encore activée. Votre administrateur possède les autorisations requises pour l’activer.", + "sharedUXPackages.card.noData.noPermission.title": "Contactez votre administrateur", + "sharedUXPackages.card.noData.title": "Ajouter Elastic Agent", "sharedUXPackages.buttonToolbar.buttons.addFromLibrary.libraryButtonLabel": "Ajouter depuis la bibliothèque", "sharedUXPackages.noDataViewsPrompt.learnMore": "Envie d'en savoir plus ?", "sharedUXPackages.noDataViewsPrompt.readDocumentation": "Lisez les documents", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index fa1ce7b24c45c..0c37c60acaf0d 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5440,11 +5440,10 @@ "share.urlService.redirect.RedirectManager.missingParamLocator": "ロケーターIDが指定されていません。URLで「l」検索パラメーターを指定します。これは既存のロケーターIDにしてください。", "share.urlService.redirect.RedirectManager.missingParamParams": "ロケーターパラメーターが指定されていません。URLで「p」検索パラメーターを指定します。これはロケーターパラメーターのJSONシリアル化オブジェクトにしてください。", "share.urlService.redirect.RedirectManager.missingParamVersion": "ロケーターパラメーターバージョンが指定されていません。URLで「v」検索パラメーターを指定します。これはロケーターパラメーターが生成されたときのKibanaのリリースバージョンです。", - "sharedUXComponents.noDataPage.elasticAgentCard.description": "Elasticエージェントを使用すると、シンプルで統一された方法でコンピューターからデータを収集するできます。", - "sharedUXComponents.noDataPage.elasticAgentCard.noPermission.description": "この統合はまだ有効ではありません。管理者にはオンにするために必要なアクセス権があります。", - "sharedUXComponents.noDataPage.elasticAgentCard.noPermission.title": "管理者にお問い合わせください", - "sharedUXComponents.noDataPage.elasticAgentCard.title": "Elasticエージェントの追加", - "sharedUXComponents.pageTemplate.noDataCard.description": "データを収集せずに続行", + "sharedUXPackages.card.noData.description": "Elasticエージェントを使用すると、シンプルで統一された方法でコンピューターからデータを収集するできます。", + "sharedUXPackages.card.noData.noPermission.description": "この統合はまだ有効ではありません。管理者にはオンにするために必要なアクセス権があります。", + "sharedUXPackages.card.noData.noPermission.title": "管理者にお問い合わせください", + "sharedUXPackages.card.noData.title": "Elasticエージェントの追加", "sharedUXPackages.buttonToolbar.buttons.addFromLibrary.libraryButtonLabel": "ライブラリから追加", "sharedUXPackages.noDataViewsPrompt.learnMore": "詳細について", "sharedUXPackages.noDataViewsPrompt.readDocumentation": "ドキュメントを読む", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 9bcc45a9ca1ab..6b6a0df9cd5e3 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5451,11 +5451,10 @@ "share.urlService.redirect.RedirectManager.missingParamLocator": "未指定定位器 ID。在 URL 中指定“l”搜索参数,其应为现有定位器 ID。", "share.urlService.redirect.RedirectManager.missingParamParams": "定位器参数未指定。在 URL 中指定“p”搜索参数,其应为定位器参数的 JSON 序列化对象。", "share.urlService.redirect.RedirectManager.missingParamVersion": "定位器参数版本未指定。在 URL 中指定“v”搜索参数,其应为生成定位器参数时 Kibana 的版本。", - "sharedUXComponents.noDataPage.elasticAgentCard.description": "使用 Elastic 代理以简单统一的方式从您的计算机中收集数据。", - "sharedUXComponents.noDataPage.elasticAgentCard.noPermission.description": "尚未启用此集成。您的管理员具有打开它所需的权限。", - "sharedUXComponents.noDataPage.elasticAgentCard.noPermission.title": "请联系您的管理员", - "sharedUXComponents.noDataPage.elasticAgentCard.title": "添加 Elastic 代理", - "sharedUXComponents.pageTemplate.noDataCard.description": "继续,而不收集数据", + "sharedUXPackages.card.noData.description": "使用 Elastic 代理以简单统一的方式从您的计算机中收集数据。", + "sharedUXPackages.card.noData.noPermission.description": "尚未启用此集成。您的管理员具有打开它所需的权限。", + "sharedUXPackages.card.noData.noPermission.title": "请联系您的管理员", + "sharedUXPackages.card.noData.title": "添加 Elastic 代理", "sharedUXPackages.buttonToolbar.buttons.addFromLibrary.libraryButtonLabel": "从库中添加", "sharedUXPackages.noDataViewsPrompt.learnMore": "希望了解详情?", "sharedUXPackages.noDataViewsPrompt.readDocumentation": "阅读文档", diff --git a/yarn.lock b/yarn.lock index 649e628ecf74a..2d8dde05811f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3351,6 +3351,10 @@ version "0.0.0" uid "" +"@kbn/shared-ux-card-no-data@link:bazel-bin/packages/shared-ux/card/no_data": + version "0.0.0" + uid "" + "@kbn/shared-ux-components@link:bazel-bin/packages/kbn-shared-ux-components": version "0.0.0" uid "" @@ -6722,6 +6726,10 @@ version "0.0.0" uid "" +"@types/kbn__shared-ux-card-no-data@link:bazel-bin/packages/shared-ux/card/no_data/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__shared-ux-components@link:bazel-bin/packages/kbn-shared-ux-components/npm_module_types": version "0.0.0" uid ""