diff --git a/awx/ui_next/src/components/CodeEditor/VariablesField.jsx b/awx/ui_next/src/components/CodeEditor/VariablesField.jsx index ed56f5376c..89260a6ea2 100644 --- a/awx/ui_next/src/components/CodeEditor/VariablesField.jsx +++ b/awx/ui_next/src/components/CodeEditor/VariablesField.jsx @@ -73,8 +73,29 @@ 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 [isExpanded, setIsExpanded] = useState(false); + const handleModeChange = newMode => { + if (newMode === YAML_MODE && !isEdited && initialYamlValue) { + helpers.setValue(initialYamlValue); + setMode(newMode); + return; + } + + try { + const newVal = + newMode === YAML_MODE + ? jsonToYaml(field.value) + : yamlToJson(field.value); + helpers.setValue(newVal); + setMode(newMode); + } catch (err) { + helpers.setError(err.message); + } + }; + return ( <> setIsExpanded(true)} mode={mode} - setMode={setMode} + setMode={handleModeChange} + setIsEdited={setIsEdited} setShouldValidate={setShouldValidate} /> @@ -155,6 +178,7 @@ function VariablesFieldInternals({ mode, setMode, onExpand, + setIsEdited, setShouldValidate, }) { const [field, meta, helpers] = useField(name); @@ -176,18 +200,7 @@ function VariablesFieldInternals({ [JSON_MODE, 'JSON'], ]} value={mode} - onChange={newMode => { - try { - const newVal = - newMode === YAML_MODE - ? jsonToYaml(field.value) - : yamlToJson(field.value); - helpers.setValue(newVal); - setMode(newMode); - } catch (err) { - helpers.setError(err.message); - } - }} + onChange={setMode} /> @@ -214,6 +227,7 @@ function VariablesFieldInternals({ readOnly={readOnly} {...field} onChange={newVal => { + setIsEdited(true); helpers.setValue(newVal); }} fullHeight={fullHeight} diff --git a/awx/ui_next/src/components/CodeEditor/VariablesField.test.jsx b/awx/ui_next/src/components/CodeEditor/VariablesField.test.jsx index 24c896069e..20efb1a2a6 100644 --- a/awx/ui_next/src/components/CodeEditor/VariablesField.test.jsx +++ b/awx/ui_next/src/components/CodeEditor/VariablesField.test.jsx @@ -51,6 +51,59 @@ describe('VariablesField', () => { }); wrapper.update(); expect(wrapper.find('CodeEditor').prop('mode')).toEqual('yaml'); + expect(wrapper.find('CodeEditor').prop('value')).toEqual( + '---\nfoo: bar\nbaz: 3' + ); + }); + + it('should retain non-expanded yaml if value not edited', async () => { + const value = '---\na: &aa [a,b,c]\nb: *aa'; + const wrapper = mountWithContexts( + + {() => ( + + )} + + ); + const buttons = wrapper.find('Button'); + expect(buttons).toHaveLength(2); + 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(value); + }); + + it('should retain expanded yaml if value is edited', async () => { + const value = '---\na: &aa [a,b,c]\nb: *aa'; + const wrapper = mountWithContexts( + + {() => ( + + )} + + ); + const buttons = wrapper.find('Button'); + expect(buttons).toHaveLength(2); + await act(async () => { + buttons.at(1).simulate('click'); + }); + wrapper.update(); + wrapper.find('CodeEditor').invoke('onChange')( + '{\n "foo": "bar",\n "baz": 3\n}' + ); + 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( 'foo: bar\nbaz: 3\n' );