mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 10:40:07 -04:00
[Cloud] ES endpoint discovery (#167122)
This commit is contained in:
parent
b90b2114a0
commit
92a92fff67
36 changed files with 662 additions and 198 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -173,6 +173,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",
|
||||
|
|
3
packages/cloud/README.md
Normal file
3
packages/cloud/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# @kbn/cloud
|
||||
|
||||
Empty package generated by @kbn/generate
|
81
packages/cloud/deployment_details/deployment_details.tsx
Normal file
81
packages/cloud/deployment_details/deployment_details.tsx
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiLink,
|
||||
EuiButtonEmpty,
|
||||
EuiSpacer,
|
||||
} 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;
|
||||
};
|
||||
|
||||
export const DeploymentDetails = ({ closeModal }: { closeModal?: () => void }) => {
|
||||
const { cloudId, elasticsearchUrl, managementUrl, learnMoreUrl, navigateToUrl } =
|
||||
useDeploymentDetails();
|
||||
const isInsideModal = !!closeModal;
|
||||
|
||||
if (!cloudId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiForm component="div">
|
||||
{/* Elastic endpoint */}
|
||||
{elasticsearchUrl && <DeploymentDetailsEsInput elasticsearchUrl={elasticsearchUrl} />}
|
||||
|
||||
{/* Cloud ID */}
|
||||
<DeploymentDetailsCloudIdInput cloudId={cloudId} />
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
{managementUrl && (
|
||||
<EuiFlexGroup gutterSize="m" justifyContent="spaceBetween" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
|
||||
<EuiButtonEmpty
|
||||
href={managementUrl}
|
||||
onClick={(e: React.MouseEvent) => {
|
||||
if (!hasActiveModifierKey(e)) {
|
||||
e.preventDefault();
|
||||
navigateToUrl(managementUrl);
|
||||
}
|
||||
if (closeModal) {
|
||||
closeModal();
|
||||
}
|
||||
}}
|
||||
flush="left"
|
||||
>
|
||||
{i18n.translate('cloud.deploymentDetails.createManageApiKeysButtonLabel', {
|
||||
defaultMessage: 'Create and manage API keys',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
{!isInsideModal && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLink external href={learnMoreUrl} target="_blank">
|
||||
{i18n.translate('cloud.deploymentDetails.learnMoreButtonLabel', {
|
||||
defaultMessage: 'Learn more',
|
||||
})}
|
||||
</EuiLink>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
)}
|
||||
</EuiForm>
|
||||
);
|
||||
};
|
|
@ -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 (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('cloud.deploymentDetails.cloudIDLabel', {
|
||||
defaultMessage: 'Cloud ID',
|
||||
})}
|
||||
fullWidth
|
||||
>
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<EuiFieldText
|
||||
value={cloudId}
|
||||
fullWidth
|
||||
disabled
|
||||
data-test-subj="deploymentDetailsCloudID"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiCopy textToCopy={cloudId}>
|
||||
{(copy) => (
|
||||
<EuiButtonIcon onClick={copy} iconType="copyClipboard" display="base" size="m" />
|
||||
)}
|
||||
</EuiCopy>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
);
|
||||
};
|
|
@ -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 (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('cloud.deploymentDetails.elasticEndpointLabel', {
|
||||
defaultMessage: 'Elastic endpoint',
|
||||
})}
|
||||
fullWidth
|
||||
>
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<EuiFieldText
|
||||
value={elasticsearchUrl}
|
||||
fullWidth
|
||||
disabled
|
||||
data-test-subj="deploymentDetailsEsEndpoint"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiCopy textToCopy={elasticsearchUrl}>
|
||||
{(copy) => (
|
||||
<EuiButtonIcon onClick={copy} iconType="copyClipboard" display="base" size="m" />
|
||||
)}
|
||||
</EuiCopy>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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<Props> = ({ closeModal }) => {
|
||||
const { learnMoreUrl } = useDeploymentDetails();
|
||||
|
||||
return (
|
||||
<EuiModal
|
||||
onClose={() => {
|
||||
closeModal();
|
||||
}}
|
||||
style={{ width: 600 }}
|
||||
data-test-subj="deploymentDetailsModal"
|
||||
>
|
||||
<EuiModalHeader>
|
||||
<EuiModalHeaderTitle>
|
||||
{i18n.translate('cloud.deploymentDetails.helpMenuLinks.endpoints', {
|
||||
defaultMessage: 'Endpoints',
|
||||
})}
|
||||
</EuiModalHeaderTitle>
|
||||
</EuiModalHeader>
|
||||
<EuiModalBody>
|
||||
<DeploymentDetails closeModal={closeModal} />
|
||||
</EuiModalBody>
|
||||
<EuiModalFooter>
|
||||
<EuiFlexGroup alignItems="baseline" justifyContent="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLink external href={learnMoreUrl} target="_blank">
|
||||
{i18n.translate('cloud.deploymentDetails.modal.learnMoreButtonLabel', {
|
||||
defaultMessage: 'Learn more',
|
||||
})}
|
||||
</EuiLink>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton onClick={closeModal} fill>
|
||||
{i18n.translate('cloud.deploymentDetails.modal.closeButtonLabel', {
|
||||
defaultMessage: 'Close',
|
||||
})}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiModalFooter>
|
||||
</EuiModal>
|
||||
);
|
||||
};
|
11
packages/cloud/deployment_details/index.ts
Normal file
11
packages/cloud/deployment_details/index.ts
Normal file
|
@ -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';
|
123
packages/cloud/deployment_details/services.tsx
Normal file
123
packages/cloud/deployment_details/services.tsx
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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 DeploymentDetailsContextValue {
|
||||
cloudId?: string;
|
||||
elasticsearchUrl?: string;
|
||||
managementUrl?: string;
|
||||
learnMoreUrl: string;
|
||||
navigateToUrl(url: string): Promise<void>;
|
||||
}
|
||||
|
||||
const DeploymentDetailsContext = React.createContext<DeploymentDetailsContextValue | null>(null);
|
||||
|
||||
/**
|
||||
* Abstract external service Provider.
|
||||
*/
|
||||
export const DeploymentDetailsProvider: FC<DeploymentDetailsContextValue> = ({
|
||||
children,
|
||||
...services
|
||||
}) => {
|
||||
return (
|
||||
<DeploymentDetailsContext.Provider value={services}>
|
||||
{children}
|
||||
</DeploymentDetailsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Kibana-specific service types.
|
||||
*/
|
||||
export interface DeploymentDetailsKibanaDependencies {
|
||||
/** CoreStart contract */
|
||||
core: {
|
||||
application: {
|
||||
navigateToUrl(url: string): Promise<void>;
|
||||
};
|
||||
};
|
||||
/** 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<DeploymentDetailsKibanaDependencies> = ({
|
||||
children,
|
||||
...services
|
||||
}) => {
|
||||
const {
|
||||
core: {
|
||||
application: { navigateToUrl },
|
||||
},
|
||||
cloud: { isCloudEnabled, cloudId, elasticsearchUrl },
|
||||
share: {
|
||||
url: { locators },
|
||||
},
|
||||
docLinks: {
|
||||
links: {
|
||||
fleet: { apiKeysLearnMore },
|
||||
},
|
||||
},
|
||||
} = services;
|
||||
|
||||
const managementUrl = locators
|
||||
.get('MANAGEMENT_APP_LOCATOR')
|
||||
?.useUrl({ sectionId: 'security', appId: 'api_keys' });
|
||||
|
||||
return (
|
||||
<DeploymentDetailsProvider
|
||||
cloudId={isCloudEnabled ? cloudId : undefined}
|
||||
elasticsearchUrl={elasticsearchUrl}
|
||||
managementUrl={managementUrl}
|
||||
learnMoreUrl={apiKeysLearnMore}
|
||||
navigateToUrl={navigateToUrl}
|
||||
>
|
||||
{children}
|
||||
</DeploymentDetailsProvider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 <DeploymentDetailsProvider /> or <DeploymentDetailsKibanaProvider />.'
|
||||
);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
13
packages/cloud/jest.config.js
Normal file
13
packages/cloud/jest.config.js
Normal file
|
@ -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: ['<rootDir>/packages/cloud'],
|
||||
};
|
5
packages/cloud/kibana.jsonc
Normal file
5
packages/cloud/kibana.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type": "shared-common",
|
||||
"id": "@kbn/cloud",
|
||||
"owner": "@elastic/kibana-core"
|
||||
}
|
6
packages/cloud/package.json
Normal file
6
packages/cloud/package.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "@kbn/cloud",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0"
|
||||
}
|
21
packages/cloud/tsconfig.json
Normal file
21
packages/cloud/tsconfig.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "target/types",
|
||||
"types": [
|
||||
"jest",
|
||||
"node",
|
||||
"react"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*"
|
||||
],
|
||||
"kbn_references": [
|
||||
"@kbn/i18n",
|
||||
]
|
||||
}
|
|
@ -67,6 +67,7 @@ const buildDefaultContentLinks = ({
|
|||
defaultMessage: 'Open an issue in GitHub',
|
||||
}),
|
||||
href: docLinks.links.kibana.createGithubIssue,
|
||||
iconType: 'logoGithub',
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -201,17 +202,40 @@ export class HeaderHelpMenu extends Component<Props, State> {
|
|||
|
||||
return (
|
||||
<Fragment>
|
||||
{defaultContentLinks.map(({ href, title, iconType }, i) => {
|
||||
const isLast = i === defaultContentLinks.length - 1;
|
||||
return (
|
||||
<Fragment key={i}>
|
||||
<EuiButtonEmpty href={href} target="_blank" size="s" flush="left" iconType={iconType}>
|
||||
{title}
|
||||
</EuiButtonEmpty>
|
||||
{!isLast && <EuiSpacer size="xs" />}
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
{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 (
|
||||
<Fragment key={i}>
|
||||
<EuiButtonEmpty
|
||||
{...hrefProps}
|
||||
onClick={onClick}
|
||||
size="s"
|
||||
flush="left"
|
||||
iconType={iconType}
|
||||
data-test-subj={dataTestSubj}
|
||||
>
|
||||
{title}
|
||||
</EuiButtonEmpty>
|
||||
{!isLast && <EuiSpacer size="xs" />}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -18,8 +18,10 @@ export interface ChromeNavControl {
|
|||
/** @public */
|
||||
export interface ChromeHelpMenuLink {
|
||||
title: string;
|
||||
href: string;
|
||||
href?: string;
|
||||
iconType?: string;
|
||||
onClick?: () => void;
|
||||
dataTestSubj?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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"],
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
],
|
||||
"requiredBundles": [
|
||||
"kibanaReact"
|
||||
],
|
||||
"requiredPlugins": [
|
||||
"share"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
<DeploymentDetailsKibanaProvider core={core} share={share} cloud={cloud} docLinks={docLinks}>
|
||||
<DeploymentDetailsModal closeModal={closeModal} />
|
||||
</DeploymentDetailsKibanaProvider>
|
||||
);
|
||||
};
|
|
@ -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,27 @@ export const createHelpMenuLinks = ({
|
|||
}),
|
||||
href: docLinks.links.kibana.feedback,
|
||||
},
|
||||
{
|
||||
title: i18n.translate('xpack.cloudLinks.helpMenuLinks.endpoints', {
|
||||
defaultMessage: 'Endpoints',
|
||||
}),
|
||||
iconType: 'console',
|
||||
dataTestSubj: 'endpointsHelpLink',
|
||||
onClick: () => {
|
||||
const modal = overlays.openModal(
|
||||
toMountPoint(
|
||||
<EndpointsModal
|
||||
core={core}
|
||||
share={share}
|
||||
cloud={cloud}
|
||||
docLinks={docLinks}
|
||||
closeModal={() => modal.close()}
|
||||
/>,
|
||||
{ theme: core.theme, i18n: core.i18n }
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return helpMenuLinks;
|
|
@ -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,12 @@ describe('maybeAddCloudLinks', () => {
|
|||
"href": "https://www.elastic.co/products/kibana/feedback?blade=kibanafeedback",
|
||||
"title": "Give feedback",
|
||||
},
|
||||
Object {
|
||||
"dataTestSubj": "endpointsHelpLink",
|
||||
"iconType": "console",
|
||||
"onClick": [Function],
|
||||
"title": "Endpoints",
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -103,6 +112,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 +167,12 @@ describe('maybeAddCloudLinks', () => {
|
|||
"href": "https://www.elastic.co/products/kibana/feedback?blade=kibanafeedback",
|
||||
"title": "Give feedback",
|
||||
},
|
||||
Object {
|
||||
"dataTestSubj": "endpointsHelpLink",
|
||||
"iconType": "console",
|
||||
"onClick": [Function],
|
||||
"title": "Endpoints",
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -172,6 +188,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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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/**/*",
|
||||
|
|
|
@ -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 = (
|
||||
<EuiHeaderLink onClick={() => setIsOpen(!isOpen)} iconType="iInCircle" iconSide="left" isActive>
|
||||
{i18n.translate('xpack.fleet.integrations.deploymentButton', {
|
||||
defaultMessage: 'View deployment details',
|
||||
})}
|
||||
</EuiHeaderLink>
|
||||
);
|
||||
|
||||
const management = managementUrl ? (
|
||||
<EuiFormRow label="API keys" fullWidth>
|
||||
<EuiFlexGroup gutterSize="m" alignItems="center">
|
||||
<EuiFlexItem>
|
||||
<EuiButton href={managementUrl}>Create and manage API keys</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiLink external href={learnMoreUrl} target="_blank">
|
||||
Learn more
|
||||
</EuiLink>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<EuiPopover
|
||||
isOpen={isOpen}
|
||||
closePopover={() => setIsOpen(false)}
|
||||
button={button}
|
||||
anchorPosition="downCenter"
|
||||
>
|
||||
<div style={{ width: 450 }}>
|
||||
<Description>
|
||||
{i18n.translate('xpack.fleet.integrations.deploymentDescription', {
|
||||
defaultMessage:
|
||||
'Send data to Elastic from your applications by referencing your deployment.',
|
||||
})}
|
||||
</Description>
|
||||
<EuiForm component="div">
|
||||
<EuiFormRow label="Cloud ID" fullWidth>
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<EuiFieldText value={cloudId} fullWidth disabled />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiCopy textToCopy={cloudId}>
|
||||
{(copy) => (
|
||||
<EuiButtonIcon
|
||||
onClick={copy}
|
||||
iconType="copyClipboard"
|
||||
display="base"
|
||||
size="m"
|
||||
/>
|
||||
)}
|
||||
</EuiCopy>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
{management}
|
||||
</EuiForm>
|
||||
</div>
|
||||
</EuiPopover>
|
||||
);
|
||||
};
|
|
@ -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 <EuiHeader sections={sections} />;
|
||||
},
|
||||
],
|
||||
} as Meta;
|
||||
|
||||
export const DeploymentDetails = () => {
|
||||
return <ConnectedComponent />;
|
||||
};
|
||||
|
||||
DeploymentDetails.args = {
|
||||
isCloudEnabled: true,
|
||||
};
|
||||
|
||||
DeploymentDetails.argTypes = {
|
||||
isCloudEnabled: {
|
||||
type: {
|
||||
name: 'boolean',
|
||||
},
|
||||
defaultValue: true,
|
||||
control: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Component = (props: PureComponentProps) => {
|
||||
return <PureComponent {...props} />;
|
||||
};
|
||||
|
||||
Component.args = {
|
||||
cloudId: 'cloud-id',
|
||||
learnMoreUrl: 'https://learn-more-url',
|
||||
managementUrl: 'https://management-url',
|
||||
};
|
|
@ -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 button = (
|
||||
<EuiHeaderLink onClick={() => setIsOpen(!isOpen)} iconType="iInCircle" iconSide="left" isActive>
|
||||
{i18n.translate('xpack.fleet.integrations.endpointsButton', {
|
||||
defaultMessage: 'Endpoints',
|
||||
})}
|
||||
</EuiHeaderLink>
|
||||
);
|
||||
|
||||
const learnMoreUrl = docLinks.links.fleet.apiKeysLearnMore;
|
||||
|
||||
return <Component {...{ cloudId, managementUrl, learnMoreUrl }} />;
|
||||
return (
|
||||
<DeploymentDetailsKibanaProvider
|
||||
core={{ application }}
|
||||
share={share}
|
||||
cloud={cloud}
|
||||
docLinks={docLinks}
|
||||
>
|
||||
<EuiPopover
|
||||
isOpen={isOpen}
|
||||
closePopover={() => setIsOpen(false)}
|
||||
button={button}
|
||||
anchorPosition="downCenter"
|
||||
>
|
||||
<div style={{ width: 450 }}>
|
||||
<DeploymentDetailsComponent />
|
||||
</div>
|
||||
</EuiPopover>
|
||||
</DeploymentDetailsKibanaProvider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -101,5 +101,6 @@
|
|||
"@kbn/core-saved-objects-base-server-internal",
|
||||
"@kbn/core-http-common",
|
||||
"@kbn/dashboard-plugin",
|
||||
"@kbn/cloud",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -16425,8 +16425,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",
|
||||
|
|
|
@ -16439,8 +16439,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": "統合設定が保存されました",
|
||||
|
|
|
@ -16439,8 +16439,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": "已保存集成设置",
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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 () => {
|
||||
|
|
|
@ -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 ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue