From d1ec4cd2216352750e80942ea38592c435052c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Fri, 22 Sep 2023 11:04:52 +0100 Subject: [PATCH 01/14] Add cloud package to expose deployment details component --- .i18nrc.json | 1 + package.json | 1 + packages/cloud/README.md | 3 + .../deployment-details/deployment_details.tsx | 122 ++++++++++++++++++ .../deployment_details_modal.tsx | 66 ++++++++++ packages/cloud/deployment-details/index.ts | 11 ++ .../cloud/deployment-details/services.tsx | 120 +++++++++++++++++ packages/cloud/index.ts | 11 ++ packages/cloud/jest.config.js | 13 ++ packages/cloud/kibana.jsonc | 5 + packages/cloud/package.json | 6 + packages/cloud/tsconfig.json | 19 +++ tsconfig.base.json | 2 + yarn.lock | 4 + 14 files changed, 384 insertions(+) create mode 100644 packages/cloud/README.md create mode 100644 packages/cloud/deployment-details/deployment_details.tsx create mode 100644 packages/cloud/deployment-details/deployment_details_modal.tsx create mode 100644 packages/cloud/deployment-details/index.ts create mode 100644 packages/cloud/deployment-details/services.tsx create mode 100644 packages/cloud/index.ts create mode 100644 packages/cloud/jest.config.js create mode 100644 packages/cloud/kibana.jsonc create mode 100644 packages/cloud/package.json create mode 100644 packages/cloud/tsconfig.json diff --git a/.i18nrc.json b/.i18nrc.json index b5e17c18d3542..4657840019f6c 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -15,6 +15,7 @@ "customIntegrations": "src/plugins/custom_integrations", "customIntegrationsPackage": "packages/kbn-custom-integrations", "dashboard": "src/plugins/dashboard", + "cloud": "packages/cloud", "domDragDrop": "packages/kbn-dom-drag-drop", "controls": "src/plugins/controls", "data": "src/plugins/data", diff --git a/package.json b/package.json index eaafb301c5dfc..572850af3a800 100644 --- a/package.json +++ b/package.json @@ -172,6 +172,7 @@ "@kbn/chart-expressions-common": "link:src/plugins/chart_expressions/common", "@kbn/chart-icons": "link:packages/kbn-chart-icons", "@kbn/charts-plugin": "link:src/plugins/charts", + "@kbn/cloud": "link:packages/cloud", "@kbn/cloud-chat-plugin": "link:x-pack/plugins/cloud_integrations/cloud_chat", "@kbn/cloud-chat-provider-plugin": "link:x-pack/plugins/cloud_integrations/cloud_chat_provider", "@kbn/cloud-data-migration-plugin": "link:x-pack/plugins/cloud_integrations/cloud_data_migration", diff --git a/packages/cloud/README.md b/packages/cloud/README.md new file mode 100644 index 0000000000000..e387c4b9be959 --- /dev/null +++ b/packages/cloud/README.md @@ -0,0 +1,3 @@ +# @kbn/cloud + +Empty package generated by @kbn/generate diff --git a/packages/cloud/deployment-details/deployment_details.tsx b/packages/cloud/deployment-details/deployment_details.tsx new file mode 100644 index 0000000000000..6f96b1b25b72c --- /dev/null +++ b/packages/cloud/deployment-details/deployment_details.tsx @@ -0,0 +1,122 @@ +/* + * 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 { + EuiForm, + EuiFormRow, + EuiFieldText, + EuiCopy, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiButtonEmpty, + EuiSpacer, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useDeploymentDetails } from './services'; + +export const DeploymentDetails = ({ closeModal }: { closeModal?: () => void }) => { + const { cloudId, elasticsearchUrl, managementUrl, learnMoreUrl, navigateToUrl } = + useDeploymentDetails(); + const isInsideModal = !!closeModal; + + if (!cloudId) { + return null; + } + + return ( + <> + + {/* Elastic endpoint */} + {elasticsearchUrl && ( + + + + + + + + {(copy) => ( + + )} + + + + + )} + + {/* Cloud ID */} + + + + + + + + {(copy) => ( + + )} + + + + + + + + {managementUrl && ( + + + {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} + { + e.preventDefault(); + navigateToUrl(managementUrl); + if (closeModal) { + closeModal(); + } + }} + flush="left" + > + {i18n.translate('cloud.deploymentDetails.createManageApiKeysButtonLabel', { + defaultMessage: 'Create and manage API keys', + })} + + + {!isInsideModal && ( + + + {i18n.translate('cloud.deploymentDetails.learnMoreButtonLabel', { + defaultMessage: 'Learn more', + })} + + + )} + + )} + + + ); +}; diff --git a/packages/cloud/deployment-details/deployment_details_modal.tsx b/packages/cloud/deployment-details/deployment_details_modal.tsx new file mode 100644 index 0000000000000..d3db46e8d1a95 --- /dev/null +++ b/packages/cloud/deployment-details/deployment_details_modal.tsx @@ -0,0 +1,66 @@ +/* + * 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, { type FC } from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiModal, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, +} from '@elastic/eui'; +import { useDeploymentDetails } from './services'; +import { DeploymentDetails } from './deployment_details'; + +interface Props { + closeModal: () => void; +} + +export const DeploymentDetailsModal: FC = ({ closeModal }) => { + const { learnMoreUrl } = useDeploymentDetails(); + + return ( + { + closeModal(); + }} + style={{ width: 600 }} + > + + + {i18n.translate('cloud.deploymentDetails.helpMenuLinks.endpoints', { + defaultMessage: 'Endpoints', + })} + + + + + + + + + + {i18n.translate('cloud.deploymentDetails.modal.learnMoreButtonLabel', { + defaultMessage: 'Learn more', + })} + + + + + Close + + + + + + ); +}; diff --git a/packages/cloud/deployment-details/index.ts b/packages/cloud/deployment-details/index.ts new file mode 100644 index 0000000000000..2f37291eecd7c --- /dev/null +++ b/packages/cloud/deployment-details/index.ts @@ -0,0 +1,11 @@ +/* + * 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 { DeploymentDetailsKibanaProvider, DeploymentDetailsProvider } from './services'; +export { DeploymentDetails } from './deployment_details'; +export { DeploymentDetailsModal } from './deployment_details_modal'; diff --git a/packages/cloud/deployment-details/services.tsx b/packages/cloud/deployment-details/services.tsx new file mode 100644 index 0000000000000..f6a93c41200b8 --- /dev/null +++ b/packages/cloud/deployment-details/services.tsx @@ -0,0 +1,120 @@ +/* + * 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'; + +export interface Services { + cloudId?: string; + elasticsearchUrl?: string; + managementUrl?: string; + learnMoreUrl: string; + navigateToUrl(url: string): Promise; +} + +const DeploymentDetailsContext = React.createContext(null); + +/** + * Abstract external service Provider. + */ +export const DeploymentDetailsProvider: FC = ({ children, ...services }) => { + return ( + + {children} + + ); +}; + +/** + * Kibana-specific service types. + */ +export interface DeploymentDetailsKibanaDependencies { + /** CoreStart contract */ + core: { + application: { + navigateToUrl(url: string): Promise; + }; + }; + /** SharePluginStart contract */ + share: { + url: { + locators: { + get( + id: string + ): undefined | { useUrl: (params: { sectionId: string; appId: string }) => string }; + }; + }; + }; + /** CloudSetup contract */ + cloud: { + isCloudEnabled: boolean; + cloudId?: string; + elasticsearchUrl?: string; + }; + /** DocLinksStart contract */ + docLinks: { + links: { + fleet: { + apiKeysLearnMore: string; + }; + }; + }; +} + +/** + * Kibana-specific Provider that maps to known dependency types. + */ +export const DeploymentDetailsKibanaProvider: FC = ({ + children, + ...services +}) => { + const { + core: { + application: { navigateToUrl }, + }, + cloud: { isCloudEnabled, cloudId = 'abc123', elasticsearchUrl = 'http//coolio.com' }, + share: { + url: { locators }, + }, + docLinks: { + links: { + fleet: { apiKeysLearnMore }, + }, + }, + } = services; + + const managementUrl = locators + .get('MANAGEMENT_APP_LOCATOR') + ?.useUrl({ sectionId: 'security', appId: 'api_keys' }); + + return ( + + {children} + + ); +}; + +/** + * React hook for accessing pre-wired services. + */ +export function useDeploymentDetails() { + const context = useContext(DeploymentDetailsContext); + + if (!context) { + throw new Error( + 'DeploymentDetailsContext is missing. Ensure your component or React root is wrapped with or .' + ); + } + + return context; +} diff --git a/packages/cloud/index.ts b/packages/cloud/index.ts new file mode 100644 index 0000000000000..b6e7485e36ab2 --- /dev/null +++ b/packages/cloud/index.ts @@ -0,0 +1,11 @@ +/* + * 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 function foo() { + return 'hello world'; +} diff --git a/packages/cloud/jest.config.js b/packages/cloud/jest.config.js new file mode 100644 index 0000000000000..174f01cfc1be6 --- /dev/null +++ b/packages/cloud/jest.config.js @@ -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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/cloud'], +}; diff --git a/packages/cloud/kibana.jsonc b/packages/cloud/kibana.jsonc new file mode 100644 index 0000000000000..e39a0dbe40617 --- /dev/null +++ b/packages/cloud/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/cloud", + "owner": "@elastic/kibana-core" +} diff --git a/packages/cloud/package.json b/packages/cloud/package.json new file mode 100644 index 0000000000000..8e0023dc5c7a3 --- /dev/null +++ b/packages/cloud/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/cloud", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/cloud/tsconfig.json b/packages/cloud/tsconfig.json new file mode 100644 index 0000000000000..dad708677fd87 --- /dev/null +++ b/packages/cloud/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 31381c8271962..76eacb45a3f32 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -128,6 +128,8 @@ "@kbn/ci-stats-shipper-cli/*": ["packages/kbn-ci-stats-shipper-cli/*"], "@kbn/cli-dev-mode": ["packages/kbn-cli-dev-mode"], "@kbn/cli-dev-mode/*": ["packages/kbn-cli-dev-mode/*"], + "@kbn/cloud": ["packages/cloud"], + "@kbn/cloud/*": ["packages/cloud/*"], "@kbn/cloud-chat-plugin": ["x-pack/plugins/cloud_integrations/cloud_chat"], "@kbn/cloud-chat-plugin/*": ["x-pack/plugins/cloud_integrations/cloud_chat/*"], "@kbn/cloud-chat-provider-plugin": ["x-pack/plugins/cloud_integrations/cloud_chat_provider"], diff --git a/yarn.lock b/yarn.lock index 54211838a60b6..2b2fa37feb3ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3243,6 +3243,10 @@ version "0.0.0" uid "" +"@kbn/cloud@link:packages/cloud": + version "0.0.0" + uid "" + "@kbn/code-editor-mocks@link:packages/shared-ux/code_editor/mocks": version "0.0.0" uid "" From 836413ea116e0f56cff4c49de72f143e04b682f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Mon, 25 Sep 2023 09:39:10 +0100 Subject: [PATCH 02/14] Update the fleet plugin to consume the package --- .../header/deployment_details.component.tsx | 102 ------------------ .../header/deployment_details.stories.tsx | 55 ---------- .../components/header/deployment_details.tsx | 47 ++++++-- .../translations/translations/fr-FR.json | 2 - .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 6 files changed, 36 insertions(+), 174 deletions(-) delete mode 100644 x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.component.tsx delete mode 100644 x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.stories.tsx diff --git a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.component.tsx b/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.component.tsx deleted file mode 100644 index 7e3b414cf0f6d..0000000000000 --- a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.component.tsx +++ /dev/null @@ -1,102 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import styled from 'styled-components'; - -import { - EuiPopover, - EuiText, - EuiForm, - EuiFormRow, - EuiFieldText, - EuiCopy, - EuiButtonIcon, - EuiFlexGroup, - EuiFlexItem, - EuiButton, - EuiLink, - EuiHeaderLink, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -export interface Props { - cloudId: string; - managementUrl?: string; - learnMoreUrl: string; -} - -const Description = styled(EuiText)` - margin-bottom: ${({ theme }) => theme.eui.euiSizeL}; -`; - -export const DeploymentDetails = ({ cloudId, learnMoreUrl, managementUrl }: Props) => { - const [isOpen, setIsOpen] = React.useState(false); - - const button = ( - setIsOpen(!isOpen)} iconType="iInCircle" iconSide="left" isActive> - {i18n.translate('xpack.fleet.integrations.deploymentButton', { - defaultMessage: 'View deployment details', - })} - - ); - - const management = managementUrl ? ( - - - - Create and manage API keys - - - - Learn more - - - - - ) : null; - - return ( - setIsOpen(false)} - button={button} - anchorPosition="downCenter" - > -
- - {i18n.translate('xpack.fleet.integrations.deploymentDescription', { - defaultMessage: - 'Send data to Elastic from your applications by referencing your deployment.', - })} - - - - - - - - - - {(copy) => ( - - )} - - - - - {management} - -
-
- ); -}; diff --git a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.stories.tsx b/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.stories.tsx deleted file mode 100644 index 5b311b3443e36..0000000000000 --- a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.stories.tsx +++ /dev/null @@ -1,55 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import type { Meta } from '@storybook/react'; -import { EuiHeader } from '@elastic/eui'; - -import { DeploymentDetails as ConnectedComponent } from './deployment_details'; -import type { Props as PureComponentProps } from './deployment_details.component'; -import { DeploymentDetails as PureComponent } from './deployment_details.component'; - -export default { - title: 'Sections/EPM/Deployment Details', - description: '', - decorators: [ - (storyFn) => { - const sections = [{ items: [] }, { items: [storyFn()] }]; - return ; - }, - ], -} as Meta; - -export const DeploymentDetails = () => { - return ; -}; - -DeploymentDetails.args = { - isCloudEnabled: true, -}; - -DeploymentDetails.argTypes = { - isCloudEnabled: { - type: { - name: 'boolean', - }, - defaultValue: true, - control: { - type: 'boolean', - }, - }, -}; - -export const Component = (props: PureComponentProps) => { - return ; -}; - -Component.args = { - cloudId: 'cloud-id', - learnMoreUrl: 'https://learn-more-url', - managementUrl: 'https://management-url', -}; diff --git a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx b/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx index 968d596a5f9d5..0258a702464a7 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx @@ -6,13 +6,18 @@ */ import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiPopover, EuiHeaderLink } from '@elastic/eui'; +import { + DeploymentDetailsKibanaProvider, + DeploymentDetails as DeploymentDetailsComponent, +} from '@kbn/cloud/deployment-details'; import { useStartServices } from '../../hooks'; -import { DeploymentDetails as Component } from './deployment_details.component'; - export const DeploymentDetails = () => { - const { share, cloud, docLinks } = useStartServices(); + const [isOpen, setIsOpen] = React.useState(false); + const { share, cloud, docLinks, application } = useStartServices(); // If the cloud plugin isn't enabled, we can't display the flyout. if (!cloud) { @@ -21,16 +26,36 @@ export const DeploymentDetails = () => { const { isCloudEnabled, cloudId } = cloud; - // If cloud isn't enabled or we don't have a cloudId we can't display the flyout. + // If cloud isn't enabled or we don't have a cloudId we don't render the button. if (!isCloudEnabled || !cloudId) { return null; } - const managementUrl = share.url.locators - .get('MANAGEMENT_APP_LOCATOR') - ?.useUrl({ sectionId: 'security', appId: 'api_keys' }); - - const learnMoreUrl = docLinks.links.fleet.apiKeysLearnMore; - - return ; + const button = ( + setIsOpen(!isOpen)} iconType="iInCircle" iconSide="left" isActive> + {i18n.translate('xpack.fleet.integrations.endpointsButton', { + defaultMessage: 'Endpoints', + })} + + ); + + return ( + + setIsOpen(false)} + button={button} + anchorPosition="downCenter" + > +
+ +
+
+
+ ); }; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 476cf52ad75b0..3d54a50ffb233 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -16432,8 +16432,6 @@ "xpack.fleet.homeIntegration.tutorialModule.noticeText.notePrefix": "Note", "xpack.fleet.initializationErrorMessageTitle": "Initialisation de Fleet impossible", "xpack.fleet.integrations.customInputsLink": "entrées personnalisées", - "xpack.fleet.integrations.deploymentButton": "Voir les détails du déploiement", - "xpack.fleet.integrations.deploymentDescription": "Envoyez des données à Elastic à partir de vos applications en référençant votre déploiement.", "xpack.fleet.integrations.discussForumLink": "forum", "xpack.fleet.integrations.installPackage.uploadedTooltip": "Cette intégration a été installée par le biais d'un chargement et ne peut pas être réinstallée automatiquement. Veuillez la charger à nouveau pour la réinstaller.", "xpack.fleet.integrations.integrationSaved": "Paramètres de l'intégration enregistrés", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f4d62e612683f..f86e1488f292d 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -16446,8 +16446,6 @@ "xpack.fleet.homeIntegration.tutorialModule.noticeText.notePrefix": "注", "xpack.fleet.initializationErrorMessageTitle": "Fleet を初期化できません", "xpack.fleet.integrations.customInputsLink": "カスタム入力", - "xpack.fleet.integrations.deploymentButton": "デプロイ詳細の表示", - "xpack.fleet.integrations.deploymentDescription": "デプロイを参照し、アプリケーションのデータをElasticに送信します。", "xpack.fleet.integrations.discussForumLink": "フォーラム", "xpack.fleet.integrations.installPackage.uploadedTooltip": "この統合はアップロードによってインストールされたため、自動的に再インストールできません。再インストールするには、もう一度アップロードしてください。", "xpack.fleet.integrations.integrationSaved": "統合設定が保存されました", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 4a5eaa855f6f7..675abbaecad78 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -16446,8 +16446,6 @@ "xpack.fleet.homeIntegration.tutorialModule.noticeText.notePrefix": "备注", "xpack.fleet.initializationErrorMessageTitle": "无法初始化 Fleet", "xpack.fleet.integrations.customInputsLink": "定制输入", - "xpack.fleet.integrations.deploymentButton": "查看部署详情", - "xpack.fleet.integrations.deploymentDescription": "通过引用部署,将数据从应用程序发送到 Elastic。", "xpack.fleet.integrations.discussForumLink": "论坛", "xpack.fleet.integrations.installPackage.uploadedTooltip": "此集成通过上传进行安装,因此无法自动重新安装。请再次将其上传,以便重新安装。", "xpack.fleet.integrations.integrationSaved": "已保存集成设置", From 5189129c841a389ca843c637d2b664591856863e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Mon, 25 Sep 2023 09:47:24 +0100 Subject: [PATCH 03/14] Update cloud integration links to open modal --- .../src/ui/header/header_help_menu.tsx | 26 ++++++++++++-- .../core-chrome-browser/src/nav_controls.ts | 3 +- .../cloud_links/kibana.jsonc | 3 ++ .../maybe_add_cloud_links/endpoints_modal.tsx | 31 ++++++++++++++++ ...help_menu_links.ts => help_menu_links.tsx} | 35 +++++++++++++++++++ .../maybe_add_cloud_links.ts | 7 +++- .../cloud_links/public/plugin.tsx | 6 +++- 7 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/endpoints_modal.tsx rename x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/{help_menu_links.ts => help_menu_links.tsx} (54%) diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header_help_menu.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header_help_menu.tsx index e1e43d43ab401..0a62c2f486440 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header_help_menu.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/header_help_menu.tsx @@ -67,6 +67,7 @@ const buildDefaultContentLinks = ({ defaultMessage: 'Open an issue in GitHub', }), href: docLinks.links.kibana.createGithubIssue, + iconType: 'logoGithub', }, ]; @@ -201,11 +202,32 @@ export class HeaderHelpMenu extends Component { return ( - {defaultContentLinks.map(({ href, title, iconType }, i) => { + {defaultContentLinks.map(({ href, title, iconType, onClick: _onClick }, i) => { const isLast = i === defaultContentLinks.length - 1; + + if (href && _onClick) { + throw new Error( + 'Only one of `href` and `onClick` should be provided for the help menu link.' + ); + } + + const hrefProps = href ? { href, target: '_blank' } : {}; + const onClick = () => { + if (!_onClick) return; + _onClick(); + this.closeMenu(); + }; + return ( - + {} + {title} {!isLast && } diff --git a/packages/core/chrome/core-chrome-browser/src/nav_controls.ts b/packages/core/chrome/core-chrome-browser/src/nav_controls.ts index 39b5d1b3b59b1..eb7ec92ac83ad 100644 --- a/packages/core/chrome/core-chrome-browser/src/nav_controls.ts +++ b/packages/core/chrome/core-chrome-browser/src/nav_controls.ts @@ -18,8 +18,9 @@ export interface ChromeNavControl { /** @public */ export interface ChromeHelpMenuLink { title: string; - href: string; + href?: string; iconType?: string; + onClick?: () => void; } /** diff --git a/x-pack/plugins/cloud_integrations/cloud_links/kibana.jsonc b/x-pack/plugins/cloud_integrations/cloud_links/kibana.jsonc index 4b6625f842f79..660f6e64a2446 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/kibana.jsonc +++ b/x-pack/plugins/cloud_integrations/cloud_links/kibana.jsonc @@ -14,6 +14,9 @@ ], "requiredBundles": [ "kibanaReact" + ], + "requiredPlugins": [ + "share" ] } } diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/endpoints_modal.tsx b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/endpoints_modal.tsx new file mode 100644 index 0000000000000..d8e2ad0ec8c93 --- /dev/null +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/endpoints_modal.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import type { CoreStart } from '@kbn/core/public'; +import type { DocLinksStart } from '@kbn/core-doc-links-browser'; +import type { CloudStart } from '@kbn/cloud-plugin/public'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import { + DeploymentDetailsKibanaProvider, + DeploymentDetailsModal, +} from '@kbn/cloud/deployment-details'; + +interface Props { + closeModal: () => void; + core: CoreStart; + docLinks: DocLinksStart; + cloud: CloudStart; + share: SharePluginStart; +} + +export const EndpointsModal = ({ core, share, cloud, docLinks, closeModal }: Props) => { + return ( + + + + ); +}; diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.ts b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.tsx similarity index 54% rename from x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.ts rename to x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.tsx index 82b0e86e6569a..42070fb47aa2b 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.ts +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.tsx @@ -4,17 +4,32 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import React from 'react'; import { i18n } from '@kbn/i18n'; import { ChromeHelpMenuLink } from '@kbn/core-chrome-browser'; import type { DocLinksStart } from '@kbn/core-doc-links-browser'; +import type { CoreStart } from '@kbn/core/public'; +import type { CloudStart } from '@kbn/cloud-plugin/public'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; + +import { EndpointsModal } from './endpoints_modal'; export const createHelpMenuLinks = ({ docLinks, helpSupportUrl, + core, + cloud, + share, }: { docLinks: DocLinksStart; + core: CoreStart; + cloud: CloudStart; + share: SharePluginStart; helpSupportUrl: string; }) => { + const { overlays } = core; + const helpMenuLinks: ChromeHelpMenuLink[] = [ { title: i18n.translate('xpack.cloudLinks.helpMenuLinks.documentation', { @@ -34,6 +49,26 @@ export const createHelpMenuLinks = ({ }), href: docLinks.links.kibana.feedback, }, + { + title: i18n.translate('xpack.cloudLinks.helpMenuLinks.endpoints', { + defaultMessage: 'Endpoints', + }), + iconType: 'console', + onClick: () => { + const modal = overlays.openModal( + toMountPoint( + modal.close()} + />, + { theme: core.theme, i18n: core.i18n } + ) + ); + }, + }, ]; return helpMenuLinks; diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.ts b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.ts index 33fb4df7bfce2..2772c87d124d3 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.ts +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.ts @@ -11,6 +11,7 @@ import { i18n } from '@kbn/i18n'; import type { CloudStart } from '@kbn/cloud-plugin/public'; import type { CoreStart } from '@kbn/core/public'; import type { SecurityPluginStart } from '@kbn/security-plugin/public'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; import { createUserMenuLinks } from './user_menu_links'; import { createHelpMenuLinks } from './help_menu_links'; @@ -18,9 +19,10 @@ export interface MaybeAddCloudLinksDeps { core: CoreStart; security: SecurityPluginStart; cloud: CloudStart; + share: SharePluginStart; } -export function maybeAddCloudLinks({ core, security, cloud }: MaybeAddCloudLinksDeps): void { +export function maybeAddCloudLinks({ core, security, cloud, share }: MaybeAddCloudLinksDeps): void { const userObservable = defer(() => security.authc.getCurrentUser()).pipe( // Check if user is a cloud user. map((user) => user.elastic_cloud_user), @@ -54,6 +56,9 @@ export function maybeAddCloudLinks({ core, security, cloud }: MaybeAddCloudLinks const helpMenuLinks = createHelpMenuLinks({ docLinks: core.docLinks, helpSupportUrl, + core, + share, + cloud, }); core.chrome.setHelpMenuLinks(helpMenuLinks); diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.tsx b/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.tsx index 38b568791b70b..bfebe531276d4 100755 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.tsx +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.tsx @@ -11,6 +11,7 @@ import type { CoreStart, Plugin } from '@kbn/core/public'; import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; import type { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/public'; import type { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; import { maybeAddCloudLinks } from './maybe_add_cloud_links'; interface CloudLinksDepsSetup { @@ -21,6 +22,7 @@ interface CloudLinksDepsSetup { interface CloudLinksDepsStart { cloud?: CloudStart; security?: SecurityPluginStart; + share: SharePluginStart; guidedOnboarding?: GuidedOnboardingPluginStart; } @@ -29,7 +31,7 @@ export class CloudLinksPlugin { public setup() {} - public start(core: CoreStart, { cloud, security, guidedOnboarding }: CloudLinksDepsStart) { + public start(core: CoreStart, { cloud, security, guidedOnboarding, share }: CloudLinksDepsStart) { if (cloud?.isCloudEnabled && !core.http.anonymousPaths.isAnonymous(window.location.pathname)) { if (guidedOnboarding?.guidedOnboardingApi?.isEnabled) { core.chrome.registerGlobalHelpExtensionMenuLink({ @@ -42,11 +44,13 @@ export class CloudLinksPlugin priority: 1000, // We want this link to be at the very top. }); } + if (security) { maybeAddCloudLinks({ core, security, cloud, + share, }); } } From 584bb54b51f026123dda43ec073f0466e7b60c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Mon, 25 Sep 2023 10:07:38 +0100 Subject: [PATCH 04/14] Update jest test --- .../maybe_add_cloud_links.test.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts index b9045fdc9a59f..9b818f0dae5d9 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts @@ -8,6 +8,7 @@ import { cloudMock } from '@kbn/cloud-plugin/public/mocks'; import { coreMock } from '@kbn/core/public/mocks'; import { securityMock } from '@kbn/security-plugin/public/mocks'; +import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; import { maybeAddCloudLinks } from './maybe_add_cloud_links'; @@ -18,6 +19,7 @@ describe('maybeAddCloudLinks', () => { maybeAddCloudLinks({ core, security, + share: sharePluginMock.createStartContract(), cloud: { ...cloudMock.createStart(), isCloudEnabled: false }, }); // Since there's a promise, let's wait for the next tick @@ -35,6 +37,7 @@ describe('maybeAddCloudLinks', () => { maybeAddCloudLinks({ security, core, + share: sharePluginMock.createStartContract(), cloud: { ...cloudMock.createStart(), isCloudEnabled: true }, }); // Since there's a promise, let's wait for the next tick @@ -90,6 +93,11 @@ describe('maybeAddCloudLinks', () => { "href": "https://www.elastic.co/products/kibana/feedback?blade=kibanafeedback", "title": "Give feedback", }, + Object { + "iconType": "console", + "onClick": [Function], + "title": "Endpoints", + }, ], ] `); @@ -103,6 +111,7 @@ describe('maybeAddCloudLinks', () => { maybeAddCloudLinks({ security, core, + share: sharePluginMock.createStartContract(), cloud: { ...cloudMock.createStart(), isCloudEnabled: true }, }); // Since there's a promise, let's wait for the next tick @@ -157,6 +166,11 @@ describe('maybeAddCloudLinks', () => { "href": "https://www.elastic.co/products/kibana/feedback?blade=kibanafeedback", "title": "Give feedback", }, + Object { + "iconType": "console", + "onClick": [Function], + "title": "Endpoints", + }, ], ] `); @@ -172,6 +186,7 @@ describe('maybeAddCloudLinks', () => { maybeAddCloudLinks({ security, core, + share: sharePluginMock.createStartContract(), cloud: { ...cloudMock.createStart(), isCloudEnabled: true }, }); // Since there's a promise, let's wait for the next tick From 462038b52aad321ff039ff4f6d2d85e44c2dd0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Mon, 25 Sep 2023 10:19:27 +0100 Subject: [PATCH 05/14] Update docs --- docs/setup/connect-to-elasticsearch.asciidoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/setup/connect-to-elasticsearch.asciidoc b/docs/setup/connect-to-elasticsearch.asciidoc index e271eb6cce5c0..fef9ae71a085b 100644 --- a/docs/setup/connect-to-elasticsearch.asciidoc +++ b/docs/setup/connect-to-elasticsearch.asciidoc @@ -54,8 +54,9 @@ Details for each programming language library that Elastic provides are in the https://www.elastic.co/guide/en/elasticsearch/client/index.html[{es} Client documentation]. If you are running {kib} on our hosted {es} Service, -click *View deployment details* on the *Integrations* view +click *Endpoints* on the *Integrations* view to verify your {es} endpoint and Cloud ID, and create API keys for integration. +Alternatively, the *Endpoints* are also accessible through the top bar help menu. [float] === Add sample data From 8092db43d302c0e91cef81dc85b1363d9698f665 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:28:44 +0000 Subject: [PATCH 06/14] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- packages/cloud/tsconfig.json | 6 ++++-- x-pack/plugins/cloud_integrations/cloud_links/tsconfig.json | 3 +++ x-pack/plugins/fleet/tsconfig.json | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/cloud/tsconfig.json b/packages/cloud/tsconfig.json index dad708677fd87..c4703bc51cf6c 100644 --- a/packages/cloud/tsconfig.json +++ b/packages/cloud/tsconfig.json @@ -10,10 +10,12 @@ }, "include": [ "**/*.ts", - "**/*.tsx", + "**/*.tsx", ], "exclude": [ "target/**/*" ], - "kbn_references": [] + "kbn_references": [ + "@kbn/i18n", + ] } diff --git a/x-pack/plugins/cloud_integrations/cloud_links/tsconfig.json b/x-pack/plugins/cloud_integrations/cloud_links/tsconfig.json index f1a67895cdd5e..43f411cadf060 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/tsconfig.json +++ b/x-pack/plugins/cloud_integrations/cloud_links/tsconfig.json @@ -23,6 +23,9 @@ "@kbn/user-profile-components", "@kbn/core-lifecycle-browser", "@kbn/kibana-react-plugin", + "@kbn/share-plugin", + "@kbn/cloud", + "@kbn/react-kibana-mount", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/fleet/tsconfig.json b/x-pack/plugins/fleet/tsconfig.json index b3f8a96417f9a..58cdfa25d1e08 100644 --- a/x-pack/plugins/fleet/tsconfig.json +++ b/x-pack/plugins/fleet/tsconfig.json @@ -101,5 +101,6 @@ "@kbn/core-saved-objects-base-server-internal", "@kbn/core-http-common", "@kbn/dashboard-plugin", + "@kbn/cloud", ] } From a2dcc690a9aaa7891e59f3ffedeca1112ba95589 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:34:33 +0000 Subject: [PATCH 07/14] [CI] Auto-commit changed files from 'node scripts/generate codeowners' --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ecfb835cbc4d0..21544e6bccb7c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -67,6 +67,7 @@ packages/kbn-ci-stats-performance-metrics @elastic/kibana-operations packages/kbn-ci-stats-reporter @elastic/kibana-operations packages/kbn-ci-stats-shipper-cli @elastic/kibana-operations packages/kbn-cli-dev-mode @elastic/kibana-operations +packages/cloud @elastic/kibana-core x-pack/plugins/cloud_integrations/cloud_chat @elastic/kibana-core x-pack/plugins/cloud_integrations/cloud_chat_provider @elastic/kibana-core x-pack/plugins/cloud_integrations/cloud_data_migration @elastic/platform-onboarding From d69e76a30af595274d60ef30a3dc964139266f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Mon, 25 Sep 2023 12:06:26 +0100 Subject: [PATCH 08/14] Add cloud functional test --- .../deployment-details/deployment_details.tsx | 14 ++++- .../deployment_details_modal.tsx | 5 +- .../cloud/deployment-details/services.tsx | 2 +- .../src/ui/header/header_help_menu.tsx | 62 ++++++++++--------- .../core-chrome-browser/src/nav_controls.ts | 1 + .../maybe_add_cloud_links/help_menu_links.tsx | 1 + x-pack/test/functional_cloud/config.ts | 3 +- .../functional_cloud/tests/cloud_links.ts | 22 +++++++ 8 files changed, 75 insertions(+), 35 deletions(-) diff --git a/packages/cloud/deployment-details/deployment_details.tsx b/packages/cloud/deployment-details/deployment_details.tsx index 6f96b1b25b72c..988217648f3e8 100644 --- a/packages/cloud/deployment-details/deployment_details.tsx +++ b/packages/cloud/deployment-details/deployment_details.tsx @@ -44,7 +44,12 @@ export const DeploymentDetails = ({ closeModal }: { closeModal?: () => void }) = > - + @@ -71,7 +76,12 @@ export const DeploymentDetails = ({ closeModal }: { closeModal?: () => void }) = > - + diff --git a/packages/cloud/deployment-details/deployment_details_modal.tsx b/packages/cloud/deployment-details/deployment_details_modal.tsx index d3db46e8d1a95..2f3d628c2ca47 100644 --- a/packages/cloud/deployment-details/deployment_details_modal.tsx +++ b/packages/cloud/deployment-details/deployment_details_modal.tsx @@ -34,6 +34,7 @@ export const DeploymentDetailsModal: FC = ({ closeModal }) => { closeModal(); }} style={{ width: 600 }} + data-test-subj="deploymentDetailsModal" > @@ -56,7 +57,9 @@ export const DeploymentDetailsModal: FC = ({ closeModal }) => { - Close + {i18n.translate('cloud.deploymentDetails.modal.closeButtonLabel', { + defaultMessage: 'Close', + })} diff --git a/packages/cloud/deployment-details/services.tsx b/packages/cloud/deployment-details/services.tsx index f6a93c41200b8..54a796feb42e5 100644 --- a/packages/cloud/deployment-details/services.tsx +++ b/packages/cloud/deployment-details/services.tsx @@ -76,7 +76,7 @@ export const DeploymentDetailsKibanaProvider: FC { return ( - {defaultContentLinks.map(({ href, title, iconType, onClick: _onClick }, i) => { - const isLast = i === defaultContentLinks.length - 1; - - if (href && _onClick) { - throw new Error( - 'Only one of `href` and `onClick` should be provided for the help menu link.' + {defaultContentLinks.map( + ({ href, title, iconType, onClick: _onClick, dataTestSubj }, i) => { + const isLast = i === defaultContentLinks.length - 1; + + if (href && _onClick) { + throw new Error( + 'Only one of `href` and `onClick` should be provided for the help menu link.' + ); + } + + const hrefProps = href ? { href, target: '_blank' } : {}; + const onClick = () => { + if (!_onClick) return; + _onClick(); + this.closeMenu(); + }; + + return ( + + + {title} + + {!isLast && } + ); } - - const hrefProps = href ? { href, target: '_blank' } : {}; - const onClick = () => { - if (!_onClick) return; - _onClick(); - this.closeMenu(); - }; - - return ( - - {} - - {title} - - {!isLast && } - - ); - })} + )} ); } diff --git a/packages/core/chrome/core-chrome-browser/src/nav_controls.ts b/packages/core/chrome/core-chrome-browser/src/nav_controls.ts index eb7ec92ac83ad..22c074862151b 100644 --- a/packages/core/chrome/core-chrome-browser/src/nav_controls.ts +++ b/packages/core/chrome/core-chrome-browser/src/nav_controls.ts @@ -21,6 +21,7 @@ export interface ChromeHelpMenuLink { href?: string; iconType?: string; onClick?: () => void; + dataTestSubj?: string; } /** diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.tsx b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.tsx index 42070fb47aa2b..15270c5876214 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.tsx +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.tsx @@ -54,6 +54,7 @@ export const createHelpMenuLinks = ({ defaultMessage: 'Endpoints', }), iconType: 'console', + dataTestSubj: 'endpointsHelpLink', onClick: () => { const modal = overlays.openModal( toMountPoint( diff --git a/x-pack/test/functional_cloud/config.ts b/x-pack/test/functional_cloud/config.ts index c3203677631a9..df75e83138ed5 100644 --- a/x-pack/test/functional_cloud/config.ts +++ b/x-pack/test/functional_cloud/config.ts @@ -44,7 +44,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { serverArgs: [ ...functionalConfig.get('kbnTestServer.serverArgs'), `--plugin-path=${samlIdPPlugin}`, - '--xpack.cloud.id=ftr_fake_cloud_id', + // Note: the base64 string in the cloud.id config contains the ES endpoint required in the functional tests + '--xpack.cloud.id=ftr_fake_cloud_id:aGVsbG8uY29tOjQ0MyRFUzEyM2FiYyRrYm4xMjNhYmM=', '--xpack.cloud.base_url=https://cloud.elastic.co', '--xpack.cloud.deployment_url=/deployments/deploymentId', '--xpack.cloud.organization_url=/organization/organizationId', diff --git a/x-pack/test/functional_cloud/tests/cloud_links.ts b/x-pack/test/functional_cloud/tests/cloud_links.ts index 873cd943ec59d..94f67401c98fd 100644 --- a/x-pack/test/functional_cloud/tests/cloud_links.ts +++ b/x-pack/test/functional_cloud/tests/cloud_links.ts @@ -46,6 +46,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await find.byCssSelector('[data-test-subj="cloudOnboardingSetupGuideLink"]') ).to.not.be(null); }); + + it('A button to open a modal to view the CloudID and ES endpoint is added', async () => { + await PageObjects.common.clickAndValidate('helpMenuButton', 'endpointsHelpLink'); + expect(await find.byCssSelector('[data-test-subj="endpointsHelpLink"]')).to.not.be(null); + + // Open the modal + await PageObjects.common.clickAndValidate('endpointsHelpLink', 'deploymentDetailsModal'); + + const esEndpointInput = await find.byCssSelector( + '[data-test-subj="deploymentDetailsEsEndpoint"]' + ); + const esEndpointValue = await esEndpointInput.getAttribute('value'); + expect(esEndpointValue).to.be('https://ES123abc.hello.com:443'); + + const cloudIdInput = await find.byCssSelector( + '[data-test-subj="deploymentDetailsCloudID"]' + ); + const cloudIdInputValue = await cloudIdInput.getAttribute('value'); + expect(cloudIdInputValue).to.be( + 'ftr_fake_cloud_id:aGVsbG8uY29tOjQ0MyRFUzEyM2FiYyRrYm4xMjNhYmM=' + ); + }); }); it('"Manage this deployment" is appended to the nav list', async () => { From c269ca67d7fb0f4f9745b7995e99d60cad81aa9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Mon, 25 Sep 2023 12:30:03 +0100 Subject: [PATCH 09/14] Change folder name to snake_case --- .../deployment_details.tsx | 0 .../deployment_details_modal.tsx | 0 .../cloud/{deployment-details => deployment_details}/index.ts | 0 .../{deployment-details => deployment_details}/services.tsx | 0 .../public/maybe_add_cloud_links/endpoints_modal.tsx | 2 +- .../integrations/components/header/deployment_details.tsx | 2 +- 6 files changed, 2 insertions(+), 2 deletions(-) rename packages/cloud/{deployment-details => deployment_details}/deployment_details.tsx (100%) rename packages/cloud/{deployment-details => deployment_details}/deployment_details_modal.tsx (100%) rename packages/cloud/{deployment-details => deployment_details}/index.ts (100%) rename packages/cloud/{deployment-details => deployment_details}/services.tsx (100%) diff --git a/packages/cloud/deployment-details/deployment_details.tsx b/packages/cloud/deployment_details/deployment_details.tsx similarity index 100% rename from packages/cloud/deployment-details/deployment_details.tsx rename to packages/cloud/deployment_details/deployment_details.tsx diff --git a/packages/cloud/deployment-details/deployment_details_modal.tsx b/packages/cloud/deployment_details/deployment_details_modal.tsx similarity index 100% rename from packages/cloud/deployment-details/deployment_details_modal.tsx rename to packages/cloud/deployment_details/deployment_details_modal.tsx diff --git a/packages/cloud/deployment-details/index.ts b/packages/cloud/deployment_details/index.ts similarity index 100% rename from packages/cloud/deployment-details/index.ts rename to packages/cloud/deployment_details/index.ts diff --git a/packages/cloud/deployment-details/services.tsx b/packages/cloud/deployment_details/services.tsx similarity index 100% rename from packages/cloud/deployment-details/services.tsx rename to packages/cloud/deployment_details/services.tsx diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/endpoints_modal.tsx b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/endpoints_modal.tsx index d8e2ad0ec8c93..7c6b23d352f1a 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/endpoints_modal.tsx +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/endpoints_modal.tsx @@ -12,7 +12,7 @@ import type { SharePluginStart } from '@kbn/share-plugin/public'; import { DeploymentDetailsKibanaProvider, DeploymentDetailsModal, -} from '@kbn/cloud/deployment-details'; +} from '@kbn/cloud/deployment_details'; interface Props { closeModal: () => void; diff --git a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx b/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx index 0258a702464a7..ea17bc3f201c4 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx @@ -11,7 +11,7 @@ import { EuiPopover, EuiHeaderLink } from '@elastic/eui'; import { DeploymentDetailsKibanaProvider, DeploymentDetails as DeploymentDetailsComponent, -} from '@kbn/cloud/deployment-details'; +} from '@kbn/cloud/deployment_details'; import { useStartServices } from '../../hooks'; From b06adf76ec47d2dc47b30ab96e02b06ea8c16f4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Tue, 26 Sep 2023 10:01:51 +0100 Subject: [PATCH 10/14] Fix jest test --- .../public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts index 9b818f0dae5d9..d680d6cce4f4f 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/maybe_add_cloud_links.test.ts @@ -94,6 +94,7 @@ describe('maybeAddCloudLinks', () => { "title": "Give feedback", }, Object { + "dataTestSubj": "endpointsHelpLink", "iconType": "console", "onClick": [Function], "title": "Endpoints", @@ -167,6 +168,7 @@ describe('maybeAddCloudLinks', () => { "title": "Give feedback", }, Object { + "dataTestSubj": "endpointsHelpLink", "iconType": "console", "onClick": [Function], "title": "Endpoints", From 3a403e0be77b4ef535a0cdde1e50af1320950967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Tue, 26 Sep 2023 10:21:55 +0100 Subject: [PATCH 11/14] Fix TS issue --- .../cloud_links/public/plugin.test.ts | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.test.ts b/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.test.ts index d928b7a6f0e8a..d2f987337a440 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.test.ts +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/plugin.test.ts @@ -11,6 +11,7 @@ import { coreMock } from '@kbn/core/public/mocks'; import { cloudMock } from '@kbn/cloud-plugin/public/mocks'; import { securityMock } from '@kbn/security-plugin/public/mocks'; import { guidedOnboardingMock } from '@kbn/guided-onboarding-plugin/public/mocks'; +import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; describe('Cloud Links Plugin - public', () => { let plugin: CloudLinksPlugin; @@ -40,7 +41,11 @@ describe('Cloud Links Plugin - public', () => { coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; - plugin.start(coreStart, { cloud, guidedOnboarding }); + plugin.start(coreStart, { + cloud, + guidedOnboarding, + share: sharePluginMock.createStartContract(), + }); expect(coreStart.chrome.registerGlobalHelpExtensionMenuLink).toHaveBeenCalledTimes(1); }); @@ -48,14 +53,22 @@ describe('Cloud Links Plugin - public', () => { const coreStart = coreMock.createStart(); coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true); const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; - plugin.start(coreStart, { cloud, guidedOnboarding }); + plugin.start(coreStart, { + cloud, + guidedOnboarding, + share: sharePluginMock.createStartContract(), + }); expect(coreStart.chrome.registerGlobalHelpExtensionMenuLink).not.toHaveBeenCalled(); }); test('does not register the Onboarding Setup Guide link when cloud is not enabled', () => { const coreStart = coreMock.createStart(); const cloud = { ...cloudMock.createStart(), isCloudEnabled: false }; - plugin.start(coreStart, { cloud, guidedOnboarding }); + plugin.start(coreStart, { + cloud, + guidedOnboarding, + share: sharePluginMock.createStartContract(), + }); expect(coreStart.chrome.registerGlobalHelpExtensionMenuLink).not.toHaveBeenCalled(); }); }); @@ -72,7 +85,11 @@ describe('Cloud Links Plugin - public', () => { coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; - plugin.start(coreStart, { cloud, guidedOnboarding }); + plugin.start(coreStart, { + cloud, + guidedOnboarding, + share: sharePluginMock.createStartContract(), + }); expect(coreStart.chrome.registerGlobalHelpExtensionMenuLink).not.toHaveBeenCalled(); }); }); @@ -83,7 +100,7 @@ describe('Cloud Links Plugin - public', () => { coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; const security = securityMock.createStart(); - plugin.start(coreStart, { cloud, security }); + plugin.start(coreStart, { cloud, security, share: sharePluginMock.createStartContract() }); expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(1); }); @@ -91,7 +108,7 @@ describe('Cloud Links Plugin - public', () => { const coreStart = coreMock.createStart(); coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; - plugin.start(coreStart, { cloud }); + plugin.start(coreStart, { cloud, share: sharePluginMock.createStartContract() }); expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); }); @@ -100,7 +117,7 @@ describe('Cloud Links Plugin - public', () => { coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true); const cloud = { ...cloudMock.createStart(), isCloudEnabled: true }; const security = securityMock.createStart(); - plugin.start(coreStart, { cloud, security }); + plugin.start(coreStart, { cloud, security, share: sharePluginMock.createStartContract() }); expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); }); @@ -108,7 +125,7 @@ describe('Cloud Links Plugin - public', () => { const coreStart = coreMock.createStart(); coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); const security = securityMock.createStart(); - plugin.start(coreStart, { security }); + plugin.start(coreStart, { security, share: sharePluginMock.createStartContract() }); expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); }); @@ -117,7 +134,7 @@ describe('Cloud Links Plugin - public', () => { coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false); const cloud = { ...cloudMock.createStart(), isCloudEnabled: false }; const security = securityMock.createStart(); - plugin.start(coreStart, { cloud, security }); + plugin.start(coreStart, { cloud, security, share: sharePluginMock.createStartContract() }); expect(maybeAddCloudLinksMock).toHaveBeenCalledTimes(0); }); }); From 4eb0f4ea036631994e92a472ca5aaa060e549c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Wed, 27 Sep 2023 10:31:52 +0100 Subject: [PATCH 12/14] Remove unused barrel file --- packages/cloud/index.ts | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 packages/cloud/index.ts diff --git a/packages/cloud/index.ts b/packages/cloud/index.ts deleted file mode 100644 index b6e7485e36ab2..0000000000000 --- a/packages/cloud/index.ts +++ /dev/null @@ -1,11 +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. - */ - -export function foo() { - return 'hello world'; -} From 241e22d020ae1e67a6efc8dbbf5271fc31c781aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Wed, 27 Sep 2023 10:57:36 +0100 Subject: [PATCH 13/14] Allow cmd+click to open "manage API keys" link --- .../cloud/deployment_details/deployment_details.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/cloud/deployment_details/deployment_details.tsx b/packages/cloud/deployment_details/deployment_details.tsx index 988217648f3e8..bb06c8031efb2 100644 --- a/packages/cloud/deployment_details/deployment_details.tsx +++ b/packages/cloud/deployment_details/deployment_details.tsx @@ -22,6 +22,10 @@ import { import { i18n } from '@kbn/i18n'; import { useDeploymentDetails } from './services'; +const hasActiveModifierKey = (event: React.MouseEvent): boolean => { + return event.metaKey || event.altKey || event.ctrlKey || event.shiftKey; +}; + export const DeploymentDetails = ({ closeModal }: { closeModal?: () => void }) => { const { cloudId, elasticsearchUrl, managementUrl, learnMoreUrl, navigateToUrl } = useDeploymentDetails(); @@ -101,9 +105,11 @@ export const DeploymentDetails = ({ closeModal }: { closeModal?: () => void }) = {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} { - e.preventDefault(); - navigateToUrl(managementUrl); + onClick={(e: React.MouseEvent) => { + if (!hasActiveModifierKey(e)) { + e.preventDefault(); + navigateToUrl(managementUrl); + } if (closeModal) { closeModal(); } From 9d4628189d0a4d6134d6ed4e5eace36e05d222d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Wed, 27 Sep 2023 11:04:27 +0100 Subject: [PATCH 14/14] Address CR changes --- .../deployment_details/deployment_details.tsx | 135 +++++------------- .../deployment_details_cloudid_input.tsx | 46 ++++++ .../deployment_details_es_input.tsx | 48 +++++++ .../cloud/deployment_details/services.tsx | 9 +- 4 files changed, 139 insertions(+), 99 deletions(-) create mode 100644 packages/cloud/deployment_details/deployment_details_cloudid_input.tsx create mode 100644 packages/cloud/deployment_details/deployment_details_es_input.tsx diff --git a/packages/cloud/deployment_details/deployment_details.tsx b/packages/cloud/deployment_details/deployment_details.tsx index bb06c8031efb2..278709f7b6d32 100644 --- a/packages/cloud/deployment_details/deployment_details.tsx +++ b/packages/cloud/deployment_details/deployment_details.tsx @@ -9,10 +9,6 @@ import React from 'react'; import { EuiForm, - EuiFormRow, - EuiFieldText, - EuiCopy, - EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiLink, @@ -21,6 +17,8 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useDeploymentDetails } from './services'; +import { DeploymentDetailsEsInput } from './deployment_details_es_input'; +import { DeploymentDetailsCloudIdInput } from './deployment_details_cloudid_input'; const hasActiveModifierKey = (event: React.MouseEvent): boolean => { return event.metaKey || event.altKey || event.ctrlKey || event.shiftKey; @@ -36,103 +34,48 @@ export const DeploymentDetails = ({ closeModal }: { closeModal?: () => void }) = } return ( - <> - - {/* Elastic endpoint */} - {elasticsearchUrl && ( - - - - - - - - {(copy) => ( - - )} - - - - - )} + + {/* Elastic endpoint */} + {elasticsearchUrl && } - {/* Cloud ID */} - - - - - - - - {(copy) => ( - - )} - - - - + {/* Cloud ID */} + - + - {managementUrl && ( - + {managementUrl && ( + + + {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} + { + if (!hasActiveModifierKey(e)) { + e.preventDefault(); + navigateToUrl(managementUrl); + } + if (closeModal) { + closeModal(); + } + }} + flush="left" + > + {i18n.translate('cloud.deploymentDetails.createManageApiKeysButtonLabel', { + defaultMessage: 'Create and manage API keys', + })} + + + {!isInsideModal && ( - {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} - { - if (!hasActiveModifierKey(e)) { - e.preventDefault(); - navigateToUrl(managementUrl); - } - if (closeModal) { - closeModal(); - } - }} - flush="left" - > - {i18n.translate('cloud.deploymentDetails.createManageApiKeysButtonLabel', { - defaultMessage: 'Create and manage API keys', + + {i18n.translate('cloud.deploymentDetails.learnMoreButtonLabel', { + defaultMessage: 'Learn more', })} - + - {!isInsideModal && ( - - - {i18n.translate('cloud.deploymentDetails.learnMoreButtonLabel', { - defaultMessage: 'Learn more', - })} - - - )} - - )} - - + )} + + )} + ); }; diff --git a/packages/cloud/deployment_details/deployment_details_cloudid_input.tsx b/packages/cloud/deployment_details/deployment_details_cloudid_input.tsx new file mode 100644 index 0000000000000..a749fe4371715 --- /dev/null +++ b/packages/cloud/deployment_details/deployment_details_cloudid_input.tsx @@ -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 React, { type FC } from 'react'; +import { + EuiFormRow, + EuiFieldText, + EuiCopy, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +export const DeploymentDetailsCloudIdInput: FC<{ cloudId: string }> = ({ cloudId }) => { + return ( + + + + + + + + {(copy) => ( + + )} + + + + + ); +}; diff --git a/packages/cloud/deployment_details/deployment_details_es_input.tsx b/packages/cloud/deployment_details/deployment_details_es_input.tsx new file mode 100644 index 0000000000000..2998b5bade543 --- /dev/null +++ b/packages/cloud/deployment_details/deployment_details_es_input.tsx @@ -0,0 +1,48 @@ +/* + * 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, { type FC } from 'react'; +import { + EuiFormRow, + EuiFieldText, + EuiCopy, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +export const DeploymentDetailsEsInput: FC<{ elasticsearchUrl: string }> = ({ + elasticsearchUrl, +}) => { + return ( + + + + + + + + {(copy) => ( + + )} + + + + + ); +}; diff --git a/packages/cloud/deployment_details/services.tsx b/packages/cloud/deployment_details/services.tsx index 54a796feb42e5..c4e8be12bb547 100644 --- a/packages/cloud/deployment_details/services.tsx +++ b/packages/cloud/deployment_details/services.tsx @@ -8,7 +8,7 @@ import React, { FC, useContext } from 'react'; -export interface Services { +export interface DeploymentDetailsContextValue { cloudId?: string; elasticsearchUrl?: string; managementUrl?: string; @@ -16,12 +16,15 @@ export interface Services { navigateToUrl(url: string): Promise; } -const DeploymentDetailsContext = React.createContext(null); +const DeploymentDetailsContext = React.createContext(null); /** * Abstract external service Provider. */ -export const DeploymentDetailsProvider: FC = ({ children, ...services }) => { +export const DeploymentDetailsProvider: FC = ({ + children, + ...services +}) => { return ( {children}