[Uptime] [Synthetics Integration] browser - add script recorder option (#115184)

* Add script recorder tab for browser based monitors

* implement policy edit flow for script recorder

* add tests and translations

* adjust types

* update metadata key and add test

* merge master

* adjust usePolicy and source_field

* revert merge master

* adjust types

* use reusable hook

* update zip url tls default fields

* rename content constant

* adjust error handling and remove ts-ignore

* adjust error default value

* remove unnecessary fragment

* adjust types

* update tech preview content

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Dominique Clarke 2021-10-20 00:13:02 -04:00 committed by GitHub
parent ba20ea1630
commit 78003671fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 735 additions and 212 deletions

View file

@ -9,9 +9,9 @@ import { BrowserFields, ConfigKeys } from '../types';
import {
Formatter,
commonFormatters,
objectToJsonFormatter,
arrayToJsonFormatter,
stringToJsonFormatter,
objectToJsonFormatter,
} from '../common/formatters';
import {
tlsValueToYamlFormatter,

View file

@ -14,7 +14,6 @@ import {
} from '../common/normalizers';
import { defaultBrowserSimpleFields, defaultBrowserAdvancedFields } from '../contexts';
import { tlsJsonToObjectNormalizer, tlsStringToObjectNormalizer } from '../tls/normalizers';
export type BrowserNormalizerMap = Record<keyof BrowserFields, Normalizer>;
@ -42,33 +41,22 @@ export const browserNormalizers: BrowserNormalizerMap = {
[ConfigKeys.PARAMS]: getBrowserNormalizer(ConfigKeys.PARAMS),
[ConfigKeys.SCREENSHOTS]: getBrowserNormalizer(ConfigKeys.SCREENSHOTS),
[ConfigKeys.SYNTHETICS_ARGS]: getBrowserJsonToJavascriptNormalizer(ConfigKeys.SYNTHETICS_ARGS),
[ConfigKeys.ZIP_URL_TLS_CERTIFICATE_AUTHORITIES]: (fields) =>
tlsJsonToObjectNormalizer(
fields?.[ConfigKeys.ZIP_URL_TLS_CERTIFICATE_AUTHORITIES]?.value,
ConfigKeys.TLS_CERTIFICATE_AUTHORITIES
),
[ConfigKeys.ZIP_URL_TLS_CERTIFICATE]: (fields) =>
tlsJsonToObjectNormalizer(
fields?.[ConfigKeys.ZIP_URL_TLS_CERTIFICATE]?.value,
ConfigKeys.TLS_CERTIFICATE
),
[ConfigKeys.ZIP_URL_TLS_KEY]: (fields) =>
tlsJsonToObjectNormalizer(fields?.[ConfigKeys.ZIP_URL_TLS_KEY]?.value, ConfigKeys.TLS_KEY),
[ConfigKeys.ZIP_URL_TLS_KEY_PASSPHRASE]: (fields) =>
tlsStringToObjectNormalizer(
fields?.[ConfigKeys.ZIP_URL_TLS_KEY_PASSPHRASE]?.value,
ConfigKeys.TLS_KEY_PASSPHRASE
),
[ConfigKeys.ZIP_URL_TLS_VERIFICATION_MODE]: (fields) =>
tlsStringToObjectNormalizer(
fields?.[ConfigKeys.ZIP_URL_TLS_VERIFICATION_MODE]?.value,
ConfigKeys.TLS_VERIFICATION_MODE
),
[ConfigKeys.ZIP_URL_TLS_VERSION]: (fields) =>
tlsJsonToObjectNormalizer(
fields?.[ConfigKeys.ZIP_URL_TLS_VERSION]?.value,
ConfigKeys.TLS_VERSION
),
[ConfigKeys.ZIP_URL_TLS_CERTIFICATE_AUTHORITIES]: getBrowserJsonToJavascriptNormalizer(
ConfigKeys.ZIP_URL_TLS_CERTIFICATE_AUTHORITIES
),
[ConfigKeys.ZIP_URL_TLS_CERTIFICATE]: getBrowserJsonToJavascriptNormalizer(
ConfigKeys.ZIP_URL_TLS_CERTIFICATE
),
[ConfigKeys.ZIP_URL_TLS_KEY]: getBrowserJsonToJavascriptNormalizer(ConfigKeys.ZIP_URL_TLS_KEY),
[ConfigKeys.ZIP_URL_TLS_KEY_PASSPHRASE]: getBrowserNormalizer(
ConfigKeys.ZIP_URL_TLS_KEY_PASSPHRASE
),
[ConfigKeys.ZIP_URL_TLS_VERIFICATION_MODE]: getBrowserNormalizer(
ConfigKeys.ZIP_URL_TLS_VERIFICATION_MODE
),
[ConfigKeys.ZIP_URL_TLS_VERSION]: getBrowserJsonToJavascriptNormalizer(
ConfigKeys.ZIP_URL_TLS_VERSION
),
[ConfigKeys.JOURNEY_FILTERS_MATCH]: getBrowserJsonToJavascriptNormalizer(
ConfigKeys.JOURNEY_FILTERS_MATCH
),

View file

@ -0,0 +1,125 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
import { render } from '../../../lib/helper/rtl_helpers';
import { ScriptRecorderFields } from './script_recorder_fields';
import { PolicyConfigContextProvider } from '../contexts';
jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({
...jest.requireActual('@elastic/eui/lib/services/accessibility/html_id_generator'),
htmlIdGenerator: () => () => `id-${Math.random()}`,
}));
const onChange = jest.fn();
describe('<ScriptRecorderFields />', () => {
let file: File;
const testScript = 'step(() => {})';
const WrappedComponent = ({
isEditable = true,
script = '',
fileName = '',
}: {
isEditable?: boolean;
script?: string;
fileName?: string;
}) => {
return (
<PolicyConfigContextProvider isEditable={isEditable}>
<ScriptRecorderFields script={script} fileName={fileName} onChange={onChange} />
</PolicyConfigContextProvider>
);
};
beforeEach(() => {
jest.clearAllMocks();
file = new File([testScript], 'samplescript.js', { type: 'text/javascript' });
});
it('renders ScriptRecorderFields', () => {
const { getByText, queryByText } = render(<WrappedComponent />);
const downloadLink = getByText('Download the Elastic Synthetics Recorder');
expect(downloadLink).toBeInTheDocument();
expect(downloadLink).toHaveAttribute('target', '_blank');
expect(queryByText('Show script')).not.toBeInTheDocument();
expect(queryByText('Remove script')).not.toBeInTheDocument();
});
it('handles uploading files', async () => {
const { getByTestId } = render(<WrappedComponent />);
const uploader = getByTestId('syntheticsFleetScriptRecorderUploader');
fireEvent.change(uploader, {
target: { files: [file] },
});
await waitFor(() => {
expect(onChange).toBeCalledWith({ scriptText: testScript, fileName: 'samplescript.js' });
});
});
it('shows user errors for invalid file types', async () => {
const { getByTestId, getByText } = render(<WrappedComponent />);
file = new File(['journey(() => {})'], 'samplescript.js', { type: 'text/javascript' });
let uploader = getByTestId('syntheticsFleetScriptRecorderUploader') as HTMLInputElement;
fireEvent.change(uploader, {
target: { files: [file] },
});
uploader = getByTestId('syntheticsFleetScriptRecorderUploader') as HTMLInputElement;
await waitFor(() => {
expect(onChange).not.toBeCalled();
expect(
getByText(
'Error uploading file. Please upload a .js file generated by the Elastic Synthetics Recorder in inline script format.'
)
).toBeInTheDocument();
});
});
it('shows show script button when script is available', () => {
const { getByText, queryByText } = render(<WrappedComponent script={testScript} />);
const showScriptBtn = getByText('Show script');
expect(queryByText(testScript)).not.toBeInTheDocument();
fireEvent.click(showScriptBtn);
expect(getByText(testScript)).toBeInTheDocument();
});
it('shows show remove script button when script is available and isEditable is true', async () => {
const { getByText, getByTestId } = render(
<WrappedComponent script={testScript} isEditable={true} />
);
const showScriptBtn = getByText('Show script');
fireEvent.click(showScriptBtn);
expect(getByText(testScript)).toBeInTheDocument();
fireEvent.click(getByTestId('euiFlyoutCloseButton'));
const removeScriptBtn = getByText('Remove script');
fireEvent.click(removeScriptBtn);
await waitFor(() => {
expect(onChange).toBeCalledWith({ scriptText: '', fileName: '' });
});
});
});

View file

@ -0,0 +1,134 @@
/*
* 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, { useState, useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiLink,
EuiFlexGroup,
EuiFlexItem,
EuiFlyout,
EuiFlyoutHeader,
EuiFormRow,
EuiCodeBlock,
EuiTitle,
EuiButton,
EuiSpacer,
EuiText,
} from '@elastic/eui';
import { usePolicyConfigContext } from '../contexts/policy_config_context';
import { Uploader } from './uploader';
interface Props {
onChange: ({ scriptText, fileName }: { scriptText: string; fileName: string }) => void;
script: string;
fileName?: string;
}
export function ScriptRecorderFields({ onChange, script, fileName }: Props) {
const [showScript, setShowScript] = useState(false);
const { isEditable } = usePolicyConfigContext();
const handleUpload = useCallback(
({ scriptText, fileName: fileNameT }: { scriptText: string; fileName: string }) => {
onChange({ scriptText, fileName: fileNameT });
},
[onChange]
);
return (
<>
<EuiSpacer size="m" />
<EuiLink href="https://github.com/elastic/synthetics-recorder/releases/" target="_blank">
<FormattedMessage
id="xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.browser.zipUrl.recorderLink"
defaultMessage="Download the Elastic Synthetics Recorder"
/>
</EuiLink>
<EuiSpacer size="m" />
{isEditable && script ? (
<EuiFormRow label="Testing script">
<EuiText size="s">
<strong>{fileName}</strong>
</EuiText>
</EuiFormRow>
) : (
<Uploader onUpload={handleUpload} />
)}
{script && (
<>
<EuiSpacer size="m" />
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={false}>
<EuiButton
onClick={() => setShowScript(true)}
iconType="editorCodeBlock"
iconSide="right"
>
<FormattedMessage
id="xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.browser.zipUrl.showScriptLabel"
defaultMessage="Show script"
/>
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
{isEditable && (
<EuiButton
onClick={() => onChange({ scriptText: '', fileName: '' })}
iconType="trash"
iconSide="right"
color="danger"
>
<FormattedMessage
id="xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.browser.zipUrl.removeScriptLabel"
defaultMessage="Remove script"
/>
</EuiButton>
)}
</EuiFlexItem>
</EuiFlexGroup>
</>
)}
{showScript && (
<EuiFlyout
ownFocus
onClose={() => setShowScript(false)}
aria-labelledby="syntheticsBrowserScriptBlockHeader"
closeButtonAriaLabel={CLOSE_BUTTON_LABEL}
>
<EuiFlyoutHeader hasBorder>
<EuiTitle size="m">
<span id="syntheticsBrowserScriptBlockHeader">
{fileName || PLACEHOLDER_FILE_NAME}
</span>
</EuiTitle>
</EuiFlyoutHeader>
<div style={{ height: '100%' }}>
<EuiCodeBlock language="js" overflowHeight={'100%'} fontSize="m" isCopyable>
{script}
</EuiCodeBlock>
</div>
</EuiFlyout>
)}
</>
);
}
const PLACEHOLDER_FILE_NAME = i18n.translate(
'xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.browser.scriptRecorder.mockFileName',
{
defaultMessage: 'test_script.js',
}
);
const CLOSE_BUTTON_LABEL = i18n.translate(
'xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.browser.scriptRecorder.closeButtonLabel',
{
defaultMessage: 'Close script flyout',
}
);

View file

@ -24,7 +24,17 @@ export const BrowserSimpleFields = memo<Props>(({ validate }) => {
setFields((prevFields) => ({ ...prevFields, [configKey]: value }));
};
const onChangeSourceField = useCallback(
({ zipUrl, folder, username, password, inlineScript, params, proxyUrl }) => {
({
zipUrl,
folder,
username,
password,
inlineScript,
params,
proxyUrl,
isGeneratedScript,
fileName,
}) => {
setFields((prevFields) => ({
...prevFields,
[ConfigKeys.SOURCE_ZIP_URL]: zipUrl,
@ -34,6 +44,13 @@ export const BrowserSimpleFields = memo<Props>(({ validate }) => {
[ConfigKeys.SOURCE_ZIP_PASSWORD]: password,
[ConfigKeys.SOURCE_INLINE]: inlineScript,
[ConfigKeys.PARAMS]: params,
[ConfigKeys.METADATA]: {
...prevFields[ConfigKeys.METADATA],
script_source: {
is_generated_script: isGeneratedScript,
file_name: fileName,
},
},
}));
},
[setFields]
@ -87,6 +104,9 @@ export const BrowserSimpleFields = memo<Props>(({ validate }) => {
password: defaultValues[ConfigKeys.SOURCE_ZIP_PASSWORD],
inlineScript: defaultValues[ConfigKeys.SOURCE_INLINE],
params: defaultValues[ConfigKeys.PARAMS],
isGeneratedScript:
defaultValues[ConfigKeys.METADATA].script_source?.is_generated_script,
fileName: defaultValues[ConfigKeys.METADATA].script_source?.file_name,
}),
[defaultValues]
)}

View file

@ -5,23 +5,28 @@
* 2.0.
*/
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import {
EuiTabbedContent,
EuiFormRow,
EuiFieldText,
EuiFieldPassword,
EuiSpacer,
EuiBetaBadge,
EuiFlexGroup,
EuiFlexItem,
} from '@elastic/eui';
import { OptionalLabel } from '../optional_label';
import { CodeEditor } from '../code_editor';
import { ScriptRecorderFields } from './script_recorder_fields';
import { ZipUrlTLSFields } from './zip_url_tls_fields';
import { MonacoEditorLangId } from '../types';
enum SourceType {
INLINE = 'syntheticsBrowserInlineConfig',
SCRIPT_RECORDER = 'syntheticsBrowserScriptRecorderConfig',
ZIP = 'syntheticsBrowserZipURLConfig',
}
@ -33,6 +38,8 @@ interface SourceConfig {
password: string;
inlineScript: string;
params: string;
isGeneratedScript?: boolean;
fileName?: string;
}
interface Props {
@ -48,12 +55,22 @@ export const defaultValues = {
password: '',
inlineScript: '',
params: '',
isGeneratedScript: false,
fileName: '',
};
const getDefaultTab = (defaultConfig: SourceConfig) => {
if (defaultConfig.inlineScript && defaultConfig.isGeneratedScript) {
return SourceType.SCRIPT_RECORDER;
} else if (defaultConfig.inlineScript) {
return SourceType.INLINE;
}
return SourceType.ZIP;
};
export const SourceField = ({ onChange, defaultConfig = defaultValues }: Props) => {
const [sourceType, setSourceType] = useState<SourceType>(
defaultConfig.inlineScript ? SourceType.INLINE : SourceType.ZIP
);
const [sourceType, setSourceType] = useState<SourceType>(getDefaultTab(defaultConfig));
const [config, setConfig] = useState<SourceConfig>(defaultConfig);
useEffect(() => {
@ -264,6 +281,52 @@ export const SourceField = ({ onChange, defaultConfig = defaultValues }: Props)
</EuiFormRow>
),
},
{
id: 'syntheticsBrowserScriptRecorderConfig',
name: (
<EuiFlexGroup responsive={false} alignItems="center" gutterSize="xs">
<EuiFlexItem grow={false}>
<FormattedMessage
id="xpack.uptime.createPackagePolicy.stepConfigure.browser.scriptRecorder.label"
defaultMessage="Script recorder"
/>
</EuiFlexItem>
<StyledBetaBadgeWrapper grow={false}>
<EuiBetaBadge
label={i18n.translate(
'xpack.uptime.createPackagePolicy.stepConfigure.browser.scriptRecorder.experimentalLabel',
{
defaultMessage: 'Tech preview',
}
)}
iconType="beaker"
tooltipContent={i18n.translate(
'xpack.uptime.createPackagePolicy.stepConfigure.browser.scriptRecorder.experimentalTooltip',
{
defaultMessage:
'Preview the quickest way to create Elastic Synthetics monitoring scripts with our Elastic Synthetics Recorder',
}
)}
/>
</StyledBetaBadgeWrapper>
</EuiFlexGroup>
),
'data-test-subj': 'syntheticsSourceTab__scriptRecorder',
content: (
<ScriptRecorderFields
onChange={({ scriptText, fileName }) =>
setConfig((prevConfig) => ({
...prevConfig,
inlineScript: scriptText,
isGeneratedScript: true,
fileName,
}))
}
script={config.inlineScript}
fileName={config.fileName}
/>
),
},
];
return (
@ -272,11 +335,17 @@ export const SourceField = ({ onChange, defaultConfig = defaultValues }: Props)
initialSelectedTab={tabs.find((tab) => tab.id === sourceType)}
autoFocus="selected"
onTabClick={(tab) => {
setSourceType(tab.id as SourceType);
if (tab.id !== sourceType) {
setConfig(defaultValues);
}
setSourceType(tab.id as SourceType);
}}
/>
);
};
const StyledBetaBadgeWrapper = styled(EuiFlexItem)`
.euiToolTipAnchor {
display: flex;
}
`;

View file

@ -0,0 +1,93 @@
/*
* 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, { useState, useRef } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFormRow, EuiFilePicker } from '@elastic/eui';
interface Props {
onUpload: ({ scriptText, fileName }: { scriptText: string; fileName: string }) => void;
}
export function Uploader({ onUpload }: Props) {
const fileReader = useRef<null | FileReader>(null);
const [error, setError] = useState<string | null>(null);
const filePickerRef = useRef<EuiFilePicker>(null);
const handleFileRead = (fileName: string) => {
const content = fileReader?.current?.result as string;
if (content?.trim().slice(0, 4) !== 'step') {
setError(PARSING_ERROR);
filePickerRef.current?.removeFiles();
return;
}
onUpload({ scriptText: content, fileName });
setError(null);
};
const handleFileChosen = (files: FileList | null) => {
if (!files || !files.length) {
onUpload({ scriptText: '', fileName: '' });
return;
}
if (files.length && files[0].type !== 'text/javascript') {
setError(INVALID_FILE_ERROR);
filePickerRef.current?.removeFiles();
return;
}
fileReader.current = new FileReader();
fileReader.current.onloadend = () => handleFileRead(files[0].name);
fileReader.current.readAsText(files[0]);
};
return (
<EuiFormRow isInvalid={Boolean(error)} error={error} label={TESTING_SCRIPT_LABEL}>
<EuiFilePicker
id="syntheticsFleetScriptRecorderUploader"
data-test-subj="syntheticsFleetScriptRecorderUploader"
ref={filePickerRef}
initialPromptText={PROMPT_TEXT}
onChange={handleFileChosen}
display={'large'}
/>
</EuiFormRow>
);
}
const TESTING_SCRIPT_LABEL = i18n.translate(
'xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.browser.uploader.fieldLabel',
{
defaultMessage: 'Testing script',
}
);
const PROMPT_TEXT = i18n.translate(
'xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.browser.uploader.label',
{
defaultMessage: 'Select recorder-generated .js file',
}
);
const INVALID_FILE_ERROR = i18n.translate(
'xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.browser.uploader.invalidFileError',
{
defaultMessage:
'Invalid file type. Please upload a .js file generated by the Elastic Synthetics Recorder.',
}
);
const PARSING_ERROR = i18n.translate(
'xpack.uptime.createPackagePolicy.stepConfigure.monitorIntegrationSettingsSection.browser.uploader.parsingError',
{
defaultMessage:
'Error uploading file. Please upload a .js file generated by the Elastic Synthetics Recorder in inline script format.',
}
);

View file

@ -12,7 +12,11 @@ import { EuiSwitch, EuiFormRow } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { TLSOptions, TLSConfig } from '../common/tls_options';
import { useBrowserSimpleFieldsContext, usePolicyConfigContext } from '../contexts';
import {
useBrowserSimpleFieldsContext,
usePolicyConfigContext,
defaultTLSFields,
} from '../contexts';
import { ConfigKeys } from '../types';
@ -67,12 +71,23 @@ export const ZipUrlTLSFields = () => {
{isZipUrlTLSEnabled ? (
<TLSOptions
defaultValues={{
certificateAuthorities: defaultValues[ConfigKeys.ZIP_URL_TLS_CERTIFICATE_AUTHORITIES],
certificate: defaultValues[ConfigKeys.ZIP_URL_TLS_CERTIFICATE],
key: defaultValues[ConfigKeys.ZIP_URL_TLS_KEY],
keyPassphrase: defaultValues[ConfigKeys.ZIP_URL_TLS_KEY_PASSPHRASE],
verificationMode: defaultValues[ConfigKeys.ZIP_URL_TLS_VERIFICATION_MODE],
version: defaultValues[ConfigKeys.ZIP_URL_TLS_VERSION],
certificateAuthorities:
defaultValues[ConfigKeys.ZIP_URL_TLS_CERTIFICATE_AUTHORITIES] ||
defaultTLSFields[ConfigKeys.TLS_CERTIFICATE_AUTHORITIES],
certificate:
defaultValues[ConfigKeys.ZIP_URL_TLS_CERTIFICATE] ||
defaultTLSFields[ConfigKeys.TLS_CERTIFICATE],
key:
defaultValues[ConfigKeys.ZIP_URL_TLS_KEY] || defaultTLSFields[ConfigKeys.TLS_KEY],
keyPassphrase:
defaultValues[ConfigKeys.ZIP_URL_TLS_KEY_PASSPHRASE] ||
defaultTLSFields[ConfigKeys.TLS_KEY_PASSPHRASE],
verificationMode:
defaultValues[ConfigKeys.ZIP_URL_TLS_VERIFICATION_MODE] ||
defaultTLSFields[ConfigKeys.TLS_VERIFICATION_MODE],
version:
defaultValues[ConfigKeys.ZIP_URL_TLS_VERSION] ||
defaultTLSFields[ConfigKeys.TLS_VERSION],
}}
onChange={handleOnChange}
tlsRole="client"

View file

@ -8,7 +8,6 @@
import React, { createContext, useContext, useMemo, useState } from 'react';
import { IBrowserSimpleFields, ConfigKeys, DataStream } from '../types';
import { defaultValues as commonDefaultValues } from '../common/default_values';
import { defaultValues as tlsDefaultValues } from '../tls/default_values';
interface IBrowserSimpleFieldsContext {
setFields: React.Dispatch<React.SetStateAction<IBrowserSimpleFields>>;
@ -24,6 +23,10 @@ interface IBrowserSimpleFieldsContextProvider {
export const initialValues: IBrowserSimpleFields = {
...commonDefaultValues,
[ConfigKeys.METADATA]: {
script_source: {
is_generated_script: false,
file_name: '',
},
is_zip_url_tls_enabled: false,
},
[ConfigKeys.MONITOR_TYPE]: DataStream.BROWSER,
@ -34,13 +37,12 @@ export const initialValues: IBrowserSimpleFields = {
[ConfigKeys.SOURCE_ZIP_PROXY_URL]: '',
[ConfigKeys.SOURCE_INLINE]: '',
[ConfigKeys.PARAMS]: '',
[ConfigKeys.ZIP_URL_TLS_CERTIFICATE_AUTHORITIES]:
tlsDefaultValues[ConfigKeys.TLS_CERTIFICATE_AUTHORITIES],
[ConfigKeys.ZIP_URL_TLS_CERTIFICATE]: tlsDefaultValues[ConfigKeys.TLS_CERTIFICATE],
[ConfigKeys.ZIP_URL_TLS_KEY]: tlsDefaultValues[ConfigKeys.TLS_KEY],
[ConfigKeys.ZIP_URL_TLS_KEY_PASSPHRASE]: tlsDefaultValues[ConfigKeys.TLS_KEY_PASSPHRASE],
[ConfigKeys.ZIP_URL_TLS_VERIFICATION_MODE]: tlsDefaultValues[ConfigKeys.TLS_VERIFICATION_MODE],
[ConfigKeys.ZIP_URL_TLS_VERSION]: tlsDefaultValues[ConfigKeys.TLS_VERSION],
[ConfigKeys.ZIP_URL_TLS_CERTIFICATE_AUTHORITIES]: undefined,
[ConfigKeys.ZIP_URL_TLS_CERTIFICATE]: undefined,
[ConfigKeys.ZIP_URL_TLS_KEY]: undefined,
[ConfigKeys.ZIP_URL_TLS_KEY_PASSPHRASE]: undefined,
[ConfigKeys.ZIP_URL_TLS_VERIFICATION_MODE]: undefined,
[ConfigKeys.ZIP_URL_TLS_VERSION]: undefined,
};
const defaultContext: IBrowserSimpleFieldsContext = {

View file

@ -7,7 +7,7 @@
export {
PolicyConfigContext,
PolicyConfigContextProvider,
initialValue as defaultMonitorType,
initialValue as defaultPolicyConfig,
usePolicyConfigContext,
} from './policy_config_context';
export {

View file

@ -18,6 +18,7 @@ interface IPolicyConfigContext {
isZipUrlTLSEnabled?: boolean;
defaultIsTLSEnabled?: boolean;
defaultIsZipUrlTLSEnabled?: boolean;
isEditable?: boolean;
}
interface IPolicyConfigContextProvider {
@ -25,6 +26,7 @@ interface IPolicyConfigContextProvider {
defaultMonitorType?: DataStream;
defaultIsTLSEnabled?: boolean;
defaultIsZipUrlTLSEnabled?: boolean;
isEditable?: boolean;
}
export const initialValue = DataStream.HTTP;
@ -45,6 +47,7 @@ const defaultContext: IPolicyConfigContext = {
defaultMonitorType: initialValue, // immutable,
defaultIsTLSEnabled: false,
defaultIsZipUrlTLSEnabled: false,
isEditable: false,
};
export const PolicyConfigContext = createContext(defaultContext);
@ -54,6 +57,7 @@ export const PolicyConfigContextProvider = ({
defaultMonitorType = initialValue,
defaultIsTLSEnabled = false,
defaultIsZipUrlTLSEnabled = false,
isEditable = false,
}: IPolicyConfigContextProvider) => {
const [monitorType, setMonitorType] = useState<DataStream>(defaultMonitorType);
const [isTLSEnabled, setIsTLSEnabled] = useState<boolean>(defaultIsTLSEnabled);
@ -70,6 +74,7 @@ export const PolicyConfigContextProvider = ({
setIsZipUrlTLSEnabled,
defaultIsTLSEnabled,
defaultIsZipUrlTLSEnabled,
isEditable,
};
}, [
monitorType,
@ -78,6 +83,7 @@ export const PolicyConfigContextProvider = ({
isZipUrlTLSEnabled,
defaultIsTLSEnabled,
defaultIsZipUrlTLSEnabled,
isEditable,
]);
return <PolicyConfigContext.Provider value={value} children={children} />;

View file

@ -54,21 +54,17 @@ const defaultTCPConfig = defaultConfig[DataStream.TCP];
describe.skip('<CustomFields />', () => {
const WrappedComponent = ({
validate = defaultValidation,
typeEditable = false,
isEditable = false,
dataStreams = [DataStream.HTTP, DataStream.TCP, DataStream.ICMP, DataStream.BROWSER],
}) => {
return (
<HTTPContextProvider>
<PolicyConfigContextProvider>
<PolicyConfigContextProvider isEditable={isEditable}>
<TCPContextProvider>
<BrowserContextProvider>
<ICMPSimpleFieldsContextProvider>
<TLSFieldsContextProvider>
<CustomFields
validate={validate}
typeEditable={typeEditable}
dataStreams={dataStreams}
/>
<CustomFields validate={validate} dataStreams={dataStreams} />
</TLSFieldsContextProvider>
</ICMPSimpleFieldsContextProvider>
</BrowserContextProvider>
@ -80,7 +76,7 @@ describe.skip('<CustomFields />', () => {
it('renders CustomFields', async () => {
const { getByText, getByLabelText, queryByLabelText } = render(<WrappedComponent />);
const monitorType = queryByLabelText('Monitor Type') as HTMLInputElement;
const monitorType = getByLabelText('Monitor Type') as HTMLInputElement;
const url = getByLabelText('URL') as HTMLInputElement;
const proxyUrl = getByLabelText('Proxy URL') as HTMLInputElement;
const monitorIntervalNumber = getByLabelText('Number') as HTMLInputElement;
@ -88,7 +84,7 @@ describe.skip('<CustomFields />', () => {
const apmServiceName = getByLabelText('APM service name') as HTMLInputElement;
const maxRedirects = getByLabelText('Max redirects') as HTMLInputElement;
const timeout = getByLabelText('Timeout in seconds') as HTMLInputElement;
expect(monitorType).not.toBeInTheDocument();
expect(monitorType).toBeInTheDocument();
expect(url).toBeInTheDocument();
expect(url.value).toEqual(defaultHTTPConfig[ConfigKeys.URLS]);
expect(proxyUrl).toBeInTheDocument();
@ -117,6 +113,13 @@ describe.skip('<CustomFields />', () => {
});
});
it('does not show monitor type dropdown when isEditable is true', async () => {
const { queryByLabelText } = render(<WrappedComponent isEditable />);
const monitorType = queryByLabelText('Monitor Type') as HTMLInputElement;
expect(monitorType).not.toBeInTheDocument();
});
it('shows SSL fields when Enable SSL Fields is checked', async () => {
const { findByLabelText, queryByLabelText } = render(<WrappedComponent />);
const enableSSL = queryByLabelText('Enable TLS configuration') as HTMLInputElement;
@ -180,7 +183,7 @@ describe.skip('<CustomFields />', () => {
it('handles switching monitor type', () => {
const { getByText, getByLabelText, queryByLabelText, getAllByLabelText } = render(
<WrappedComponent typeEditable />
<WrappedComponent />
);
const monitorType = getByLabelText('Monitor Type') as HTMLInputElement;
expect(monitorType).toBeInTheDocument();
@ -244,7 +247,7 @@ describe.skip('<CustomFields />', () => {
});
it('shows resolve hostnames locally field when proxy url is filled for tcp monitors', () => {
const { getByLabelText, queryByLabelText } = render(<WrappedComponent typeEditable />);
const { getByLabelText, queryByLabelText } = render(<WrappedComponent />);
const monitorType = getByLabelText('Monitor Type') as HTMLInputElement;
fireEvent.change(monitorType, { target: { value: DataStream.TCP } });
@ -302,10 +305,7 @@ describe.skip('<CustomFields />', () => {
it('does not show monitor options that are not contained in datastreams', async () => {
const { getByText, queryByText, queryByLabelText } = render(
<WrappedComponent
dataStreams={[DataStream.HTTP, DataStream.TCP, DataStream.ICMP]}
typeEditable
/>
<WrappedComponent dataStreams={[DataStream.HTTP, DataStream.TCP, DataStream.ICMP]} />
);
const monitorType = queryByLabelText('Monitor Type') as HTMLInputElement;

View file

@ -30,13 +30,13 @@ import { BrowserSimpleFields } from './browser/simple_fields';
import { BrowserAdvancedFields } from './browser/advanced_fields';
interface Props {
typeEditable?: boolean;
validate: Validation;
dataStreams?: DataStream[];
}
export const CustomFields = memo<Props>(({ typeEditable = false, validate, dataStreams = [] }) => {
const { monitorType, setMonitorType, isTLSEnabled, setIsTLSEnabled } = usePolicyConfigContext();
export const CustomFields = memo<Props>(({ validate, dataStreams = [] }) => {
const { monitorType, setMonitorType, isTLSEnabled, setIsTLSEnabled, isEditable } =
usePolicyConfigContext();
const isHTTP = monitorType === DataStream.HTTP;
const isTCP = monitorType === DataStream.TCP;
@ -88,7 +88,7 @@ export const CustomFields = memo<Props>(({ typeEditable = false, validate, dataS
>
<EuiFlexGroup>
<EuiFlexItem>
{typeEditable && (
{!isEditable && (
<EuiFormRow
label={
<FormattedMessage

View file

@ -0,0 +1,131 @@
/*
* 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 { useMemo } from 'react';
import {
PolicyConfig,
DataStream,
ConfigKeys,
HTTPFields,
TCPFields,
ICMPFields,
BrowserFields,
} from '../types';
import {
usePolicyConfigContext,
useTCPSimpleFieldsContext,
useTCPAdvancedFieldsContext,
useICMPSimpleFieldsContext,
useHTTPSimpleFieldsContext,
useHTTPAdvancedFieldsContext,
useTLSFieldsContext,
useBrowserSimpleFieldsContext,
useBrowserAdvancedFieldsContext,
defaultHTTPAdvancedFields,
defaultHTTPSimpleFields,
defaultICMPSimpleFields,
defaultTCPSimpleFields,
defaultTCPAdvancedFields,
defaultBrowserSimpleFields,
defaultBrowserAdvancedFields,
defaultTLSFields,
} from '../contexts';
export const defaultConfig: PolicyConfig = {
[DataStream.HTTP]: {
...defaultHTTPSimpleFields,
...defaultHTTPAdvancedFields,
...defaultTLSFields,
},
[DataStream.TCP]: {
...defaultTCPSimpleFields,
...defaultTCPAdvancedFields,
...defaultTLSFields,
},
[DataStream.ICMP]: defaultICMPSimpleFields,
[DataStream.BROWSER]: {
...defaultBrowserSimpleFields,
...defaultBrowserAdvancedFields,
...defaultTLSFields,
},
};
/**
* Exports Synthetics-specific package policy instructions
* for use in the Ingest app create / edit package policy
*/
export const usePolicy = (name: string) => {
const { isTLSEnabled, isZipUrlTLSEnabled } = usePolicyConfigContext();
const { fields: httpSimpleFields } = useHTTPSimpleFieldsContext();
const { fields: tcpSimpleFields } = useTCPSimpleFieldsContext();
const { fields: icmpSimpleFields } = useICMPSimpleFieldsContext();
const { fields: browserSimpleFields } = useBrowserSimpleFieldsContext();
const { fields: httpAdvancedFields } = useHTTPAdvancedFieldsContext();
const { fields: tcpAdvancedFields } = useTCPAdvancedFieldsContext();
const { fields: browserAdvancedFields } = useBrowserAdvancedFieldsContext();
const { fields: tlsFields } = useTLSFieldsContext();
const metadata = useMemo(
() => ({
is_tls_enabled: isTLSEnabled,
is_zip_url_tls_enabled: isZipUrlTLSEnabled,
}),
[isTLSEnabled, isZipUrlTLSEnabled]
);
const policyConfig: PolicyConfig = useMemo(
() => ({
[DataStream.HTTP]: {
...httpSimpleFields,
...httpAdvancedFields,
...tlsFields,
[ConfigKeys.METADATA]: {
...httpSimpleFields[ConfigKeys.METADATA],
...metadata,
},
[ConfigKeys.NAME]: name,
} as HTTPFields,
[DataStream.TCP]: {
...tcpSimpleFields,
...tcpAdvancedFields,
...tlsFields,
[ConfigKeys.METADATA]: {
...tcpSimpleFields[ConfigKeys.METADATA],
...metadata,
},
[ConfigKeys.NAME]: name,
} as TCPFields,
[DataStream.ICMP]: {
...icmpSimpleFields,
[ConfigKeys.NAME]: name,
} as ICMPFields,
[DataStream.BROWSER]: {
...browserSimpleFields,
...browserAdvancedFields,
[ConfigKeys.METADATA]: {
...browserSimpleFields[ConfigKeys.METADATA],
...metadata,
},
[ConfigKeys.NAME]: name,
} as BrowserFields,
}),
[
metadata,
httpSimpleFields,
httpAdvancedFields,
tcpSimpleFields,
tcpAdvancedFields,
icmpSimpleFields,
browserSimpleFields,
browserAdvancedFields,
tlsFields,
name,
]
);
return policyConfig;
};

View file

@ -4,11 +4,10 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { useUpdatePolicy } from './use_update_policy';
import { renderHook } from '@testing-library/react-hooks';
import { NewPackagePolicy } from '../../../../fleet/public';
import { validate } from './validation';
import { useUpdatePolicy } from './use_update_policy';
import { NewPackagePolicy } from '../../../../../fleet/public';
import { validate } from '../validation';
import {
ConfigKeys,
DataStream,
@ -20,8 +19,8 @@ import {
ITLSFields,
HTTPFields,
BrowserFields,
} from './types';
import { defaultConfig } from './synthetics_policy_create_extension';
} from '../types';
import { defaultConfig } from '../synthetics_policy_create_extension';
describe('useBarChartsHooks', () => {
const newPolicy: NewPackagePolicy = {

View file

@ -5,9 +5,9 @@
* 2.0.
*/
import { useEffect, useRef, useState } from 'react';
import { NewPackagePolicy } from '../../../../fleet/public';
import { ConfigKeys, DataStream, Validation, ICustomFields } from './types';
import { formatters } from './helpers/formatters';
import { NewPackagePolicy } from '../../../../../fleet/public';
import { ConfigKeys, DataStream, Validation, ICustomFields } from '../types';
import { formatters } from '../helpers/formatters';
interface Props {
monitorType: DataStream;

View file

@ -8,36 +8,21 @@
import React, { memo, useEffect, useMemo } from 'react';
import { PackagePolicyCreateExtensionComponentProps } from '../../../../fleet/public';
import { useTrackPageview } from '../../../../observability/public';
import {
PolicyConfig,
DataStream,
ConfigKeys,
HTTPFields,
TCPFields,
ICMPFields,
BrowserFields,
} from './types';
import { PolicyConfig, DataStream } from './types';
import {
usePolicyConfigContext,
useTCPSimpleFieldsContext,
useTCPAdvancedFieldsContext,
useICMPSimpleFieldsContext,
useHTTPSimpleFieldsContext,
useHTTPAdvancedFieldsContext,
useTLSFieldsContext,
useBrowserSimpleFieldsContext,
useBrowserAdvancedFieldsContext,
defaultHTTPAdvancedFields,
defaultHTTPSimpleFields,
defaultICMPSimpleFields,
defaultHTTPAdvancedFields,
defaultTCPSimpleFields,
defaultTCPAdvancedFields,
defaultICMPSimpleFields,
defaultBrowserSimpleFields,
defaultBrowserAdvancedFields,
defaultTLSFields,
} from './contexts';
import { CustomFields } from './custom_fields';
import { useUpdatePolicy } from './use_update_policy';
import { useUpdatePolicy } from './hooks/use_update_policy';
import { usePolicy } from './hooks/use_policy';
import { validate } from './validation';
export const defaultConfig: PolicyConfig = {
@ -65,55 +50,12 @@ export const defaultConfig: PolicyConfig = {
*/
export const SyntheticsPolicyCreateExtension = memo<PackagePolicyCreateExtensionComponentProps>(
({ newPolicy, onChange }) => {
const { monitorType, isTLSEnabled, isZipUrlTLSEnabled } = usePolicyConfigContext();
const { fields: httpSimpleFields } = useHTTPSimpleFieldsContext();
const { fields: tcpSimpleFields } = useTCPSimpleFieldsContext();
const { fields: icmpSimpleFields } = useICMPSimpleFieldsContext();
const { fields: browserSimpleFields } = useBrowserSimpleFieldsContext();
const { fields: httpAdvancedFields } = useHTTPAdvancedFieldsContext();
const { fields: tcpAdvancedFields } = useTCPAdvancedFieldsContext();
const { fields: browserAdvancedFields } = useBrowserAdvancedFieldsContext();
const { fields: tlsFields } = useTLSFieldsContext();
const metaData = useMemo(
() => ({
is_tls_enabled: isTLSEnabled,
is_zip_url_tls_enabled: isZipUrlTLSEnabled,
}),
[isTLSEnabled, isZipUrlTLSEnabled]
);
const policyConfig: PolicyConfig = {
[DataStream.HTTP]: {
...httpSimpleFields,
...httpAdvancedFields,
...tlsFields,
[ConfigKeys.METADATA]: metaData,
[ConfigKeys.NAME]: newPolicy.name,
} as HTTPFields,
[DataStream.TCP]: {
...tcpSimpleFields,
...tcpAdvancedFields,
...tlsFields,
[ConfigKeys.METADATA]: metaData,
[ConfigKeys.NAME]: newPolicy.name,
} as TCPFields,
[DataStream.ICMP]: {
...icmpSimpleFields,
[ConfigKeys.NAME]: newPolicy.name,
} as ICMPFields,
[DataStream.BROWSER]: {
...browserSimpleFields,
...browserAdvancedFields,
...tlsFields,
[ConfigKeys.METADATA]: metaData,
[ConfigKeys.NAME]: newPolicy.name,
} as BrowserFields,
};
useTrackPageview({ app: 'fleet', path: 'syntheticsCreate' });
useTrackPageview({ app: 'fleet', path: 'syntheticsCreate', delay: 15000 });
const { monitorType } = usePolicyConfigContext();
const policyConfig: PolicyConfig = usePolicy(newPolicy.name);
const dataStreams: DataStream[] = useMemo(() => {
return newPolicy.inputs.map((input) => {
return input.type.replace(/synthetics\//g, '') as DataStream;
@ -143,7 +85,7 @@ export const SyntheticsPolicyCreateExtension = memo<PackagePolicyCreateExtension
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return <CustomFields typeEditable validate={validate[monitorType]} dataStreams={dataStreams} />;
return <CustomFields validate={validate[monitorType]} dataStreams={dataStreams} />;
}
);
SyntheticsPolicyCreateExtension.displayName = 'SyntheticsPolicyCreateExtension';

View file

@ -5,32 +5,14 @@
* 2.0.
*/
import React, { memo, useMemo } from 'react';
import React, { memo } from 'react';
import { PackagePolicyEditExtensionComponentProps } from '../../../../fleet/public';
import { useTrackPageview } from '../../../../observability/public';
import {
usePolicyConfigContext,
useTCPSimpleFieldsContext,
useTCPAdvancedFieldsContext,
useICMPSimpleFieldsContext,
useHTTPSimpleFieldsContext,
useHTTPAdvancedFieldsContext,
useTLSFieldsContext,
useBrowserSimpleFieldsContext,
useBrowserAdvancedFieldsContext,
} from './contexts';
import {
ICustomFields,
DataStream,
HTTPFields,
TCPFields,
ICMPFields,
BrowserFields,
ConfigKeys,
PolicyConfig,
} from './types';
import { usePolicyConfigContext } from './contexts';
import { ICustomFields, PolicyConfig } from './types';
import { CustomFields } from './custom_fields';
import { useUpdatePolicy } from './use_update_policy';
import { useUpdatePolicy } from './hooks/use_update_policy';
import { usePolicy } from './hooks/use_policy';
import { validate } from './validation';
interface SyntheticsPolicyEditExtensionProps {
@ -47,50 +29,9 @@ export const SyntheticsPolicyEditExtension = memo<SyntheticsPolicyEditExtensionP
({ newPolicy, onChange, defaultConfig }) => {
useTrackPageview({ app: 'fleet', path: 'syntheticsEdit' });
useTrackPageview({ app: 'fleet', path: 'syntheticsEdit', delay: 15000 });
const { monitorType, isTLSEnabled, isZipUrlTLSEnabled } = usePolicyConfigContext();
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 { fields: browserSimpleFields } = useBrowserSimpleFieldsContext();
const { fields: browserAdvancedFields } = useBrowserAdvancedFieldsContext();
const metadata = useMemo(
() => ({
is_tls_enabled: isTLSEnabled,
is_zip_url_tls_enabled: isZipUrlTLSEnabled,
}),
[isTLSEnabled, isZipUrlTLSEnabled]
);
const policyConfig: PolicyConfig = {
[DataStream.HTTP]: {
...httpSimpleFields,
...httpAdvancedFields,
...tlsFields,
[ConfigKeys.METADATA]: metadata,
[ConfigKeys.NAME]: newPolicy.name,
} as HTTPFields,
[DataStream.TCP]: {
...tcpSimpleFields,
...tcpAdvancedFields,
...tlsFields,
[ConfigKeys.METADATA]: metadata,
[ConfigKeys.NAME]: newPolicy.name,
} as TCPFields,
[DataStream.ICMP]: {
...icmpSimpleFields,
[ConfigKeys.NAME]: newPolicy.name,
} as ICMPFields,
[DataStream.BROWSER]: {
...browserSimpleFields,
...browserAdvancedFields,
[ConfigKeys.METADATA]: metadata,
[ConfigKeys.NAME]: newPolicy.name,
} as BrowserFields,
};
const { monitorType } = usePolicyConfigContext();
const policyConfig: PolicyConfig = usePolicy(newPolicy.name);
useUpdatePolicy({
defaultConfig,

View file

@ -1075,6 +1075,59 @@ describe('<SyntheticsPolicyEditExtension />', () => {
expect(queryByLabelText('Host')).not.toBeInTheDocument();
});
it.each([
[true, 'Testing script'],
[false, 'Inline script'],
])(
'browser monitors - auto selects the right tab depending on source metadata',
async (isGeneratedScript, text) => {
const currentPolicy = {
...defaultCurrentPolicy,
inputs: [
{
...defaultNewPolicy.inputs[0],
enabled: false,
},
{
...defaultNewPolicy.inputs[1],
enabled: false,
},
{
...defaultNewPolicy.inputs[2],
enabled: false,
},
{
...defaultNewPolicy.inputs[3],
enabled: true,
streams: [
{
...defaultNewPolicy.inputs[3].streams[0],
vars: {
...defaultNewPolicy.inputs[3].streams[0].vars,
'source.inline.script': {
type: 'yaml',
value: JSON.stringify('step(() => {})'),
},
__ui: {
type: 'yaml',
value: JSON.stringify({
script_source: {
is_generated_script: isGeneratedScript,
},
}),
},
},
},
],
},
],
};
const { getByText } = render(<WrappedComponent policy={currentPolicy} />);
expect(getByText(text)).toBeInTheDocument();
}
);
it('hides tls fields when metadata.is_tls_enabled is false', async () => {
const { getByLabelText, queryByLabelText } = render(
<WrappedComponent

View file

@ -97,6 +97,7 @@ export const SyntheticsPolicyEditExtensionWrapper = memo<PackagePolicyEditExtens
defaultMonitorType={monitorType}
defaultIsTLSEnabled={isTLSEnabled}
defaultIsZipUrlTLSEnabled={isZipUrlTLSEnabled}
isEditable={true}
>
<TLSFieldsContextProvider defaultValues={isTLSEnabled ? defaultTLSConfig : undefined}>
<HTTPContextProvider defaultValues={fullDefaultConfig?.[DataStream.HTTP]}>

View file

@ -129,6 +129,10 @@ export enum ConfigKeys {
export interface Metadata {
is_tls_enabled?: boolean;
is_zip_url_tls_enabled?: boolean;
script_source?: {
is_generated_script: boolean;
file_name: string;
};
}
export interface ICommonFields {