diff --git a/awx/ui_next/src/components/CodeEditor/CodeEditor.jsx b/awx/ui_next/src/components/CodeEditor/CodeEditor.jsx index fac99894f4..c112ccc651 100644 --- a/awx/ui_next/src/components/CodeEditor/CodeEditor.jsx +++ b/awx/ui_next/src/components/CodeEditor/CodeEditor.jsx @@ -11,7 +11,6 @@ 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'; config.set('loadWorkerFromBlob', false); @@ -140,7 +139,8 @@ function CodeEditor({ mode={aceModes[mode] || 'text'} className={`pf-c-form-control ${className}`} theme="github" - onChange={debounce(onChange, 250)} + onChange={onChange} + debounceChangePeriod={250} value={value} onFocus={onFocus} onBlur={onBlur} diff --git a/awx/ui_next/src/components/CodeEditor/VariablesField.jsx b/awx/ui_next/src/components/CodeEditor/VariablesField.jsx index 89260a6ea2..3b1b1e528f 100644 --- a/awx/ui_next/src/components/CodeEditor/VariablesField.jsx +++ b/awx/ui_next/src/components/CodeEditor/VariablesField.jsx @@ -73,13 +73,15 @@ function VariablesField({ }, [shouldValidate, validate] // eslint-disable-line react-hooks/exhaustive-deps ); - const [initialYamlValue] = useState(mode === YAML_MODE ? field.value : null); - const [isEdited, setIsEdited] = useState(false); + const [lastYamlValue, setLastYamlValue] = useState( + mode === YAML_MODE ? field.value : null + ); + const [isJsonEdited, setIsJsonEdited] = useState(false); const [isExpanded, setIsExpanded] = useState(false); const handleModeChange = newMode => { - if (newMode === YAML_MODE && !isEdited && initialYamlValue) { - helpers.setValue(initialYamlValue); + if (newMode === YAML_MODE && !isJsonEdited && lastYamlValue !== null) { + helpers.setValue(lastYamlValue); setMode(newMode); return; } @@ -96,6 +98,16 @@ function VariablesField({ } }; + const handleChange = newVal => { + helpers.setValue(newVal); + if (mode === JSON_MODE) { + setIsJsonEdited(true); + } else { + setLastYamlValue(newVal); + setIsJsonEdited(false); + } + }; + return ( <> setIsExpanded(true)} mode={mode} setMode={handleModeChange} - setIsEdited={setIsEdited} setShouldValidate={setShouldValidate} + handleChange={handleChange} /> @@ -178,10 +190,10 @@ function VariablesFieldInternals({ mode, setMode, onExpand, - setIsEdited, setShouldValidate, + handleChange, }) { - const [field, meta, helpers] = useField(name); + const [field, meta] = useField(name); return (
@@ -226,10 +238,7 @@ function VariablesFieldInternals({ mode={mode} readOnly={readOnly} {...field} - onChange={newVal => { - setIsEdited(true); - helpers.setValue(newVal); - }} + onChange={handleChange} fullHeight={fullHeight} onFocus={() => setShouldValidate(false)} onBlur={() => setShouldValidate(true)} diff --git a/awx/ui_next/src/components/CodeEditor/VariablesField.test.jsx b/awx/ui_next/src/components/CodeEditor/VariablesField.test.jsx index 20efb1a2a6..72326f06cf 100644 --- a/awx/ui_next/src/components/CodeEditor/VariablesField.test.jsx +++ b/awx/ui_next/src/components/CodeEditor/VariablesField.test.jsx @@ -56,7 +56,7 @@ describe('VariablesField', () => { ); }); - it('should retain non-expanded yaml if value not edited', async () => { + it('should retain non-expanded yaml if JSON value not edited', async () => { const value = '---\na: &aa [a,b,c]\nb: *aa'; const wrapper = mountWithContexts( @@ -80,7 +80,7 @@ describe('VariablesField', () => { expect(wrapper.find('CodeEditor').prop('value')).toEqual(value); }); - it('should retain expanded yaml if value is edited', async () => { + it('should retain expanded yaml if JSON value is edited', async () => { const value = '---\na: &aa [a,b,c]\nb: *aa'; const wrapper = mountWithContexts( @@ -109,6 +109,34 @@ describe('VariablesField', () => { ); }); + it('should retain non-expanded yaml if YAML value is edited', async () => { + const value = '---\na: &aa [a,b,c]\nb: *aa'; + const wrapper = mountWithContexts( + + {() => ( + + )} + + ); + wrapper.find('CodeEditor').invoke('onChange')( + '---\na: &aa [a,b,c]\nb: *aa\n' + ); + const buttons = wrapper.find('Button'); + await act(async () => { + buttons.at(1).simulate('click'); + }); + wrapper.update(); + const buttons2 = wrapper.find('Button'); + await act(async () => { + buttons2.at(0).simulate('click'); + }); + wrapper.update(); + expect(wrapper.find('CodeEditor').prop('mode')).toEqual('yaml'); + expect(wrapper.find('CodeEditor').prop('value')).toEqual( + '---\na: &aa [a,b,c]\nb: *aa\n' + ); + }); + it('should set Formik error if yaml is invalid', async () => { const value = '---\nfoo bar\n'; const wrapper = mountWithContexts(