diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/http_context.tsx b/x-pack/plugins/uptime/public/components/fleet_package/contexts/http_context.tsx new file mode 100644 index 00000000000000..d1306836afa9c8 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/fleet_package/contexts/http_context.tsx @@ -0,0 +1,60 @@ +/* + * 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, { createContext, useContext, useMemo, useState } from 'react'; +import { IHTTPSimpleFields, ConfigKeys, ScheduleUnit, DataStream } from '../types'; + +interface IHTTPSimpleFieldsContext { + setFields: React.Dispatch>; + fields: IHTTPSimpleFields; + defaultValues: IHTTPSimpleFields; +} + +interface IHTTPSimpleFieldsContextProvider { + children: React.ReactNode; + defaultValues?: IHTTPSimpleFields; +} + +export const initialValues = { + [ConfigKeys.URLS]: '', + [ConfigKeys.MAX_REDIRECTS]: '0', + [ConfigKeys.MONITOR_TYPE]: DataStream.HTTP, + [ConfigKeys.SCHEDULE]: { + number: '3', + unit: ScheduleUnit.MINUTES, + }, + [ConfigKeys.APM_SERVICE_NAME]: '', + [ConfigKeys.TAGS]: [], + [ConfigKeys.TIMEOUT]: '16', +}; + +const defaultContext: IHTTPSimpleFieldsContext = { + setFields: (_fields: React.SetStateAction) => { + throw new Error( + 'setFields was not initialized for HTTP Simple Fields, set it when you invoke the context' + ); + }, + fields: initialValues, // mutable + defaultValues: initialValues, // immutable +}; + +export const HTTPSimpleFieldsContext = createContext(defaultContext); + +export const HTTPSimpleFieldsContextProvider = ({ + children, + defaultValues = initialValues, +}: IHTTPSimpleFieldsContextProvider) => { + const [fields, setFields] = useState(defaultValues); + + const value = useMemo(() => { + return { fields, setFields, defaultValues }; + }, [fields, defaultValues]); + + return ; +}; + +export const useHTTPSimpleFieldsContext = () => useContext(HTTPSimpleFieldsContext); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/http_provider.tsx b/x-pack/plugins/uptime/public/components/fleet_package/contexts/http_provider.tsx new file mode 100644 index 00000000000000..e48de76862e24a --- /dev/null +++ b/x-pack/plugins/uptime/public/components/fleet_package/contexts/http_provider.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { ReactNode } from 'react'; +import { IHTTPSimpleFields, IHTTPAdvancedFields, ITLSFields, ConfigKeys } from '../types'; +import { + HTTPSimpleFieldsContextProvider, + HTTPAdvancedFieldsContextProvider, + TLSFieldsContextProvider, +} from '.'; + +interface HTTPContextProviderProps { + defaultValues?: any; + children: ReactNode; +} + +export const HTTPContextProvider = ({ defaultValues, children }: HTTPContextProviderProps) => { + const httpAdvancedFields: IHTTPAdvancedFields | undefined = defaultValues + ? { + [ConfigKeys.USERNAME]: defaultValues[ConfigKeys.USERNAME], + [ConfigKeys.PASSWORD]: defaultValues[ConfigKeys.PASSWORD], + [ConfigKeys.PROXY_URL]: defaultValues[ConfigKeys.PROXY_URL], + [ConfigKeys.RESPONSE_BODY_CHECK_NEGATIVE]: + defaultValues[ConfigKeys.RESPONSE_BODY_CHECK_NEGATIVE], + [ConfigKeys.RESPONSE_BODY_CHECK_POSITIVE]: + defaultValues[ConfigKeys.RESPONSE_BODY_CHECK_POSITIVE], + [ConfigKeys.RESPONSE_BODY_INDEX]: defaultValues[ConfigKeys.RESPONSE_BODY_INDEX], + [ConfigKeys.RESPONSE_HEADERS_CHECK]: defaultValues[ConfigKeys.RESPONSE_HEADERS_CHECK], + [ConfigKeys.RESPONSE_HEADERS_INDEX]: defaultValues[ConfigKeys.RESPONSE_HEADERS_INDEX], + [ConfigKeys.RESPONSE_STATUS_CHECK]: defaultValues[ConfigKeys.RESPONSE_STATUS_CHECK], + [ConfigKeys.REQUEST_BODY_CHECK]: defaultValues[ConfigKeys.REQUEST_BODY_CHECK], + [ConfigKeys.REQUEST_HEADERS_CHECK]: defaultValues[ConfigKeys.REQUEST_HEADERS_CHECK], + [ConfigKeys.REQUEST_METHOD_CHECK]: defaultValues[ConfigKeys.REQUEST_METHOD_CHECK], + } + : undefined; + const httpSimpleFields: IHTTPSimpleFields | undefined = defaultValues + ? { + [ConfigKeys.APM_SERVICE_NAME]: defaultValues[ConfigKeys.APM_SERVICE_NAME], + [ConfigKeys.MAX_REDIRECTS]: defaultValues[ConfigKeys.MAX_REDIRECTS], + [ConfigKeys.MONITOR_TYPE]: defaultValues[ConfigKeys.MONITOR_TYPE], + [ConfigKeys.SCHEDULE]: defaultValues[ConfigKeys.SCHEDULE], + [ConfigKeys.TAGS]: defaultValues[ConfigKeys.TAGS], + [ConfigKeys.TIMEOUT]: defaultValues[ConfigKeys.TIMEOUT], + [ConfigKeys.URLS]: defaultValues[ConfigKeys.URLS], + } + : undefined; + const tlsFields: ITLSFields | undefined = defaultValues + ? { + [ConfigKeys.TLS_CERTIFICATE_AUTHORITIES]: + defaultValues[ConfigKeys.TLS_CERTIFICATE_AUTHORITIES], + [ConfigKeys.TLS_CERTIFICATE]: defaultValues[ConfigKeys.TLS_CERTIFICATE], + [ConfigKeys.TLS_KEY]: defaultValues[ConfigKeys.TLS_KEY], + [ConfigKeys.TLS_KEY_PASSPHRASE]: defaultValues[ConfigKeys.TLS_KEY_PASSPHRASE], + [ConfigKeys.TLS_VERIFICATION_MODE]: defaultValues[ConfigKeys.TLS_VERIFICATION_MODE], + [ConfigKeys.TLS_VERSION]: defaultValues[ConfigKeys.TLS_VERSION], + } + : undefined; + return ( + + + {children} + + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/icmp_context.tsx b/x-pack/plugins/uptime/public/components/fleet_package/contexts/icmp_context.tsx new file mode 100644 index 00000000000000..93c67c6133ce9f --- /dev/null +++ b/x-pack/plugins/uptime/public/components/fleet_package/contexts/icmp_context.tsx @@ -0,0 +1,61 @@ +/* + * 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, { createContext, useContext, useMemo, useState } from 'react'; +import { IICMPSimpleFields, ConfigKeys, ScheduleUnit, DataStream } from '../types'; + +interface IICMPSimpleFieldsContext { + setFields: React.Dispatch>; + fields: IICMPSimpleFields; + defaultValues: IICMPSimpleFields; +} + +interface IICMPSimpleFieldsContextProvider { + children: React.ReactNode; + defaultValues?: IICMPSimpleFields; +} + +export const initialValues = { + [ConfigKeys.HOSTS]: '', + [ConfigKeys.MAX_REDIRECTS]: '0', + [ConfigKeys.MONITOR_TYPE]: DataStream.ICMP, + [ConfigKeys.SCHEDULE]: { + number: '3', + unit: ScheduleUnit.MINUTES, + }, + [ConfigKeys.APM_SERVICE_NAME]: '', + [ConfigKeys.TAGS]: [], + [ConfigKeys.TIMEOUT]: '16', + [ConfigKeys.WAIT]: '1', +}; + +const defaultContext: IICMPSimpleFieldsContext = { + setFields: (_fields: React.SetStateAction) => { + throw new Error( + 'setFields was not initialized for ICMP Simple Fields, set it when you invoke the context' + ); + }, + fields: initialValues, // mutable + defaultValues: initialValues, // immutable +}; + +export const ICMPSimpleFieldsContext = createContext(defaultContext); + +export const ICMPSimpleFieldsContextProvider = ({ + children, + defaultValues = initialValues, +}: IICMPSimpleFieldsContextProvider) => { + const [fields, setFields] = useState(defaultValues); + + const value = useMemo(() => { + return { fields, setFields, defaultValues }; + }, [fields, defaultValues]); + + return ; +}; + +export const useICMPSimpleFieldsContext = () => useContext(ICMPSimpleFieldsContext); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/index.ts b/x-pack/plugins/uptime/public/components/fleet_package/contexts/index.ts index bea3e9d5641a57..f84a4e75df922a 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/contexts/index.ts +++ b/x-pack/plugins/uptime/public/components/fleet_package/contexts/index.ts @@ -6,11 +6,29 @@ */ export { - SimpleFieldsContext, - SimpleFieldsContextProvider, - initialValues as defaultSimpleFields, - useSimpleFieldsContext, -} from './simple_fields_context'; + MonitorTypeContext, + MonitorTypeContextProvider, + initialValue as defaultMonitorType, + useMonitorTypeContext, +} from './monitor_type_context'; +export { + HTTPSimpleFieldsContext, + HTTPSimpleFieldsContextProvider, + initialValues as defaultHTTPSimpleFields, + useHTTPSimpleFieldsContext, +} from './http_context'; +export { + TCPSimpleFieldsContext, + TCPSimpleFieldsContextProvider, + initialValues as defaultTCPSimpleFields, + useTCPSimpleFieldsContext, +} from './tcp_context'; +export { + ICMPSimpleFieldsContext, + ICMPSimpleFieldsContextProvider, + initialValues as defaultICMPSimpleFields, + useICMPSimpleFieldsContext, +} from './icmp_context'; export { TCPAdvancedFieldsContext, TCPAdvancedFieldsContextProvider, @@ -29,3 +47,5 @@ export { initialValues as defaultTLSFields, useTLSFieldsContext, } from './tls_fields_context'; +export { HTTPContextProvider } from './http_provider'; +export { TCPContextProvider } from './tcp_provider'; diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/monitor_type_context.tsx b/x-pack/plugins/uptime/public/components/fleet_package/contexts/monitor_type_context.tsx new file mode 100644 index 00000000000000..6e9a5de83c2fe1 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/fleet_package/contexts/monitor_type_context.tsx @@ -0,0 +1,47 @@ +/* + * 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, { createContext, useContext, useMemo, useState } from 'react'; +import { DataStream } from '../types'; + +interface IMonitorTypeFieldsContext { + setMonitorType: React.Dispatch>; + monitorType: DataStream; + defaultValue: DataStream; +} + +interface IMonitorTypeFieldsContextProvider { + children: React.ReactNode; + defaultValue?: DataStream; +} + +export const initialValue = DataStream.HTTP; + +const defaultContext: IMonitorTypeFieldsContext = { + setMonitorType: (_monitorType: React.SetStateAction) => { + throw new Error('setMonitorType was not initialized, set it when you invoke the context'); + }, + monitorType: initialValue, // mutable + defaultValue: initialValue, // immutable +}; + +export const MonitorTypeContext = createContext(defaultContext); + +export const MonitorTypeContextProvider = ({ + children, + defaultValue = initialValue, +}: IMonitorTypeFieldsContextProvider) => { + const [monitorType, setMonitorType] = useState(defaultValue); + + const value = useMemo(() => { + return { monitorType, setMonitorType, defaultValue }; + }, [monitorType, defaultValue]); + + return ; +}; + +export const useMonitorTypeContext = () => useContext(MonitorTypeContext); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/simple_fields_context.tsx b/x-pack/plugins/uptime/public/components/fleet_package/contexts/simple_fields_context.tsx deleted file mode 100644 index 1d981ed4c2c8fb..00000000000000 --- a/x-pack/plugins/uptime/public/components/fleet_package/contexts/simple_fields_context.tsx +++ /dev/null @@ -1,60 +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, { createContext, useContext, useMemo, useState } from 'react'; -import { ISimpleFields, ConfigKeys, ScheduleUnit, DataStream } from '../types'; - -interface ISimpleFieldsContext { - setFields: React.Dispatch>; - fields: ISimpleFields; - defaultValues: ISimpleFields; -} - -interface ISimpleFieldsContextProvider { - children: React.ReactNode; - defaultValues?: ISimpleFields; -} - -export const initialValues = { - [ConfigKeys.HOSTS]: '', - [ConfigKeys.MAX_REDIRECTS]: '0', - [ConfigKeys.MONITOR_TYPE]: DataStream.HTTP, - [ConfigKeys.SCHEDULE]: { - number: '3', - unit: ScheduleUnit.MINUTES, - }, - [ConfigKeys.APM_SERVICE_NAME]: '', - [ConfigKeys.TAGS]: [], - [ConfigKeys.TIMEOUT]: '16', - [ConfigKeys.URLS]: '', - [ConfigKeys.WAIT]: '1', -}; - -const defaultContext: ISimpleFieldsContext = { - setFields: (_fields: React.SetStateAction) => { - throw new Error('setSimpleFields was not initialized, set it when you invoke the context'); - }, - fields: initialValues, // mutable - defaultValues: initialValues, // immutable -}; - -export const SimpleFieldsContext = createContext(defaultContext); - -export const SimpleFieldsContextProvider = ({ - children, - defaultValues = initialValues, -}: ISimpleFieldsContextProvider) => { - const [fields, setFields] = useState(defaultValues); - - const value = useMemo(() => { - return { fields, setFields, defaultValues }; - }, [fields, defaultValues]); - - return ; -}; - -export const useSimpleFieldsContext = () => useContext(SimpleFieldsContext); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/tcp_context.tsx b/x-pack/plugins/uptime/public/components/fleet_package/contexts/tcp_context.tsx new file mode 100644 index 00000000000000..6020a7ff2bff8d --- /dev/null +++ b/x-pack/plugins/uptime/public/components/fleet_package/contexts/tcp_context.tsx @@ -0,0 +1,60 @@ +/* + * 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, { createContext, useContext, useMemo, useState } from 'react'; +import { ITCPSimpleFields, ConfigKeys, ScheduleUnit, DataStream } from '../types'; + +interface ITCPSimpleFieldsContext { + setFields: React.Dispatch>; + fields: ITCPSimpleFields; + defaultValues: ITCPSimpleFields; +} + +interface ITCPSimpleFieldsContextProvider { + children: React.ReactNode; + defaultValues?: ITCPSimpleFields; +} + +export const initialValues = { + [ConfigKeys.HOSTS]: '', + [ConfigKeys.MAX_REDIRECTS]: '0', + [ConfigKeys.MONITOR_TYPE]: DataStream.TCP, + [ConfigKeys.SCHEDULE]: { + number: '3', + unit: ScheduleUnit.MINUTES, + }, + [ConfigKeys.APM_SERVICE_NAME]: '', + [ConfigKeys.TAGS]: [], + [ConfigKeys.TIMEOUT]: '16', +}; + +const defaultContext: ITCPSimpleFieldsContext = { + setFields: (_fields: React.SetStateAction) => { + throw new Error( + 'setFields was not initialized for TCP Simple Fields, set it when you invoke the context' + ); + }, + fields: initialValues, // mutable + defaultValues: initialValues, // immutable +}; + +export const TCPSimpleFieldsContext = createContext(defaultContext); + +export const TCPSimpleFieldsContextProvider = ({ + children, + defaultValues = initialValues, +}: ITCPSimpleFieldsContextProvider) => { + const [fields, setFields] = useState(defaultValues); + + const value = useMemo(() => { + return { fields, setFields, defaultValues }; + }, [fields, defaultValues]); + + return ; +}; + +export const useTCPSimpleFieldsContext = () => useContext(TCPSimpleFieldsContext); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/contexts/tcp_provider.tsx b/x-pack/plugins/uptime/public/components/fleet_package/contexts/tcp_provider.tsx new file mode 100644 index 00000000000000..666839803f4d67 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/fleet_package/contexts/tcp_provider.tsx @@ -0,0 +1,62 @@ +/* + * 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, { ReactNode } from 'react'; +import { ConfigKeys, ITCPSimpleFields, ITCPAdvancedFields, ITLSFields } from '../types'; +import { + TCPSimpleFieldsContextProvider, + TCPAdvancedFieldsContextProvider, + TLSFieldsContextProvider, +} from '.'; + +interface TCPContextProviderProps { + defaultValues?: any; + children: ReactNode; +} + +/** + * Exports Synthetics-specific package policy instructions + * for use in the Ingest app create / edit package policy + */ +export const TCPContextProvider = ({ defaultValues, children }: TCPContextProviderProps) => { + const tcpSimpleFields: ITCPSimpleFields | undefined = defaultValues + ? { + [ConfigKeys.APM_SERVICE_NAME]: defaultValues[ConfigKeys.APM_SERVICE_NAME], + [ConfigKeys.HOSTS]: defaultValues[ConfigKeys.HOSTS], + [ConfigKeys.MONITOR_TYPE]: defaultValues[ConfigKeys.MONITOR_TYPE], + [ConfigKeys.SCHEDULE]: defaultValues[ConfigKeys.SCHEDULE], + [ConfigKeys.TAGS]: defaultValues[ConfigKeys.TAGS], + [ConfigKeys.TIMEOUT]: defaultValues[ConfigKeys.TIMEOUT], + } + : undefined; + const tcpAdvancedFields: ITCPAdvancedFields | undefined = defaultValues + ? { + [ConfigKeys.PROXY_URL]: defaultValues[ConfigKeys.PROXY_URL], + [ConfigKeys.PROXY_USE_LOCAL_RESOLVER]: defaultValues[ConfigKeys.PROXY_USE_LOCAL_RESOLVER], + [ConfigKeys.RESPONSE_RECEIVE_CHECK]: defaultValues[ConfigKeys.RESPONSE_RECEIVE_CHECK], + [ConfigKeys.REQUEST_SEND_CHECK]: defaultValues[ConfigKeys.REQUEST_SEND_CHECK], + } + : undefined; + const tlsFields: ITLSFields | undefined = defaultValues + ? { + [ConfigKeys.TLS_CERTIFICATE_AUTHORITIES]: + defaultValues[ConfigKeys.TLS_CERTIFICATE_AUTHORITIES], + [ConfigKeys.TLS_CERTIFICATE]: defaultValues[ConfigKeys.TLS_CERTIFICATE], + [ConfigKeys.TLS_KEY]: defaultValues[ConfigKeys.TLS_KEY], + [ConfigKeys.TLS_KEY_PASSPHRASE]: defaultValues[ConfigKeys.TLS_KEY_PASSPHRASE], + [ConfigKeys.TLS_VERIFICATION_MODE]: defaultValues[ConfigKeys.TLS_VERIFICATION_MODE], + [ConfigKeys.TLS_VERSION]: defaultValues[ConfigKeys.TLS_VERSION], + } + : undefined; + return ( + + + {children} + + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/fleet_package/custom_fields.test.tsx b/x-pack/plugins/uptime/public/components/fleet_package/custom_fields.test.tsx index b5fec58d4da850..e114ea72b8f49c 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/custom_fields.test.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/custom_fields.test.tsx @@ -9,18 +9,15 @@ import React from 'react'; import { fireEvent, waitFor } from '@testing-library/react'; import { render } from '../../lib/helper/rtl_helpers'; import { - SimpleFieldsContextProvider, - HTTPAdvancedFieldsContextProvider, - TCPAdvancedFieldsContextProvider, - TLSFieldsContextProvider, - defaultSimpleFields, - defaultTLSFields, - defaultHTTPAdvancedFields, - defaultTCPAdvancedFields, + TCPContextProvider, + HTTPContextProvider, + ICMPSimpleFieldsContextProvider, + MonitorTypeContextProvider, } from './contexts'; import { CustomFields } from './custom_fields'; import { ConfigKeys, DataStream, ScheduleUnit } from './types'; import { validate as centralValidation } from './validation'; +import { defaultConfig } from './synthetics_policy_create_extension'; // ensures that fields appropriately match to their label jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ @@ -29,25 +26,21 @@ jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ const defaultValidation = centralValidation[DataStream.HTTP]; -const defaultConfig = { - ...defaultSimpleFields, - ...defaultTLSFields, - ...defaultHTTPAdvancedFields, - ...defaultTCPAdvancedFields, -}; +const defaultHTTPConfig = defaultConfig[DataStream.HTTP]; +const defaultTCPConfig = defaultConfig[DataStream.TCP]; describe('', () => { const WrappedComponent = ({ validate = defaultValidation, typeEditable = false }) => { return ( - - - - + + + + - - - - + + + + ); }; @@ -63,20 +56,20 @@ describe('', () => { const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement; expect(monitorType).not.toBeInTheDocument(); expect(url).toBeInTheDocument(); - expect(url.value).toEqual(defaultConfig[ConfigKeys.URLS]); + expect(url.value).toEqual(defaultHTTPConfig[ConfigKeys.URLS]); expect(proxyUrl).toBeInTheDocument(); - expect(proxyUrl.value).toEqual(defaultConfig[ConfigKeys.PROXY_URL]); + expect(proxyUrl.value).toEqual(defaultHTTPConfig[ConfigKeys.PROXY_URL]); expect(monitorIntervalNumber).toBeInTheDocument(); - expect(monitorIntervalNumber.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].number); + expect(monitorIntervalNumber.value).toEqual(defaultHTTPConfig[ConfigKeys.SCHEDULE].number); expect(monitorIntervalUnit).toBeInTheDocument(); - expect(monitorIntervalUnit.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].unit); + expect(monitorIntervalUnit.value).toEqual(defaultHTTPConfig[ConfigKeys.SCHEDULE].unit); // expect(tags).toBeInTheDocument(); expect(apmServiceName).toBeInTheDocument(); - expect(apmServiceName.value).toEqual(defaultConfig[ConfigKeys.APM_SERVICE_NAME]); + expect(apmServiceName.value).toEqual(defaultHTTPConfig[ConfigKeys.APM_SERVICE_NAME]); expect(maxRedirects).toBeInTheDocument(); - expect(maxRedirects.value).toEqual(`${defaultConfig[ConfigKeys.MAX_REDIRECTS]}`); + expect(maxRedirects.value).toEqual(`${defaultHTTPConfig[ConfigKeys.MAX_REDIRECTS]}`); expect(timeout).toBeInTheDocument(); - expect(timeout.value).toEqual(`${defaultConfig[ConfigKeys.TIMEOUT]}`); + expect(timeout.value).toEqual(`${defaultHTTPConfig[ConfigKeys.TIMEOUT]}`); // ensure other monitor type options are not in the DOM expect(queryByLabelText('Host')).not.toBeInTheDocument(); @@ -116,11 +109,15 @@ describe('', () => { expect(verificationMode).toBeInTheDocument(); await waitFor(() => { - expect(ca.value).toEqual(defaultConfig[ConfigKeys.TLS_CERTIFICATE_AUTHORITIES].value); - expect(clientKey.value).toEqual(defaultConfig[ConfigKeys.TLS_KEY].value); - expect(clientKeyPassphrase.value).toEqual(defaultConfig[ConfigKeys.TLS_KEY_PASSPHRASE].value); - expect(clientCertificate.value).toEqual(defaultConfig[ConfigKeys.TLS_CERTIFICATE].value); - expect(verificationMode.value).toEqual(defaultConfig[ConfigKeys.TLS_VERIFICATION_MODE].value); + expect(ca.value).toEqual(defaultHTTPConfig[ConfigKeys.TLS_CERTIFICATE_AUTHORITIES].value); + expect(clientKey.value).toEqual(defaultHTTPConfig[ConfigKeys.TLS_KEY].value); + expect(clientKeyPassphrase.value).toEqual( + defaultHTTPConfig[ConfigKeys.TLS_KEY_PASSPHRASE].value + ); + expect(clientCertificate.value).toEqual(defaultHTTPConfig[ConfigKeys.TLS_CERTIFICATE].value); + expect(verificationMode.value).toEqual( + defaultHTTPConfig[ConfigKeys.TLS_VERIFICATION_MODE].value + ); }); }); @@ -157,14 +154,14 @@ describe('', () => { ); const monitorType = getByLabelText('Monitor Type') as HTMLInputElement; expect(monitorType).toBeInTheDocument(); - expect(monitorType.value).toEqual(defaultConfig[ConfigKeys.MONITOR_TYPE]); + expect(monitorType.value).toEqual(defaultHTTPConfig[ConfigKeys.MONITOR_TYPE]); fireEvent.change(monitorType, { target: { value: DataStream.TCP } }); // expect tcp fields to be in the DOM const host = getByLabelText('Host:Port') as HTMLInputElement; expect(host).toBeInTheDocument(); - expect(host.value).toEqual(defaultConfig[ConfigKeys.HOSTS]); + expect(host.value).toEqual(defaultTCPConfig[ConfigKeys.HOSTS]); // expect HTTP fields not to be in the DOM expect(queryByLabelText('URL')).not.toBeInTheDocument(); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/custom_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/custom_fields.tsx index e6703a6eaa97cd..0d9291261b82d6 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/custom_fields.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/custom_fields.tsx @@ -5,28 +5,26 @@ * 2.0. */ -import React, { useEffect, useState, memo } from 'react'; +import React, { useState, memo } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFlexGroup, EuiFlexItem, EuiForm, EuiFormRow, - EuiFieldText, - EuiFieldNumber, EuiSelect, EuiSpacer, EuiDescribedFormGroup, EuiCheckbox, } from '@elastic/eui'; -import { ConfigKeys, DataStream, ISimpleFields, Validation } from './types'; -import { useSimpleFieldsContext } from './contexts'; +import { ConfigKeys, DataStream, Validation } from './types'; +import { useMonitorTypeContext } from './contexts'; import { TLSFields, TLSRole } from './tls_fields'; -import { ComboBox } from './combo_box'; -import { OptionalLabel } from './optional_label'; -import { HTTPAdvancedFields } from './http_advanced_fields'; -import { TCPAdvancedFields } from './tcp_advanced_fields'; -import { ScheduleField } from './schedule_field'; +import { HTTPSimpleFields } from './http/simple_fields'; +import { HTTPAdvancedFields } from './http/advanced_fields'; +import { TCPSimpleFields } from './tcp/simple_fields'; +import { TCPAdvancedFields } from './tcp/advanced_fields'; +import { ICMPSimpleFields } from './icmp/simple_fields'; interface Props { typeEditable?: boolean; @@ -37,26 +35,22 @@ interface Props { export const CustomFields = memo( ({ typeEditable = false, isTLSEnabled: defaultIsTLSEnabled = false, validate }) => { const [isTLSEnabled, setIsTLSEnabled] = useState(defaultIsTLSEnabled); - const { fields, setFields, defaultValues } = useSimpleFieldsContext(); - const { type } = fields; + const { monitorType, setMonitorType } = useMonitorTypeContext(); - const isHTTP = fields[ConfigKeys.MONITOR_TYPE] === DataStream.HTTP; - const isTCP = fields[ConfigKeys.MONITOR_TYPE] === DataStream.TCP; - const isICMP = fields[ConfigKeys.MONITOR_TYPE] === DataStream.ICMP; + const isHTTP = monitorType === DataStream.HTTP; + const isTCP = monitorType === DataStream.TCP; - // reset monitor type specific fields any time a monitor type is switched - useEffect(() => { - if (typeEditable) { - setFields((prevFields: ISimpleFields) => ({ - ...prevFields, - [ConfigKeys.HOSTS]: defaultValues[ConfigKeys.HOSTS], - [ConfigKeys.URLS]: defaultValues[ConfigKeys.URLS], - })); + const renderSimpleFields = (type: DataStream) => { + switch (type) { + case DataStream.HTTP: + return ; + case DataStream.ICMP: + return ; + case DataStream.TCP: + return ; + default: + return null; } - }, [defaultValues, type, typeEditable, setFields]); - - const handleInputChange = ({ value, configKey }: { value: unknown; configKey: ConfigKeys }) => { - setFields((prevFields) => ({ ...prevFields, [configKey]: value })); }; return ( @@ -88,7 +82,7 @@ export const CustomFields = memo( defaultMessage="Monitor Type" /> } - isInvalid={!!validate[ConfigKeys.MONITOR_TYPE]?.(fields[ConfigKeys.MONITOR_TYPE])} + isInvalid={!!validate[ConfigKeys.MONITOR_TYPE]?.(monitorType)} error={ ( > - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.MONITOR_TYPE, - }) - } + value={monitorType} + onChange={(event) => setMonitorType(event.target.value as DataStream)} data-test-subj="syntheticsMonitorTypeField" /> )} - {isHTTP && ( - - } - isInvalid={!!validate[ConfigKeys.URLS]?.(fields[ConfigKeys.URLS])} - error={ - - } - > - - handleInputChange({ value: event.target.value, configKey: ConfigKeys.URLS }) - } - data-test-subj="syntheticsUrlField" - /> - - )} - {isTCP && ( - - } - isInvalid={!!validate[ConfigKeys.HOSTS]?.(fields[ConfigKeys.HOSTS])} - error={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.HOSTS, - }) - } - data-test-subj="syntheticsTCPHostField" - /> - - )} - {isICMP && ( - - } - isInvalid={!!validate[ConfigKeys.HOSTS]?.(fields[ConfigKeys.HOSTS])} - error={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.HOSTS, - }) - } - data-test-subj="syntheticsICMPHostField" - /> - - )} - - } - isInvalid={!!validate[ConfigKeys.SCHEDULE]?.(fields[ConfigKeys.SCHEDULE])} - error={ - - } - > - - handleInputChange({ - value: schedule, - configKey: ConfigKeys.SCHEDULE, - }) - } - number={fields[ConfigKeys.SCHEDULE].number} - unit={fields[ConfigKeys.SCHEDULE].unit} - /> - - {isICMP && ( - - } - isInvalid={!!validate[ConfigKeys.WAIT]?.(fields[ConfigKeys.WAIT])} - error={ - - } - labelAppend={} - helpText={ - - } - > - - handleInputChange({ value: event.target.value, configKey: ConfigKeys.WAIT }) - } - step={'any'} - /> - - )} - - } - labelAppend={} - helpText={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.APM_SERVICE_NAME, - }) - } - data-test-subj="syntheticsAPMServiceName" - /> - - {isHTTP && ( - - } - isInvalid={ - !!validate[ConfigKeys.MAX_REDIRECTS]?.(fields[ConfigKeys.MAX_REDIRECTS]) - } - error={ - - } - labelAppend={} - helpText={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.MAX_REDIRECTS, - }) - } - /> - - )} - - } - isInvalid={ - !!validate[ConfigKeys.TIMEOUT]?.( - fields[ConfigKeys.TIMEOUT], - fields[ConfigKeys.SCHEDULE].number, - fields[ConfigKeys.SCHEDULE].unit - ) - } - error={ - - } - helpText={ - - } - > - - handleInputChange({ - value: event.target.value, - configKey: ConfigKeys.TIMEOUT, - }) - } - step={'any'} - /> - - - } - labelAppend={} - helpText={ - - } - > - handleInputChange({ value, configKey: ConfigKeys.TAGS })} - data-test-subj="syntheticsTags" - /> - + {renderSimpleFields(monitorType)} diff --git a/x-pack/plugins/uptime/public/components/fleet_package/http_advanced_fields.test.tsx b/x-pack/plugins/uptime/public/components/fleet_package/http/advanced_fields.test.tsx similarity index 95% rename from x-pack/plugins/uptime/public/components/fleet_package/http_advanced_fields.test.tsx rename to x-pack/plugins/uptime/public/components/fleet_package/http/advanced_fields.test.tsx index b1a37be1bffb67..69c1d897f7847d 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/http_advanced_fields.test.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/http/advanced_fields.test.tsx @@ -7,14 +7,14 @@ import React from 'react'; import { fireEvent } from '@testing-library/react'; -import { render } from '../../lib/helper/rtl_helpers'; -import { HTTPAdvancedFields } from './http_advanced_fields'; -import { ConfigKeys, DataStream, HTTPMethod, IHTTPAdvancedFields, Validation } from './types'; +import { render } from '../../../lib/helper/rtl_helpers'; +import { HTTPAdvancedFields } from './advanced_fields'; +import { ConfigKeys, DataStream, HTTPMethod, IHTTPAdvancedFields, Validation } from '../types'; import { HTTPAdvancedFieldsContextProvider, defaultHTTPAdvancedFields as defaultConfig, -} from './contexts'; -import { validate as centralValidation } from './validation'; +} from '../contexts'; +import { validate as centralValidation } from '../validation'; jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ htmlIdGenerator: () => () => `id-${Math.random()}`, diff --git a/x-pack/plugins/uptime/public/components/fleet_package/http_advanced_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/http/advanced_fields.tsx similarity index 97% rename from x-pack/plugins/uptime/public/components/fleet_package/http_advanced_fields.tsx rename to x-pack/plugins/uptime/public/components/fleet_package/http/advanced_fields.tsx index 568ff526efb6e9..aeaa452c38db96 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/http_advanced_fields.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/http/advanced_fields.tsx @@ -20,15 +20,15 @@ import { EuiFieldPassword, } from '@elastic/eui'; -import { useHTTPAdvancedFieldsContext } from './contexts'; +import { useHTTPAdvancedFieldsContext } from '../contexts'; -import { ConfigKeys, HTTPMethod, Validation } from './types'; +import { ConfigKeys, HTTPMethod, Validation } from '../types'; -import { OptionalLabel } from './optional_label'; -import { HeaderField } from './header_field'; -import { RequestBodyField } from './request_body_field'; -import { ResponseBodyIndexField } from './index_response_body_field'; -import { ComboBox } from './combo_box'; +import { OptionalLabel } from '../optional_label'; +import { HeaderField } from '../header_field'; +import { RequestBodyField } from '../request_body_field'; +import { ResponseBodyIndexField } from '../index_response_body_field'; +import { ComboBox } from '../combo_box'; interface Props { validate: Validation; diff --git a/x-pack/plugins/uptime/public/components/fleet_package/http/simple_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/http/simple_fields.tsx new file mode 100644 index 00000000000000..d17b8c997e9e8d --- /dev/null +++ b/x-pack/plugins/uptime/public/components/fleet_package/http/simple_fields.tsx @@ -0,0 +1,200 @@ +/* + * 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, { memo } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiFormRow, EuiFieldText, EuiFieldNumber } from '@elastic/eui'; +import { ConfigKeys, Validation } from '../types'; +import { useHTTPSimpleFieldsContext } from '../contexts'; +import { ComboBox } from '../combo_box'; +import { OptionalLabel } from '../optional_label'; +import { ScheduleField } from '../schedule_field'; + +interface Props { + validate: Validation; +} + +export const HTTPSimpleFields = memo(({ validate }) => { + const { fields, setFields } = useHTTPSimpleFieldsContext(); + const handleInputChange = ({ value, configKey }: { value: unknown; configKey: ConfigKeys }) => { + setFields((prevFields) => ({ ...prevFields, [configKey]: value })); + }; + + return ( + <> + + } + isInvalid={!!validate[ConfigKeys.URLS]?.(fields[ConfigKeys.URLS])} + error={ + + } + > + + handleInputChange({ value: event.target.value, configKey: ConfigKeys.URLS }) + } + data-test-subj="syntheticsUrlField" + /> + + + } + isInvalid={!!validate[ConfigKeys.SCHEDULE]?.(fields[ConfigKeys.SCHEDULE])} + error={ + + } + > + + handleInputChange({ + value: schedule, + configKey: ConfigKeys.SCHEDULE, + }) + } + number={fields[ConfigKeys.SCHEDULE].number} + unit={fields[ConfigKeys.SCHEDULE].unit} + /> + + + } + labelAppend={} + helpText={ + + } + > + + handleInputChange({ + value: event.target.value, + configKey: ConfigKeys.APM_SERVICE_NAME, + }) + } + data-test-subj="syntheticsAPMServiceName" + /> + + + } + isInvalid={!!validate[ConfigKeys.MAX_REDIRECTS]?.(fields[ConfigKeys.MAX_REDIRECTS])} + error={ + + } + labelAppend={} + helpText={ + + } + > + + handleInputChange({ + value: event.target.value, + configKey: ConfigKeys.MAX_REDIRECTS, + }) + } + /> + + + } + isInvalid={ + !!validate[ConfigKeys.TIMEOUT]?.( + fields[ConfigKeys.TIMEOUT], + fields[ConfigKeys.SCHEDULE].number, + fields[ConfigKeys.SCHEDULE].unit + ) + } + error={ + + } + helpText={ + + } + > + + handleInputChange({ + value: event.target.value, + configKey: ConfigKeys.TIMEOUT, + }) + } + step={'any'} + /> + + + } + labelAppend={} + helpText={ + + } + > + handleInputChange({ value, configKey: ConfigKeys.TAGS })} + data-test-subj="syntheticsTags" + /> + + + ); +}); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/icmp/simple_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/icmp/simple_fields.tsx new file mode 100644 index 00000000000000..3ca07c70673677 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/fleet_package/icmp/simple_fields.tsx @@ -0,0 +1,204 @@ +/* + * 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, { memo } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiFormRow, EuiFieldText, EuiFieldNumber } from '@elastic/eui'; +import { ConfigKeys, Validation } from '../types'; +import { useICMPSimpleFieldsContext } from '../contexts'; +import { ComboBox } from '../combo_box'; +import { OptionalLabel } from '../optional_label'; +import { ScheduleField } from '../schedule_field'; + +interface Props { + validate: Validation; +} + +export const ICMPSimpleFields = memo(({ validate }) => { + const { fields, setFields } = useICMPSimpleFieldsContext(); + const handleInputChange = ({ value, configKey }: { value: unknown; configKey: ConfigKeys }) => { + setFields((prevFields) => ({ ...prevFields, [configKey]: value })); + }; + + return ( + <> + + } + isInvalid={!!validate[ConfigKeys.HOSTS]?.(fields[ConfigKeys.HOSTS])} + error={ + + } + > + + handleInputChange({ + value: event.target.value, + configKey: ConfigKeys.HOSTS, + }) + } + data-test-subj="syntheticsICMPHostField" + /> + + + } + isInvalid={!!validate[ConfigKeys.SCHEDULE]?.(fields[ConfigKeys.SCHEDULE])} + error={ + + } + > + + handleInputChange({ + value: schedule, + configKey: ConfigKeys.SCHEDULE, + }) + } + number={fields[ConfigKeys.SCHEDULE].number} + unit={fields[ConfigKeys.SCHEDULE].unit} + /> + + + } + isInvalid={!!validate[ConfigKeys.WAIT]?.(fields[ConfigKeys.WAIT])} + error={ + + } + labelAppend={} + helpText={ + + } + > + + handleInputChange({ + value: event.target.value, + configKey: ConfigKeys.WAIT, + }) + } + step={'any'} + /> + + + } + labelAppend={} + helpText={ + + } + > + + handleInputChange({ + value: event.target.value, + configKey: ConfigKeys.APM_SERVICE_NAME, + }) + } + data-test-subj="syntheticsAPMServiceName" + /> + + + } + isInvalid={ + !!validate[ConfigKeys.TIMEOUT]?.( + fields[ConfigKeys.TIMEOUT], + fields[ConfigKeys.SCHEDULE].number, + fields[ConfigKeys.SCHEDULE].unit + ) + } + error={ + + } + helpText={ + + } + > + + handleInputChange({ + value: event.target.value, + configKey: ConfigKeys.TIMEOUT, + }) + } + step={'any'} + /> + + + } + labelAppend={} + helpText={ + + } + > + handleInputChange({ value, configKey: ConfigKeys.TAGS })} + data-test-subj="syntheticsTags" + /> + + + ); +}); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension.tsx b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension.tsx index 1306308f8ba4e1..90e7e7d7bb7333 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension.tsx @@ -9,37 +9,62 @@ import React, { memo, useContext, useEffect } from 'react'; import useDebounce from 'react-use/lib/useDebounce'; import { PackagePolicyCreateExtensionComponentProps } from '../../../../fleet/public'; import { useTrackPageview } from '../../../../observability/public'; -import { Config, ConfigKeys, DataStream } from './types'; +import { PolicyConfig, DataStream } from './types'; import { - SimpleFieldsContext, + MonitorTypeContext, HTTPAdvancedFieldsContext, TCPAdvancedFieldsContext, TLSFieldsContext, + HTTPSimpleFieldsContext, + TCPSimpleFieldsContext, + ICMPSimpleFieldsContext, + defaultHTTPAdvancedFields, + defaultHTTPSimpleFields, + defaultICMPSimpleFields, + defaultTCPSimpleFields, + defaultTCPAdvancedFields, + defaultTLSFields, } from './contexts'; import { CustomFields } from './custom_fields'; import { useUpdatePolicy } from './use_update_policy'; import { validate } from './validation'; +export const defaultConfig: PolicyConfig = { + [DataStream.HTTP]: { + ...defaultHTTPSimpleFields, + ...defaultHTTPAdvancedFields, + ...defaultTLSFields, + }, + [DataStream.TCP]: { + ...defaultTCPSimpleFields, + ...defaultTCPAdvancedFields, + ...defaultTLSFields, + }, + [DataStream.ICMP]: defaultICMPSimpleFields, +}; + /** * Exports Synthetics-specific package policy instructions * for use in the Ingest app create / edit package policy */ export const SyntheticsPolicyCreateExtension = memo( ({ newPolicy, onChange }) => { - const { fields: simpleFields } = useContext(SimpleFieldsContext); + const { monitorType } = useContext(MonitorTypeContext); + const { fields: httpSimpleFields } = useContext(HTTPSimpleFieldsContext); + const { fields: tcpSimpleFields } = useContext(TCPSimpleFieldsContext); + const { fields: icmpSimpleFields } = useContext(ICMPSimpleFieldsContext); const { fields: httpAdvancedFields } = useContext(HTTPAdvancedFieldsContext); const { fields: tcpAdvancedFields } = useContext(TCPAdvancedFieldsContext); const { fields: tlsFields } = useContext(TLSFieldsContext); - const defaultConfig: Config = { - name: '', - ...simpleFields, - ...httpAdvancedFields, - ...tcpAdvancedFields, - ...tlsFields, - }; useTrackPageview({ app: 'fleet', path: 'syntheticsCreate' }); useTrackPageview({ app: 'fleet', path: 'syntheticsCreate', delay: 15000 }); - const { config, setConfig } = useUpdatePolicy({ defaultConfig, newPolicy, onChange, validate }); + const { setConfig } = useUpdatePolicy({ + monitorType, + defaultConfig, + newPolicy, + onChange, + validate, + }); // Fleet will initialize the create form with a default name for the integratin policy, however, // for synthetics, we want the user to explicitely type in a name to use as the monitor name, @@ -57,24 +82,40 @@ export const SyntheticsPolicyCreateExtension = memo { - setConfig((prevConfig) => ({ - ...prevConfig, - ...simpleFields, - ...httpAdvancedFields, - ...tcpAdvancedFields, - ...tlsFields, - // ensure proxyUrl is not overwritten - [ConfigKeys.PROXY_URL]: - simpleFields[ConfigKeys.MONITOR_TYPE] === DataStream.HTTP - ? httpAdvancedFields[ConfigKeys.PROXY_URL] - : tcpAdvancedFields[ConfigKeys.PROXY_URL], - })); + setConfig(() => { + switch (monitorType) { + case DataStream.HTTP: + return { + ...httpSimpleFields, + ...httpAdvancedFields, + ...tlsFields, + }; + case DataStream.TCP: + return { + ...tcpSimpleFields, + ...tcpAdvancedFields, + ...tlsFields, + }; + case DataStream.ICMP: + return { + ...icmpSimpleFields, + }; + } + }); }, 250, - [setConfig, simpleFields, httpAdvancedFields, tcpAdvancedFields, tlsFields] + [ + setConfig, + httpSimpleFields, + tcpSimpleFields, + icmpSimpleFields, + httpAdvancedFields, + tcpAdvancedFields, + tlsFields, + ] ); - return ; + return ; } ); SyntheticsPolicyCreateExtension.displayName = 'SyntheticsPolicyCreateExtension'; diff --git a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension_wrapper.test.tsx b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension_wrapper.test.tsx index a16f2ba87d79ab..395b5d67abeb0b 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension_wrapper.test.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension_wrapper.test.tsx @@ -9,22 +9,10 @@ import React from 'react'; import { fireEvent, waitFor } from '@testing-library/react'; import { render } from '../../lib/helper/rtl_helpers'; import { NewPackagePolicy } from '../../../../fleet/public'; -import { - defaultSimpleFields, - defaultTLSFields, - defaultHTTPAdvancedFields, - defaultTCPAdvancedFields, -} from './contexts'; import { SyntheticsPolicyCreateExtensionWrapper } from './synthetics_policy_create_extension_wrapper'; +import { defaultConfig } from './synthetics_policy_create_extension'; import { ConfigKeys, DataStream, ScheduleUnit, VerificationMode } from './types'; -const defaultConfig = { - ...defaultSimpleFields, - ...defaultTLSFields, - ...defaultHTTPAdvancedFields, - ...defaultTCPAdvancedFields, -}; - // ensures that fields appropriately match to their label jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ htmlIdGenerator: () => () => `id-${Math.random()}`, @@ -266,6 +254,9 @@ const defaultNewPolicy: NewPackagePolicy = { }, }; +const defaultHTTPConfig = defaultConfig[DataStream.HTTP]; +const defaultTCPConfig = defaultConfig[DataStream.TCP]; + describe('', () => { const onChange = jest.fn(); const WrappedComponent = ({ newPolicy = defaultNewPolicy }) => { @@ -283,21 +274,21 @@ describe('', () => { const maxRedirects = getByLabelText('Max redirects') as HTMLInputElement; const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement; expect(monitorType).toBeInTheDocument(); - expect(monitorType.value).toEqual(defaultConfig[ConfigKeys.MONITOR_TYPE]); + expect(monitorType.value).toEqual(DataStream.HTTP); expect(url).toBeInTheDocument(); - expect(url.value).toEqual(defaultConfig[ConfigKeys.URLS]); + expect(url.value).toEqual(defaultHTTPConfig[ConfigKeys.URLS]); expect(proxyUrl).toBeInTheDocument(); - expect(proxyUrl.value).toEqual(defaultConfig[ConfigKeys.PROXY_URL]); + expect(proxyUrl.value).toEqual(defaultHTTPConfig[ConfigKeys.PROXY_URL]); expect(monitorIntervalNumber).toBeInTheDocument(); - expect(monitorIntervalNumber.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].number); + expect(monitorIntervalNumber.value).toEqual(defaultHTTPConfig[ConfigKeys.SCHEDULE].number); expect(monitorIntervalUnit).toBeInTheDocument(); - expect(monitorIntervalUnit.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].unit); + expect(monitorIntervalUnit.value).toEqual(defaultHTTPConfig[ConfigKeys.SCHEDULE].unit); expect(apmServiceName).toBeInTheDocument(); - expect(apmServiceName.value).toEqual(defaultConfig[ConfigKeys.APM_SERVICE_NAME]); + expect(apmServiceName.value).toEqual(defaultHTTPConfig[ConfigKeys.APM_SERVICE_NAME]); expect(maxRedirects).toBeInTheDocument(); - expect(maxRedirects.value).toEqual(`${defaultConfig[ConfigKeys.MAX_REDIRECTS]}`); + expect(maxRedirects.value).toEqual(`${defaultHTTPConfig[ConfigKeys.MAX_REDIRECTS]}`); expect(timeout).toBeInTheDocument(); - expect(timeout.value).toEqual(`${defaultConfig[ConfigKeys.TIMEOUT]}`); + expect(timeout.value).toEqual(`${defaultHTTPConfig[ConfigKeys.TIMEOUT]}`); // ensure other monitor type options are not in the DOM expect(queryByLabelText('Host')).not.toBeInTheDocument(); @@ -425,7 +416,7 @@ describe('', () => { const { getByText, getByLabelText, queryByLabelText } = render(); const monitorType = getByLabelText('Monitor Type') as HTMLInputElement; expect(monitorType).toBeInTheDocument(); - expect(monitorType.value).toEqual(defaultConfig[ConfigKeys.MONITOR_TYPE]); + expect(monitorType.value).toEqual(DataStream.HTTP); fireEvent.change(monitorType, { target: { value: DataStream.TCP } }); await waitFor(() => { @@ -452,7 +443,7 @@ describe('', () => { const host = getByLabelText('Host:Port') as HTMLInputElement; expect(host).toBeInTheDocument(); - expect(host.value).toEqual(defaultConfig[ConfigKeys.HOSTS]); + expect(host.value).toEqual(defaultTCPConfig[ConfigKeys.HOSTS]); // expect HTTP fields not to be in the DOM expect(queryByLabelText('URL')).not.toBeInTheDocument(); @@ -467,29 +458,6 @@ describe('', () => { fireEvent.change(monitorType, { target: { value: DataStream.ICMP } }); - await waitFor(() => { - expect(onChange).toBeCalledWith({ - isValid: false, - updatedPolicy: { - ...defaultNewPolicy, - inputs: [ - { - ...defaultNewPolicy.inputs[0], - enabled: false, - }, - { - ...defaultNewPolicy.inputs[1], - enabled: false, - }, - { - ...defaultNewPolicy.inputs[2], - enabled: true, - }, - ], - }, - }); - }); - // expect ICMP fields to be in the DOM expect(getByLabelText('Wait in seconds')).toBeInTheDocument(); @@ -721,23 +689,27 @@ describe('', () => { await waitFor(() => { fireEvent.change(ca, { target: { value: 'certificateAuthorities' } }); - expect(ca.value).toEqual(defaultConfig[ConfigKeys.TLS_CERTIFICATE_AUTHORITIES].value); + expect(ca.value).toEqual(defaultHTTPConfig[ConfigKeys.TLS_CERTIFICATE_AUTHORITIES].value); }); await waitFor(() => { fireEvent.change(clientCertificate, { target: { value: 'clientCertificate' } }); - expect(clientCertificate.value).toEqual(defaultConfig[ConfigKeys.TLS_KEY].value); + expect(clientCertificate.value).toEqual(defaultHTTPConfig[ConfigKeys.TLS_KEY].value); }); await waitFor(() => { fireEvent.change(clientKey, { target: { value: 'clientKey' } }); - expect(clientKey.value).toEqual(defaultConfig[ConfigKeys.TLS_KEY].value); + expect(clientKey.value).toEqual(defaultHTTPConfig[ConfigKeys.TLS_KEY].value); }); await waitFor(() => { fireEvent.change(clientKeyPassphrase, { target: { value: 'clientKeyPassphrase' } }); - expect(clientKeyPassphrase.value).toEqual(defaultConfig[ConfigKeys.TLS_KEY_PASSPHRASE].value); + expect(clientKeyPassphrase.value).toEqual( + defaultHTTPConfig[ConfigKeys.TLS_KEY_PASSPHRASE].value + ); }); await waitFor(() => { fireEvent.change(verificationMode, { target: { value: VerificationMode.NONE } }); - expect(verificationMode.value).toEqual(defaultConfig[ConfigKeys.TLS_VERIFICATION_MODE].value); + expect(verificationMode.value).toEqual( + defaultHTTPConfig[ConfigKeys.TLS_VERIFICATION_MODE].value + ); }); await waitFor(() => { diff --git a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension_wrapper.tsx b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension_wrapper.tsx index 688ee24bd2330a..88bb8e7871459d 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension_wrapper.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_create_extension_wrapper.tsx @@ -9,9 +9,10 @@ import React, { memo } from 'react'; import { PackagePolicyCreateExtensionComponentProps } from '../../../../fleet/public'; import { SyntheticsPolicyCreateExtension } from './synthetics_policy_create_extension'; import { - SimpleFieldsContextProvider, - HTTPAdvancedFieldsContextProvider, - TCPAdvancedFieldsContextProvider, + MonitorTypeContextProvider, + TCPContextProvider, + ICMPSimpleFieldsContextProvider, + HTTPContextProvider, TLSFieldsContextProvider, } from './contexts'; @@ -22,15 +23,17 @@ import { export const SyntheticsPolicyCreateExtensionWrapper = memo( ({ newPolicy, onChange }) => { return ( - - - + + + - + + + - - - + + + ); } ); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension.tsx b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension.tsx index e29a5c6a363ed5..8a3c42c10bc14a 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension.tsx @@ -5,17 +5,20 @@ * 2.0. */ -import React, { memo, useContext } from 'react'; +import React, { memo } from 'react'; import useDebounce from 'react-use/lib/useDebounce'; import { PackagePolicyEditExtensionComponentProps } from '../../../../fleet/public'; import { useTrackPageview } from '../../../../observability/public'; import { - SimpleFieldsContext, - HTTPAdvancedFieldsContext, - TCPAdvancedFieldsContext, - TLSFieldsContext, + useMonitorTypeContext, + useTCPSimpleFieldsContext, + useTCPAdvancedFieldsContext, + useICMPSimpleFieldsContext, + useHTTPSimpleFieldsContext, + useHTTPAdvancedFieldsContext, + useTLSFieldsContext, } from './contexts'; -import { Config, ConfigKeys, DataStream } from './types'; +import { PolicyConfig, DataStream } from './types'; import { CustomFields } from './custom_fields'; import { useUpdatePolicy } from './use_update_policy'; import { validate } from './validation'; @@ -23,7 +26,7 @@ import { validate } from './validation'; interface SyntheticsPolicyEditExtensionProps { newPolicy: PackagePolicyEditExtensionComponentProps['newPolicy']; onChange: PackagePolicyEditExtensionComponentProps['onChange']; - defaultConfig: Config; + defaultConfig: PolicyConfig; isTLSEnabled: boolean; } /** @@ -34,37 +37,57 @@ export const SyntheticsPolicyEditExtension = memo { useTrackPageview({ app: 'fleet', path: 'syntheticsEdit' }); useTrackPageview({ app: 'fleet', path: 'syntheticsEdit', delay: 15000 }); - const { fields: simpleFields } = useContext(SimpleFieldsContext); - const { fields: httpAdvancedFields } = useContext(HTTPAdvancedFieldsContext); - const { fields: tcpAdvancedFields } = useContext(TCPAdvancedFieldsContext); - const { fields: tlsFields } = useContext(TLSFieldsContext); - const { config, setConfig } = useUpdatePolicy({ defaultConfig, newPolicy, onChange, validate }); + const { monitorType } = useMonitorTypeContext(); + const { fields: httpSimpleFields } = useHTTPSimpleFieldsContext(); + const { fields: tcpSimpleFields } = useTCPSimpleFieldsContext(); + const { fields: icmpSimpleFields } = useICMPSimpleFieldsContext(); + const { fields: httpAdvancedFields } = useHTTPAdvancedFieldsContext(); + const { fields: tcpAdvancedFields } = useTCPAdvancedFieldsContext(); + const { fields: tlsFields } = useTLSFieldsContext(); + const { setConfig } = useUpdatePolicy({ + defaultConfig, + newPolicy, + onChange, + validate, + monitorType, + }); useDebounce( () => { - setConfig((prevConfig) => ({ - ...prevConfig, - ...simpleFields, - ...httpAdvancedFields, - ...tcpAdvancedFields, - ...tlsFields, - // ensure proxyUrl is not overwritten - [ConfigKeys.PROXY_URL]: - simpleFields[ConfigKeys.MONITOR_TYPE] === DataStream.HTTP - ? httpAdvancedFields[ConfigKeys.PROXY_URL] - : tcpAdvancedFields[ConfigKeys.PROXY_URL], - })); + setConfig(() => { + switch (monitorType) { + case DataStream.HTTP: + return { + ...httpSimpleFields, + ...httpAdvancedFields, + ...tlsFields, + }; + case DataStream.TCP: + return { + ...tcpSimpleFields, + ...tcpAdvancedFields, + ...tlsFields, + }; + case DataStream.ICMP: + return { + ...icmpSimpleFields, + }; + } + }); }, 250, - [setConfig, simpleFields, httpAdvancedFields, tcpAdvancedFields, tlsFields] + [ + setConfig, + httpSimpleFields, + httpAdvancedFields, + tcpSimpleFields, + tcpAdvancedFields, + icmpSimpleFields, + tlsFields, + ] ); - return ( - - ); + return ; } ); SyntheticsPolicyEditExtension.displayName = 'SyntheticsPolicyEditExtension'; diff --git a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension_wrapper.test.tsx b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension_wrapper.test.tsx index e6981b9a850e1f..fec6c504a445f0 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension_wrapper.test.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension_wrapper.test.tsx @@ -11,25 +11,13 @@ import { render } from '../../lib/helper/rtl_helpers'; import { NewPackagePolicy } from '../../../../fleet/public'; import { SyntheticsPolicyEditExtensionWrapper } from './synthetics_policy_edit_extension_wrapper'; import { ConfigKeys, DataStream, ScheduleUnit } from './types'; -import { - defaultSimpleFields, - defaultTLSFields, - defaultHTTPAdvancedFields, - defaultTCPAdvancedFields, -} from './contexts'; +import { defaultConfig } from './synthetics_policy_create_extension'; // ensures that fields appropriately match to their label jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ htmlIdGenerator: () => () => `id-${Math.random()}`, })); -const defaultConfig = { - ...defaultSimpleFields, - ...defaultTLSFields, - ...defaultHTTPAdvancedFields, - ...defaultTCPAdvancedFields, -}; - const defaultNewPolicy: NewPackagePolicy = { name: 'samplePolicyName', description: '', @@ -277,6 +265,10 @@ const defaultCurrentPolicy: any = { created_by: '', }; +const defaultHTTPConfig = defaultConfig[DataStream.HTTP]; +const defaultICMPConfig = defaultConfig[DataStream.ICMP]; +const defaultTCPConfig = defaultConfig[DataStream.TCP]; + describe('', () => { const onChange = jest.fn(); const WrappedComponent = ({ policy = defaultCurrentPolicy, newPolicy = defaultNewPolicy }) => { @@ -301,24 +293,24 @@ describe('', () => { const verificationMode = getByLabelText('Verification mode') as HTMLInputElement; const enableTLSConfig = getByLabelText('Enable TLS configuration') as HTMLInputElement; expect(url).toBeInTheDocument(); - expect(url.value).toEqual(defaultConfig[ConfigKeys.URLS]); + expect(url.value).toEqual(defaultHTTPConfig[ConfigKeys.URLS]); expect(proxyUrl).toBeInTheDocument(); - expect(proxyUrl.value).toEqual(defaultConfig[ConfigKeys.PROXY_URL]); + expect(proxyUrl.value).toEqual(defaultHTTPConfig[ConfigKeys.PROXY_URL]); expect(monitorIntervalNumber).toBeInTheDocument(); - expect(monitorIntervalNumber.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].number); + expect(monitorIntervalNumber.value).toEqual(defaultHTTPConfig[ConfigKeys.SCHEDULE].number); expect(monitorIntervalUnit).toBeInTheDocument(); - expect(monitorIntervalUnit.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].unit); + expect(monitorIntervalUnit.value).toEqual(defaultHTTPConfig[ConfigKeys.SCHEDULE].unit); expect(apmServiceName).toBeInTheDocument(); - expect(apmServiceName.value).toEqual(defaultConfig[ConfigKeys.APM_SERVICE_NAME]); + expect(apmServiceName.value).toEqual(defaultHTTPConfig[ConfigKeys.APM_SERVICE_NAME]); expect(maxRedirects).toBeInTheDocument(); - expect(maxRedirects.value).toEqual(`${defaultConfig[ConfigKeys.MAX_REDIRECTS]}`); + expect(maxRedirects.value).toEqual(`${defaultHTTPConfig[ConfigKeys.MAX_REDIRECTS]}`); expect(timeout).toBeInTheDocument(); - expect(timeout.value).toEqual(`${defaultConfig[ConfigKeys.TIMEOUT]}`); + expect(timeout.value).toEqual(`${defaultHTTPConfig[ConfigKeys.TIMEOUT]}`); // expect TLS settings to be in the document when at least one tls key is populated expect(enableTLSConfig.checked).toBe(true); expect(verificationMode).toBeInTheDocument(); expect(verificationMode.value).toEqual( - `${defaultConfig[ConfigKeys.TLS_VERIFICATION_MODE].value}` + `${defaultHTTPConfig[ConfigKeys.TLS_VERIFICATION_MODE].value}` ); // ensure other monitor type options are not in the DOM @@ -651,15 +643,21 @@ describe('', () => { streams: [ { ...defaultNewPolicy.inputs[0].streams[0], - vars: Object.keys(httpVars || []).reduce< - Record - >((acc, key) => { - acc[key] = { - value: undefined, - type: `${httpVars?.[key].type}`, - }; - return acc; - }, {}), + vars: { + ...Object.keys(httpVars || []).reduce< + Record + >((acc, key) => { + acc[key] = { + value: undefined, + type: `${httpVars?.[key].type}`, + }; + return acc; + }, {}), + [ConfigKeys.MONITOR_TYPE]: { + value: 'http', + type: 'text', + }, + }, }, ], }, @@ -680,19 +678,19 @@ describe('', () => { const enableTLSConfig = getByLabelText('Enable TLS configuration') as HTMLInputElement; expect(url).toBeInTheDocument(); - expect(url.value).toEqual(defaultConfig[ConfigKeys.URLS]); + expect(url.value).toEqual(defaultHTTPConfig[ConfigKeys.URLS]); expect(proxyUrl).toBeInTheDocument(); - expect(proxyUrl.value).toEqual(defaultConfig[ConfigKeys.PROXY_URL]); + expect(proxyUrl.value).toEqual(defaultHTTPConfig[ConfigKeys.PROXY_URL]); expect(monitorIntervalNumber).toBeInTheDocument(); - expect(monitorIntervalNumber.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].number); + expect(monitorIntervalNumber.value).toEqual(defaultHTTPConfig[ConfigKeys.SCHEDULE].number); expect(monitorIntervalUnit).toBeInTheDocument(); - expect(monitorIntervalUnit.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].unit); + expect(monitorIntervalUnit.value).toEqual(defaultHTTPConfig[ConfigKeys.SCHEDULE].unit); expect(apmServiceName).toBeInTheDocument(); - expect(apmServiceName.value).toEqual(defaultConfig[ConfigKeys.APM_SERVICE_NAME]); + expect(apmServiceName.value).toEqual(defaultHTTPConfig[ConfigKeys.APM_SERVICE_NAME]); expect(maxRedirects).toBeInTheDocument(); - expect(maxRedirects.value).toEqual(`${defaultConfig[ConfigKeys.MAX_REDIRECTS]}`); + expect(maxRedirects.value).toEqual(`${defaultHTTPConfig[ConfigKeys.MAX_REDIRECTS]}`); expect(timeout).toBeInTheDocument(); - expect(timeout.value).toEqual(`${defaultConfig[ConfigKeys.TIMEOUT]}`); + expect(timeout.value).toEqual(`${defaultHTTPConfig[ConfigKeys.TIMEOUT]}`); /* expect TLS settings not to be in the document when and Enable TLS settings not to be checked * when all TLS values are falsey */ @@ -709,7 +707,7 @@ describe('', () => { await waitFor(() => { const requestMethod = getByLabelText('Request method') as HTMLInputElement; expect(requestMethod).toBeInTheDocument(); - expect(requestMethod.value).toEqual(`${defaultConfig[ConfigKeys.REQUEST_METHOD_CHECK]}`); + expect(requestMethod.value).toEqual(`${defaultHTTPConfig[ConfigKeys.REQUEST_METHOD_CHECK]}`); }); }); @@ -752,24 +750,24 @@ describe('', () => { const { getByText, getByLabelText, queryByLabelText } = render( ); - const url = getByLabelText('Host:Port') as HTMLInputElement; + const host = getByLabelText('Host:Port') as HTMLInputElement; const proxyUrl = getByLabelText('Proxy URL') as HTMLInputElement; const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement; const monitorIntervalUnit = getByLabelText('Unit') as HTMLInputElement; const apmServiceName = getByLabelText('APM service name') as HTMLInputElement; const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement; - expect(url).toBeInTheDocument(); - expect(url.value).toEqual(defaultConfig[ConfigKeys.URLS]); + expect(host).toBeInTheDocument(); + expect(host.value).toEqual(defaultTCPConfig[ConfigKeys.HOSTS]); expect(proxyUrl).toBeInTheDocument(); - expect(proxyUrl.value).toEqual(defaultConfig[ConfigKeys.PROXY_URL]); + expect(proxyUrl.value).toEqual(defaultTCPConfig[ConfigKeys.PROXY_URL]); expect(monitorIntervalNumber).toBeInTheDocument(); - expect(monitorIntervalNumber.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].number); + expect(monitorIntervalNumber.value).toEqual(defaultTCPConfig[ConfigKeys.SCHEDULE].number); expect(monitorIntervalUnit).toBeInTheDocument(); - expect(monitorIntervalUnit.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].unit); + expect(monitorIntervalUnit.value).toEqual(defaultTCPConfig[ConfigKeys.SCHEDULE].unit); expect(apmServiceName).toBeInTheDocument(); - expect(apmServiceName.value).toEqual(defaultConfig[ConfigKeys.APM_SERVICE_NAME]); + expect(apmServiceName.value).toEqual(defaultTCPConfig[ConfigKeys.APM_SERVICE_NAME]); expect(timeout).toBeInTheDocument(); - expect(timeout.value).toEqual(`${defaultConfig[ConfigKeys.TIMEOUT]}`); + expect(timeout.value).toEqual(`${defaultTCPConfig[ConfigKeys.TIMEOUT]}`); // ensure other monitor type options are not in the DOM expect(queryByLabelText('Url')).not.toBeInTheDocument(); @@ -825,24 +823,24 @@ describe('', () => { const { getByLabelText, queryByLabelText } = render( ); - const url = getByLabelText('Host') as HTMLInputElement; + const host = getByLabelText('Host') as HTMLInputElement; const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement; const monitorIntervalUnit = getByLabelText('Unit') as HTMLInputElement; const apmServiceName = getByLabelText('APM service name') as HTMLInputElement; const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement; const wait = getByLabelText('Wait in seconds') as HTMLInputElement; - expect(url).toBeInTheDocument(); - expect(url.value).toEqual(defaultConfig[ConfigKeys.URLS]); + expect(host).toBeInTheDocument(); + expect(host.value).toEqual(defaultICMPConfig[ConfigKeys.HOSTS]); expect(monitorIntervalNumber).toBeInTheDocument(); - expect(monitorIntervalNumber.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].number); + expect(monitorIntervalNumber.value).toEqual(defaultICMPConfig[ConfigKeys.SCHEDULE].number); expect(monitorIntervalUnit).toBeInTheDocument(); - expect(monitorIntervalUnit.value).toEqual(defaultConfig[ConfigKeys.SCHEDULE].unit); + expect(monitorIntervalUnit.value).toEqual(defaultICMPConfig[ConfigKeys.SCHEDULE].unit); expect(apmServiceName).toBeInTheDocument(); - expect(apmServiceName.value).toEqual(defaultConfig[ConfigKeys.APM_SERVICE_NAME]); + expect(apmServiceName.value).toEqual(defaultICMPConfig[ConfigKeys.APM_SERVICE_NAME]); expect(timeout).toBeInTheDocument(); - expect(timeout.value).toEqual(`${defaultConfig[ConfigKeys.TIMEOUT]}`); + expect(timeout.value).toEqual(`${defaultICMPConfig[ConfigKeys.TIMEOUT]}`); expect(wait).toBeInTheDocument(); - expect(wait.value).toEqual(`${defaultConfig[ConfigKeys.WAIT]}`); + expect(wait.value).toEqual(`${defaultICMPConfig[ConfigKeys.WAIT]}`); // ensure other monitor type options are not in the DOM expect(queryByLabelText('Url')).not.toBeInTheDocument(); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension_wrapper.tsx b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension_wrapper.tsx index 85b38e05fdbc89..0bafef61166d26 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension_wrapper.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/synthetics_policy_edit_extension_wrapper.tsx @@ -7,17 +7,26 @@ import React, { memo, useMemo } from 'react'; import { PackagePolicyEditExtensionComponentProps } from '../../../../fleet/public'; -import { Config, ConfigKeys, ContentType, contentTypesToMode } from './types'; +import { + PolicyConfig, + ConfigKeys, + ContentType, + DataStream, + ICustomFields, + contentTypesToMode, +} from './types'; import { SyntheticsPolicyEditExtension } from './synthetics_policy_edit_extension'; import { - SimpleFieldsContextProvider, - HTTPAdvancedFieldsContextProvider, - TCPAdvancedFieldsContextProvider, - TLSFieldsContextProvider, - defaultSimpleFields, + MonitorTypeContextProvider, + HTTPContextProvider, + TCPContextProvider, + defaultTCPSimpleFields, + defaultHTTPSimpleFields, + defaultICMPSimpleFields, defaultHTTPAdvancedFields, defaultTCPAdvancedFields, defaultTLSFields, + ICMPSimpleFieldsContextProvider, } from './contexts'; /** @@ -26,21 +35,29 @@ import { */ export const SyntheticsPolicyEditExtensionWrapper = memo( ({ policy: currentPolicy, newPolicy, onChange }) => { - const { enableTLS: isTLSEnabled, config: defaultConfig } = useMemo(() => { - const fallbackConfig: Config = { - name: '', - ...defaultSimpleFields, - ...defaultHTTPAdvancedFields, - ...defaultTCPAdvancedFields, - ...defaultTLSFields, + const { enableTLS: isTLSEnabled, config: defaultConfig, monitorType } = useMemo(() => { + const fallbackConfig: PolicyConfig = { + [DataStream.HTTP]: { + ...defaultHTTPSimpleFields, + ...defaultHTTPAdvancedFields, + ...defaultTLSFields, + }, + [DataStream.TCP]: { + ...defaultTCPSimpleFields, + ...defaultTCPAdvancedFields, + ...defaultTLSFields, + }, + [DataStream.ICMP]: defaultICMPSimpleFields, }; let enableTLS = false; const getDefaultConfig = () => { const currentInput = currentPolicy.inputs.find((input) => input.enabled === true); const vars = currentInput?.streams[0]?.vars; + const type: DataStream = vars?.[ConfigKeys.MONITOR_TYPE].value as DataStream; + const fallbackConfigForMonitorType = fallbackConfig[type] as Partial; const configKeys: ConfigKeys[] = Object.values(ConfigKeys); - const formattedDefaultConfig = configKeys.reduce( + const formatttedDefaultConfigForMonitorType = configKeys.reduce( (acc: Record, key: ConfigKeys) => { const value = vars?.[key]?.value; switch (key) { @@ -59,12 +76,14 @@ export const SyntheticsPolicyEditExtensionWrapper = memo { if ( headerKey === 'Content-Type' && contentTypesToMode[headers[headerKey] as ContentType] ) { - type = contentTypesToMode[headers[headerKey] as ContentType]; + requestBodyType = contentTypesToMode[headers[headerKey] as ContentType]; return true; } }); acc[key] = { value: requestBodyValue, - type, + type: requestBodyType, }; break; case ConfigKeys.TLS_KEY_PASSPHRASE: case ConfigKeys.TLS_VERIFICATION_MODE: acc[key] = { - value: value ?? fallbackConfig[key].value, + value: value ?? fallbackConfigForMonitorType[key]?.value, isEnabled: !!value, }; if (!!value) { @@ -112,7 +131,7 @@ export const SyntheticsPolicyEditExtensionWrapper = memo - - - + + + + - - - - + + + + ); } ); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/tcp_advanced_fields.test.tsx b/x-pack/plugins/uptime/public/components/fleet_package/tcp/advanced_fields.test.tsx similarity index 92% rename from x-pack/plugins/uptime/public/components/fleet_package/tcp_advanced_fields.test.tsx rename to x-pack/plugins/uptime/public/components/fleet_package/tcp/advanced_fields.test.tsx index 77551f9aa80114..78a6724fc8cfbf 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/tcp_advanced_fields.test.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/tcp/advanced_fields.test.tsx @@ -7,13 +7,13 @@ import React from 'react'; import { fireEvent } from '@testing-library/react'; -import { render } from '../../lib/helper/rtl_helpers'; -import { TCPAdvancedFields } from './tcp_advanced_fields'; +import { render } from '../../../lib/helper/rtl_helpers'; +import { TCPAdvancedFields } from './advanced_fields'; import { TCPAdvancedFieldsContextProvider, defaultTCPAdvancedFields as defaultConfig, -} from './contexts'; -import { ConfigKeys, ITCPAdvancedFields } from './types'; +} from '../contexts'; +import { ConfigKeys, ITCPAdvancedFields } from '../types'; // ensures fields and labels map appropriately jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ diff --git a/x-pack/plugins/uptime/public/components/fleet_package/tcp_advanced_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/tcp/advanced_fields.tsx similarity index 97% rename from x-pack/plugins/uptime/public/components/fleet_package/tcp_advanced_fields.tsx rename to x-pack/plugins/uptime/public/components/fleet_package/tcp/advanced_fields.tsx index 161de0f0af8d0f..9db07afa559b9d 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/tcp_advanced_fields.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/tcp/advanced_fields.tsx @@ -16,11 +16,11 @@ import { EuiSpacer, } from '@elastic/eui'; -import { useTCPAdvancedFieldsContext } from './contexts'; +import { useTCPAdvancedFieldsContext } from '../contexts'; -import { ConfigKeys } from './types'; +import { ConfigKeys } from '../types'; -import { OptionalLabel } from './optional_label'; +import { OptionalLabel } from '../optional_label'; export const TCPAdvancedFields = () => { const { fields, setFields } = useTCPAdvancedFieldsContext(); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/tcp/simple_fields.tsx b/x-pack/plugins/uptime/public/components/fleet_package/tcp/simple_fields.tsx new file mode 100644 index 00000000000000..82c77a63611f2d --- /dev/null +++ b/x-pack/plugins/uptime/public/components/fleet_package/tcp/simple_fields.tsx @@ -0,0 +1,171 @@ +/* + * 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, { memo } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiFormRow, EuiFieldText, EuiFieldNumber } from '@elastic/eui'; +import { ConfigKeys, Validation } from '../types'; +import { useTCPSimpleFieldsContext } from '../contexts'; +import { ComboBox } from '../combo_box'; +import { OptionalLabel } from '../optional_label'; +import { ScheduleField } from '../schedule_field'; + +interface Props { + validate: Validation; +} + +export const TCPSimpleFields = memo(({ validate }) => { + const { fields, setFields } = useTCPSimpleFieldsContext(); + const handleInputChange = ({ value, configKey }: { value: unknown; configKey: ConfigKeys }) => { + setFields((prevFields) => ({ ...prevFields, [configKey]: value })); + }; + + return ( + <> + + } + isInvalid={!!validate[ConfigKeys.HOSTS]?.(fields[ConfigKeys.HOSTS])} + error={ + + } + > + + handleInputChange({ + value: event.target.value, + configKey: ConfigKeys.HOSTS, + }) + } + data-test-subj="syntheticsTCPHostField" + /> + + + + } + isInvalid={!!validate[ConfigKeys.SCHEDULE]?.(fields[ConfigKeys.SCHEDULE])} + error={ + + } + > + + handleInputChange({ + value: schedule, + configKey: ConfigKeys.SCHEDULE, + }) + } + number={fields[ConfigKeys.SCHEDULE].number} + unit={fields[ConfigKeys.SCHEDULE].unit} + /> + + + } + labelAppend={} + helpText={ + + } + > + + handleInputChange({ + value: event.target.value, + configKey: ConfigKeys.APM_SERVICE_NAME, + }) + } + data-test-subj="syntheticsAPMServiceName" + /> + + + } + isInvalid={ + !!validate[ConfigKeys.TIMEOUT]?.( + fields[ConfigKeys.TIMEOUT], + fields[ConfigKeys.SCHEDULE].number, + fields[ConfigKeys.SCHEDULE].unit + ) + } + error={ + + } + helpText={ + + } + > + + handleInputChange({ + value: event.target.value, + configKey: ConfigKeys.TIMEOUT, + }) + } + step={'any'} + /> + + + } + labelAppend={} + helpText={ + + } + > + handleInputChange({ value, configKey: ConfigKeys.TAGS })} + data-test-subj="syntheticsTags" + /> + + + ); +}); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/types.tsx b/x-pack/plugins/uptime/public/components/fleet_package/types.tsx index 802d5f08fd6468..4d44b4f074e829 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/types.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/types.tsx @@ -105,6 +105,28 @@ export interface ISimpleFields { [ConfigKeys.WAIT]: string; } +export interface ICommonFields { + [ConfigKeys.MONITOR_TYPE]: DataStream; + [ConfigKeys.SCHEDULE]: { number: string; unit: ScheduleUnit }; + [ConfigKeys.APM_SERVICE_NAME]: string; + [ConfigKeys.TIMEOUT]: string; + [ConfigKeys.TAGS]: string[]; +} + +export type IHTTPSimpleFields = { + [ConfigKeys.MAX_REDIRECTS]: string; + [ConfigKeys.URLS]: string; +} & ICommonFields; + +export type ITCPSimpleFields = { + [ConfigKeys.HOSTS]: string; +} & ICommonFields; + +export type IICMPSimpleFields = { + [ConfigKeys.HOSTS]: string; + [ConfigKeys.WAIT]: string; +} & ICommonFields; + export interface ITLSFields { [ConfigKeys.TLS_CERTIFICATE_AUTHORITIES]: { value: string; @@ -154,11 +176,21 @@ export interface ITCPAdvancedFields { [ConfigKeys.REQUEST_SEND_CHECK]: string; } -export type ICustomFields = ISimpleFields & ITLSFields & IHTTPAdvancedFields & ITCPAdvancedFields; +export type HTTPFields = IHTTPSimpleFields & IHTTPAdvancedFields & ITLSFields; +export type TCPFields = ITCPSimpleFields & ITCPAdvancedFields & ITLSFields; +export type ICMPFields = IICMPSimpleFields; + +export type ICustomFields = HTTPFields & + TCPFields & + ICMPFields & { + [ConfigKeys.NAME]: string; + }; -export type Config = { - [ConfigKeys.NAME]: string; -} & ICustomFields; +export interface PolicyConfig { + [DataStream.HTTP]: HTTPFields; + [DataStream.TCP]: TCPFields; + [DataStream.ICMP]: ICMPFields; +} export type Validation = Partial void>>; diff --git a/x-pack/plugins/uptime/public/components/fleet_package/use_update_policy.test.tsx b/x-pack/plugins/uptime/public/components/fleet_package/use_update_policy.test.tsx index 3732791f895dcb..5a62aec90032d9 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/use_update_policy.test.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/use_update_policy.test.tsx @@ -10,20 +10,7 @@ import { act, renderHook } from '@testing-library/react-hooks'; import { NewPackagePolicy } from '../../../../fleet/public'; import { validate } from './validation'; import { ConfigKeys, DataStream, TLSVersion } from './types'; -import { - defaultSimpleFields, - defaultTLSFields, - defaultHTTPAdvancedFields, - defaultTCPAdvancedFields, -} from './contexts'; - -const defaultConfig = { - name: '', - ...defaultSimpleFields, - ...defaultTLSFields, - ...defaultHTTPAdvancedFields, - ...defaultTCPAdvancedFields, -}; +import { defaultConfig } from './synthetics_policy_create_extension'; describe('useBarChartsHooks', () => { const newPolicy: NewPackagePolicy = { @@ -269,10 +256,10 @@ describe('useBarChartsHooks', () => { it('handles http data stream', () => { const onChange = jest.fn(); const { result } = renderHook((props) => useUpdatePolicy(props), { - initialProps: { defaultConfig, newPolicy, onChange, validate }, + initialProps: { defaultConfig, newPolicy, onChange, validate, monitorType: DataStream.HTTP }, }); - expect(result.current.config).toMatchObject({ ...defaultConfig }); + expect(result.current.config).toMatchObject({ ...defaultConfig[DataStream.HTTP] }); // expect only http to be enabled expect(result.current.updatedPolicy.inputs[0].enabled).toBe(true); @@ -281,28 +268,28 @@ describe('useBarChartsHooks', () => { expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.MONITOR_TYPE].value - ).toEqual(defaultConfig[ConfigKeys.MONITOR_TYPE]); + ).toEqual(defaultConfig[DataStream.HTTP][ConfigKeys.MONITOR_TYPE]); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.URLS].value - ).toEqual(defaultConfig[ConfigKeys.URLS]); + ).toEqual(defaultConfig[DataStream.HTTP][ConfigKeys.URLS]); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.SCHEDULE].value ).toEqual( JSON.stringify( - `@every ${defaultConfig[ConfigKeys.SCHEDULE].number}${ - defaultConfig[ConfigKeys.SCHEDULE].unit + `@every ${defaultConfig[DataStream.HTTP][ConfigKeys.SCHEDULE].number}${ + defaultConfig[DataStream.HTTP][ConfigKeys.SCHEDULE].unit }` ) ); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.PROXY_URL].value - ).toEqual(defaultConfig[ConfigKeys.PROXY_URL]); + ).toEqual(defaultConfig[DataStream.HTTP][ConfigKeys.PROXY_URL]); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.APM_SERVICE_NAME].value - ).toEqual(defaultConfig[ConfigKeys.APM_SERVICE_NAME]); + ).toEqual(defaultConfig[DataStream.HTTP][ConfigKeys.APM_SERVICE_NAME]); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.TIMEOUT].value - ).toEqual(`${defaultConfig[ConfigKeys.TIMEOUT]}s`); + ).toEqual(`${defaultConfig[DataStream.HTTP][ConfigKeys.TIMEOUT]}s`); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ ConfigKeys.RESPONSE_BODY_CHECK_POSITIVE @@ -316,29 +303,29 @@ describe('useBarChartsHooks', () => { expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.RESPONSE_STATUS_CHECK] .value - ).toEqual(JSON.stringify(defaultConfig[ConfigKeys.RESPONSE_STATUS_CHECK])); + ).toEqual(null); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.REQUEST_HEADERS_CHECK] .value - ).toEqual(JSON.stringify(defaultConfig[ConfigKeys.REQUEST_HEADERS_CHECK])); + ).toEqual(null); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.RESPONSE_HEADERS_CHECK] .value - ).toEqual(JSON.stringify(defaultConfig[ConfigKeys.RESPONSE_HEADERS_CHECK])); + ).toEqual(null); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.RESPONSE_BODY_INDEX] .value - ).toEqual(defaultConfig[ConfigKeys.RESPONSE_BODY_INDEX]); + ).toEqual(defaultConfig[DataStream.HTTP][ConfigKeys.RESPONSE_BODY_INDEX]); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.RESPONSE_HEADERS_INDEX] .value - ).toEqual(defaultConfig[ConfigKeys.RESPONSE_HEADERS_INDEX]); + ).toEqual(defaultConfig[DataStream.HTTP][ConfigKeys.RESPONSE_HEADERS_INDEX]); }); it('stringifies array values and returns null for empty array values', () => { const onChange = jest.fn(); const { result } = renderHook((props) => useUpdatePolicy(props), { - initialProps: { defaultConfig, newPolicy, onChange, validate }, + initialProps: { defaultConfig, newPolicy, onChange, validate, monitorType: DataStream.HTTP }, }); act(() => { @@ -419,16 +406,8 @@ describe('useBarChartsHooks', () => { it('handles tcp data stream', () => { const onChange = jest.fn(); - const tcpConfig = { - ...defaultConfig, - [ConfigKeys.MONITOR_TYPE]: DataStream.TCP, - }; const { result } = renderHook((props) => useUpdatePolicy(props), { - initialProps: { defaultConfig, newPolicy, onChange, validate }, - }); - - act(() => { - result.current.setConfig(tcpConfig); + initialProps: { defaultConfig, newPolicy, onChange, validate, monitorType: DataStream.TCP }, }); // expect only tcp to be enabled @@ -443,55 +422,47 @@ describe('useBarChartsHooks', () => { expect( result.current.updatedPolicy.inputs[1]?.streams[0]?.vars?.[ConfigKeys.MONITOR_TYPE].value - ).toEqual(tcpConfig[ConfigKeys.MONITOR_TYPE]); + ).toEqual(defaultConfig[DataStream.TCP][ConfigKeys.MONITOR_TYPE]); expect( result.current.updatedPolicy.inputs[1]?.streams[0]?.vars?.[ConfigKeys.HOSTS].value - ).toEqual(defaultConfig[ConfigKeys.HOSTS]); + ).toEqual(defaultConfig[DataStream.TCP][ConfigKeys.HOSTS]); expect( result.current.updatedPolicy.inputs[1]?.streams[0]?.vars?.[ConfigKeys.SCHEDULE].value ).toEqual( JSON.stringify( - `@every ${defaultConfig[ConfigKeys.SCHEDULE].number}${ - defaultConfig[ConfigKeys.SCHEDULE].unit + `@every ${defaultConfig[DataStream.TCP][ConfigKeys.SCHEDULE].number}${ + defaultConfig[DataStream.TCP][ConfigKeys.SCHEDULE].unit }` ) ); expect( result.current.updatedPolicy.inputs[1]?.streams[0]?.vars?.[ConfigKeys.PROXY_URL].value - ).toEqual(tcpConfig[ConfigKeys.PROXY_URL]); + ).toEqual(defaultConfig[DataStream.TCP][ConfigKeys.PROXY_URL]); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.APM_SERVICE_NAME].value - ).toEqual(tcpConfig[ConfigKeys.APM_SERVICE_NAME]); + ).toEqual(defaultConfig[DataStream.TCP][ConfigKeys.APM_SERVICE_NAME]); expect( result.current.updatedPolicy.inputs[1]?.streams[0]?.vars?.[ConfigKeys.TIMEOUT].value - ).toEqual(`${tcpConfig[ConfigKeys.TIMEOUT]}s`); + ).toEqual(`${defaultConfig[DataStream.TCP][ConfigKeys.TIMEOUT]}s`); expect( result.current.updatedPolicy.inputs[1]?.streams[0]?.vars?.[ ConfigKeys.PROXY_USE_LOCAL_RESOLVER ].value - ).toEqual(tcpConfig[ConfigKeys.PROXY_USE_LOCAL_RESOLVER]); + ).toEqual(defaultConfig[DataStream.TCP][ConfigKeys.PROXY_USE_LOCAL_RESOLVER]); expect( result.current.updatedPolicy.inputs[1]?.streams[0]?.vars?.[ConfigKeys.RESPONSE_RECEIVE_CHECK] .value - ).toEqual(tcpConfig[ConfigKeys.RESPONSE_RECEIVE_CHECK]); + ).toEqual(defaultConfig[DataStream.TCP][ConfigKeys.RESPONSE_RECEIVE_CHECK]); expect( result.current.updatedPolicy.inputs[1]?.streams[0]?.vars?.[ConfigKeys.REQUEST_SEND_CHECK] .value - ).toEqual(tcpConfig[ConfigKeys.REQUEST_SEND_CHECK]); + ).toEqual(defaultConfig[DataStream.TCP][ConfigKeys.REQUEST_SEND_CHECK]); }); it('handles icmp data stream', () => { const onChange = jest.fn(); - const icmpConfig = { - ...defaultConfig, - [ConfigKeys.MONITOR_TYPE]: DataStream.ICMP, - }; const { result } = renderHook((props) => useUpdatePolicy(props), { - initialProps: { defaultConfig, newPolicy, onChange, validate }, - }); - - act(() => { - result.current.setConfig(icmpConfig); + initialProps: { defaultConfig, newPolicy, onChange, validate, monitorType: DataStream.ICMP }, }); // expect only icmp to be enabled @@ -506,25 +477,27 @@ describe('useBarChartsHooks', () => { expect( result.current.updatedPolicy.inputs[2]?.streams[0]?.vars?.[ConfigKeys.MONITOR_TYPE].value - ).toEqual(icmpConfig[ConfigKeys.MONITOR_TYPE]); + ).toEqual(defaultConfig[DataStream.ICMP][ConfigKeys.MONITOR_TYPE]); expect( result.current.updatedPolicy.inputs[2]?.streams[0]?.vars?.[ConfigKeys.HOSTS].value - ).toEqual(icmpConfig[ConfigKeys.HOSTS]); + ).toEqual(defaultConfig[DataStream.ICMP][ConfigKeys.HOSTS]); expect( result.current.updatedPolicy.inputs[2]?.streams[0]?.vars?.[ConfigKeys.SCHEDULE].value ).toEqual( JSON.stringify( - `@every ${icmpConfig[ConfigKeys.SCHEDULE].number}${icmpConfig[ConfigKeys.SCHEDULE].unit}` + `@every ${defaultConfig[DataStream.ICMP][ConfigKeys.SCHEDULE].number}${ + defaultConfig[DataStream.ICMP][ConfigKeys.SCHEDULE].unit + }` ) ); expect( result.current.updatedPolicy.inputs[0]?.streams[0]?.vars?.[ConfigKeys.APM_SERVICE_NAME].value - ).toEqual(defaultConfig[ConfigKeys.APM_SERVICE_NAME]); + ).toEqual(defaultConfig[DataStream.ICMP][ConfigKeys.APM_SERVICE_NAME]); expect( result.current.updatedPolicy.inputs[2]?.streams[0]?.vars?.[ConfigKeys.TIMEOUT].value - ).toEqual(`${icmpConfig[ConfigKeys.TIMEOUT]}s`); + ).toEqual(`${defaultConfig[DataStream.ICMP][ConfigKeys.TIMEOUT]}s`); expect( result.current.updatedPolicy.inputs[2]?.streams[0]?.vars?.[ConfigKeys.WAIT].value - ).toEqual(`${icmpConfig[ConfigKeys.WAIT]}s`); + ).toEqual(`${defaultConfig[DataStream.ICMP][ConfigKeys.WAIT]}s`); }); }); diff --git a/x-pack/plugins/uptime/public/components/fleet_package/use_update_policy.ts b/x-pack/plugins/uptime/public/components/fleet_package/use_update_policy.ts index cb11e9f9c4a9b1..2b2fb22866463f 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/use_update_policy.ts +++ b/x-pack/plugins/uptime/public/components/fleet_package/use_update_policy.ts @@ -6,10 +6,11 @@ */ import { useEffect, useRef, useState } from 'react'; import { NewPackagePolicy } from '../../../../fleet/public'; -import { ConfigKeys, Config, DataStream, Validation } from './types'; +import { ConfigKeys, PolicyConfig, DataStream, Validation, ICustomFields } from './types'; interface Props { - defaultConfig: Config; + monitorType: DataStream; + defaultConfig: PolicyConfig; newPolicy: NewPackagePolicy; onChange: (opts: { /** is current form state is valid */ @@ -20,22 +21,27 @@ interface Props { validate: Record; } -export const useUpdatePolicy = ({ defaultConfig, newPolicy, onChange, validate }: Props) => { +export const useUpdatePolicy = ({ + monitorType, + defaultConfig, + newPolicy, + onChange, + validate, +}: Props) => { const [updatedPolicy, setUpdatedPolicy] = useState(newPolicy); // Update the integration policy with our custom fields - const [config, setConfig] = useState(defaultConfig); - const currentConfig = useRef(defaultConfig); + const [config, setConfig] = useState>(defaultConfig[monitorType]); + const currentConfig = useRef>(defaultConfig[monitorType]); useEffect(() => { - const { type } = config; const configKeys = Object.keys(config) as ConfigKeys[]; - const validationKeys = Object.keys(validate[type]) as ConfigKeys[]; + const validationKeys = Object.keys(validate[monitorType]) as ConfigKeys[]; const configDidUpdate = configKeys.some((key) => config[key] !== currentConfig.current[key]); const isValid = - !!newPolicy.name && !validationKeys.find((key) => validate[type][key]?.(config[key])); + !!newPolicy.name && !validationKeys.find((key) => validate[monitorType][key]?.(config[key])); const formattedPolicy = { ...newPolicy }; const currentInput = formattedPolicy.inputs.find( - (input) => input.type === `synthetics/${type}` + (input) => input.type === `synthetics/${monitorType}` ); const dataStream = currentInput?.streams[0]; @@ -51,17 +57,19 @@ export const useUpdatePolicy = ({ defaultConfig, newPolicy, onChange, validate } if (configItem) { switch (key) { case ConfigKeys.SCHEDULE: - configItem.value = JSON.stringify(`@every ${config[key].number}${config[key].unit}`); // convert to cron + configItem.value = JSON.stringify( + `@every ${config[key]?.number}${config[key]?.unit}` + ); // convert to cron break; case ConfigKeys.RESPONSE_BODY_CHECK_NEGATIVE: case ConfigKeys.RESPONSE_BODY_CHECK_POSITIVE: case ConfigKeys.RESPONSE_STATUS_CHECK: case ConfigKeys.TAGS: - configItem.value = config[key].length ? JSON.stringify(config[key]) : null; + configItem.value = config[key]?.length ? JSON.stringify(config[key]) : null; break; case ConfigKeys.RESPONSE_HEADERS_CHECK: case ConfigKeys.REQUEST_HEADERS_CHECK: - configItem.value = Object.keys(config[key]).length + configItem.value = Object.keys(config?.[key] || []).length ? JSON.stringify(config[key]) : null; break; @@ -70,26 +78,26 @@ export const useUpdatePolicy = ({ defaultConfig, newPolicy, onChange, validate } configItem.value = config[key] ? `${config[key]}s` : null; // convert to cron break; case ConfigKeys.REQUEST_BODY_CHECK: - configItem.value = config[key].value ? JSON.stringify(config[key].value) : null; // only need value of REQUEST_BODY_CHECK for outputted policy + configItem.value = config[key]?.value ? JSON.stringify(config[key]?.value) : null; // only need value of REQUEST_BODY_CHECK for outputted policy break; case ConfigKeys.TLS_CERTIFICATE: case ConfigKeys.TLS_CERTIFICATE_AUTHORITIES: case ConfigKeys.TLS_KEY: configItem.value = - config[key].isEnabled && config[key].value - ? JSON.stringify(config[key].value) + config[key]?.isEnabled && config[key]?.value + ? JSON.stringify(config[key]?.value) : null; // only add tls settings if they are enabled by the user break; case ConfigKeys.TLS_VERSION: configItem.value = - config[key].isEnabled && config[key].value.length - ? JSON.stringify(config[key].value) + config[key]?.isEnabled && config[key]?.value.length + ? JSON.stringify(config[key]?.value) : null; // only add tls settings if they are enabled by the user break; case ConfigKeys.TLS_KEY_PASSPHRASE: case ConfigKeys.TLS_VERIFICATION_MODE: configItem.value = - config[key].isEnabled && config[key].value ? config[key].value : null; // only add tls settings if they are enabled by the user + config[key]?.isEnabled && config[key]?.value ? config[key]?.value : null; // only add tls settings if they are enabled by the user break; default: configItem.value = @@ -104,7 +112,7 @@ export const useUpdatePolicy = ({ defaultConfig, newPolicy, onChange, validate } updatedPolicy: formattedPolicy, }); } - }, [config, currentConfig, newPolicy, onChange, validate]); + }, [config, currentConfig, newPolicy, onChange, validate, monitorType]); // update our local config state ever time name, which is managed by fleet, changes useEffect(() => { diff --git a/x-pack/plugins/uptime/public/components/fleet_package/validation.tsx b/x-pack/plugins/uptime/public/components/fleet_package/validation.tsx index 5197cb9299e45e..f3057baf10381f 100644 --- a/x-pack/plugins/uptime/public/components/fleet_package/validation.tsx +++ b/x-pack/plugins/uptime/public/components/fleet_package/validation.tsx @@ -48,10 +48,6 @@ function validateTimeout({ // validation functions return true when invalid const validateCommon = { - [ConfigKeys.MAX_REDIRECTS]: (value: unknown) => - (!!value && !`${value}`.match(digitsOnly)) || - parseFloat(value as ICustomFields[ConfigKeys.MAX_REDIRECTS]) < 0, - [ConfigKeys.MONITOR_TYPE]: (value: unknown) => !value, [ConfigKeys.SCHEDULE]: (value: unknown) => { const { number, unit } = value as ICustomFields[ConfigKeys.SCHEDULE]; const parsedFloat = parseFloat(number); @@ -84,6 +80,9 @@ const validateHTTP = { const headers = value as ICustomFields[ConfigKeys.REQUEST_HEADERS_CHECK]; return validateHeaders(headers); }, + [ConfigKeys.MAX_REDIRECTS]: (value: unknown) => + (!!value && !`${value}`.match(digitsOnly)) || + parseFloat(value as ICustomFields[ConfigKeys.MAX_REDIRECTS]) < 0, [ConfigKeys.URLS]: (value: unknown) => !value, ...validateCommon, };