mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Uptime] [Synthetics Integration] transition to monaco code editor (#102642)
* update synthetics integration code editor * add basic support for xml and javascript * fix types Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
564807c0b0
commit
34490a355e
9 changed files with 84 additions and 77 deletions
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
|
||||
/* eslint-disable @kbn/eslint/module_migration */
|
||||
|
||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
|
||||
import 'monaco-editor/esm/vs/base/common/worker/simpleWorker';
|
||||
|
@ -23,4 +22,7 @@ import 'monaco-editor/esm/vs/editor/contrib/hover/hover.js'; // Needed for hover
|
|||
import 'monaco-editor/esm/vs/editor/contrib/parameterHints/parameterHints.js'; // Needed for signature
|
||||
import 'monaco-editor/esm/vs/editor/contrib/bracketMatching/bracketMatching.js'; // Needed for brackets matching highlight
|
||||
|
||||
import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution.js'; // Needed for basic javascript support
|
||||
import 'monaco-editor/esm/vs/basic-languages/xml/xml.contribution.js'; // Needed for basic xml support
|
||||
|
||||
export { monaco };
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import React from 'react';
|
||||
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { EuiPanel } from '@elastic/eui';
|
||||
import { CodeEditor as MonacoCodeEditor } from '../../../../../../src/plugins/kibana_react/public';
|
||||
|
||||
import { MonacoEditorLangId } from './types';
|
||||
|
||||
const CodeEditorContainer = styled(EuiPanel)`
|
||||
padding: 0;
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
ariaLabel: string;
|
||||
id: string;
|
||||
languageId: MonacoEditorLangId;
|
||||
onChange: (value: string) => void;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const CodeEditor = ({ ariaLabel, id, languageId, onChange, value }: Props) => {
|
||||
return (
|
||||
<CodeEditorContainer borderRadius="none" hasShadow={false} hasBorder={true}>
|
||||
<div id={`${id}-editor`} aria-label={ariaLabel} data-test-subj="codeEditorContainer">
|
||||
<MonacoCodeEditor
|
||||
languageId={languageId}
|
||||
width="100%"
|
||||
height="250px"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
options={{
|
||||
renderValidationDecorations: value ? 'on' : 'off',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</CodeEditorContainer>
|
||||
);
|
||||
};
|
|
@ -36,7 +36,7 @@ export const initialValues = {
|
|||
[ConfigKeys.RESPONSE_STATUS_CHECK]: [],
|
||||
[ConfigKeys.REQUEST_BODY_CHECK]: {
|
||||
value: '',
|
||||
type: Mode.TEXT,
|
||||
type: Mode.PLAINTEXT,
|
||||
},
|
||||
[ConfigKeys.REQUEST_HEADERS_CHECK]: {},
|
||||
[ConfigKeys.REQUEST_METHOD_CHECK]: HTTPMethod.GET,
|
||||
|
|
|
@ -76,14 +76,14 @@ describe('<HeaderField />', () => {
|
|||
});
|
||||
|
||||
it('handles content mode', async () => {
|
||||
const contentMode: Mode = Mode.TEXT;
|
||||
const contentMode: Mode = Mode.PLAINTEXT;
|
||||
render(
|
||||
<HeaderField defaultValue={defaultValue} onChange={onChange} contentMode={contentMode} />
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(onChange).toBeCalledWith({
|
||||
'Content-Type': contentTypes[Mode.TEXT],
|
||||
'Content-Type': contentTypes[Mode.PLAINTEXT],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -61,7 +61,7 @@ export const HeaderField = ({ contentMode, defaultValue, onChange }: Props) => {
|
|||
|
||||
export const contentTypes: Record<Mode, ContentType> = {
|
||||
[Mode.JSON]: ContentType.JSON,
|
||||
[Mode.TEXT]: ContentType.TEXT,
|
||||
[Mode.PLAINTEXT]: ContentType.TEXT,
|
||||
[Mode.XML]: ContentType.XML,
|
||||
[Mode.FORM]: ContentType.FORM,
|
||||
};
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { fireEvent, waitFor } from '@testing-library/react';
|
||||
import { render } from '../../lib/helper/rtl_helpers';
|
||||
|
@ -16,7 +18,7 @@ jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({
|
|||
}));
|
||||
|
||||
describe('<RequestBodyField />', () => {
|
||||
const defaultMode = Mode.TEXT;
|
||||
const defaultMode = Mode.PLAINTEXT;
|
||||
const defaultValue = 'sample value';
|
||||
const WrappedComponent = () => {
|
||||
const [config, setConfig] = useState({
|
||||
|
|
|
@ -5,67 +5,13 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { stringify, parse } from 'query-string';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { stringify, parse } from 'query-string';
|
||||
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { EuiCodeEditor, EuiPanel, EuiTabbedContent } from '@elastic/eui';
|
||||
|
||||
import { Mode } from './types';
|
||||
|
||||
import { EuiTabbedContent } from '@elastic/eui';
|
||||
import { Mode, MonacoEditorLangId } from './types';
|
||||
import { KeyValuePairsField, Pair } from './key_value_field';
|
||||
|
||||
import 'brace/theme/github';
|
||||
import 'brace/mode/xml';
|
||||
import 'brace/mode/json';
|
||||
import 'brace/ext/language_tools';
|
||||
|
||||
const CodeEditorContainer = styled(EuiPanel)`
|
||||
padding: 0;
|
||||
`;
|
||||
|
||||
enum ResponseBodyType {
|
||||
CODE = 'code',
|
||||
FORM = 'form',
|
||||
}
|
||||
|
||||
const CodeEditor = ({
|
||||
ariaLabel,
|
||||
id,
|
||||
mode,
|
||||
onChange,
|
||||
value,
|
||||
}: {
|
||||
ariaLabel: string;
|
||||
id: string;
|
||||
mode: Mode;
|
||||
onChange: (value: string) => void;
|
||||
value: string;
|
||||
}) => {
|
||||
return (
|
||||
<CodeEditorContainer borderRadius="none" hasShadow={false} hasBorder={true}>
|
||||
<div id={`${id}-editor`}>
|
||||
<EuiCodeEditor
|
||||
mode={mode}
|
||||
theme="github"
|
||||
width="100%"
|
||||
height="250px"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
setOptions={{
|
||||
fontSize: '14px',
|
||||
enableBasicAutocompletion: true,
|
||||
enableSnippets: true,
|
||||
enableLiveAutocompletion: true,
|
||||
}}
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
</div>
|
||||
</CodeEditorContainer>
|
||||
);
|
||||
};
|
||||
import { CodeEditor } from './code_editor';
|
||||
|
||||
interface Props {
|
||||
onChange: (requestBody: { type: Mode; value: string }) => void;
|
||||
|
@ -73,6 +19,11 @@ interface Props {
|
|||
value: string;
|
||||
}
|
||||
|
||||
enum ResponseBodyType {
|
||||
CODE = 'code',
|
||||
FORM = 'form',
|
||||
}
|
||||
|
||||
// TO DO: Look into whether or not code editor reports errors, in order to prevent form submission on an error
|
||||
export const RequestBodyField = ({ onChange, type, value }: Props) => {
|
||||
const [values, setValues] = useState<Record<ResponseBodyType, string>>({
|
||||
|
@ -129,9 +80,9 @@ export const RequestBodyField = ({ onChange, type, value }: Props) => {
|
|||
|
||||
const tabs = [
|
||||
{
|
||||
id: Mode.TEXT,
|
||||
name: modeLabels[Mode.TEXT],
|
||||
'data-test-subj': `syntheticsRequestBodyTab__${Mode.TEXT}`,
|
||||
id: Mode.PLAINTEXT,
|
||||
name: modeLabels[Mode.PLAINTEXT],
|
||||
'data-test-subj': `syntheticsRequestBodyTab__${Mode.PLAINTEXT}`,
|
||||
content: (
|
||||
<CodeEditor
|
||||
ariaLabel={i18n.translate(
|
||||
|
@ -140,8 +91,8 @@ export const RequestBodyField = ({ onChange, type, value }: Props) => {
|
|||
defaultMessage: 'Text code editor',
|
||||
}
|
||||
)}
|
||||
id={Mode.TEXT}
|
||||
mode={Mode.TEXT}
|
||||
id={Mode.PLAINTEXT}
|
||||
languageId={MonacoEditorLangId.PLAINTEXT}
|
||||
onChange={(code) =>
|
||||
setValues((prevValues) => ({ ...prevValues, [ResponseBodyType.CODE]: code }))
|
||||
}
|
||||
|
@ -162,7 +113,7 @@ export const RequestBodyField = ({ onChange, type, value }: Props) => {
|
|||
}
|
||||
)}
|
||||
id={Mode.JSON}
|
||||
mode={Mode.JSON}
|
||||
languageId={MonacoEditorLangId.JSON}
|
||||
onChange={(code) =>
|
||||
setValues((prevValues) => ({ ...prevValues, [ResponseBodyType.CODE]: code }))
|
||||
}
|
||||
|
@ -183,7 +134,7 @@ export const RequestBodyField = ({ onChange, type, value }: Props) => {
|
|||
}
|
||||
)}
|
||||
id={Mode.XML}
|
||||
mode={Mode.XML}
|
||||
languageId={MonacoEditorLangId.XML}
|
||||
onChange={(code) =>
|
||||
setValues((prevValues) => ({ ...prevValues, [ResponseBodyType.CODE]: code }))
|
||||
}
|
||||
|
@ -229,7 +180,7 @@ const modeLabels = {
|
|||
defaultMessage: 'Form',
|
||||
}
|
||||
),
|
||||
[Mode.TEXT]: i18n.translate(
|
||||
[Mode.PLAINTEXT]: i18n.translate(
|
||||
'xpack.uptime.createPackagePolicy.stepConfigure.requestBodyType.text',
|
||||
{
|
||||
defaultMessage: 'Text',
|
||||
|
|
|
@ -25,10 +25,17 @@ export enum ResponseBodyIndexPolicy {
|
|||
ON_ERROR = 'on_error',
|
||||
}
|
||||
|
||||
export enum MonacoEditorLangId {
|
||||
JSON = 'xjson',
|
||||
PLAINTEXT = 'plaintext',
|
||||
XML = 'xml',
|
||||
JAVASCRIPT = 'javascript',
|
||||
}
|
||||
|
||||
export enum Mode {
|
||||
FORM = 'form',
|
||||
JSON = 'json',
|
||||
TEXT = 'text',
|
||||
PLAINTEXT = 'text',
|
||||
XML = 'xml',
|
||||
}
|
||||
|
||||
|
@ -192,11 +199,11 @@ export interface PolicyConfig {
|
|||
[DataStream.ICMP]: ICMPFields;
|
||||
}
|
||||
|
||||
export type Validation = Partial<Record<ConfigKeys, (value: unknown, ...args: any[]) => void>>;
|
||||
export type Validation = Partial<Record<ConfigKeys, (value: unknown, ...args: any[]) => boolean>>;
|
||||
|
||||
export const contentTypesToMode = {
|
||||
[ContentType.FORM]: Mode.FORM,
|
||||
[ContentType.JSON]: Mode.JSON,
|
||||
[ContentType.TEXT]: Mode.TEXT,
|
||||
[ContentType.TEXT]: Mode.PLAINTEXT,
|
||||
[ContentType.XML]: Mode.XML,
|
||||
};
|
||||
|
|
|
@ -277,7 +277,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
},
|
||||
requestBody: {
|
||||
type: 'xml',
|
||||
value: '<samplexml>samplexml',
|
||||
value: '<samplexml>samplexml<samplexml>',
|
||||
},
|
||||
indexResponseBody: false,
|
||||
indexResponseHeaders: false,
|
||||
|
@ -308,7 +308,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
},
|
||||
'check.response.headers': advancedConfig.responseHeaders,
|
||||
'check.response.status': [advancedConfig.responseStatusCheck],
|
||||
'check.request.body': `${advancedConfig.requestBody.value}</samplexml>`, // code editor adds closing tag
|
||||
'check.request.body': advancedConfig.requestBody.value,
|
||||
'check.response.body.positive': [advancedConfig.responseBodyCheckPositive],
|
||||
'check.response.body.negative': [advancedConfig.responseBodyCheckNegative],
|
||||
'response.include_body': advancedConfig.indexResponseBody ? 'on_error' : 'never',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue