From 5a994e0f1ae5c49beb8a2458d3032f2a3c19dc65 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 25 Feb 2020 14:46:50 -0500 Subject: [PATCH 1/2] [Fleet] Agent enrollment flyout --- .../components/agent_enrollment.tsx | 227 ------------------ .../agent_enrollment_flyout/index.tsx | 46 ++++ .../agent_enrollment_flyout/instructions.tsx | 127 ++++++++++ .../agent_enrollment_flyout/key_selection.tsx | 124 ++++++++++ .../components/enrollment_api_keys/index.tsx | 15 +- .../container/index.tsx | 10 - .../enrollment_instructions/index.tsx | 59 +---- .../enrollment_instructions/manual/index.tsx | 36 +++ .../enrollment_instructions/shell/index.tsx | 83 +------ .../shell/mac_commands.ts | 43 ---- .../enrollment_instructions/tools/index.tsx | 10 - .../fleet/agent_list_page/components/index.ts | 2 +- .../sections/fleet/agent_list_page/index.tsx | 5 +- .../scripts/dev_agent/script.ts | 5 +- 14 files changed, 352 insertions(+), 440 deletions(-) delete mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment.tsx create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/key_selection.tsx delete mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/container/index.tsx create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/manual/index.tsx delete mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/shell/mac_commands.ts delete mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/tools/index.tsx diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment.tsx deleted file mode 100644 index 93fcc0c4e670a..0000000000000 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment.tsx +++ /dev/null @@ -1,227 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import React, { Fragment, useState } from 'react'; -import { - EuiButton, - EuiButtonEmpty, - EuiFilterButton, - EuiFilterGroup, - EuiFlexGroup, - EuiFlexItem, - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutFooter, - EuiFlyoutHeader, - EuiFormRow, - EuiHorizontalRule, - EuiSelect, - EuiSpacer, - EuiText, - EuiTitle, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - EnrollmentApiKeysTable, - useEnrollmentApiKey, - useEnrollmentApiKeys, -} from './enrollment_api_keys'; -import { - ContainerEnrollmentInstructions, - ShellEnrollmentInstructions, - ToolsEnrollmentInstructions, -} from './enrollment_instructions'; -import { useCore, useConfig } from '../../../../hooks'; - -interface RouterProps { - onClose: () => void; -} - -export const AgentEnrollmentFlyout: React.FunctionComponent = ({ onClose }) => { - const core = useCore(); - const config = useConfig(); - const [quickInstallType, setQuickInstallType] = useState<'shell' | 'container' | 'tools'>( - 'shell' - ); - // api keys - const enrollmentApiKeys = useEnrollmentApiKeys({ - currentPage: 1, - pageSize: 1000, - }); - const [selectedApiKeyId, setSelectedApiKeyId] = useState(null); - React.useEffect(() => { - if (!selectedApiKeyId && enrollmentApiKeys.data && enrollmentApiKeys.data.list.length > 0) { - setSelectedApiKeyId(enrollmentApiKeys.data.list[0].id); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [enrollmentApiKeys.data]); - const apiKey = useEnrollmentApiKey(selectedApiKeyId); - const kibanaUrl = - config.fleet.kibana.host ?? `${window.location.origin}${core.http.basePath.get()}`; - const kibanaCASha256 = config.fleet.kibana.ca_sha256; - - const header = ( - - -

- -

-
- - -

- -

-
-
- ); - - const configOptions = enrollmentApiKeys.data - ? enrollmentApiKeys.data.list.map(key => ({ - value: key.id, - text: key.name, - })) - : []; - - const [apiKeyListVisible, setApiKeyListVisble] = useState(false); - const renderedConfigSelect = ( - <> - - } - > - setSelectedApiKeyId(e.target.value)} - /> - - - { - setApiKeyListVisble(!apiKeyListVisible); - }} - iconType={apiKeyListVisible ? 'arrowUp' : 'arrowDown'} - iconSide="right" - size="xs" - flush="left" - > - {apiKeyListVisible ? ( - - ) : ( - - )} - - {apiKeyListVisible && ( - <> - - enrollmentApiKeys.refresh()} /> - - )} - - ); - - const renderedInstructions = apiKey.data && ( - - -
- -
-
- - - setQuickInstallType('shell')} - > - - - setQuickInstallType('container')} - > - - - setQuickInstallType('tools')} - > - - - - - {quickInstallType === 'shell' ? ( - - ) : null} - {quickInstallType === 'container' ? : null} - {quickInstallType === 'tools' ? : null} -
- ); - - const body = ( - - {renderedConfigSelect} - - {renderedInstructions} - - ); - - const footer = ( - - - - - Close - - - - - Continue - - - - - ); - - return ( - - {header} - {body} - {footer} - - ); -}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx new file mode 100644 index 0000000000000..2e87f75ef0edb --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.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; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { useState } from 'react'; +import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { AgentConfig } from '../../../../../types'; +import { APIKeySelection } from './key_selection'; +import { EnrollmentInstructions } from './instructions'; + +interface Props { + onClose: () => void; + agentConfigs: AgentConfig[]; +} + +export const AgentEnrollmentFlyout: React.FunctionComponent = ({ + onClose, + agentConfigs = [], +}) => { + const [selectedAPIKeyId, setSelectedAPIKeyId] = useState(null); + + return ( + + + +

+ +

+
+
+ + setSelectedAPIKeyId(keyId)} + /> + + + +
+ ); +}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx new file mode 100644 index 0000000000000..1d561e36d768e --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiSpacer, EuiText, EuiButtonGroup, EuiSteps } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { useEnrollmentApiKey } from '../enrollment_api_keys'; +import { ShellEnrollmentInstructions, ManualInstructions } from '../enrollment_instructions'; +import { useCore, useGetAgents } from '../../../../../hooks'; +import { Loading } from '../../../components'; + +interface Props { + selectedAPIKeyId: string | null; +} +function useNewEnrolledAgents() { + // New enrolled agents + const [timestamp] = useState(new Date().toISOString()); + const agentsRequest = useGetAgents( + { + perPage: 100, + page: 1, + showInactive: false, + }, + { + pollIntervalMs: 3000, + } + ); + return React.useMemo(() => { + if (!agentsRequest.data) { + return []; + } + + return agentsRequest.data.list.filter(agent => agent.enrolled_at >= timestamp); + }, [agentsRequest.data, timestamp]); +} + +export const EnrollmentInstructions: React.FunctionComponent = ({ selectedAPIKeyId }) => { + const core = useCore(); + const [installType, setInstallType] = useState<'quickInstall' | 'manual'>('quickInstall'); + + const apiKey = useEnrollmentApiKey(selectedAPIKeyId); + + const newAgents = useNewEnrolledAgents(); + if (!apiKey.data) { + return null; + } + + return ( + <> + { + setInstallType(installType === 'manual' ? 'quickInstall' : 'manual'); + }} + buttonSize="m" + isFullWidth + /> + + {installType === 'manual' ? ( + + ) : ( + + ), + }, + { + title: i18n.translate('xpack.ingestManager.agentEnrollment.stepTestAgents', { + defaultMessage: 'Test Agents', + }), + children: ( + + {!newAgents.length ? ( + <> + + + + ) : ( + <> + + + + )} + + ), + }, + ]} + /> + )} + + ); +}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/key_selection.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/key_selection.tsx new file mode 100644 index 0000000000000..92a467ae0b1e1 --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/key_selection.tsx @@ -0,0 +1,124 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { useState } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSelect, EuiSpacer, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { useEnrollmentApiKeys, CreateApiKeyButton } from '../enrollment_api_keys'; +import { AgentConfig } from '../../../../../types'; + +interface Props { + onKeyChange: (keyId: string | null) => void; + agentConfigs: AgentConfig[]; +} + +export const APIKeySelection: React.FunctionComponent = ({ onKeyChange, agentConfigs }) => { + const enrollmentAPIKeysRequest = useEnrollmentApiKeys({ + currentPage: 1, + pageSize: 1000, + }); + + const [selectedState, setSelectedState] = useState<{ + agentConfigId: string | null; + enrollmentAPIKeyId: string | null; + }>({ + agentConfigId: agentConfigs.length ? agentConfigs[0].id : null, + enrollmentAPIKeyId: null, + }); + const filteredEnrollmentAPIKeys = React.useMemo(() => { + if (!selectedState.agentConfigId || !enrollmentAPIKeysRequest.data) { + return []; + } + + return enrollmentAPIKeysRequest.data.list.filter( + key => key.policy_id === selectedState.agentConfigId + ); + }, [enrollmentAPIKeysRequest.data, selectedState.agentConfigId]); + + // Select first API key when config change + React.useEffect(() => { + if (!selectedState.enrollmentAPIKeyId && filteredEnrollmentAPIKeys.length > 0) { + const enrollmentAPIKeyId = filteredEnrollmentAPIKeys[0].id; + setSelectedState({ + agentConfigId: selectedState.agentConfigId, + enrollmentAPIKeyId, + }); + onKeyChange(enrollmentAPIKeyId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [filteredEnrollmentAPIKeys, selectedState.enrollmentAPIKeyId, selectedState.agentConfigId]); + + return ( + <> + + + + + + + + } + > + ({ + value: agentConfig.id, + text: agentConfig.name, + }))} + value={selectedState.agentConfigId || undefined} + onChange={e => + setSelectedState({ + agentConfigId: e.target.value, + enrollmentAPIKeyId: null, + }) + } + /> + + + + + } + labelAppend={ + + { + await enrollmentAPIKeysRequest.refresh(); + }} + /> + + } + > + ({ + value: key.id, + text: key.name, + }))} + value={selectedState.enrollmentAPIKeyId || undefined} + onChange={e => { + setSelectedState({ + ...selectedState, + enrollmentAPIKeyId: e.target.value, + }); + onKeyChange(selectedState.enrollmentAPIKeyId); + }} + /> + + + + + ); +}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_api_keys/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_api_keys/index.tsx index 831881e745521..ed564b6f80bf8 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_api_keys/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_api_keys/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { useState } from 'react'; -import { EuiBasicTable, EuiButtonEmpty, EuiSpacer, EuiPopover } from '@elastic/eui'; +import { EuiBasicTable, EuiButtonEmpty, EuiSpacer, EuiPopover, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { usePagination, sendRequest } from '../../../../../hooks'; @@ -95,24 +95,21 @@ export const EnrollmentApiKeysTable: React.FunctionComponent<{ ); }; -const CreateApiKeyButton: React.FunctionComponent<{ onChange: () => void }> = ({ onChange }) => { +export const CreateApiKeyButton: React.FunctionComponent<{ onChange: () => void }> = ({ + onChange, +}) => { const [isOpen, setIsOpen] = React.useState(false); return ( setIsOpen(true)} - color="text" - iconType={'plusInCircle'} - size="xs" - > + setIsOpen(true)} color="primary"> - + } isOpen={isOpen} closePopover={() => setIsOpen(false)} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/container/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/container/index.tsx deleted file mode 100644 index 6ba4193b17e5a..0000000000000 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/container/index.tsx +++ /dev/null @@ -1,10 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import React from 'react'; - -export const ContainerEnrollmentInstructions: React.FunctionComponent = () => { - return
Container instructions
; -}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/index.tsx index d51fa12b9a3c4..34233a00e630a 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/index.tsx @@ -3,61 +3,6 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; -import { EuiSteps, EuiText, EuiCodeBlock } from '@elastic/eui'; -import { Writer } from 'mustache'; -export { ShellEnrollmentInstructions } from './shell'; -export { ContainerEnrollmentInstructions } from './container'; -export { ToolsEnrollmentInstructions } from './tools'; - -export type ManualEnrollmentInstructions = Array<{ - title: string; - textPre?: string; - commands?: string; - commandsLang?: 'bash' | 'yaml'; -}>; - -export const ManualEnrollmentSteps: React.FunctionComponent<{ - instructions: ManualEnrollmentInstructions; -}> = ({ instructions }) => ( - ({ - title, - children: ( - - {textPre ?

{textPre}

: null} - {commands ? ( - // TODO: Increase overflowHeight when https://github.com/elastic/eui/issues/2435 is fixed - // or be smarter with setting this number before release - - {replaceTemplateStrings(commands.trim())} - - ) : null} -
- ), - }))} - /> -); -// Setup for replacing template variables in install instructions -const mustacheWriter = new Writer(); - -// do not html escape output -// @ts-ignore -mustacheWriter.escapedValue = function escapedValue(token, context) { - const value = context.lookup(token[1]); - if (value != null) { - return value; - } -}; - -// Configure available variable values -export function replaceTemplateStrings(text: string = '') { - const variables = { - config: { - enrollmentToken: 'sometesttoken', - }, - }; - mustacheWriter.parse(text); - return mustacheWriter.render(text, variables, () => {}); -} +export { ShellEnrollmentInstructions } from './shell'; +export { ManualInstructions } from './manual'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/manual/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/manual/index.tsx new file mode 100644 index 0000000000000..b1da4583b74cc --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/manual/index.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiText, EuiSpacer } from '@elastic/eui'; +import React from 'react'; + +export const ManualInstructions: React.FunctionComponent = () => { + return ( + <> + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam vestibulum ullamcorper + turpis vitae interdum. Maecenas orci magna, auctor volutpat pellentesque eu, consectetur id + est. Nunc orci lacus, condimentum vel congue ac, fringilla eget tortor. Aliquam blandit, + nisi et congue euismod, leo lectus blandit risus, eu blandit erat metus sit amet leo. Nam + dictum lobortis condimentum. + + + + Vivamus sem sapien, dictum eu tellus vel, rutrum aliquam purus. Cras quis cursus nibh. + Aliquam fermentum ipsum nec turpis luctus lobortis. Nulla facilisi. Etiam nec fringilla + urna, sed vehicula ipsum. Quisque vel pellentesque lorem, at egestas enim. Nunc semper elit + lectus, in sollicitudin erat fermentum in. Pellentesque tempus massa eget purus pharetra + blandit. + + + + Mauris congue enim nulla, nec semper est posuere non. Donec et eros eu nisi gravida + malesuada eget in velit. Morbi placerat semper euismod. Suspendisse potenti. Morbi quis + porta erat, quis cursus nulla. Aenean mauris lorem, mollis in mattis et, lobortis a lectus. + + + ); +}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/shell/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/shell/index.tsx index a626664b16d43..04e84902bc9d4 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/shell/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/shell/index.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useState } from 'react'; +import React, { useState } from 'react'; import { EuiButtonEmpty, EuiContextMenuItem, @@ -11,12 +11,7 @@ import { EuiCopy, EuiFieldText, EuiPopover, - EuiSpacer, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { ManualEnrollmentInstructions, ManualEnrollmentSteps } from '../'; -import * as MAC_COMMANDS from './mac_commands'; import { EnrollmentAPIKey } from '../../../../../../types'; // No need for i18n as these are platform names @@ -26,44 +21,6 @@ const PLATFORMS = { linux: 'Linux', }; -// Manual instructions based on platform -const PLATFORM_INSTRUCTIONS: { - [key: string]: ManualEnrollmentInstructions; -} = { - macos: [ - { - title: i18n.translate( - 'xpack.ingestManager.agentEnrollment.typeShell.manualInstall.stepOneTitle', - { - defaultMessage: 'Download and install Elastic Agent', - } - ), - textPre: 'Lorem ipsum instructions here.', - commands: MAC_COMMANDS.INSTALL, - }, - { - title: i18n.translate( - 'xpack.ingestManager.agentEnrollment.typeShell.manualInstall.stepTwoTitle', - { - defaultMessage: 'Edit the configuration', - } - ), - textPre: 'Modify the configuration file to set the connection information:', - commands: MAC_COMMANDS.CONFIG, - commandsLang: 'yaml', - }, - { - title: i18n.translate( - 'xpack.ingestManager.agentEnrollment.typeShell.manualInstall.stepThreeTitle', - { - defaultMessage: 'Start the agent', - } - ), - commands: MAC_COMMANDS.START, - }, - ], -}; - interface Props { kibanaUrl: string; kibanaCASha256?: string; @@ -78,7 +35,6 @@ export const ShellEnrollmentInstructions: React.FunctionComponent = ({ // Platform state const [currentPlatform, setCurrentPlatform] = useState('macos'); const [isPlatformOptionsOpen, setIsPlatformOptionsOpen] = useState(false); - const [isManualInstallationOpen, setIsManualInstallationOpen] = useState(false); // Build quick installation command const quickInstallInstructions = `${ @@ -88,7 +44,7 @@ export const ShellEnrollmentInstructions: React.FunctionComponent = ({ } sh -c "$(curl ${kibanaUrl}/api/ingest_manager/fleet/install/${currentPlatform})"`; return ( - + <> = ({ } append={ - {copy => ( - - - - )} + {copy => } } /> - - - - setIsManualInstallationOpen(!isManualInstallationOpen)} - iconType={isManualInstallationOpen ? 'arrowUp' : 'arrowDown'} - iconSide="right" - size="xs" - flush="left" - > - - - - {isManualInstallationOpen ? ( - - - - - ) : null} - + ); }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/shell/mac_commands.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/shell/mac_commands.ts deleted file mode 100644 index e853dcf1100cc..0000000000000 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/shell/mac_commands.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export const INSTALL = ` -curl -L -O https://artifacts.elastic.co/downloads/some-file-to-download.tar.gz -tar xzvf some-file-to-download.tar.gz -cd some-file-to-download/ -`; - -export const CONFIG = ` -output.elasticsearch: - hosts: [""] - username: "elastic" - password: "" -setup.kibana: - host: "" -output.elasticsearch: - hosts: [""] - username: "elastic" - password: "" -setup.kibana: - host: "" -output.elasticsearch: - hosts: [""] - username: "elastic" - password: "" -setup.kibana: - host: "" -output.elasticsearch: - hosts: [""] - username: "elastic" - password: "" -setup.kibana: - host: "" -`; - -export const START = ` -./somefile setup -./somefile --token={{config.enrollmentToken}} -`; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/tools/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/tools/index.tsx deleted file mode 100644 index 3d1418d8c522e..0000000000000 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/enrollment_instructions/tools/index.tsx +++ /dev/null @@ -1,10 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import React from 'react'; - -export const ToolsEnrollmentInstructions: React.FunctionComponent = () => { - return
Tools instructions
; -}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/index.ts index 828f239fbe59f..c82c82db6f713 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/index.ts @@ -3,4 +3,4 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -export { AgentEnrollmentFlyout } from './agent_enrollment'; +export { AgentEnrollmentFlyout } from './agent_enrollment_flyout'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx index f2e6660cdc58c..31d550fbb3ab7 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx @@ -248,7 +248,10 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { ]} > {isEnrollmentFlyoutOpen ? ( - setIsEnrollmentFlyoutOpen(false)} /> + setIsEnrollmentFlyoutOpen(false)} + /> ) : null}

diff --git a/x-pack/plugins/ingest_manager/scripts/dev_agent/script.ts b/x-pack/plugins/ingest_manager/scripts/dev_agent/script.ts index d971210ef5c96..c7b8edd0c332e 100644 --- a/x-pack/plugins/ingest_manager/scripts/dev_agent/script.ts +++ b/x-pack/plugins/ingest_manager/scripts/dev_agent/script.ts @@ -40,9 +40,8 @@ run( log.info('Enrolled with sucess', agent); while (!closing) { - await new Promise((resolve, reject) => - setTimeout(() => checkin(kibanaUrl, agent, log).then(resolve, reject), CHECKIN_INTERVAL) - ); + await checkin(kibanaUrl, agent, log); + await new Promise((resolve, reject) => setTimeout(() => resolve(), CHECKIN_INTERVAL)); } }, { From dab972df6f5f01dab5669ed5b53231c076a92823 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Thu, 27 Feb 2020 18:00:29 -0500 Subject: [PATCH 2/2] [Fleet] Fix after review --- .../agent_enrollment_flyout/index.tsx | 33 ++++- .../agent_enrollment_flyout/instructions.tsx | 1 - .../agent_enrollment_flyout/key_selection.tsx | 125 +++++++++++++++--- 3 files changed, 135 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx index 2e87f75ef0edb..60256599c6680 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/index.tsx @@ -4,7 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { useState } from 'react'; -import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiSpacer, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiButton, + EuiFlyoutFooter, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { AgentConfig } from '../../../../../types'; import { APIKeySelection } from './key_selection'; @@ -41,6 +52,26 @@ export const AgentEnrollmentFlyout: React.FunctionComponent = ({ + + + + + + + + + + + + + + ); }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx index 1d561e36d768e..97434d2178852 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/components/agent_enrollment_flyout/instructions.tsx @@ -108,7 +108,6 @@ export const EnrollmentInstructions: React.FunctionComponent = ({ selecte ) : ( <> - void; agentConfigs: AgentConfig[]; } +function useCreateApiKeyForm(configId: string | null, onSuccess: (keyId: string) => void) { + const { notifications } = useCore(); + const [isLoading, setIsLoading] = useState(false); + const apiKeyNameInput = useInput(''); + + const onSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + setIsLoading(true); + try { + const res = await sendRequest({ + method: 'post', + path: enrollmentAPIKeyRouteService.getCreatePath(), + body: JSON.stringify({ + name: apiKeyNameInput.value, + config_id: configId, + }), + }); + apiKeyNameInput.clear(); + setIsLoading(false); + onSuccess(res.data.item.id); + } catch (err) { + notifications.toasts.addError(err as Error, { + title: 'Error', + }); + setIsLoading(false); + } + }; + + return { + isLoading, + onSubmit, + apiKeyNameInput, + }; +} + export const APIKeySelection: React.FunctionComponent = ({ onKeyChange, agentConfigs }) => { const enrollmentAPIKeysRequest = useEnrollmentApiKeys({ currentPage: 1, @@ -33,7 +80,7 @@ export const APIKeySelection: React.FunctionComponent = ({ onKeyChange, a } return enrollmentAPIKeysRequest.data.list.filter( - key => key.policy_id === selectedState.agentConfigId + key => key.config_id === selectedState.agentConfigId ); }, [enrollmentAPIKeysRequest.data, selectedState.agentConfigId]); @@ -50,6 +97,16 @@ export const APIKeySelection: React.FunctionComponent = ({ onKeyChange, a // eslint-disable-next-line react-hooks/exhaustive-deps }, [filteredEnrollmentAPIKeys, selectedState.enrollmentAPIKeyId, selectedState.agentConfigId]); + const [showAPIKeyForm, setShowAPIKeyForm] = useState(false); + const apiKeyForm = useCreateApiKeyForm(selectedState.agentConfigId, async (keyId: string) => { + const res = await enrollmentAPIKeysRequest.refresh(); + setSelectedState({ + ...selectedState, + enrollmentAPIKeyId: res.data?.list.find(key => key.id === keyId)?.id ?? null, + }); + setShowAPIKeyForm(false); + }); + return ( <> @@ -94,28 +151,52 @@ export const APIKeySelection: React.FunctionComponent = ({ onKeyChange, a } labelAppend={ - { - await enrollmentAPIKeysRequest.refresh(); - }} - /> + setShowAPIKeyForm(!showAPIKeyForm)} color="primary"> + {showAPIKeyForm ? ( + + ) : ( + + )} + } > - ({ - value: key.id, - text: key.name, - }))} - value={selectedState.enrollmentAPIKeyId || undefined} - onChange={e => { - setSelectedState({ - ...selectedState, - enrollmentAPIKeyId: e.target.value, - }); - onKeyChange(selectedState.enrollmentAPIKeyId); - }} - /> + {showAPIKeyForm ? ( +
+ + + ) : ( + ({ + value: key.id, + text: key.name, + }))} + value={selectedState.enrollmentAPIKeyId || undefined} + onChange={e => { + setSelectedState({ + ...selectedState, + enrollmentAPIKeyId: e.target.value, + }); + onKeyChange(selectedState.enrollmentAPIKeyId); + }} + /> + )}