diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/django.ts b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/django.ts index 686fcd02765492..97b5f3315bcdbf 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/django.ts +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/django.ts @@ -39,7 +39,7 @@ ELASTIC_APM = {curlyOpen} defaultMessage: 'Use if APM Server requires a secret token', } )} -'SECRET_TOKEN': '{{secretToken}}', +'SECRET_TOKEN': '{{{secretToken}}}', # ${i18n.translate( 'xpack.apm.tutorial.djangoClient.configure.commands.setCustomApmServerUrlComment', @@ -49,7 +49,7 @@ ELASTIC_APM = {curlyOpen} values: { defaultApmServerUrl: 'http://localhost:8200' }, } )} -'SERVER_URL': '{{apmServerUrl}}', +'SERVER_URL': '{{{apmServerUrl}}}', # ${i18n.translate( 'xpack.apm.tutorial.djangoClient.configure.commands.setServiceEnvironmentComment', diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/dotnet.ts b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/dotnet.ts index d11234e0b546c6..0ed7a874a95aea 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/dotnet.ts +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/dotnet.ts @@ -8,8 +8,8 @@ export const dotnet = `{ "ElasticApm": { -"SecretToken": "{{secretToken}}", -"ServerUrls": "{{apmServerUrl}}", //Set custom APM Server URL (default: http://localhost:8200) +"SecretToken": "{{{secretToken}}}", +"ServerUrls": "{{{apmServerUrl}}}", //Set custom APM Server URL (default: http://localhost:8200) "ServiceName": "MyApp", //allowed characters: a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application "Environment": "production", // Set the service environment } diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/flask.ts b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/flask.ts index d97b5e71723280..e4d7fd188e7c6f 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/flask.ts +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/flask.ts @@ -46,7 +46,7 @@ app.config['ELASTIC_APM'] = {curlyOpen} defaultMessage: 'Use if APM Server requires a secret token', } )} -'SECRET_TOKEN': '{{secretToken}}', +'SECRET_TOKEN': '{{{secretToken}}}', # ${i18n.translate( 'xpack.apm.tutorial.flaskClient.configure.commands.setCustomApmServerUrlComment', @@ -56,7 +56,7 @@ app.config['ELASTIC_APM'] = {curlyOpen} values: { defaultApmServerUrl: 'http://localhost:8200' }, } )} -'SERVER_URL': '{{apmServerUrl}}', +'SERVER_URL': '{{{apmServerUrl}}}', # ${i18n.translate( 'xpack.apm.tutorial.flaskClient.configure.commands.setServiceEnvironmentComment', diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/go.ts b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/go.ts index a1878dc382764f..a3900420d6fdec 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/go.ts +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/go.ts @@ -38,7 +38,7 @@ export ELASTIC_APM_SERVICE_NAME= values: { defaultApmServerUrl: 'http://localhost:8200' }, } )} -export ELASTIC_APM_SERVER_URL={{apmServerUrl}} +export ELASTIC_APM_SERVER_URL={{{apmServerUrl}}} # ${i18n.translate( 'xpack.apm.tutorial.goClient.configure.commands.useIfApmRequiresTokenComment', @@ -46,7 +46,7 @@ export ELASTIC_APM_SERVER_URL={{apmServerUrl}} defaultMessage: 'Use if APM Server requires a secret token', } )} -export ELASTIC_APM_SECRET_TOKEN={{secretToken}} +export ELASTIC_APM_SECRET_TOKEN={{{secretToken}}} # ${i18n.translate( 'xpack.apm.tutorial.goClient.configure.commands.setServiceEnvironment', diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/java.ts b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/java.ts index 2d8c38d73966c1..28590f889b4a4b 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/java.ts +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/java.ts @@ -7,8 +7,8 @@ export const java = `java -javaagent:/path/to/elastic-apm-agent-.jar \\ -Delastic.apm.service_name=my-application \\ --Delastic.apm.server_urls= {{apmServerUrl}} \\ --Delastic.apm.secret_token= {{secretToken}} \\ +-Delastic.apm.server_urls= {{{apmServerUrl}}} \\ +-Delastic.apm.secret_token= {{{{secretToken}}}} \\ -Delastic.apm.environment=production \\ -Delastic.apm.application_packages=org.example \\ -jar my-application.jar`; diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/node.ts b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/node.ts index 553d861cfb0c30..31f9fac0ed480d 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/node.ts +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/node.ts @@ -35,7 +35,7 @@ serviceName: '', defaultMessage: 'Use if APM Server requires a secret token', } )} -secretToken: '{{secretToken}}', +secretToken: '{{{secretToken}}}', // ${i18n.translate( 'xpack.apm.tutorial.nodeClient.configure.commands.setCustomApmServerUrlComment', @@ -45,7 +45,7 @@ secretToken: '{{secretToken}}', values: { defaultApmServerUrl: 'http://localhost:8200' }, } )} -serverUrl: '{{apmServerUrl}}', +serverUrl: '{{{apmServerUrl}}}', // ${i18n.translate( 'xpack.apm.tutorial.nodeClient.configure.commands.setCustomServiceEnvironmentComment', diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/php.ts b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/php.ts index 443f3def8bb536..ea7e8764f89ad1 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/php.ts +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/php.ts @@ -5,7 +5,7 @@ * 2.0. */ -export const php = `elastic_apm.server_url="{{apmServerUrl}}" -elastic.apm.secret_token="{{secretToken}}" +export const php = `elastic_apm.server_url="{{{apmServerUrl}}}" +elastic.apm.secret_token="{{{secretToken}}}" elastic_apm.service_name="My service" `; diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rack.ts b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rack.ts index 55043042e1e36c..7adf99366f615d 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rack.ts +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rack.ts @@ -30,7 +30,7 @@ service_name: 'my-service' defaultMessage: 'Use if APM Server requires a token', } )} -secret_token: '{{secretToken}}' +secret_token: '{{{secretToken}}}' # ${i18n.translate( 'xpack.apm.tutorial.rackClient.createConfig.commands.setCustomApmServerComment', @@ -39,7 +39,7 @@ secret_token: '{{secretToken}}' values: { defaultServerUrl: 'http://localhost:8200' }, } )} -server_url: {{apmServerUrl}}, +server_url: {{{apmServerUrl}}}, # ${i18n.translate( 'xpack.apm.tutorial.rackClient.createConfig.commands.setServiceEnvironment', diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rails.ts b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rails.ts index e0663709e10203..faf816c6b5bb71 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rails.ts +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rails.ts @@ -13,10 +13,10 @@ export const rails = `# config/elastic_apm.yml: service_name: 'my-service' # Use if APM Server requires a secret token -secret_token: '{{secretToken}}' +secret_token: '{{{secretToken}}}' # Set the custom APM Server URL (default: http://localhost:8200) -server_url: '{{apmServerUrl}}' +server_url: '{{{apmServerUrl}}}' # Set the service environment environment: 'production'`; diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rum.ts b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rum.ts index 91a8283c8ae63e..96e5ed6b082655 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rum.ts +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/commands/rum.ts @@ -28,7 +28,7 @@ var apm = initApm({ values: { defaultApmServerUrl: 'http://localhost:8200' }, } )} - serverUrl: '{{apmServerUrl}}', + serverUrl: '{{{apmServerUrl}}}', // ${i18n.translate( 'xpack.apm.tutorial.jsClient.installDependency.commands.setServiceVersionComment', diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/environment_configuration_selector.tsx b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/environment_configuration_selector.tsx new file mode 100644 index 00000000000000..e22eec6b1ed3ef --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/environment_configuration_selector.tsx @@ -0,0 +1,132 @@ +/* + * 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 { + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiPopover, + EuiPopoverFooter, + EuiPopoverTitle, + EuiSelectable, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useEffect, useState } from 'react'; +import styled from 'styled-components'; +import { px } from '../../../../style/variables'; + +export interface EnvironmentConfigurationOption { + key: string; + label: string; + apmServerUrl?: string; + secretToken?: string; + checked?: 'on'; +} + +const StyledEuiButtomEmpty = styled(EuiButtonEmpty)` + .euiButtonContent { + display: flex; + justify-content: space-between; + } +`; + +interface Props { + options: EnvironmentConfigurationOption[]; + selectedOption?: EnvironmentConfigurationOption; + onChange: (selectedOption?: EnvironmentConfigurationOption) => void; + fleetLink: { + label: string; + href: string; + }; +} + +function findCheckedOption(options: EnvironmentConfigurationOption[]) { + return options.find(({ checked }) => checked === 'on'); +} + +export function EnvironmentConfigurationSelector({ + options, + selectedOption, + onChange, + fleetLink, +}: Props) { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const [availableOptions, setAvailableOptions] = useState< + EnvironmentConfigurationOption[] + >(options); + + useEffect(() => { + const checkedOption = findCheckedOption(availableOptions); + onChange(checkedOption); + }, [availableOptions, onChange]); + + function toggleIsPopoverOpen() { + setIsPopoverOpen((state) => !state); + } + + return ( + + {selectedOption?.label} + + } + isOpen={isPopoverOpen} + closePopover={toggleIsPopoverOpen} + > +
+ { + const nextSelectedOption = findCheckedOption(newOptions); + // When there is no checked option don't update the options so we always have at least one option selected + if (nextSelectedOption) { + setAvailableOptions(newOptions); + } + }} + singleSelection + > + {(list, search) => { + return ( + <> + {search} + {list} + + + + + {fleetLink.label} + + + + + + ); + }} + +
+
+ ); +} diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/index.test.tsx b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/index.test.tsx new file mode 100644 index 00000000000000..270a97b79ec1cd --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/index.test.tsx @@ -0,0 +1,298 @@ +/* + * 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 { getEnvironmentConfigurationOptions } from './'; +import { APIReturnType } from '../../../../services/rest/createCallApmApi'; + +type APIResponseType = APIReturnType<'GET /api/apm/fleet/agents'>; + +const policyElasticAgentOnCloud = { + id: '3', + name: 'policy-elastic-agent-on-cloud', + apmServerUrl: 'baz', + secretToken: 'baz', +}; + +const agents = [ + { + id: '1', + name: 'agent foo', + apmServerUrl: 'foo', + secretToken: 'foo', + }, + { + id: '2', + name: 'agent bar', + apmServerUrl: 'bar', + secretToken: 'bar', + }, +]; + +describe('Tutorial config agent', () => { + describe('getEnvironmentConfigurationOptions', () => { + describe('running on cloud', () => { + describe('with APM on cloud', () => { + it('shows apm on cloud standalone option', () => { + const data: APIResponseType = { + agents: [], + cloudStandaloneSetup: { + apmServerUrl: 'foo', + secretToken: 'bar', + }, + hasPolicyElasticOnCloud: false, + }; + const options = getEnvironmentConfigurationOptions({ + isCloudEnabled: true, + data, + }); + expect(options).toEqual([ + { + key: 'cloud_standalone', + label: 'Default Standalone configuration', + apmServerUrl: 'foo', + secretToken: 'bar', + checked: 'on', + }, + ]); + }); + it('shows apm on cloud standalone option and fleet agents options', () => { + const data: APIResponseType = { + agents, + cloudStandaloneSetup: { + apmServerUrl: 'foo', + secretToken: 'bar', + }, + hasPolicyElasticOnCloud: false, + }; + const options = getEnvironmentConfigurationOptions({ + isCloudEnabled: true, + data, + }); + expect(options).toEqual([ + { + key: 'cloud_standalone', + label: 'Default Standalone configuration', + apmServerUrl: 'foo', + secretToken: 'bar', + checked: 'on', + }, + { + key: '1', + label: 'agent foo', + apmServerUrl: 'foo', + secretToken: 'foo', + checked: undefined, + }, + { + key: '2', + label: 'agent bar', + apmServerUrl: 'bar', + secretToken: 'bar', + checked: undefined, + }, + ]); + }); + it('selects policy elastic agent on cloud when available', () => { + const data: APIResponseType = { + agents: [policyElasticAgentOnCloud, ...agents], + cloudStandaloneSetup: { + apmServerUrl: 'foo', + secretToken: 'bar', + }, + hasPolicyElasticOnCloud: true, + }; + const options = getEnvironmentConfigurationOptions({ + isCloudEnabled: true, + data, + }); + expect(options).toEqual([ + { + key: 'cloud_standalone', + label: 'Default Standalone configuration', + apmServerUrl: 'foo', + secretToken: 'bar', + checked: undefined, + }, + { + key: '3', + label: 'policy-elastic-agent-on-cloud', + apmServerUrl: 'baz', + secretToken: 'baz', + checked: 'on', + }, + { + key: '1', + label: 'agent foo', + apmServerUrl: 'foo', + secretToken: 'foo', + checked: undefined, + }, + { + key: '2', + label: 'agent bar', + apmServerUrl: 'bar', + secretToken: 'bar', + checked: undefined, + }, + ]); + }); + }); + describe('with APM on prem', () => { + it('shows apm on prem standalone option', () => { + const data: APIResponseType = { + agents: [], + cloudStandaloneSetup: undefined, + hasPolicyElasticOnCloud: false, + }; + const options = getEnvironmentConfigurationOptions({ + isCloudEnabled: true, + data, + }); + expect(options).toEqual([ + { + key: 'onPrem_standalone', + label: 'Default Standalone configuration', + apmServerUrl: 'http://localhost:8200', + secretToken: '', + checked: 'on', + }, + ]); + }); + it('shows apm on prem standalone option and fleet agents options', () => { + const data: APIResponseType = { + agents, + cloudStandaloneSetup: undefined, + hasPolicyElasticOnCloud: false, + }; + const options = getEnvironmentConfigurationOptions({ + isCloudEnabled: true, + data, + }); + expect(options).toEqual([ + { + key: 'onPrem_standalone', + label: 'Default Standalone configuration', + apmServerUrl: 'http://localhost:8200', + secretToken: '', + checked: 'on', + }, + { + key: '1', + label: 'agent foo', + apmServerUrl: 'foo', + secretToken: 'foo', + checked: undefined, + }, + { + key: '2', + label: 'agent bar', + apmServerUrl: 'bar', + secretToken: 'bar', + checked: undefined, + }, + ]); + }); + it('selects policy elastic agent on cloud when available', () => { + const data: APIResponseType = { + agents: [policyElasticAgentOnCloud, ...agents], + cloudStandaloneSetup: undefined, + hasPolicyElasticOnCloud: true, + }; + const options = getEnvironmentConfigurationOptions({ + isCloudEnabled: true, + data, + }); + expect(options).toEqual([ + { + key: 'onPrem_standalone', + label: 'Default Standalone configuration', + apmServerUrl: 'http://localhost:8200', + secretToken: '', + checked: undefined, + }, + { + key: '3', + label: 'policy-elastic-agent-on-cloud', + apmServerUrl: 'baz', + secretToken: 'baz', + checked: 'on', + }, + { + key: '1', + label: 'agent foo', + apmServerUrl: 'foo', + secretToken: 'foo', + checked: undefined, + }, + { + key: '2', + label: 'agent bar', + apmServerUrl: 'bar', + secretToken: 'bar', + checked: undefined, + }, + ]); + }); + }); + }); + describe('Running on prem', () => { + it('shows apm on prem standalone option', () => { + const data: APIResponseType = { + agents: [], + cloudStandaloneSetup: undefined, + hasPolicyElasticOnCloud: false, + }; + const options = getEnvironmentConfigurationOptions({ + isCloudEnabled: false, + data, + }); + expect(options).toEqual([ + { + key: 'onPrem_standalone', + label: 'Default Standalone configuration', + apmServerUrl: 'http://localhost:8200', + secretToken: '', + checked: 'on', + }, + ]); + }); + it('shows apm on prem standalone option and fleet agents options', () => { + const data: APIResponseType = { + agents, + cloudStandaloneSetup: undefined, + hasPolicyElasticOnCloud: false, + }; + const options = getEnvironmentConfigurationOptions({ + isCloudEnabled: false, + data, + }); + expect(options).toEqual([ + { + key: 'onPrem_standalone', + label: 'Default Standalone configuration', + apmServerUrl: 'http://localhost:8200', + secretToken: '', + checked: 'on', + }, + { + key: '1', + label: 'agent foo', + apmServerUrl: 'foo', + secretToken: 'foo', + checked: undefined, + }, + { + key: '2', + label: 'agent bar', + apmServerUrl: 'bar', + secretToken: 'bar', + checked: undefined, + }, + ]); + }); + }); + }); +}); diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/index.tsx b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/index.tsx index b6e882a7a48ef0..290ee78bd1e948 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/tutorial/config_agent/index.tsx @@ -5,25 +5,26 @@ * 2.0. */ import { - EuiButton, - EuiButtonEmpty, EuiCodeBlock, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, - EuiPopover, - EuiPopoverFooter, - EuiPopoverTitle, - EuiSelectable, EuiSpacer, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { HttpStart } from 'kibana/public'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; import { APIReturnType } from '../../../../services/rest/createCallApmApi'; import { CopyCommands } from '../copy_commands'; +import { + EnvironmentConfigurationOption, + EnvironmentConfigurationSelector, +} from './environment_configuration_selector'; import { getCommands } from './commands/get_commands'; +const POLICY_ELASTIC_AGENT_ON_CLOUD = 'policy-elastic-agent-on-cloud'; + interface Props { variantId: string; http: HttpStart; @@ -37,29 +38,71 @@ const CentralizedContainer = styled.div` align-items: center; `; -const onPremStandaloneOption = { - key: 'onPrem_standalone', - label: 'Default Standalone configuration', - apmServerUrl: 'http://localhost:8200', - secretKey: '', - checked: 'on', -}; - type APIResponseType = APIReturnType<'GET /api/apm/fleet/agents'>; -const INITIAL_STATE: APIResponseType = { - agentsCredentials: [], - cloudAgentPolicyCredential: undefined, - cloudCredentials: undefined, -}; - -type SelectValuesType = 'onPrem_standalone' | 'cloud_standalone' | string; - -interface Credential { - key: string; - label: string; - apmServerUrl?: string; - secretToken?: string; - checked?: 'on'; + +const DEFAULT_STANDALONE_CONFIG_LABEL = i18n.translate( + 'xpack.apm.tutorial.agent_config.defaultStandaloneConfig', + { defaultMessage: 'Default Standalone configuration' } +); + +const MANAGE_FLEET_POLICIES_LABEL = i18n.translate( + 'xpack.apm.tutorial.agent_config.manageFleetPolicies', + { defaultMessage: 'Manage fleet policies' } +); + +const GET_STARTED_WITH_FLEET_LABEL = i18n.translate( + 'xpack.apm.tutorial.agent_config.getStartedWithFleet', + { defaultMessage: 'Get started with fleet' } +); + +export function getEnvironmentConfigurationOptions({ + isCloudEnabled, + data, +}: { + isCloudEnabled: boolean; + data: APIResponseType; +}) { + const newOptions: EnvironmentConfigurationOption[] = []; + // When running on cloud and apm.url is defined + if (isCloudEnabled && data.cloudStandaloneSetup?.apmServerUrl) { + // pushes APM cloud standalone + newOptions.push({ + key: 'cloud_standalone', + label: DEFAULT_STANDALONE_CONFIG_LABEL, + apmServerUrl: data.cloudStandaloneSetup?.apmServerUrl, + secretToken: data.cloudStandaloneSetup?.secretToken, + checked: data.hasPolicyElasticOnCloud ? undefined : 'on', + }); + } else { + // pushes APM onprem standalone + newOptions.push({ + key: 'onPrem_standalone', + label: DEFAULT_STANDALONE_CONFIG_LABEL, + apmServerUrl: 'http://localhost:8200', + secretToken: '', + checked: data.hasPolicyElasticOnCloud ? undefined : 'on', + }); + } + + // remaining agents with APM integration + newOptions.push( + ...data.agents.map( + ({ + id, + name, + apmServerUrl, + secretToken, + }): EnvironmentConfigurationOption => ({ + key: id, + label: name, + apmServerUrl, + secretToken, + checked: name === POLICY_ELASTIC_AGENT_ON_CLOUD ? 'on' : undefined, + }) + ) + ); + + return newOptions; } function TutorialAgentSecretTokenSelector({ @@ -68,16 +111,16 @@ function TutorialAgentSecretTokenSelector({ basePath, isCloudEnabled, }: Props) { - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const [data, setData] = useState(INITIAL_STATE); + const [data, setData] = useState({ + agents: [], + hasPolicyElasticOnCloud: false, + cloudStandaloneSetup: undefined, + }); const [isLoading, setIsLoading] = useState(true); - const [options, setOptions] = useState([]); - const [option, setOption] = useState(); - - useEffect(() => { - const checkedOption = options.find(({ checked }) => checked === 'on'); - setOption(checkedOption); - }, [options]); + const [ + selectedOption, + setSelectedOption, + ] = useState(); useEffect(() => { async function fetchData() { @@ -93,50 +136,9 @@ function TutorialAgentSecretTokenSelector({ fetchData(); }, [http]); - useEffect(() => { - const newOptions = []; - if (isCloudEnabled) { - // has Elastic Cloud managed policy - if (data.cloudAgentPolicyCredential) { - const { - id, - name, - apmServerUrl, - secretToken, - } = data.cloudAgentPolicyCredential; - newOptions.push({ - key: id, - label: name, - apmServerUrl, - secretToken, - checked: 'on', - }); - } else { - // adds standalone cloud - newOptions.push({ - key: 'cloud_standalone', - label: 'Default Standalone configuration', - apmServerUrl: data.cloudCredentials?.apmServerUrl, - secretToken: data.cloudCredentials?.secretToken, - checked: 'on', - }); - } - } else { - // when onPrem - newOptions.push(onPremStandaloneOption); - } - - newOptions.push( - ...data.agentsCredentials?.map( - ({ id, name, apmServerUrl, secretToken }) => ({ - key: id, - label: name, - apmServerUrl, - secretToken, - }) - ) - ); - setOptions(newOptions); + // Depending the environment running (onPrem/Cloud) different values must be available and automatically selected + const options = useMemo(() => { + return getEnvironmentConfigurationOptions({ isCloudEnabled, data }); }, [data, isCloudEnabled]); if (isLoading) { @@ -150,52 +152,34 @@ function TutorialAgentSecretTokenSelector({ const command = getCommands({ variantId, environmentDetails: { - apmServerUrl: option?.apmServerUrl, - secretToken: option?.secretToken, + apmServerUrl: selectedOption?.apmServerUrl, + secretToken: selectedOption?.secretToken, }, }); - function toggleIsPopoverOpen() { - setIsPopoverOpen((state) => !state); - } + const hasFleetAgents = !!data.agents.length; + const fleetLink = hasFleetAgents + ? { + label: MANAGE_FLEET_POLICIES_LABEL, + href: `${basePath}/app/fleet#/policies`, + } + : { + label: GET_STARTED_WITH_FLEET_LABEL, + href: `${basePath}/app/fleet#/integrations/detail/apm-0.2.0/overview`, + }; return ( <> - - {option?.label} - + + setSelectedOption(newSelectedOption) } - isOpen={isPopoverOpen} - closePopover={toggleIsPopoverOpen} - > - setOptions(newOptions)} - singleSelection - > - {(list, search) => ( -
- {search} - {list} - - - Manage this list - - -
- )} -
-
+ fleetLink={fleetLink} + />
diff --git a/x-pack/plugins/apm/public/components/shared/tutorial/copy_commands.tsx b/x-pack/plugins/apm/public/components/shared/tutorial/copy_commands.tsx index 9e02efef059194..c5261cfc1dc042 100644 --- a/x-pack/plugins/apm/public/components/shared/tutorial/copy_commands.tsx +++ b/x-pack/plugins/apm/public/components/shared/tutorial/copy_commands.tsx @@ -5,6 +5,7 @@ * 2.0. */ import { EuiButton, EuiCopy } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import React from 'react'; interface Props { @@ -15,7 +16,9 @@ export function CopyCommands({ commands }: Props) { {(copy) => ( - Copy snippet + {i18n.translate('xpack.apm.tutorial.copySnippet', { + defaultMessage: 'Copy snippet', + })} )} diff --git a/x-pack/plugins/apm/server/routes/fleet.ts b/x-pack/plugins/apm/server/routes/fleet.ts index 3e2d63a5e70e41..3e16228ef1b99b 100644 --- a/x-pack/plugins/apm/server/routes/fleet.ts +++ b/x-pack/plugins/apm/server/routes/fleet.ts @@ -6,7 +6,6 @@ */ import { keyBy } from 'lodash'; -import { AgentPolicy, PackagePolicy } from '../../../fleet/common'; import { getFleetAgents } from '../lib/fleet/get_agents'; import { getApmPackgePolicies } from '../lib/fleet/get_apm_package_policies'; import { createApmServerRoute } from './create_apm_server_route'; @@ -27,27 +26,12 @@ const hasFleetDataRoute = createApmServerRoute({ }, }); -function getAgentPolicyCredentials( - agent: AgentPolicy, - policiesGroupedById: Record -) { - const packagePolicy = policiesGroupedById[agent.id]; - const apmServerCompiledInputs = - packagePolicy.inputs[0].compiled_input['apm-server']; - return { - id: agent.id, - name: agent.name, - apmServerUrl: apmServerCompiledInputs?.host, - secretToken: apmServerCompiledInputs?.secret_token, - }; -} - const fleetAgentsRoute = createApmServerRoute({ endpoint: 'GET /api/apm/fleet/agents', options: { tags: [] }, handler: async ({ core, plugins }) => { const cloudSetup = plugins.cloud?.setup; - const cloudCredentials = cloudSetup + const cloudStandaloneSetup = cloudSetup ? { apmServerUrl: cloudSetup?.apm.url, secretToken: cloudSetup?.apm.secretToken, @@ -70,17 +54,23 @@ const fleetAgentsRoute = createApmServerRoute({ fleetPluginStart, }); - const cloudAgentPolicy = agents.find( + const hasPolicyElasticOnCloud = agents.some( ({ name }) => name === POLICY_ELASTIC_AGENT_ON_CLOUD ); return { - cloudAgentPolicyCredential: cloudAgentPolicy - ? getAgentPolicyCredentials(cloudAgentPolicy, policiesGroupedById) - : undefined, - cloudCredentials, - agentsCredentials: agents.map((agent) => { - return getAgentPolicyCredentials(agent, policiesGroupedById); + hasPolicyElasticOnCloud, + cloudStandaloneSetup, + agents: agents.map((agent) => { + const packagePolicy = policiesGroupedById[agent.id]; + const apmServerCompiledInputs = + packagePolicy.inputs[0].compiled_input['apm-server']; + return { + id: agent.id, + name: agent.name, + apmServerUrl: apmServerCompiledInputs?.host, + secretToken: apmServerCompiledInputs?.secret_token, + }; }), }; },