mirror of
https://github.com/ansible/awx.git
synced 2026-01-12 02:19:58 -03:30
Merge pull request #6130 from mabashian/general-toggle-component
Refactors YamlJsonToggle component into a generic Toggle component Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
commit
5dc4e30820
@ -2,9 +2,9 @@ import React, { useState, useEffect } from 'react';
|
||||
import { string, node, number } from 'prop-types';
|
||||
import { Split, SplitItem, TextListItemVariants } from '@patternfly/react-core';
|
||||
import { DetailName, DetailValue } from '@components/DetailList';
|
||||
import MultiButtonToggle from '@components/MultiButtonToggle';
|
||||
import { yamlToJson, jsonToYaml, isJson } from '@util/yaml';
|
||||
import CodeMirrorInput from './CodeMirrorInput';
|
||||
import YamlJsonToggle from './YamlJsonToggle';
|
||||
import { JSON_MODE, YAML_MODE } from './constants';
|
||||
|
||||
function getValueAsMode(value, mode) {
|
||||
@ -50,8 +50,9 @@ function VariablesDetail({ value, label, rows }) {
|
||||
</div>
|
||||
</SplitItem>
|
||||
<SplitItem>
|
||||
<YamlJsonToggle
|
||||
mode={mode}
|
||||
<MultiButtonToggle
|
||||
buttons={[[YAML_MODE, 'YAML'], [JSON_MODE, 'JSON']]}
|
||||
value={mode}
|
||||
onChange={newMode => {
|
||||
try {
|
||||
setCurrentValue(getValueAsMode(currentValue, newMode));
|
||||
|
||||
@ -31,12 +31,12 @@ describe('<VariablesDetail>', () => {
|
||||
const wrapper = shallow(
|
||||
<VariablesDetail value="---foo: bar" label="Variables" />
|
||||
);
|
||||
wrapper.find('YamlJsonToggle').invoke('onChange')('javascript');
|
||||
wrapper.find('MultiButtonToggle').invoke('onChange')('javascript');
|
||||
const input = wrapper.find('Styled(CodeMirrorInput)');
|
||||
expect(input.prop('mode')).toEqual('javascript');
|
||||
expect(input.prop('value')).toEqual('{\n "foo": "bar"\n}');
|
||||
|
||||
wrapper.find('YamlJsonToggle').invoke('onChange')('yaml');
|
||||
wrapper.find('MultiButtonToggle').invoke('onChange')('yaml');
|
||||
const input2 = wrapper.find('Styled(CodeMirrorInput)');
|
||||
expect(input2.prop('mode')).toEqual('yaml');
|
||||
expect(input2.prop('value')).toEqual('foo: bar\n');
|
||||
@ -53,7 +53,7 @@ describe('<VariablesDetail>', () => {
|
||||
<VariablesDetail value="---foo: bar" label="Variables" />
|
||||
);
|
||||
act(() => {
|
||||
wrapper.find('YamlJsonToggle').invoke('onChange')('javascript');
|
||||
wrapper.find('MultiButtonToggle').invoke('onChange')('javascript');
|
||||
});
|
||||
wrapper.setProps({
|
||||
value: '---bar: baz',
|
||||
@ -73,7 +73,7 @@ describe('<VariablesDetail>', () => {
|
||||
test('should default empty json to "{}"', () => {
|
||||
const wrapper = mount(<VariablesDetail value="" label="Variables" />);
|
||||
act(() => {
|
||||
wrapper.find('YamlJsonToggle').invoke('onChange')('javascript');
|
||||
wrapper.find('MultiButtonToggle').invoke('onChange')('javascript');
|
||||
});
|
||||
wrapper.setProps({ value: '' });
|
||||
const input = wrapper.find('Styled(CodeMirrorInput)');
|
||||
|
||||
@ -6,9 +6,9 @@ import { useField } from 'formik';
|
||||
import styled from 'styled-components';
|
||||
import { Split, SplitItem } from '@patternfly/react-core';
|
||||
import { CheckboxField } from '@components/FormField';
|
||||
import MultiButtonToggle from '@components/MultiButtonToggle';
|
||||
import { yamlToJson, jsonToYaml, isJson } from '@util/yaml';
|
||||
import CodeMirrorInput from './CodeMirrorInput';
|
||||
import YamlJsonToggle from './YamlJsonToggle';
|
||||
import { JSON_MODE, YAML_MODE } from './constants';
|
||||
|
||||
const FieldHeader = styled.div`
|
||||
@ -34,8 +34,9 @@ function VariablesField({ i18n, id, name, label, readOnly, promptId }) {
|
||||
</label>
|
||||
</SplitItem>
|
||||
<SplitItem>
|
||||
<YamlJsonToggle
|
||||
mode={mode}
|
||||
<MultiButtonToggle
|
||||
buttons={[[YAML_MODE, 'YAML'], [JSON_MODE, 'JSON']]}
|
||||
value={mode}
|
||||
onChange={newMode => {
|
||||
try {
|
||||
const newVal =
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
import React, { useState } from 'react';
|
||||
import { string, func, bool, number } from 'prop-types';
|
||||
import { Button, Split, SplitItem } from '@patternfly/react-core';
|
||||
import { Split, SplitItem } from '@patternfly/react-core';
|
||||
import styled from 'styled-components';
|
||||
import { yamlToJson, jsonToYaml, isJson } from '@util/yaml';
|
||||
import MultiButtonToggle from '@components/MultiButtonToggle';
|
||||
import CodeMirrorInput from './CodeMirrorInput';
|
||||
import ButtonGroup from './ButtonGroup';
|
||||
import { JSON_MODE, YAML_MODE } from './constants';
|
||||
|
||||
function formatJson(jsonString) {
|
||||
return JSON.stringify(JSON.parse(jsonString), null, 2);
|
||||
}
|
||||
|
||||
const SmallButton = styled(Button)`
|
||||
padding: 3px 8px;
|
||||
font-size: var(--pf-global--FontSize--xs);
|
||||
`;
|
||||
|
||||
const SplitItemRight = styled(SplitItem)`
|
||||
margin-bottom: 5px;
|
||||
`;
|
||||
@ -47,40 +42,22 @@ function VariablesInput(props) {
|
||||
</label>
|
||||
</SplitItem>
|
||||
<SplitItemRight>
|
||||
<ButtonGroup>
|
||||
<SmallButton
|
||||
onClick={() => {
|
||||
if (mode === YAML_MODE) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
onChange(jsonToYaml(value));
|
||||
setMode(YAML_MODE);
|
||||
} catch (err) {
|
||||
onError(err.message);
|
||||
}
|
||||
}}
|
||||
variant={mode === YAML_MODE ? 'primary' : 'secondary'}
|
||||
>
|
||||
YAML
|
||||
</SmallButton>
|
||||
<SmallButton
|
||||
onClick={() => {
|
||||
<MultiButtonToggle
|
||||
buttons={[[YAML_MODE, 'YAML'], [JSON_MODE, 'JSON']]}
|
||||
value={mode}
|
||||
onChange={newMode => {
|
||||
try {
|
||||
if (mode === JSON_MODE) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
onChange(jsonToYaml(value));
|
||||
} else {
|
||||
onChange(yamlToJson(value));
|
||||
setMode(JSON_MODE);
|
||||
} catch (err) {
|
||||
onError(err.message);
|
||||
}
|
||||
}}
|
||||
variant={mode === JSON_MODE ? 'primary' : 'secondary'}
|
||||
>
|
||||
JSON
|
||||
</SmallButton>
|
||||
</ButtonGroup>
|
||||
setMode(newMode);
|
||||
} catch (err) {
|
||||
onError(err.message);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</SplitItemRight>
|
||||
</Split>
|
||||
<CodeMirrorInput
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
import React from 'react';
|
||||
import { oneOf, func } from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import { Button } from '@patternfly/react-core';
|
||||
import ButtonGroup from './ButtonGroup';
|
||||
|
||||
const SmallButton = styled(Button)`
|
||||
padding: 3px 8px;
|
||||
font-size: var(--pf-global--FontSize--xs);
|
||||
`;
|
||||
|
||||
const YAML_MODE = 'yaml';
|
||||
const JSON_MODE = 'javascript';
|
||||
|
||||
function YamlJsonToggle({ mode, onChange }) {
|
||||
const setMode = newMode => {
|
||||
if (mode !== newMode) {
|
||||
onChange(newMode);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ButtonGroup>
|
||||
<SmallButton
|
||||
onClick={() => setMode(YAML_MODE)}
|
||||
variant={mode === YAML_MODE ? 'primary' : 'secondary'}
|
||||
>
|
||||
YAML
|
||||
</SmallButton>
|
||||
<SmallButton
|
||||
onClick={() => setMode(JSON_MODE)}
|
||||
variant={mode === JSON_MODE ? 'primary' : 'secondary'}
|
||||
>
|
||||
JSON
|
||||
</SmallButton>
|
||||
</ButtonGroup>
|
||||
);
|
||||
}
|
||||
YamlJsonToggle.propTypes = {
|
||||
mode: oneOf([YAML_MODE, JSON_MODE]).isRequired,
|
||||
onChange: func.isRequired,
|
||||
};
|
||||
|
||||
export default YamlJsonToggle;
|
||||
@ -0,0 +1,67 @@
|
||||
import React from 'react';
|
||||
import { func, string } from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import { Button } from '@patternfly/react-core';
|
||||
import ButtonGroup from './ButtonGroup';
|
||||
|
||||
const SmallButton = styled(Button)`
|
||||
padding: 3px 8px;
|
||||
font-size: var(--pf-global--FontSize--xs);
|
||||
`;
|
||||
|
||||
function MultiButtonToggle({ buttons, value, onChange }) {
|
||||
const setValue = newValue => {
|
||||
if (value !== newValue) {
|
||||
onChange(newValue);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ButtonGroup>
|
||||
{buttons &&
|
||||
buttons.map(([buttonValue, buttonLabel]) => (
|
||||
<SmallButton
|
||||
key={buttonLabel}
|
||||
onClick={() => setValue(buttonValue)}
|
||||
variant={buttonValue === value ? 'primary' : 'secondary'}
|
||||
>
|
||||
{buttonLabel}
|
||||
</SmallButton>
|
||||
))}
|
||||
</ButtonGroup>
|
||||
);
|
||||
}
|
||||
|
||||
const buttonsPropType = {
|
||||
isRequired: ({ buttons }) => {
|
||||
if (!buttons) {
|
||||
return new Error(
|
||||
`The prop buttons is marked as required in MultiButtonToggle, but its value is '${buttons}'`
|
||||
);
|
||||
}
|
||||
// We expect this data structure to look like:
|
||||
// [[value(unrestricted type), label(string)], [value(unrestricted type), label(string)], ...]
|
||||
if (
|
||||
!Array.isArray(buttons) ||
|
||||
buttons.length < 2 ||
|
||||
buttons.reduce(
|
||||
(prevVal, button) => prevVal || typeof button[1] !== 'string',
|
||||
false
|
||||
)
|
||||
) {
|
||||
return new Error(
|
||||
`Invalid prop buttons supplied to MultiButtonToggle. Validation failed.`
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
};
|
||||
|
||||
MultiButtonToggle.propTypes = {
|
||||
buttons: buttonsPropType.isRequired,
|
||||
value: string.isRequired,
|
||||
onChange: func.isRequired,
|
||||
};
|
||||
|
||||
export default MultiButtonToggle;
|
||||
@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import MultiButtonToggle from './MultiButtonToggle';
|
||||
|
||||
describe('<MultiButtonToggle />', () => {
|
||||
let wrapper;
|
||||
const onChange = jest.fn();
|
||||
beforeAll(() => {
|
||||
wrapper = mount(
|
||||
<MultiButtonToggle
|
||||
buttons={[['yaml', 'YAML'], ['json', 'JSON']]}
|
||||
value="yaml"
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
});
|
||||
afterAll(() => {
|
||||
wrapper.unmount();
|
||||
});
|
||||
it('should render buttons successfully', () => {
|
||||
const buttons = wrapper.find('Button');
|
||||
expect(buttons.length).toBe(2);
|
||||
expect(buttons.at(0).props().variant).toBe('primary');
|
||||
expect(buttons.at(1).props().variant).toBe('secondary');
|
||||
});
|
||||
it('should call onChange function when button clicked', () => {
|
||||
const buttons = wrapper.find('Button');
|
||||
buttons.at(1).simulate('click');
|
||||
expect(onChange).toHaveBeenCalledWith('json');
|
||||
});
|
||||
});
|
||||
1
awx/ui_next/src/components/MultiButtonToggle/index.js
Normal file
1
awx/ui_next/src/components/MultiButtonToggle/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './MultiButtonToggle';
|
||||
Loading…
x
Reference in New Issue
Block a user