mirror of
https://github.com/ansible/awx.git
synced 2026-05-15 21:37:42 -02:30
Merge pull request #9281 from keithjgrant/8905-codemirror-replacement
AceEditor - codemirror replacement Reviewed-by: John Hill <johill@redhat.com> https://github.com/unlikelyzero
This commit is contained in:
@@ -17,6 +17,7 @@ This is a list of high-level changes for each release of AWX. A full list of com
|
|||||||
- Added pending workflow approval count to the application header https://github.com/ansible/awx/pull/9334
|
- Added pending workflow approval count to the application header https://github.com/ansible/awx/pull/9334
|
||||||
- Added user interface for management jobs: https://github.com/ansible/awx/pull/9224
|
- Added user interface for management jobs: https://github.com/ansible/awx/pull/9224
|
||||||
- Added toast message to show notification template test result to notification templates list https://github.com/ansible/awx/pull/9318
|
- Added toast message to show notification template test result to notification templates list https://github.com/ansible/awx/pull/9318
|
||||||
|
- Replaced CodeMirror with AceEditor for editing template variables and notification templates https://github.com/ansible/awx/pull/9281
|
||||||
|
|
||||||
# 17.1.0 (March 9th, 2021)
|
# 17.1.0 (March 9th, 2021)
|
||||||
- Addressed a security issue in AWX (CVE-2021-20253)
|
- Addressed a security issue in AWX (CVE-2021-20253)
|
||||||
|
|||||||
40
awx/ui_next/package-lock.json
generated
40
awx/ui_next/package-lock.json
generated
@@ -2786,6 +2786,11 @@
|
|||||||
"negotiator": "0.6.2"
|
"negotiator": "0.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ace-builds": {
|
||||||
|
"version": "1.4.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.12.tgz",
|
||||||
|
"integrity": "sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg=="
|
||||||
|
},
|
||||||
"acorn": {
|
"acorn": {
|
||||||
"version": "7.4.1",
|
"version": "7.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||||
@@ -4947,11 +4952,6 @@
|
|||||||
"q": "^1.1.2"
|
"q": "^1.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"codemirror": {
|
|
||||||
"version": "5.58.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.58.3.tgz",
|
|
||||||
"integrity": "sha512-KBhB+juiyOOgn0AqtRmWyAT3yoElkuvWTI6hsHa9E6GQrl6bk/fdAYcvuqW1/upO9T9rtEtapWdw4XYcNiVDEA=="
|
|
||||||
},
|
|
||||||
"collection-visit": {
|
"collection-visit": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
|
||||||
@@ -6230,6 +6230,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"diff-match-patch": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="
|
||||||
|
},
|
||||||
"diff-sequences": {
|
"diff-sequences": {
|
||||||
"version": "24.9.0",
|
"version": "24.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz",
|
||||||
@@ -11295,11 +11300,15 @@
|
|||||||
"integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
|
"integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"lodash.get": {
|
||||||
|
"version": "4.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||||
|
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
|
||||||
|
},
|
||||||
"lodash.isequal": {
|
"lodash.isequal": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||||
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
|
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"lodash.memoize": {
|
"lodash.memoize": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
@@ -14175,6 +14184,18 @@
|
|||||||
"prop-types": "^15.6.2"
|
"prop-types": "^15.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-ace": {
|
||||||
|
"version": "9.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-ace/-/react-ace-9.3.0.tgz",
|
||||||
|
"integrity": "sha512-RWPDwVobLvyD0wDoHHQqEnn9pNQBhMnmo6LmRACkaXxAg3UQZpse6x9JFLC5EXyWby+P3uolIlQPct4NFEBPNg==",
|
||||||
|
"requires": {
|
||||||
|
"ace-builds": "^1.4.6",
|
||||||
|
"diff-match-patch": "^1.0.4",
|
||||||
|
"lodash.get": "^4.4.2",
|
||||||
|
"lodash.isequal": "^4.5.0",
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-app-polyfill": {
|
"react-app-polyfill": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz",
|
||||||
@@ -14203,11 +14224,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-codemirror2": {
|
|
||||||
"version": "6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-rutEKVgvFhWcy/GeVA1hFbqrO89qLqgqdhUr7YhYgIzdyICdlRQv+ztuNvOFQMXrO0fLt0VkaYOdMdYdQgsSUA=="
|
|
||||||
},
|
|
||||||
"react-dev-utils": {
|
"react-dev-utils": {
|
||||||
"version": "10.2.1",
|
"version": "10.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz",
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
"@patternfly/react-core": "^4.90.2",
|
"@patternfly/react-core": "^4.90.2",
|
||||||
"@patternfly/react-icons": "4.7.22",
|
"@patternfly/react-icons": "4.7.22",
|
||||||
"@patternfly/react-table": "^4.19.15",
|
"@patternfly/react-table": "^4.19.15",
|
||||||
|
"ace-builds": "^1.4.12",
|
||||||
"ansi-to-html": "^0.6.11",
|
"ansi-to-html": "^0.6.11",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"codemirror": "^5.47.0",
|
|
||||||
"d3": "^5.12.0",
|
"d3": "^5.12.0",
|
||||||
"dagre": "^0.8.4",
|
"dagre": "^0.8.4",
|
||||||
"formik": "^2.1.2",
|
"formik": "^2.1.2",
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^3.13.1",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-codemirror2": "^6.0.0",
|
"react-ace": "^9.3.0",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
"react-router-dom": "^5.1.2",
|
"react-router-dom": "^5.1.2",
|
||||||
"react-virtualized": "^9.21.1",
|
"react-virtualized": "^9.21.1",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import styled from 'styled-components';
|
|||||||
import { BrandName } from '../../variables';
|
import { BrandName } from '../../variables';
|
||||||
import AnsibleSelect from '../AnsibleSelect';
|
import AnsibleSelect from '../AnsibleSelect';
|
||||||
import FormField from '../FormField';
|
import FormField from '../FormField';
|
||||||
import { VariablesField } from '../CodeMirrorInput';
|
import { VariablesField } from '../CodeEditor';
|
||||||
import {
|
import {
|
||||||
FormColumnLayout,
|
FormColumnLayout,
|
||||||
FormFullWidthLayout,
|
FormFullWidthLayout,
|
||||||
|
|||||||
193
awx/ui_next/src/components/CodeEditor/CodeEditor.jsx
Normal file
193
awx/ui_next/src/components/CodeEditor/CodeEditor.jsx
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
import React, { useEffect, useRef, useCallback } from 'react';
|
||||||
|
import { oneOf, bool, number, string, func } from 'prop-types';
|
||||||
|
import ReactAce from 'react-ace';
|
||||||
|
import 'ace-builds/src-noconflict/mode-json';
|
||||||
|
import 'ace-builds/src-noconflict/mode-javascript';
|
||||||
|
import 'ace-builds/src-noconflict/mode-yaml';
|
||||||
|
import 'ace-builds/src-noconflict/mode-django';
|
||||||
|
import 'ace-builds/src-noconflict/theme-github';
|
||||||
|
import { withI18n } from '@lingui/react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import debounce from '../../util/debounce';
|
||||||
|
|
||||||
|
const LINE_HEIGHT = 24;
|
||||||
|
const PADDING = 12;
|
||||||
|
|
||||||
|
const FocusWrapper = styled.div`
|
||||||
|
&& + .keyboard-help-text {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.1s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-within + .keyboard-help-text {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .ace_hidden-cursors .ace_cursor {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const AceEditor = styled(ReactAce)`
|
||||||
|
font-family: var(--pf-global--FontFamily--monospace);
|
||||||
|
max-height: 90vh;
|
||||||
|
|
||||||
|
& .ace_gutter,
|
||||||
|
& .ace_scroller {
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .ace_mobile-menu {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
${props =>
|
||||||
|
props.hasErrors &&
|
||||||
|
`
|
||||||
|
&& {
|
||||||
|
--pf-c-form-control--PaddingRight: var(--pf-c-form-control--invalid--PaddingRight);
|
||||||
|
--pf-c-form-control--BorderBottomColor: var(--pf-c-form-control--invalid--BorderBottomColor);
|
||||||
|
padding-right: 24px;
|
||||||
|
padding-bottom: var(--pf-c-form-control--invalid--PaddingBottom);
|
||||||
|
background: var(--pf-c-form-control--invalid--Background);
|
||||||
|
border-bottom-width: var(--pf-c-form-control--invalid--BorderBottomWidth);
|
||||||
|
}`}
|
||||||
|
|
||||||
|
${props =>
|
||||||
|
props.setOptions.readOnly &&
|
||||||
|
`
|
||||||
|
&& .ace_cursor {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`;
|
||||||
|
AceEditor.displayName = 'AceEditor';
|
||||||
|
|
||||||
|
function CodeEditor({
|
||||||
|
id,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
mode,
|
||||||
|
readOnly,
|
||||||
|
hasErrors,
|
||||||
|
rows,
|
||||||
|
fullHeight,
|
||||||
|
className,
|
||||||
|
i18n,
|
||||||
|
}) {
|
||||||
|
const wrapper = useRef(null);
|
||||||
|
const editor = useRef(null);
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
function removeTextareaTabIndex() {
|
||||||
|
const editorInput = editor.current.refEditor?.querySelector('textarea');
|
||||||
|
if (editorInput && !readOnly) {
|
||||||
|
editorInput.tabIndex = -1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[readOnly]
|
||||||
|
);
|
||||||
|
|
||||||
|
const listen = useCallback(event => {
|
||||||
|
if (wrapper.current === document.activeElement && event.key === 'Enter') {
|
||||||
|
const editorInput = editor.current.refEditor?.querySelector('textarea');
|
||||||
|
if (!editorInput) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
editorInput.focus();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(function addKeyEventListeners() {
|
||||||
|
const wrapperEl = wrapper.current;
|
||||||
|
wrapperEl.addEventListener('keydown', listen);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
wrapperEl.removeEventListener('keydown', listen);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const aceModes = {
|
||||||
|
javascript: 'json',
|
||||||
|
yaml: 'yaml',
|
||||||
|
jinja2: 'django',
|
||||||
|
};
|
||||||
|
|
||||||
|
const numRows = fullHeight ? value.split('\n').length : rows;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FocusWrapper ref={wrapper} tabIndex={readOnly ? -1 : 0}>
|
||||||
|
<AceEditor
|
||||||
|
mode={aceModes[mode] || 'text'}
|
||||||
|
className={`pf-c-form-control ${className}`}
|
||||||
|
theme="github"
|
||||||
|
onChange={debounce(onChange, 250)}
|
||||||
|
value={value}
|
||||||
|
name={id || 'code-editor'}
|
||||||
|
editorProps={{ $blockScrolling: true }}
|
||||||
|
fontSize={16}
|
||||||
|
width="100%"
|
||||||
|
height={`${numRows * LINE_HEIGHT + PADDING}px`}
|
||||||
|
hasErrors={hasErrors}
|
||||||
|
setOptions={{
|
||||||
|
readOnly,
|
||||||
|
highlightActiveLine: !readOnly,
|
||||||
|
highlightGutterLine: !readOnly,
|
||||||
|
useWorker: false,
|
||||||
|
showPrintMargin: false,
|
||||||
|
}}
|
||||||
|
commands={[
|
||||||
|
{
|
||||||
|
name: 'escape',
|
||||||
|
bindKey: { win: 'Esc', mac: 'Esc' },
|
||||||
|
exec: () => {
|
||||||
|
wrapper.current.focus();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab escape',
|
||||||
|
bindKey: { win: 'Shift-Tab', mac: 'Shift-Tab' },
|
||||||
|
exec: () => {
|
||||||
|
wrapper.current.focus();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
ref={editor}
|
||||||
|
/>
|
||||||
|
</FocusWrapper>
|
||||||
|
{!readOnly && (
|
||||||
|
<div
|
||||||
|
className="pf-c-form__helper-text keyboard-help-text"
|
||||||
|
aria-live="polite"
|
||||||
|
>
|
||||||
|
{i18n._(t`Press Enter to edit. Press ESC to stop editing.`)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
CodeEditor.propTypes = {
|
||||||
|
value: string.isRequired,
|
||||||
|
onChange: func,
|
||||||
|
mode: oneOf(['javascript', 'yaml', 'jinja2']).isRequired,
|
||||||
|
readOnly: bool,
|
||||||
|
hasErrors: bool,
|
||||||
|
fullHeight: bool,
|
||||||
|
rows: number,
|
||||||
|
className: string,
|
||||||
|
};
|
||||||
|
CodeEditor.defaultProps = {
|
||||||
|
readOnly: false,
|
||||||
|
onChange: () => {},
|
||||||
|
rows: 6,
|
||||||
|
fullHeight: false,
|
||||||
|
hasErrors: false,
|
||||||
|
className: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withI18n()(CodeEditor);
|
||||||
44
awx/ui_next/src/components/CodeEditor/CodeEditor.test.jsx
Normal file
44
awx/ui_next/src/components/CodeEditor/CodeEditor.test.jsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
|
||||||
|
import CodeEditor from './CodeEditor';
|
||||||
|
import debounce from '../../util/debounce';
|
||||||
|
|
||||||
|
jest.mock('../../util/debounce');
|
||||||
|
|
||||||
|
describe('CodeEditor', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
document.body.createTextRange = jest.fn();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass value and mode through to ace editor', () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
const wrapper = mountWithContexts(
|
||||||
|
<CodeEditor value={'---\nfoo: bar'} onChange={onChange} mode="yaml" />
|
||||||
|
);
|
||||||
|
const aceEditor = wrapper.find('AceEditor');
|
||||||
|
expect(aceEditor.prop('mode')).toEqual('yaml');
|
||||||
|
expect(aceEditor.prop('setOptions').readOnly).toEqual(false);
|
||||||
|
expect(aceEditor.prop('value')).toEqual('---\nfoo: bar');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should trigger onChange prop', () => {
|
||||||
|
debounce.mockImplementation(fn => fn);
|
||||||
|
const onChange = jest.fn();
|
||||||
|
const wrapper = mountWithContexts(
|
||||||
|
<CodeEditor value="---" onChange={onChange} mode="yaml" />
|
||||||
|
);
|
||||||
|
const aceEditor = wrapper.find('AceEditor');
|
||||||
|
aceEditor.prop('onChange')('newvalue');
|
||||||
|
expect(onChange).toHaveBeenCalledWith('newvalue');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render in read only mode', () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
const wrapper = mountWithContexts(
|
||||||
|
<CodeEditor value="---" onChange={onChange} mode="yaml" readOnly />
|
||||||
|
);
|
||||||
|
const aceEditor = wrapper.find('AceEditor');
|
||||||
|
expect(aceEditor.prop('setOptions').readOnly).toEqual(true);
|
||||||
|
expect(aceEditor.prop('value')).toEqual('---');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -11,10 +11,10 @@ import {
|
|||||||
} from 'prop-types';
|
} from 'prop-types';
|
||||||
import { useField } from 'formik';
|
import { useField } from 'formik';
|
||||||
import { FormGroup } from '@patternfly/react-core';
|
import { FormGroup } from '@patternfly/react-core';
|
||||||
import CodeMirrorInput from './CodeMirrorInput';
|
import CodeEditor from './CodeEditor';
|
||||||
import Popover from '../Popover';
|
import Popover from '../Popover';
|
||||||
|
|
||||||
function CodeMirrorField({
|
function CodeEditorField({
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
label,
|
label,
|
||||||
@@ -39,7 +39,7 @@ function CodeMirrorField({
|
|||||||
label={label}
|
label={label}
|
||||||
labelIcon={<Popover content={tooltip} />}
|
labelIcon={<Popover content={tooltip} />}
|
||||||
>
|
>
|
||||||
<CodeMirrorInput
|
<CodeEditor
|
||||||
id={id}
|
id={id}
|
||||||
{...rest}
|
{...rest}
|
||||||
{...field}
|
{...field}
|
||||||
@@ -51,7 +51,7 @@ function CodeMirrorField({
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
CodeMirrorField.propTypes = {
|
CodeEditorField.propTypes = {
|
||||||
helperText: string,
|
helperText: string,
|
||||||
id: string.isRequired,
|
id: string.isRequired,
|
||||||
name: string.isRequired,
|
name: string.isRequired,
|
||||||
@@ -63,7 +63,7 @@ CodeMirrorField.propTypes = {
|
|||||||
rows: number,
|
rows: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
CodeMirrorField.defaultProps = {
|
CodeEditorField.defaultProps = {
|
||||||
helperText: '',
|
helperText: '',
|
||||||
validate: () => {},
|
validate: () => {},
|
||||||
isRequired: false,
|
isRequired: false,
|
||||||
@@ -71,4 +71,4 @@ CodeMirrorField.defaultProps = {
|
|||||||
rows: 5,
|
rows: 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CodeMirrorField;
|
export default CodeEditorField;
|
||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
isJsonObject,
|
isJsonObject,
|
||||||
isJsonString,
|
isJsonString,
|
||||||
} from '../../util/yaml';
|
} from '../../util/yaml';
|
||||||
import CodeMirrorInput from './CodeMirrorInput';
|
import CodeEditor from './CodeEditor';
|
||||||
import { JSON_MODE, YAML_MODE } from './constants';
|
import { JSON_MODE, YAML_MODE } from './constants';
|
||||||
|
|
||||||
function getValueAsMode(value, mode) {
|
function getValueAsMode(value, mode) {
|
||||||
@@ -99,7 +99,7 @@ function VariablesDetail({ dataCy, helpText, value, label, rows, fullHeight }) {
|
|||||||
fullWidth
|
fullWidth
|
||||||
css="grid-column: 1 / -1; margin-top: -20px"
|
css="grid-column: 1 / -1; margin-top: -20px"
|
||||||
>
|
>
|
||||||
<CodeMirrorInput
|
<CodeEditor
|
||||||
mode={mode}
|
mode={mode}
|
||||||
value={currentValue}
|
value={currentValue}
|
||||||
readOnly
|
readOnly
|
||||||
@@ -6,11 +6,11 @@ import VariablesDetail from './VariablesDetail';
|
|||||||
jest.mock('../../api');
|
jest.mock('../../api');
|
||||||
|
|
||||||
describe('<VariablesDetail>', () => {
|
describe('<VariablesDetail>', () => {
|
||||||
test('should render readonly CodeMirrorInput', () => {
|
test('should render readonly CodeEditor', () => {
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<VariablesDetail value="---foo: bar" label="Variables" />
|
<VariablesDetail value="---foo: bar" label="Variables" />
|
||||||
);
|
);
|
||||||
const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput');
|
const input = wrapper.find('VariablesDetail___StyledCodeEditor');
|
||||||
expect(input).toHaveLength(1);
|
expect(input).toHaveLength(1);
|
||||||
expect(input.prop('mode')).toEqual('yaml');
|
expect(input.prop('mode')).toEqual('yaml');
|
||||||
expect(input.prop('value')).toEqual('---foo: bar');
|
expect(input.prop('value')).toEqual('---foo: bar');
|
||||||
@@ -21,7 +21,7 @@ describe('<VariablesDetail>', () => {
|
|||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<VariablesDetail value='{"foo": "bar"}' label="Variables" />
|
<VariablesDetail value='{"foo": "bar"}' label="Variables" />
|
||||||
);
|
);
|
||||||
const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput');
|
const input = wrapper.find('VariablesDetail___StyledCodeEditor');
|
||||||
expect(input).toHaveLength(1);
|
expect(input).toHaveLength(1);
|
||||||
expect(input.prop('mode')).toEqual('javascript');
|
expect(input.prop('mode')).toEqual('javascript');
|
||||||
expect(input.prop('value')).toEqual('{"foo": "bar"}');
|
expect(input.prop('value')).toEqual('{"foo": "bar"}');
|
||||||
@@ -32,12 +32,12 @@ describe('<VariablesDetail>', () => {
|
|||||||
<VariablesDetail value="---foo: bar" label="Variables" />
|
<VariablesDetail value="---foo: bar" label="Variables" />
|
||||||
);
|
);
|
||||||
wrapper.find('MultiButtonToggle').invoke('onChange')('javascript');
|
wrapper.find('MultiButtonToggle').invoke('onChange')('javascript');
|
||||||
const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput');
|
const input = wrapper.find('VariablesDetail___StyledCodeEditor');
|
||||||
expect(input.prop('mode')).toEqual('javascript');
|
expect(input.prop('mode')).toEqual('javascript');
|
||||||
expect(input.prop('value')).toEqual('{\n "foo": "bar"\n}');
|
expect(input.prop('value')).toEqual('{\n "foo": "bar"\n}');
|
||||||
|
|
||||||
wrapper.find('MultiButtonToggle').invoke('onChange')('yaml');
|
wrapper.find('MultiButtonToggle').invoke('onChange')('yaml');
|
||||||
const input2 = wrapper.find('VariablesDetail___StyledCodeMirrorInput');
|
const input2 = wrapper.find('VariablesDetail___StyledCodeEditor');
|
||||||
expect(input2.prop('mode')).toEqual('yaml');
|
expect(input2.prop('mode')).toEqual('yaml');
|
||||||
expect(input2.prop('value')).toEqual('foo: bar\n');
|
expect(input2.prop('value')).toEqual('foo: bar\n');
|
||||||
});
|
});
|
||||||
@@ -46,9 +46,7 @@ describe('<VariablesDetail>', () => {
|
|||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<VariablesDetail value="" label="Variables" />
|
<VariablesDetail value="" label="Variables" />
|
||||||
);
|
);
|
||||||
expect(wrapper.find('VariablesDetail___StyledCodeMirrorInput').length).toBe(
|
expect(wrapper.find('VariablesDetail___StyledCodeEditor').length).toBe(1);
|
||||||
1
|
|
||||||
);
|
|
||||||
expect(wrapper.find('div.pf-c-form__label').text()).toBe('Variables');
|
expect(wrapper.find('div.pf-c-form__label').text()).toBe('Variables');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -63,7 +61,7 @@ describe('<VariablesDetail>', () => {
|
|||||||
value: '---bar: baz',
|
value: '---bar: baz',
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput');
|
const input = wrapper.find('VariablesDetail___StyledCodeEditor');
|
||||||
expect(input.prop('mode')).toEqual('javascript');
|
expect(input.prop('mode')).toEqual('javascript');
|
||||||
expect(input.prop('value')).toEqual('{\n "bar": "baz"\n}');
|
expect(input.prop('value')).toEqual('{\n "bar": "baz"\n}');
|
||||||
});
|
});
|
||||||
@@ -72,7 +70,7 @@ describe('<VariablesDetail>', () => {
|
|||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<VariablesDetail value="" label="Variables" />
|
<VariablesDetail value="" label="Variables" />
|
||||||
);
|
);
|
||||||
const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput');
|
const input = wrapper.find('VariablesDetail___StyledCodeEditor');
|
||||||
expect(input.prop('value')).toEqual('---');
|
expect(input.prop('value')).toEqual('---');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -84,7 +82,7 @@ describe('<VariablesDetail>', () => {
|
|||||||
wrapper.find('MultiButtonToggle').invoke('onChange')('javascript');
|
wrapper.find('MultiButtonToggle').invoke('onChange')('javascript');
|
||||||
});
|
});
|
||||||
wrapper.setProps({ value: '' });
|
wrapper.setProps({ value: '' });
|
||||||
const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput');
|
const input = wrapper.find('VariablesDetail___StyledCodeEditor');
|
||||||
expect(input.prop('value')).toEqual('{}');
|
expect(input.prop('value')).toEqual('{}');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -8,7 +8,7 @@ import { Split, SplitItem } from '@patternfly/react-core';
|
|||||||
import { CheckboxField } from '../FormField';
|
import { CheckboxField } from '../FormField';
|
||||||
import MultiButtonToggle from '../MultiButtonToggle';
|
import MultiButtonToggle from '../MultiButtonToggle';
|
||||||
import { yamlToJson, jsonToYaml, isJsonString } from '../../util/yaml';
|
import { yamlToJson, jsonToYaml, isJsonString } from '../../util/yaml';
|
||||||
import CodeMirrorInput from './CodeMirrorInput';
|
import CodeEditor from './CodeEditor';
|
||||||
import Popover from '../Popover';
|
import Popover from '../Popover';
|
||||||
import { JSON_MODE, YAML_MODE } from './constants';
|
import { JSON_MODE, YAML_MODE } from './constants';
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ function VariablesField({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</FieldHeader>
|
</FieldHeader>
|
||||||
<CodeMirrorInput
|
<CodeEditor
|
||||||
mode={mode}
|
mode={mode}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
{...field}
|
{...field}
|
||||||
@@ -9,7 +9,7 @@ describe('VariablesField', () => {
|
|||||||
document.body.createTextRange = jest.fn();
|
document.body.createTextRange = jest.fn();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render code mirror input', () => {
|
it('should render code editor', () => {
|
||||||
const value = '---\n';
|
const value = '---\n';
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<Formik initialValues={{ variables: value }}>
|
<Formik initialValues={{ variables: value }}>
|
||||||
@@ -18,12 +18,12 @@ describe('VariablesField', () => {
|
|||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
);
|
);
|
||||||
const codemirror = wrapper.find('Controlled');
|
const codeEditor = wrapper.find('CodeEditor');
|
||||||
expect(codemirror.prop('value')).toEqual(value);
|
expect(codeEditor.prop('value')).toEqual(value);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render yaml/json toggles', async () => {
|
it('should toggle between yaml/json', async () => {
|
||||||
const value = '---\n';
|
const value = '---\nfoo: bar\nbaz: 3';
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<Formik initialValues={{ variables: value }}>
|
<Formik initialValues={{ variables: value }}>
|
||||||
{() => (
|
{() => (
|
||||||
@@ -39,7 +39,10 @@ describe('VariablesField', () => {
|
|||||||
buttons.at(1).simulate('click');
|
buttons.at(1).simulate('click');
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.find('CodeMirrorInput').prop('mode')).toEqual('javascript');
|
expect(wrapper.find('CodeEditor').prop('mode')).toEqual('javascript');
|
||||||
|
expect(wrapper.find('CodeEditor').prop('value')).toEqual(
|
||||||
|
'{\n "foo": "bar",\n "baz": 3\n}'
|
||||||
|
);
|
||||||
const buttons2 = wrapper.find('Button');
|
const buttons2 = wrapper.find('Button');
|
||||||
expect(buttons2.at(0).prop('variant')).toEqual('secondary');
|
expect(buttons2.at(0).prop('variant')).toEqual('secondary');
|
||||||
expect(buttons2.at(1).prop('variant')).toEqual('primary');
|
expect(buttons2.at(1).prop('variant')).toEqual('primary');
|
||||||
@@ -47,7 +50,10 @@ describe('VariablesField', () => {
|
|||||||
buttons2.at(0).simulate('click');
|
buttons2.at(0).simulate('click');
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.find('CodeMirrorInput').prop('mode')).toEqual('yaml');
|
expect(wrapper.find('CodeEditor').prop('mode')).toEqual('yaml');
|
||||||
|
expect(wrapper.find('CodeEditor').prop('value')).toEqual(
|
||||||
|
'foo: bar\nbaz: 3\n'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set Formik error if yaml is invalid', async () => {
|
it('should set Formik error if yaml is invalid', async () => {
|
||||||
@@ -65,10 +71,11 @@ describe('VariablesField', () => {
|
|||||||
.simulate('click');
|
.simulate('click');
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|
||||||
const field = wrapper.find('CodeMirrorInput');
|
const field = wrapper.find('CodeEditor');
|
||||||
expect(field.prop('hasErrors')).toEqual(true);
|
expect(field.prop('hasErrors')).toEqual(true);
|
||||||
expect(wrapper.find('.pf-m-error')).toHaveLength(1);
|
expect(wrapper.find('.pf-m-error')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render tooltip', () => {
|
it('should render tooltip', () => {
|
||||||
const value = '---\n';
|
const value = '---\n';
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
@@ -102,9 +109,7 @@ describe('VariablesField', () => {
|
|||||||
</Formik>
|
</Formik>
|
||||||
);
|
);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('CodeMirrorInput').invoke('onChange')(
|
wrapper.find('CodeEditor').invoke('onChange')('---\nnewval: changed');
|
||||||
'---\nnewval: changed'
|
|
||||||
);
|
|
||||||
wrapper.find('form').simulate('submit');
|
wrapper.find('form').simulate('submit');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -129,6 +134,6 @@ describe('VariablesField', () => {
|
|||||||
</Formik>
|
</Formik>
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(wrapper.find('CodeMirrorInput').prop('mode')).toEqual('javascript');
|
expect(wrapper.find('CodeEditor').prop('mode')).toEqual('javascript');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -4,7 +4,7 @@ import { Split, SplitItem } from '@patternfly/react-core';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { yamlToJson, jsonToYaml, isJsonString } from '../../util/yaml';
|
import { yamlToJson, jsonToYaml, isJsonString } from '../../util/yaml';
|
||||||
import MultiButtonToggle from '../MultiButtonToggle';
|
import MultiButtonToggle from '../MultiButtonToggle';
|
||||||
import CodeMirrorInput from './CodeMirrorInput';
|
import CodeEditor from './CodeEditor';
|
||||||
import { JSON_MODE, YAML_MODE } from './constants';
|
import { JSON_MODE, YAML_MODE } from './constants';
|
||||||
|
|
||||||
function formatJson(jsonString) {
|
function formatJson(jsonString) {
|
||||||
@@ -63,7 +63,7 @@ function VariablesInput(props) {
|
|||||||
/>
|
/>
|
||||||
</SplitItemRight>
|
</SplitItemRight>
|
||||||
</Split>
|
</Split>
|
||||||
<CodeMirrorInput
|
<CodeEditor
|
||||||
mode={mode}
|
mode={mode}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
value={value}
|
value={value}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import CodeMirrorInput from './CodeMirrorInput';
|
import CodeEditor from './CodeEditor';
|
||||||
|
|
||||||
export default CodeMirrorInput;
|
export default CodeEditor;
|
||||||
export { default as CodeMirrorField } from './CodeMirrorField';
|
export { default as CodeEditorField } from './CodeEditorField';
|
||||||
export { default as VariablesDetail } from './VariablesDetail';
|
export { default as VariablesDetail } from './VariablesDetail';
|
||||||
export { default as VariablesInput } from './VariablesInput';
|
export { default as VariablesInput } from './VariablesInput';
|
||||||
export { default as VariablesField } from './VariablesField';
|
export { default as VariablesField } from './VariablesField';
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import { oneOf, bool, number, string, func } from 'prop-types';
|
|
||||||
import { Controlled as ReactCodeMirror } from 'react-codemirror2';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import 'codemirror/mode/javascript/javascript';
|
|
||||||
import 'codemirror/mode/yaml/yaml';
|
|
||||||
import 'codemirror/mode/jinja2/jinja2';
|
|
||||||
import 'codemirror/lib/codemirror.css';
|
|
||||||
import 'codemirror/addon/display/placeholder';
|
|
||||||
|
|
||||||
const LINE_HEIGHT = 24;
|
|
||||||
const PADDING = 12;
|
|
||||||
|
|
||||||
const CodeMirror = styled(ReactCodeMirror)`
|
|
||||||
&& {
|
|
||||||
height: initial;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .CodeMirror {
|
|
||||||
height: ${props =>
|
|
||||||
props.fullHeight ? 'auto' : `${props.rows * LINE_HEIGHT + PADDING}px`};
|
|
||||||
font-family: var(--pf-global--FontFamily--monospace);
|
|
||||||
}
|
|
||||||
|
|
||||||
${props =>
|
|
||||||
props.hasErrors &&
|
|
||||||
`
|
|
||||||
&& {
|
|
||||||
--pf-c-form-control--PaddingRight: var(--pf-c-form-control--invalid--PaddingRight);
|
|
||||||
--pf-c-form-control--BorderBottomColor: var(--pf-c-form-control--invalid--BorderBottomColor);
|
|
||||||
padding-right: 24px;
|
|
||||||
padding-bottom: var(--pf-c-form-control--invalid--PaddingBottom);
|
|
||||||
background: var(--pf-c-form-control--invalid--Background);
|
|
||||||
border-bottom-width: var(--pf-c-form-control--invalid--BorderBottomWidth);
|
|
||||||
}`}
|
|
||||||
|
|
||||||
${props =>
|
|
||||||
props.options &&
|
|
||||||
props.options.readOnly &&
|
|
||||||
`
|
|
||||||
&,
|
|
||||||
&:hover {
|
|
||||||
--pf-c-form-control--BorderBottomColor: var(--pf-global--BorderColor--300);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-cursors {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-lines {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-scroll {
|
|
||||||
background-color: var(--pf-c-form-control--disabled--BackgroundColor);
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
${props =>
|
|
||||||
props.options &&
|
|
||||||
props.options.placeholder &&
|
|
||||||
`
|
|
||||||
.CodeMirror-empty {
|
|
||||||
pre.CodeMirror-placeholder {
|
|
||||||
color: var(--pf-c-form-control--placeholder--Color);
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
`;
|
|
||||||
|
|
||||||
function CodeMirrorInput({
|
|
||||||
value,
|
|
||||||
onChange,
|
|
||||||
mode,
|
|
||||||
readOnly,
|
|
||||||
hasErrors,
|
|
||||||
rows,
|
|
||||||
fullHeight,
|
|
||||||
className,
|
|
||||||
placeholder,
|
|
||||||
}) {
|
|
||||||
// Workaround for CodeMirror bug: If CodeMirror renders in a modal on the
|
|
||||||
// modal's initial render, it appears as an empty box due to mis-calculated
|
|
||||||
// element height. Forcing an initial render before mounting <CodeMirror>
|
|
||||||
// fixes this.
|
|
||||||
const [isInitialized, setIsInitialized] = useState(false);
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isInitialized) {
|
|
||||||
setIsInitialized(true);
|
|
||||||
}
|
|
||||||
}, [isInitialized]);
|
|
||||||
if (!isInitialized) {
|
|
||||||
return <div />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CodeMirror
|
|
||||||
className={`pf-c-form-control ${className}`}
|
|
||||||
value={value}
|
|
||||||
onBeforeChange={(editor, data, val) => onChange(val)}
|
|
||||||
mode={mode}
|
|
||||||
hasErrors={hasErrors}
|
|
||||||
options={{
|
|
||||||
smartIndent: false,
|
|
||||||
lineNumbers: true,
|
|
||||||
lineWrapping: true,
|
|
||||||
placeholder,
|
|
||||||
readOnly,
|
|
||||||
}}
|
|
||||||
fullHeight={fullHeight}
|
|
||||||
rows={rows}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
CodeMirrorInput.propTypes = {
|
|
||||||
value: string.isRequired,
|
|
||||||
onChange: func,
|
|
||||||
mode: oneOf(['javascript', 'yaml', 'jinja2']).isRequired,
|
|
||||||
readOnly: bool,
|
|
||||||
hasErrors: bool,
|
|
||||||
fullHeight: bool,
|
|
||||||
rows: number,
|
|
||||||
className: string,
|
|
||||||
};
|
|
||||||
CodeMirrorInput.defaultProps = {
|
|
||||||
readOnly: false,
|
|
||||||
onChange: () => {},
|
|
||||||
rows: 6,
|
|
||||||
fullHeight: false,
|
|
||||||
hasErrors: false,
|
|
||||||
className: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CodeMirrorInput;
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { mount } from 'enzyme';
|
|
||||||
import CodeMirrorInput from './CodeMirrorInput';
|
|
||||||
|
|
||||||
describe('CodeMirrorInput', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
document.body.createTextRange = jest.fn();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should trigger onChange prop', () => {
|
|
||||||
const onChange = jest.fn();
|
|
||||||
const wrapper = mount(
|
|
||||||
<CodeMirrorInput value="---\n" onChange={onChange} mode="yaml" />
|
|
||||||
);
|
|
||||||
const codemirror = wrapper.find('Controlled');
|
|
||||||
expect(codemirror.prop('mode')).toEqual('yaml');
|
|
||||||
expect(codemirror.prop('options').readOnly).toEqual(false);
|
|
||||||
codemirror.prop('onBeforeChange')(null, null, 'newvalue');
|
|
||||||
expect(onChange).toHaveBeenCalledWith('newvalue');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render in read only mode', () => {
|
|
||||||
const onChange = jest.fn();
|
|
||||||
const wrapper = mount(
|
|
||||||
<CodeMirrorInput value="---\n" onChange={onChange} mode="yaml" readOnly />
|
|
||||||
);
|
|
||||||
const codemirror = wrapper.find('Controlled');
|
|
||||||
expect(codemirror.prop('options').readOnly).toEqual(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
} from 'prop-types';
|
} from 'prop-types';
|
||||||
import { TextListItemVariants } from '@patternfly/react-core';
|
import { TextListItemVariants } from '@patternfly/react-core';
|
||||||
import { DetailName, DetailValue } from './Detail';
|
import { DetailName, DetailValue } from './Detail';
|
||||||
import CodeMirrorInput from '../CodeMirrorInput';
|
import CodeEditor from '../CodeEditor';
|
||||||
import Popover from '../Popover';
|
import Popover from '../Popover';
|
||||||
|
|
||||||
function CodeDetail({
|
function CodeDetail({
|
||||||
@@ -52,7 +52,7 @@ function CodeDetail({
|
|||||||
css="grid-column: 1 / -1; margin-top: -20px"
|
css="grid-column: 1 / -1; margin-top: -20px"
|
||||||
data-cy={valueCy}
|
data-cy={valueCy}
|
||||||
>
|
>
|
||||||
<CodeMirrorInput
|
<CodeEditor
|
||||||
mode={mode}
|
mode={mode}
|
||||||
value={value}
|
value={value}
|
||||||
readOnly
|
readOnly
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { t } from '@lingui/macro';
|
|||||||
import { Form, FormGroup } from '@patternfly/react-core';
|
import { Form, FormGroup } from '@patternfly/react-core';
|
||||||
import FormField, { FormSubmitError } from '../FormField';
|
import FormField, { FormSubmitError } from '../FormField';
|
||||||
import FormActionGroup from '../FormActionGroup/FormActionGroup';
|
import FormActionGroup from '../FormActionGroup/FormActionGroup';
|
||||||
import { VariablesField } from '../CodeMirrorInput';
|
import { VariablesField } from '../CodeEditor';
|
||||||
import { InventoryLookup } from '../Lookup';
|
import { InventoryLookup } from '../Lookup';
|
||||||
import { FormColumnLayout, FormFullWidthLayout } from '../FormLayout';
|
import { FormColumnLayout, FormFullWidthLayout } from '../FormLayout';
|
||||||
import Popover from '../Popover';
|
import Popover from '../Popover';
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import styled from 'styled-components';
|
|||||||
import FormField from '../../FormField';
|
import FormField from '../../FormField';
|
||||||
import { TagMultiSelect } from '../../MultiSelect';
|
import { TagMultiSelect } from '../../MultiSelect';
|
||||||
import AnsibleSelect from '../../AnsibleSelect';
|
import AnsibleSelect from '../../AnsibleSelect';
|
||||||
import { VariablesField } from '../../CodeMirrorInput';
|
import { VariablesField } from '../../CodeEditor';
|
||||||
import Popover from '../../Popover';
|
import Popover from '../../Popover';
|
||||||
|
|
||||||
const FieldHeader = styled.div`
|
const FieldHeader = styled.div`
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { toTitleCase } from '../../util/strings';
|
|||||||
import CredentialChip from '../CredentialChip';
|
import CredentialChip from '../CredentialChip';
|
||||||
import ChipGroup from '../ChipGroup';
|
import ChipGroup from '../ChipGroup';
|
||||||
import { DetailList, Detail, UserDateDetail } from '../DetailList';
|
import { DetailList, Detail, UserDateDetail } from '../DetailList';
|
||||||
import { VariablesDetail } from '../CodeMirrorInput';
|
import { VariablesDetail } from '../CodeEditor';
|
||||||
|
|
||||||
import PromptProjectDetail from './PromptProjectDetail';
|
import PromptProjectDetail from './PromptProjectDetail';
|
||||||
import PromptInventorySourceDetail from './PromptInventorySourceDetail';
|
import PromptInventorySourceDetail from './PromptInventorySourceDetail';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Link } from 'react-router-dom';
|
|||||||
|
|
||||||
import { Chip, List, ListItem } from '@patternfly/react-core';
|
import { Chip, List, ListItem } from '@patternfly/react-core';
|
||||||
import { Detail, DeletedDetail } from '../DetailList';
|
import { Detail, DeletedDetail } from '../DetailList';
|
||||||
import { VariablesDetail } from '../CodeMirrorInput';
|
import { VariablesDetail } from '../CodeEditor';
|
||||||
import CredentialChip from '../CredentialChip';
|
import CredentialChip from '../CredentialChip';
|
||||||
import ChipGroup from '../ChipGroup';
|
import ChipGroup from '../ChipGroup';
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import CredentialChip from '../CredentialChip';
|
|||||||
import ChipGroup from '../ChipGroup';
|
import ChipGroup from '../ChipGroup';
|
||||||
import Sparkline from '../Sparkline';
|
import Sparkline from '../Sparkline';
|
||||||
import { Detail, DeletedDetail } from '../DetailList';
|
import { Detail, DeletedDetail } from '../DetailList';
|
||||||
import { VariablesDetail } from '../CodeMirrorInput';
|
import { VariablesDetail } from '../CodeEditor';
|
||||||
import { toTitleCase } from '../../util/strings';
|
import { toTitleCase } from '../../util/strings';
|
||||||
|
|
||||||
function PromptJobTemplateDetail({ i18n, resource }) {
|
function PromptJobTemplateDetail({ i18n, resource }) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Chip, List, ListItem } from '@patternfly/react-core';
|
|||||||
import CredentialChip from '../CredentialChip';
|
import CredentialChip from '../CredentialChip';
|
||||||
import ChipGroup from '../ChipGroup';
|
import ChipGroup from '../ChipGroup';
|
||||||
import { Detail } from '../DetailList';
|
import { Detail } from '../DetailList';
|
||||||
import { VariablesDetail } from '../CodeMirrorInput';
|
import { VariablesDetail } from '../CodeEditor';
|
||||||
import Sparkline from '../Sparkline';
|
import Sparkline from '../Sparkline';
|
||||||
import { toTitleCase } from '../../util/strings';
|
import { toTitleCase } from '../../util/strings';
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import {
|
|||||||
import DeleteButton from '../../DeleteButton';
|
import DeleteButton from '../../DeleteButton';
|
||||||
import ErrorDetail from '../../ErrorDetail';
|
import ErrorDetail from '../../ErrorDetail';
|
||||||
import ChipGroup from '../../ChipGroup';
|
import ChipGroup from '../../ChipGroup';
|
||||||
import { VariablesDetail } from '../../CodeMirrorInput';
|
import { VariablesDetail } from '../../CodeEditor';
|
||||||
import { parseVariableField } from '../../../util/yaml';
|
import { parseVariableField } from '../../../util/yaml';
|
||||||
|
|
||||||
const PromptDivider = styled(Divider)`
|
const PromptDivider = styled(Divider)`
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { SearchPlusIcon } from '@patternfly/react-icons';
|
|||||||
import { formatDateString } from '../../util/dates';
|
import { formatDateString } from '../../util/dates';
|
||||||
|
|
||||||
import { DetailList, Detail } from '../../components/DetailList';
|
import { DetailList, Detail } from '../../components/DetailList';
|
||||||
import { VariablesDetail } from '../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../components/CodeEditor';
|
||||||
|
|
||||||
function ActivityStreamDetailButton({ i18n, streamItem, user, description }) {
|
function ActivityStreamDetailButton({ i18n, streamItem, user, description }) {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ import {
|
|||||||
UserDateDetail,
|
UserDateDetail,
|
||||||
} from '../../../components/DetailList';
|
} from '../../../components/DetailList';
|
||||||
import ChipGroup from '../../../components/ChipGroup';
|
import ChipGroup from '../../../components/ChipGroup';
|
||||||
import CodeMirrorInput from '../../../components/CodeMirrorInput';
|
import CodeEditor from '../../../components/CodeEditor';
|
||||||
import CredentialChip from '../../../components/CredentialChip';
|
import CredentialChip from '../../../components/CredentialChip';
|
||||||
import ErrorDetail from '../../../components/ErrorDetail';
|
import ErrorDetail from '../../../components/ErrorDetail';
|
||||||
import { CredentialsAPI, CredentialTypesAPI } from '../../../api';
|
import { CredentialsAPI, CredentialTypesAPI } from '../../../api';
|
||||||
import { Credential } from '../../../types';
|
import { Credential } from '../../../types';
|
||||||
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
||||||
|
|
||||||
const PluginInputMetadata = styled(CodeMirrorInput)`
|
const PluginInputMetadata = styled(CodeEditor)`
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ describe('<CredentialDetail />', () => {
|
|||||||
expect(sshKeyUnlockDetail.length).toBe(1);
|
expect(sshKeyUnlockDetail.length).toBe(1);
|
||||||
expect(sshKeyUnlockDetail.find('CredentialChip').length).toBe(1);
|
expect(sshKeyUnlockDetail.find('CredentialChip').length).toBe(1);
|
||||||
expect(
|
expect(
|
||||||
wrapper.find('CodeMirrorInput#credential-ssh_key_unlock-metadata').props()
|
wrapper.find('CodeEditor#credential-ssh_key_unlock-metadata').props()
|
||||||
.value
|
.value
|
||||||
).toBe(JSON.stringify(mockInputSource.metadata, null, 2));
|
).toBe(JSON.stringify(mockInputSource.metadata, null, 2));
|
||||||
expectDetailToMatch(
|
expectDetailToMatch(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { t } from '@lingui/macro';
|
|||||||
import { Link, useHistory } from 'react-router-dom';
|
import { Link, useHistory } from 'react-router-dom';
|
||||||
import { Button } from '@patternfly/react-core';
|
import { Button } from '@patternfly/react-core';
|
||||||
|
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import AlertModal from '../../../components/AlertModal';
|
import AlertModal from '../../../components/AlertModal';
|
||||||
import { CardBody, CardActionsRow } from '../../../components/Card';
|
import { CardBody, CardActionsRow } from '../../../components/Card';
|
||||||
import DeleteButton from '../../../components/DeleteButton';
|
import DeleteButton from '../../../components/DeleteButton';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { withI18n } from '@lingui/react';
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
|
||||||
import { Form } from '@patternfly/react-core';
|
import { Form } from '@patternfly/react-core';
|
||||||
import { VariablesField } from '../../../components/CodeMirrorInput';
|
import { VariablesField } from '../../../components/CodeEditor';
|
||||||
import FormField, { FormSubmitError } from '../../../components/FormField';
|
import FormField, { FormSubmitError } from '../../../components/FormField';
|
||||||
import FormActionGroup from '../../../components/FormActionGroup';
|
import FormActionGroup from '../../../components/FormActionGroup';
|
||||||
import { required } from '../../../util/validators';
|
import { required } from '../../../util/validators';
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
Detail,
|
Detail,
|
||||||
UserDateDetail,
|
UserDateDetail,
|
||||||
} from '../../../components/DetailList';
|
} from '../../../components/DetailList';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import Sparkline from '../../../components/Sparkline';
|
import Sparkline from '../../../components/Sparkline';
|
||||||
import DeleteButton from '../../../components/DeleteButton';
|
import DeleteButton from '../../../components/DeleteButton';
|
||||||
import { HostsAPI } from '../../../api';
|
import { HostsAPI } from '../../../api';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { t } from '@lingui/macro';
|
|||||||
import { Host } from '../../../types';
|
import { Host } from '../../../types';
|
||||||
import { CardBody } from '../../../components/Card';
|
import { CardBody } from '../../../components/Card';
|
||||||
import { DetailList } from '../../../components/DetailList';
|
import { DetailList } from '../../../components/DetailList';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import ContentError from '../../../components/ContentError';
|
import ContentError from '../../../components/ContentError';
|
||||||
import ContentLoading from '../../../components/ContentLoading';
|
import ContentLoading from '../../../components/ContentLoading';
|
||||||
import useRequest from '../../../util/useRequest';
|
import useRequest from '../../../util/useRequest';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { t } from '@lingui/macro';
|
|||||||
import { Link, useHistory } from 'react-router-dom';
|
import { Link, useHistory } from 'react-router-dom';
|
||||||
import { Button, Label } from '@patternfly/react-core';
|
import { Button, Label } from '@patternfly/react-core';
|
||||||
|
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import AlertModal from '../../../components/AlertModal';
|
import AlertModal from '../../../components/AlertModal';
|
||||||
import { CardBody, CardActionsRow } from '../../../components/Card';
|
import { CardBody, CardActionsRow } from '../../../components/Card';
|
||||||
import DeleteButton from '../../../components/DeleteButton';
|
import DeleteButton from '../../../components/DeleteButton';
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
SubFormLayout,
|
SubFormLayout,
|
||||||
} from '../../../components/FormLayout';
|
} from '../../../components/FormLayout';
|
||||||
import CredentialLookup from '../../../components/Lookup/CredentialLookup';
|
import CredentialLookup from '../../../components/Lookup/CredentialLookup';
|
||||||
import { VariablesField } from '../../../components/CodeMirrorInput';
|
import { VariablesField } from '../../../components/CodeEditor';
|
||||||
|
|
||||||
function ContainerGroupFormFields({ i18n, instanceGroup }) {
|
function ContainerGroupFormFields({ i18n, instanceGroup }) {
|
||||||
const { setFieldValue } = useFormikContext();
|
const { setFieldValue } = useFormikContext();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
Detail,
|
Detail,
|
||||||
UserDateDetail,
|
UserDateDetail,
|
||||||
} from '../../../components/DetailList';
|
} from '../../../components/DetailList';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import DeleteButton from '../../../components/DeleteButton';
|
import DeleteButton from '../../../components/DeleteButton';
|
||||||
import ErrorDetail from '../../../components/ErrorDetail';
|
import ErrorDetail from '../../../components/ErrorDetail';
|
||||||
import ContentError from '../../../components/ContentError';
|
import ContentError from '../../../components/ContentError';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { t } from '@lingui/macro';
|
|||||||
import { Button } from '@patternfly/react-core';
|
import { Button } from '@patternfly/react-core';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { useHistory, useParams } from 'react-router-dom';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import { CardBody, CardActionsRow } from '../../../components/Card';
|
import { CardBody, CardActionsRow } from '../../../components/Card';
|
||||||
import ErrorDetail from '../../../components/ErrorDetail';
|
import ErrorDetail from '../../../components/ErrorDetail';
|
||||||
import AlertModal from '../../../components/AlertModal';
|
import AlertModal from '../../../components/AlertModal';
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
Detail,
|
Detail,
|
||||||
UserDateDetail,
|
UserDateDetail,
|
||||||
} from '../../../components/DetailList';
|
} from '../../../components/DetailList';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import Sparkline from '../../../components/Sparkline';
|
import Sparkline from '../../../components/Sparkline';
|
||||||
import DeleteButton from '../../../components/DeleteButton';
|
import DeleteButton from '../../../components/DeleteButton';
|
||||||
import { HostsAPI } from '../../../api';
|
import { HostsAPI } from '../../../api';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { t } from '@lingui/macro';
|
|||||||
import { Host } from '../../../types';
|
import { Host } from '../../../types';
|
||||||
import { CardBody } from '../../../components/Card';
|
import { CardBody } from '../../../components/Card';
|
||||||
import { DetailList } from '../../../components/DetailList';
|
import { DetailList } from '../../../components/DetailList';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import ContentError from '../../../components/ContentError';
|
import ContentError from '../../../components/ContentError';
|
||||||
import ContentLoading from '../../../components/ContentLoading';
|
import ContentLoading from '../../../components/ContentLoading';
|
||||||
import useRequest from '../../../util/useRequest';
|
import useRequest from '../../../util/useRequest';
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { t } from '@lingui/macro';
|
|||||||
import { Button, List, ListItem } from '@patternfly/react-core';
|
import { Button, List, ListItem } from '@patternfly/react-core';
|
||||||
import AlertModal from '../../../components/AlertModal';
|
import AlertModal from '../../../components/AlertModal';
|
||||||
import { CardBody, CardActionsRow } from '../../../components/Card';
|
import { CardBody, CardActionsRow } from '../../../components/Card';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import ContentError from '../../../components/ContentError';
|
import ContentError from '../../../components/ContentError';
|
||||||
import ContentLoading from '../../../components/ContentLoading';
|
import ContentLoading from '../../../components/ContentLoading';
|
||||||
import CredentialChip from '../../../components/CredentialChip';
|
import CredentialChip from '../../../components/CredentialChip';
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import useRequest, { useDismissableError } from '../../../util/useRequest';
|
|||||||
import AlertModal from '../../../components/AlertModal';
|
import AlertModal from '../../../components/AlertModal';
|
||||||
import { CardBody, CardActionsRow } from '../../../components/Card';
|
import { CardBody, CardActionsRow } from '../../../components/Card';
|
||||||
import ChipGroup from '../../../components/ChipGroup';
|
import ChipGroup from '../../../components/ChipGroup';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import ContentError from '../../../components/ContentError';
|
import ContentError from '../../../components/ContentError';
|
||||||
import ContentLoading from '../../../components/ContentLoading';
|
import ContentLoading from '../../../components/ContentLoading';
|
||||||
import DeleteButton from '../../../components/DeleteButton';
|
import DeleteButton from '../../../components/DeleteButton';
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ describe('<SmartInventoryEdit />', () => {
|
|||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should render CodeEditor field', () => {
|
||||||
|
expect(wrapper.find('CodeEditor').prop('value')).toEqual('---');
|
||||||
|
});
|
||||||
|
|
||||||
test('should fetch related instance groups on initial render', async () => {
|
test('should fetch related instance groups on initial render', async () => {
|
||||||
expect(InventoriesAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
|
expect(InventoriesAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
UserDateDetail,
|
UserDateDetail,
|
||||||
} from '../../../components/DetailList';
|
} from '../../../components/DetailList';
|
||||||
import Sparkline from '../../../components/Sparkline';
|
import Sparkline from '../../../components/Sparkline';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
|
|
||||||
function SmartInventoryHostDetail({ host, i18n }) {
|
function SmartInventoryHostDetail({ host, i18n }) {
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { t } from '@lingui/macro';
|
|||||||
import { func, number, shape } from 'prop-types';
|
import { func, number, shape } from 'prop-types';
|
||||||
|
|
||||||
import { Form } from '@patternfly/react-core';
|
import { Form } from '@patternfly/react-core';
|
||||||
import { VariablesField } from '../../../components/CodeMirrorInput';
|
import { VariablesField } from '../../../components/CodeEditor';
|
||||||
import FormField, { FormSubmitError } from '../../../components/FormField';
|
import FormField, { FormSubmitError } from '../../../components/FormField';
|
||||||
import FormActionGroup from '../../../components/FormActionGroup';
|
import FormActionGroup from '../../../components/FormActionGroup';
|
||||||
import { required } from '../../../util/validators';
|
import { required } from '../../../util/validators';
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ describe('<InventoryForm />', () => {
|
|||||||
1
|
1
|
||||||
);
|
);
|
||||||
expect(wrapper.find('VariablesField[label="Variables"]').length).toBe(1);
|
expect(wrapper.find('VariablesField[label="Variables"]').length).toBe(1);
|
||||||
|
expect(wrapper.find('CodeEditor').prop('value')).toEqual('---');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should update form values', async () => {
|
test('should update form values', async () => {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { t } from '@lingui/macro';
|
|||||||
import { CardBody } from '../../../components/Card';
|
import { CardBody } from '../../../components/Card';
|
||||||
import FormField, { FormSubmitError } from '../../../components/FormField';
|
import FormField, { FormSubmitError } from '../../../components/FormField';
|
||||||
import FormActionGroup from '../../../components/FormActionGroup/FormActionGroup';
|
import FormActionGroup from '../../../components/FormActionGroup/FormActionGroup';
|
||||||
import { VariablesField } from '../../../components/CodeMirrorInput';
|
import { VariablesField } from '../../../components/CodeEditor';
|
||||||
import { required } from '../../../util/validators';
|
import { required } from '../../../util/validators';
|
||||||
import {
|
import {
|
||||||
FormColumnLayout,
|
FormColumnLayout,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useField } from 'formik';
|
|||||||
import { FormGroup } from '@patternfly/react-core';
|
import { FormGroup } from '@patternfly/react-core';
|
||||||
import { minMaxValue, regExp } from '../../../../util/validators';
|
import { minMaxValue, regExp } from '../../../../util/validators';
|
||||||
import AnsibleSelect from '../../../../components/AnsibleSelect';
|
import AnsibleSelect from '../../../../components/AnsibleSelect';
|
||||||
import { VariablesField } from '../../../../components/CodeMirrorInput';
|
import { VariablesField } from '../../../../components/CodeEditor';
|
||||||
import FormField, { CheckboxField } from '../../../../components/FormField';
|
import FormField, { CheckboxField } from '../../../../components/FormField';
|
||||||
import {
|
import {
|
||||||
FormFullWidthLayout,
|
FormFullWidthLayout,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useLocation } from 'react-router-dom';
|
|||||||
import { func, shape, arrayOf } from 'prop-types';
|
import { func, shape, arrayOf } from 'prop-types';
|
||||||
import { Form } from '@patternfly/react-core';
|
import { Form } from '@patternfly/react-core';
|
||||||
import { InstanceGroup } from '../../../types';
|
import { InstanceGroup } from '../../../types';
|
||||||
import { VariablesField } from '../../../components/CodeMirrorInput';
|
import { VariablesField } from '../../../components/CodeEditor';
|
||||||
import ContentError from '../../../components/ContentError';
|
import ContentError from '../../../components/ContentError';
|
||||||
import ContentLoading from '../../../components/ContentLoading';
|
import ContentLoading from '../../../components/ContentLoading';
|
||||||
import FormActionGroup from '../../../components/FormActionGroup';
|
import FormActionGroup from '../../../components/FormActionGroup';
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
import { CardBody, CardActionsRow } from '../../../components/Card';
|
import { CardBody, CardActionsRow } from '../../../components/Card';
|
||||||
import ChipGroup from '../../../components/ChipGroup';
|
import ChipGroup from '../../../components/ChipGroup';
|
||||||
import CredentialChip from '../../../components/CredentialChip';
|
import CredentialChip from '../../../components/CredentialChip';
|
||||||
import { VariablesInput as _VariablesInput } from '../../../components/CodeMirrorInput';
|
import { VariablesInput as _VariablesInput } from '../../../components/CodeEditor';
|
||||||
import DeleteButton from '../../../components/DeleteButton';
|
import DeleteButton from '../../../components/DeleteButton';
|
||||||
import ErrorDetail from '../../../components/ErrorDetail';
|
import ErrorDetail from '../../../components/ErrorDetail';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { AllHtmlEntities } from 'html-entities';
|
|||||||
import StatusIcon from '../../../components/StatusIcon';
|
import StatusIcon from '../../../components/StatusIcon';
|
||||||
import { DetailList, Detail } from '../../../components/DetailList';
|
import { DetailList, Detail } from '../../../components/DetailList';
|
||||||
import ContentEmpty from '../../../components/ContentEmpty';
|
import ContentEmpty from '../../../components/ContentEmpty';
|
||||||
import CodeMirrorInput from '../../../components/CodeMirrorInput';
|
import CodeEditor from '../../../components/CodeEditor';
|
||||||
|
|
||||||
const entities = new AllHtmlEntities();
|
const entities = new AllHtmlEntities();
|
||||||
|
|
||||||
@@ -45,18 +45,18 @@ const processEventStatus = event => {
|
|||||||
return status;
|
return status;
|
||||||
};
|
};
|
||||||
|
|
||||||
const processCodeMirrorValue = value => {
|
const processCodeEditorValue = value => {
|
||||||
let codeMirrorValue;
|
let codeEditorValue;
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
codeMirrorValue = false;
|
codeEditorValue = false;
|
||||||
} else if (value === '') {
|
} else if (value === '') {
|
||||||
codeMirrorValue = ' ';
|
codeEditorValue = ' ';
|
||||||
} else if (typeof value === 'string') {
|
} else if (typeof value === 'string') {
|
||||||
codeMirrorValue = entities.encode(value);
|
codeEditorValue = entities.encode(value);
|
||||||
} else {
|
} else {
|
||||||
codeMirrorValue = value;
|
codeEditorValue = value;
|
||||||
}
|
}
|
||||||
return codeMirrorValue;
|
return codeEditorValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
const processStdOutValue = hostEvent => {
|
const processStdOutValue = hostEvent => {
|
||||||
@@ -90,9 +90,9 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false, i18n }) {
|
|||||||
setActiveTabKey(tabIndex);
|
setActiveTabKey(tabIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
const jsonObj = processCodeMirrorValue(hostEvent?.event_data?.res);
|
const jsonObj = processCodeEditorValue(hostEvent?.event_data?.res);
|
||||||
const stdErr = processCodeMirrorValue(hostEvent?.event_data?.res?.stderr);
|
const stdErr = processCodeEditorValue(hostEvent?.event_data?.res?.stderr);
|
||||||
const stdOut = processCodeMirrorValue(processStdOutValue(hostEvent));
|
const stdOut = processCodeEditorValue(processStdOutValue(hostEvent));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@@ -145,7 +145,7 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false, i18n }) {
|
|||||||
aria-label={i18n._(t`JSON tab`)}
|
aria-label={i18n._(t`JSON tab`)}
|
||||||
>
|
>
|
||||||
{activeTabKey === 1 && jsonObj ? (
|
{activeTabKey === 1 && jsonObj ? (
|
||||||
<CodeMirrorInput
|
<CodeEditor
|
||||||
mode="javascript"
|
mode="javascript"
|
||||||
readOnly
|
readOnly
|
||||||
value={JSON.stringify(jsonObj, null, 2)}
|
value={JSON.stringify(jsonObj, null, 2)}
|
||||||
@@ -163,7 +163,7 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false, i18n }) {
|
|||||||
aria-label={i18n._(t`Standard out tab`)}
|
aria-label={i18n._(t`Standard out tab`)}
|
||||||
>
|
>
|
||||||
{activeTabKey === 2 && stdOut ? (
|
{activeTabKey === 2 && stdOut ? (
|
||||||
<CodeMirrorInput
|
<CodeEditor
|
||||||
mode="javascript"
|
mode="javascript"
|
||||||
readOnly
|
readOnly
|
||||||
value={stdOut}
|
value={stdOut}
|
||||||
@@ -181,7 +181,7 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false, i18n }) {
|
|||||||
aria-label={i18n._(t`Standard error tab`)}
|
aria-label={i18n._(t`Standard error tab`)}
|
||||||
>
|
>
|
||||||
{activeTabKey === 3 && stdErr ? (
|
{activeTabKey === 3 && stdErr ? (
|
||||||
<CodeMirrorInput
|
<CodeEditor
|
||||||
mode="javascript"
|
mode="javascript"
|
||||||
readOnly
|
readOnly
|
||||||
onChange={() => {}}
|
onChange={() => {}}
|
||||||
|
|||||||
@@ -188,12 +188,12 @@ describe('HostEventModal', () => {
|
|||||||
expect(jsonSection.find('EmptyState').length).toBe(1);
|
expect(jsonSection.find('EmptyState').length).toBe(1);
|
||||||
wrapper.find('button[aria-label="JSON tab"]').simulate('click');
|
wrapper.find('button[aria-label="JSON tab"]').simulate('click');
|
||||||
findSections(wrapper);
|
findSections(wrapper);
|
||||||
expect(jsonSection.find('CodeMirrorInput').length).toBe(1);
|
expect(jsonSection.find('CodeEditor').length).toBe(1);
|
||||||
|
|
||||||
const codemirror = jsonSection.find('CodeMirrorInput Controlled');
|
const codeEditor = jsonSection.find('CodeEditor');
|
||||||
expect(codemirror.prop('mode')).toBe('javascript');
|
expect(codeEditor.prop('mode')).toBe('javascript');
|
||||||
expect(codemirror.prop('options').readOnly).toBe(true);
|
expect(codeEditor.prop('readOnly')).toBe(true);
|
||||||
expect(codemirror.prop('value')).toEqual(jsonValue);
|
expect(codeEditor.prop('value')).toEqual(jsonValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display Standard Out tab content on tab click', () => {
|
test('should display Standard Out tab content on tab click', () => {
|
||||||
@@ -205,12 +205,12 @@ describe('HostEventModal', () => {
|
|||||||
expect(standardOutSection.find('EmptyState').length).toBe(1);
|
expect(standardOutSection.find('EmptyState').length).toBe(1);
|
||||||
wrapper.find('button[aria-label="Standard out tab"]').simulate('click');
|
wrapper.find('button[aria-label="Standard out tab"]').simulate('click');
|
||||||
findSections(wrapper);
|
findSections(wrapper);
|
||||||
expect(standardOutSection.find('CodeMirrorInput').length).toBe(1);
|
expect(standardOutSection.find('CodeEditor').length).toBe(1);
|
||||||
|
|
||||||
const codemirror = standardOutSection.find('CodeMirrorInput Controlled');
|
const codeEditor = standardOutSection.find('CodeEditor');
|
||||||
expect(codemirror.prop('mode')).toBe('javascript');
|
expect(codeEditor.prop('mode')).toBe('javascript');
|
||||||
expect(codemirror.prop('options').readOnly).toBe(true);
|
expect(codeEditor.prop('readOnly')).toBe(true);
|
||||||
expect(codemirror.prop('value')).toEqual(hostEvent.event_data.res.stdout);
|
expect(codeEditor.prop('value')).toEqual(hostEvent.event_data.res.stdout);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display Standard Error tab content on tab click', () => {
|
test('should display Standard Error tab content on tab click', () => {
|
||||||
@@ -229,12 +229,12 @@ describe('HostEventModal', () => {
|
|||||||
expect(standardErrorSection.find('EmptyState').length).toBe(1);
|
expect(standardErrorSection.find('EmptyState').length).toBe(1);
|
||||||
wrapper.find('button[aria-label="Standard error tab"]').simulate('click');
|
wrapper.find('button[aria-label="Standard error tab"]').simulate('click');
|
||||||
findSections(wrapper);
|
findSections(wrapper);
|
||||||
expect(standardErrorSection.find('CodeMirrorInput').length).toBe(1);
|
expect(standardErrorSection.find('CodeEditor').length).toBe(1);
|
||||||
|
|
||||||
const codemirror = standardErrorSection.find('CodeMirrorInput Controlled');
|
const codeEditor = standardErrorSection.find('CodeEditor');
|
||||||
expect(codemirror.prop('mode')).toBe('javascript');
|
expect(codeEditor.prop('mode')).toBe('javascript');
|
||||||
expect(codemirror.prop('options').readOnly).toBe(true);
|
expect(codeEditor.prop('readOnly')).toBe(true);
|
||||||
expect(codemirror.prop('value')).toEqual(' ');
|
expect(codeEditor.prop('value')).toEqual(' ');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should call onClose when close button is clicked', () => {
|
test('should call onClose when close button is clicked', () => {
|
||||||
@@ -263,8 +263,8 @@ describe('HostEventModal', () => {
|
|||||||
);
|
);
|
||||||
wrapper.find('button[aria-label="Standard out tab"]').simulate('click');
|
wrapper.find('button[aria-label="Standard out tab"]').simulate('click');
|
||||||
findSections(wrapper);
|
findSections(wrapper);
|
||||||
const codemirror = standardOutSection.find('CodeMirrorInput Controlled');
|
const codeEditor = standardOutSection.find('CodeEditor');
|
||||||
expect(codemirror.prop('value')).toEqual('foo bar');
|
expect(codeEditor.prop('value')).toEqual('foo bar');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render standard out of yum task', () => {
|
test('should render standard out of yum task', () => {
|
||||||
@@ -282,7 +282,7 @@ describe('HostEventModal', () => {
|
|||||||
);
|
);
|
||||||
wrapper.find('button[aria-label="Standard out tab"]').simulate('click');
|
wrapper.find('button[aria-label="Standard out tab"]').simulate('click');
|
||||||
findSections(wrapper);
|
findSections(wrapper);
|
||||||
const codemirror = standardOutSection.find('CodeMirrorInput Controlled');
|
const codeEditor = standardOutSection.find('CodeEditor');
|
||||||
expect(codemirror.prop('value')).toEqual('baz');
|
expect(codeEditor.prop('value')).toEqual('baz');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
FormFullWidthLayout,
|
FormFullWidthLayout,
|
||||||
SubFormLayout,
|
SubFormLayout,
|
||||||
} from '../../../components/FormLayout';
|
} from '../../../components/FormLayout';
|
||||||
import CodeMirrorField from '../../../components/CodeMirrorInput/CodeMirrorField';
|
import CodeEditorField from '../../../components/CodeEditor/CodeEditorField';
|
||||||
|
|
||||||
function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
||||||
const [useCustomField, , useCustomHelpers] = useField('useCustomMessages');
|
const [useCustomField, , useCustomHelpers] = useField('useCustomMessages');
|
||||||
@@ -102,7 +102,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
</Text>
|
</Text>
|
||||||
<FormFullWidthLayout>
|
<FormFullWidthLayout>
|
||||||
{showMessages && (
|
{showMessages && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="start-message"
|
id="start-message"
|
||||||
name="messages.started.message"
|
name="messages.started.message"
|
||||||
label={i18n._(t`Start message`)}
|
label={i18n._(t`Start message`)}
|
||||||
@@ -111,7 +111,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showBodies && (
|
{showBodies && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="start-body"
|
id="start-body"
|
||||||
name="messages.started.body"
|
name="messages.started.body"
|
||||||
label={i18n._(t`Start message body`)}
|
label={i18n._(t`Start message body`)}
|
||||||
@@ -120,7 +120,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showMessages && (
|
{showMessages && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="success-message"
|
id="success-message"
|
||||||
name="messages.success.message"
|
name="messages.success.message"
|
||||||
label={i18n._(t`Success message`)}
|
label={i18n._(t`Success message`)}
|
||||||
@@ -129,7 +129,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showBodies && (
|
{showBodies && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="success-body"
|
id="success-body"
|
||||||
name="messages.success.body"
|
name="messages.success.body"
|
||||||
label={i18n._(t`Success message body`)}
|
label={i18n._(t`Success message body`)}
|
||||||
@@ -138,7 +138,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showMessages && (
|
{showMessages && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="error-message"
|
id="error-message"
|
||||||
name="messages.error.message"
|
name="messages.error.message"
|
||||||
label={i18n._(t`Error message`)}
|
label={i18n._(t`Error message`)}
|
||||||
@@ -147,7 +147,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showBodies && (
|
{showBodies && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="error-body"
|
id="error-body"
|
||||||
name="messages.error.body"
|
name="messages.error.body"
|
||||||
label={i18n._(t`Error message body`)}
|
label={i18n._(t`Error message body`)}
|
||||||
@@ -156,7 +156,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showMessages && (
|
{showMessages && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="wf-approved-message"
|
id="wf-approved-message"
|
||||||
name="messages.workflow_approval.approved.message"
|
name="messages.workflow_approval.approved.message"
|
||||||
label={i18n._(t`Workflow approved message`)}
|
label={i18n._(t`Workflow approved message`)}
|
||||||
@@ -165,7 +165,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showBodies && (
|
{showBodies && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="wf-approved-body"
|
id="wf-approved-body"
|
||||||
name="messages.workflow_approval.approved.body"
|
name="messages.workflow_approval.approved.body"
|
||||||
label={i18n._(t`Workflow approved message body`)}
|
label={i18n._(t`Workflow approved message body`)}
|
||||||
@@ -174,7 +174,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showMessages && (
|
{showMessages && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="wf-denied-message"
|
id="wf-denied-message"
|
||||||
name="messages.workflow_approval.denied.message"
|
name="messages.workflow_approval.denied.message"
|
||||||
label={i18n._(t`Workflow denied message`)}
|
label={i18n._(t`Workflow denied message`)}
|
||||||
@@ -183,7 +183,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showBodies && (
|
{showBodies && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="wf-denied-body"
|
id="wf-denied-body"
|
||||||
name="messages.workflow_approval.denied.body"
|
name="messages.workflow_approval.denied.body"
|
||||||
label={i18n._(t`Workflow denied message body`)}
|
label={i18n._(t`Workflow denied message body`)}
|
||||||
@@ -192,7 +192,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showMessages && (
|
{showMessages && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="wf-running-message"
|
id="wf-running-message"
|
||||||
name="messages.workflow_approval.running.message"
|
name="messages.workflow_approval.running.message"
|
||||||
label={i18n._(t`Workflow pending message`)}
|
label={i18n._(t`Workflow pending message`)}
|
||||||
@@ -201,7 +201,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showBodies && (
|
{showBodies && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="wf-running-body"
|
id="wf-running-body"
|
||||||
name="messages.workflow_approval.running.body"
|
name="messages.workflow_approval.running.body"
|
||||||
label={i18n._(t`Workflow pending message body`)}
|
label={i18n._(t`Workflow pending message body`)}
|
||||||
@@ -210,7 +210,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showMessages && (
|
{showMessages && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="wf-timed-out-message"
|
id="wf-timed-out-message"
|
||||||
name="messages.workflow_approval.timed_out.message"
|
name="messages.workflow_approval.timed_out.message"
|
||||||
label={i18n._(t`Workflow timed out message`)}
|
label={i18n._(t`Workflow timed out message`)}
|
||||||
@@ -219,7 +219,7 @@ function CustomMessagesSubForm({ defaultMessages, type, i18n }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showBodies && (
|
{showBodies && (
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="wf-timed-out-body"
|
id="wf-timed-out-body"
|
||||||
name="messages.workflow_approval.timed_out.body"
|
name="messages.workflow_approval.timed_out.body"
|
||||||
label={i18n._(t`Workflow timed out message body`)}
|
label={i18n._(t`Workflow timed out message body`)}
|
||||||
|
|||||||
@@ -79,6 +79,33 @@ describe('<NotificationTemplateForm />', () => {
|
|||||||
).toEqual(defaultMessages);
|
).toEqual(defaultMessages);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should render custom messages fields', () => {
|
||||||
|
const wrapper = mountWithContexts(
|
||||||
|
<NotificationTemplateForm
|
||||||
|
template={{
|
||||||
|
...template,
|
||||||
|
messages: {
|
||||||
|
started: {
|
||||||
|
message: 'Started',
|
||||||
|
body: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
defaultMessages={defaultMessages}
|
||||||
|
detailUrl="/notification_templates/3/detail"
|
||||||
|
onSubmit={jest.fn()}
|
||||||
|
onCancel={jest.fn()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('CodeEditor')
|
||||||
|
.at(0)
|
||||||
|
.prop('value')
|
||||||
|
).toEqual('Started');
|
||||||
|
});
|
||||||
|
|
||||||
test('should submit', async () => {
|
test('should submit', async () => {
|
||||||
const handleSubmit = jest.fn();
|
const handleSubmit = jest.fn();
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import FormField, {
|
|||||||
ArrayTextField,
|
ArrayTextField,
|
||||||
} from '../../../components/FormField';
|
} from '../../../components/FormField';
|
||||||
import AnsibleSelect from '../../../components/AnsibleSelect';
|
import AnsibleSelect from '../../../components/AnsibleSelect';
|
||||||
import { CodeMirrorField } from '../../../components/CodeMirrorInput';
|
import { CodeEditorField } from '../../../components/CodeEditor';
|
||||||
import {
|
import {
|
||||||
combine,
|
combine,
|
||||||
required,
|
required,
|
||||||
@@ -470,7 +470,7 @@ function WebhookFields({ i18n }) {
|
|||||||
name="notification_configuration.disable_ssl_verification"
|
name="notification_configuration.disable_ssl_verification"
|
||||||
/>
|
/>
|
||||||
<FormFullWidthLayout>
|
<FormFullWidthLayout>
|
||||||
<CodeMirrorField
|
<CodeEditorField
|
||||||
id="webhook-headers"
|
id="webhook-headers"
|
||||||
name="notification_configuration.headers"
|
name="notification_configuration.headers"
|
||||||
label={i18n._(t`HTTP Headers`)}
|
label={i18n._(t`HTTP Headers`)}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ describe('<GitHubEdit />', () => {
|
|||||||
target: { value: 'new key', name: 'SOCIAL_AUTH_GITHUB_KEY' },
|
target: { value: 'new key', name: 'SOCIAL_AUTH_GITHUB_KEY' },
|
||||||
});
|
});
|
||||||
wrapper
|
wrapper
|
||||||
.find('CodeMirrorInput#SOCIAL_AUTH_GITHUB_ORGANIZATION_MAP')
|
.find('CodeEditor#SOCIAL_AUTH_GITHUB_ORGANIZATION_MAP')
|
||||||
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ describe('<GitHubEnterpriseEdit />', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
wrapper
|
wrapper
|
||||||
.find('CodeMirrorInput#SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP')
|
.find('CodeEditor#SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP')
|
||||||
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|||||||
@@ -135,9 +135,7 @@ describe('<GitHubEnterpriseOrgEdit />', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
wrapper
|
wrapper
|
||||||
.find(
|
.find('CodeEditor#SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP')
|
||||||
'CodeMirrorInput#SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP'
|
|
||||||
)
|
|
||||||
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|||||||
@@ -129,9 +129,7 @@ describe('<GitHubEnterpriseTeamEdit />', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
wrapper
|
wrapper
|
||||||
.find(
|
.find('CodeEditor#SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP')
|
||||||
'CodeMirrorInput#SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP'
|
|
||||||
)
|
|
||||||
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ describe('<GitHubOrgEdit />', () => {
|
|||||||
target: { value: 'new org', name: 'SOCIAL_AUTH_GITHUB_ORG_NAME' },
|
target: { value: 'new org', name: 'SOCIAL_AUTH_GITHUB_ORG_NAME' },
|
||||||
});
|
});
|
||||||
wrapper
|
wrapper
|
||||||
.find('CodeMirrorInput#SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP')
|
.find('CodeEditor#SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP')
|
||||||
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ describe('<GitHubTeamEdit />', () => {
|
|||||||
target: { value: '12345', name: 'SOCIAL_AUTH_GITHUB_TEAM_ID' },
|
target: { value: '12345', name: 'SOCIAL_AUTH_GITHUB_TEAM_ID' },
|
||||||
});
|
});
|
||||||
wrapper
|
wrapper
|
||||||
.find('CodeMirrorInput#SOCIAL_AUTH_GITHUB_TEAM_ORGANIZATION_MAP')
|
.find('CodeEditor#SOCIAL_AUTH_GITHUB_TEAM_ORGANIZATION_MAP')
|
||||||
.invoke('onChange')('{\n"Default":{\n"users":\ntrue\n}\n}');
|
.invoke('onChange')('{\n"Default":{\n"users":\ntrue\n}\n}');
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ describe('<GoogleOAuth2Edit />', () => {
|
|||||||
target: { value: 'new key', name: 'SOCIAL_AUTH_GOOGLE_OAUTH2_KEY' },
|
target: { value: 'new key', name: 'SOCIAL_AUTH_GOOGLE_OAUTH2_KEY' },
|
||||||
});
|
});
|
||||||
wrapper
|
wrapper
|
||||||
.find('CodeMirrorInput#SOCIAL_AUTH_GOOGLE_OAUTH2_ORGANIZATION_MAP')
|
.find('CodeEditor#SOCIAL_AUTH_GOOGLE_OAUTH2_ORGANIZATION_MAP')
|
||||||
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ describe('<LDAPEdit />', () => {
|
|||||||
name: 'AUTH_LDAP_SERVER_URI',
|
name: 'AUTH_LDAP_SERVER_URI',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
wrapper.find('CodeMirrorInput#AUTH_LDAP_TEAM_MAP').invoke('onChange')(
|
wrapper.find('CodeEditor#AUTH_LDAP_TEAM_MAP').invoke('onChange')(
|
||||||
'{\n"LDAP Sales":{\n"organization":\n"mock org"\n}\n}'
|
'{\n"LDAP Sales":{\n"organization":\n"mock org"\n}\n}'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
import FileUploadIcon from '@patternfly/react-icons/dist/js/icons/file-upload-icon';
|
import FileUploadIcon from '@patternfly/react-icons/dist/js/icons/file-upload-icon';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import AnsibleSelect from '../../../components/AnsibleSelect';
|
import AnsibleSelect from '../../../components/AnsibleSelect';
|
||||||
import CodeMirrorInput from '../../../components/CodeMirrorInput';
|
import CodeEditor from '../../../components/CodeEditor';
|
||||||
import { PasswordInput } from '../../../components/FormField';
|
import { PasswordInput } from '../../../components/FormField';
|
||||||
import { FormFullWidthLayout } from '../../../components/FormLayout';
|
import { FormFullWidthLayout } from '../../../components/FormLayout';
|
||||||
import Popover from '../../../components/Popover';
|
import Popover from '../../../components/Popover';
|
||||||
@@ -284,7 +284,7 @@ const ObjectField = withI18n()(({ i18n, name, config, isRequired = false }) => {
|
|||||||
popoverContent={config.help_text}
|
popoverContent={config.help_text}
|
||||||
validated={isValid ? 'default' : 'error'}
|
validated={isValid ? 'default' : 'error'}
|
||||||
>
|
>
|
||||||
<CodeMirrorInput
|
<CodeEditor
|
||||||
{...field}
|
{...field}
|
||||||
fullHeight
|
fullHeight
|
||||||
id={name}
|
id={name}
|
||||||
|
|||||||
@@ -214,15 +214,15 @@ describe('Setting form fields', () => {
|
|||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
);
|
);
|
||||||
expect(wrapper.find('CodeMirrorInput')).toHaveLength(1);
|
expect(wrapper.find('CodeEditor')).toHaveLength(1);
|
||||||
expect(wrapper.find('CodeMirrorInput').prop('value')).toBe(
|
expect(wrapper.find('CodeEditor').prop('value')).toBe(
|
||||||
'["one", "two", "three"]'
|
'["one", "two", "three"]'
|
||||||
);
|
);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('CodeMirrorInput').invoke('onChange')('[]');
|
wrapper.find('CodeEditor').invoke('onChange')('[]');
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.find('CodeMirrorInput').prop('value')).toBe('[]');
|
expect(wrapper.find('CodeEditor').prop('value')).toBe('[]');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('FileUploadField renders the expected content', async () => {
|
test('FileUploadField renders the expected content', async () => {
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ export function assertVariableDetail(wrapper, label, value) {
|
|||||||
wrapper.find(`CodeDetail[label="${label}"] .pf-c-form__label`).text()
|
wrapper.find(`CodeDetail[label="${label}"] .pf-c-form__label`).text()
|
||||||
).toBe(label);
|
).toBe(label);
|
||||||
expect(
|
expect(
|
||||||
wrapper.find(`CodeDetail[label="${label}"] CodeMirrorInput`).prop('value')
|
wrapper.find(`CodeDetail[label="${label}"] CodeEditor`).prop('value')
|
||||||
).toBe(value);
|
).toBe(value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import {
|
|||||||
import DeleteButton from '../../../components/DeleteButton';
|
import DeleteButton from '../../../components/DeleteButton';
|
||||||
import ErrorDetail from '../../../components/ErrorDetail';
|
import ErrorDetail from '../../../components/ErrorDetail';
|
||||||
import { LaunchButton } from '../../../components/LaunchButton';
|
import { LaunchButton } from '../../../components/LaunchButton';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import { JobTemplatesAPI } from '../../../api';
|
import { JobTemplatesAPI } from '../../../api';
|
||||||
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { WorkflowJobTemplatesAPI } from '../../../api';
|
|||||||
import AlertModal from '../../../components/AlertModal';
|
import AlertModal from '../../../components/AlertModal';
|
||||||
import { CardBody, CardActionsRow } from '../../../components/Card';
|
import { CardBody, CardActionsRow } from '../../../components/Card';
|
||||||
import ChipGroup from '../../../components/ChipGroup';
|
import ChipGroup from '../../../components/ChipGroup';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||||
import DeleteButton from '../../../components/DeleteButton';
|
import DeleteButton from '../../../components/DeleteButton';
|
||||||
import {
|
import {
|
||||||
DetailList,
|
DetailList,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
FormCheckboxLayout,
|
FormCheckboxLayout,
|
||||||
SubFormLayout,
|
SubFormLayout,
|
||||||
} from '../../../components/FormLayout';
|
} from '../../../components/FormLayout';
|
||||||
import { VariablesField } from '../../../components/CodeMirrorInput';
|
import { VariablesField } from '../../../components/CodeEditor';
|
||||||
import { required } from '../../../util/validators';
|
import { required } from '../../../util/validators';
|
||||||
import { JobTemplate } from '../../../types';
|
import { JobTemplate } from '../../../types';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
InventoryLookup,
|
InventoryLookup,
|
||||||
ExecutionEnvironmentLookup,
|
ExecutionEnvironmentLookup,
|
||||||
} from '../../../components/Lookup';
|
} from '../../../components/Lookup';
|
||||||
import { VariablesField } from '../../../components/CodeMirrorInput';
|
import { VariablesField } from '../../../components/CodeEditor';
|
||||||
import FormActionGroup from '../../../components/FormActionGroup';
|
import FormActionGroup from '../../../components/FormActionGroup';
|
||||||
import ContentError from '../../../components/ContentError';
|
import ContentError from '../../../components/ContentError';
|
||||||
import CheckboxField from '../../../components/FormField/CheckboxField';
|
import CheckboxField from '../../../components/FormField/CheckboxField';
|
||||||
|
|||||||
Reference in New Issue
Block a user