mirror of
https://github.com/ansible/awx.git
synced 2026-05-07 01:17:37 -02:30
make VariablesInput detect whether value is JSON or YAML on init
This commit is contained in:
110
awx/ui_next/src/components/CodeMirrorInput/VariablesInput.jsx
Normal file
110
awx/ui_next/src/components/CodeMirrorInput/VariablesInput.jsx
Normal file
@@ -0,0 +1,110 @@
|
||||
import React, { useState } from 'react';
|
||||
import { string, func, bool, number } from 'prop-types';
|
||||
import { Button, Split, SplitItem } from '@patternfly/react-core';
|
||||
import styled from 'styled-components';
|
||||
import ButtonGroup from '@components/ButtonGroup';
|
||||
import { yamlToJson, jsonToYaml, isJson } from '@util/yaml';
|
||||
import CodeMirrorInput from './CodeMirrorInput';
|
||||
|
||||
const YAML_MODE = 'yaml';
|
||||
const JSON_MODE = 'javascript';
|
||||
|
||||
const SmallButton = styled(Button)`
|
||||
padding: 3px 8px;
|
||||
font-size: var(--pf-global--FontSize--xs);
|
||||
`;
|
||||
|
||||
function VariablesInput (props) {
|
||||
const { id, label, readOnly, rows, error, onError, className } = props;
|
||||
// eslint-disable-next-line react/destructuring-assignment
|
||||
const [value, setValue] = useState(props.value);
|
||||
const [mode, setMode] = useState(isJson(value) ? JSON_MODE : YAML_MODE);
|
||||
// eslint-disable-next-line react/destructuring-assignment
|
||||
const isControlled = !!props.onChange;
|
||||
|
||||
const onChange = (newValue) => {
|
||||
if (isControlled) {
|
||||
props.onChange(newValue);
|
||||
}
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`pf-c-form__group ${className || ''}`}>
|
||||
<Split gutter="sm">
|
||||
<SplitItem>
|
||||
<label htmlFor={id} className="pf-c-form__label">{label}</label>
|
||||
</SplitItem>
|
||||
<SplitItem>
|
||||
<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={() => {
|
||||
if (mode === JSON_MODE) { return; }
|
||||
try {
|
||||
onChange(yamlToJson(value));
|
||||
setMode(JSON_MODE);
|
||||
} catch (err) {
|
||||
onError(err.message);
|
||||
}
|
||||
}}
|
||||
variant={mode === JSON_MODE ? 'primary' : 'secondary'}
|
||||
>
|
||||
JSON
|
||||
</SmallButton>
|
||||
</ButtonGroup>
|
||||
</SplitItem>
|
||||
</Split>
|
||||
<CodeMirrorInput
|
||||
mode={mode}
|
||||
readOnly={readOnly}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
rows={rows}
|
||||
hasErrors={!!error}
|
||||
/>
|
||||
{error ? (
|
||||
<div
|
||||
className="pf-c-form__helper-text pf-m-error"
|
||||
aria-live="polite"
|
||||
>
|
||||
{error}
|
||||
</div>
|
||||
) : null }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
VariablesInput.propTypes = {
|
||||
id: string.isRequired,
|
||||
label: string.isRequired,
|
||||
value: string.isRequired,
|
||||
readOnly: bool,
|
||||
error: string,
|
||||
rows: number,
|
||||
onChange: func,
|
||||
onError: func,
|
||||
};
|
||||
VariablesInput.defaultProps = {
|
||||
readOnly: false,
|
||||
onChange: null,
|
||||
rows: 6,
|
||||
error: null,
|
||||
onError: () => {},
|
||||
};
|
||||
|
||||
export default styled(VariablesInput)`
|
||||
--pf-c-form__label--FontSize: var(--pf-global--FontSize--sm);
|
||||
`;
|
||||
@@ -14,9 +14,13 @@ export function ucFirst(str) {
|
||||
return `${str[0].toUpperCase()}${str.substr(1)}`;
|
||||
}
|
||||
|
||||
export const toTitleCase = string =>
|
||||
string
|
||||
export const toTitleCase = string => {
|
||||
if (!string) {
|
||||
return '';
|
||||
}
|
||||
return string
|
||||
.toLowerCase()
|
||||
.split('_')
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' ');
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { pluralize, getArticle, ucFirst } from './strings';
|
||||
import { pluralize, getArticle, ucFirst, toTitleCase } from './strings';
|
||||
|
||||
describe('string utils', () => {
|
||||
describe('pluralize', () => {
|
||||
@@ -31,4 +31,14 @@ describe('string utils', () => {
|
||||
expect(ucFirst('team')).toEqual('Team');
|
||||
});
|
||||
});
|
||||
|
||||
describe('toTitleCase', () => {
|
||||
test('should upper case each word', () => {
|
||||
expect(toTitleCase('a_string_of_words')).toEqual('A String Of Words');
|
||||
});
|
||||
|
||||
test('should return empty string for undefined', () => {
|
||||
expect(toTitleCase(undefined)).toEqual('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,3 +21,15 @@ export function jsonToYaml(jsonString) {
|
||||
}
|
||||
return yaml.safeDump(value);
|
||||
}
|
||||
|
||||
export function isJson (jsonString) {
|
||||
if (typeof jsonString !== 'string') { return false; }
|
||||
let value;
|
||||
try {
|
||||
value = JSON.parse(jsonString);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return typeof value === 'object' && value !== null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user