mirror of
https://github.com/ansible/awx.git
synced 2026-01-21 14:38:00 -03:30
add expand button to VariablesField
This commit is contained in:
parent
a52f050f44
commit
b1ce5e24e3
@ -77,7 +77,8 @@
|
||||
"resizeOrientation",
|
||||
"src",
|
||||
"theme",
|
||||
"gridColumns"
|
||||
"gridColumns",
|
||||
"rows"
|
||||
],
|
||||
"ignore": ["Ansible", "Tower", "JSON", "YAML", "lg"],
|
||||
"ignoreComponent": [
|
||||
|
||||
@ -77,6 +77,13 @@ function CodeEditor({
|
||||
className,
|
||||
i18n,
|
||||
}) {
|
||||
if (typeof rows !== 'number' && rows !== 'auto') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warning(
|
||||
`CodeEditor: Unexpected value for 'rows': ${rows}; expected number or 'auto'`
|
||||
);
|
||||
}
|
||||
|
||||
const wrapper = useRef(null);
|
||||
const editor = useRef(null);
|
||||
|
||||
@ -117,7 +124,8 @@ function CodeEditor({
|
||||
jinja2: 'django',
|
||||
};
|
||||
|
||||
const numRows = fullHeight ? value.split('\n').length : rows;
|
||||
const numRows = rows === 'auto' ? value.split('\n').length : rows;
|
||||
const height = fullHeight ? '50vh' : `${numRows * LINE_HEIGHT + PADDING}px`;
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -132,7 +140,7 @@ function CodeEditor({
|
||||
editorProps={{ $blockScrolling: true }}
|
||||
fontSize={16}
|
||||
width="100%"
|
||||
height={`${numRows * LINE_HEIGHT + PADDING}px`}
|
||||
height={height}
|
||||
hasErrors={hasErrors}
|
||||
setOptions={{
|
||||
readOnly,
|
||||
@ -178,7 +186,7 @@ CodeEditor.propTypes = {
|
||||
readOnly: bool,
|
||||
hasErrors: bool,
|
||||
fullHeight: bool,
|
||||
rows: number,
|
||||
rows: oneOf(number, string),
|
||||
className: string,
|
||||
};
|
||||
CodeEditor.defaultProps = {
|
||||
|
||||
@ -2,7 +2,14 @@ import 'styled-components/macro';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { node, number, oneOfType, shape, string, arrayOf } from 'prop-types';
|
||||
import { Trans, withI18n } from '@lingui/react';
|
||||
import { Split, SplitItem, TextListItemVariants } from '@patternfly/react-core';
|
||||
import { t } from '@lingui/macro';
|
||||
import {
|
||||
Split,
|
||||
SplitItem,
|
||||
TextListItemVariants,
|
||||
Button,
|
||||
} from '@patternfly/react-core';
|
||||
import { ExpandArrowsAltIcon } from '@patternfly/react-icons';
|
||||
import { DetailName, DetailValue } from '../DetailList';
|
||||
import MultiButtonToggle from '../MultiButtonToggle';
|
||||
import Popover from '../Popover';
|
||||
@ -29,13 +36,22 @@ function getValueAsMode(value, mode) {
|
||||
return mode === YAML_MODE ? jsonToYaml(value) : yamlToJson(value);
|
||||
}
|
||||
|
||||
function VariablesDetail({ dataCy, helpText, value, label, rows, fullHeight }) {
|
||||
function VariablesDetail({
|
||||
dataCy,
|
||||
helpText,
|
||||
value,
|
||||
label,
|
||||
rows,
|
||||
fullHeight,
|
||||
i18n,
|
||||
}) {
|
||||
const [mode, setMode] = useState(
|
||||
isJsonObject(value) || isJsonString(value) ? JSON_MODE : YAML_MODE
|
||||
);
|
||||
const [currentValue, setCurrentValue] = useState(
|
||||
isJsonObject(value) ? JSON.stringify(value, null, 2) : value || '---'
|
||||
);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
@ -61,35 +77,48 @@ function VariablesDetail({ dataCy, helpText, value, label, rows, fullHeight }) {
|
||||
css="grid-column: 1 / -1"
|
||||
>
|
||||
<Split hasGutter>
|
||||
<SplitItem>
|
||||
<div className="pf-c-form__label">
|
||||
<span
|
||||
className="pf-c-form__label-text"
|
||||
css="font-weight: var(--pf-global--FontWeight--bold)"
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
{helpText && (
|
||||
<Popover header={label} content={helpText} id={dataCy} />
|
||||
)}
|
||||
</div>
|
||||
<SplitItem isFilled>
|
||||
<Split hasGutter>
|
||||
<SplitItem>
|
||||
<div className="pf-c-form__label">
|
||||
<span
|
||||
className="pf-c-form__label-text"
|
||||
css="font-weight: var(--pf-global--FontWeight--bold)"
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
{helpText && (
|
||||
<Popover header={label} content={helpText} id={dataCy} />
|
||||
)}
|
||||
</div>
|
||||
</SplitItem>
|
||||
<SplitItem>
|
||||
<MultiButtonToggle
|
||||
buttons={[
|
||||
[YAML_MODE, 'YAML'],
|
||||
[JSON_MODE, 'JSON'],
|
||||
]}
|
||||
value={mode}
|
||||
onChange={newMode => {
|
||||
try {
|
||||
setCurrentValue(getValueAsMode(currentValue, newMode));
|
||||
setMode(newMode);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</SplitItem>
|
||||
</Split>
|
||||
</SplitItem>
|
||||
<SplitItem>
|
||||
<MultiButtonToggle
|
||||
buttons={[
|
||||
[YAML_MODE, 'YAML'],
|
||||
[JSON_MODE, 'JSON'],
|
||||
]}
|
||||
value={mode}
|
||||
onChange={newMode => {
|
||||
try {
|
||||
setCurrentValue(getValueAsMode(currentValue, newMode));
|
||||
setMode(newMode);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
variant="plain"
|
||||
aria-label={i18n._(t`Expand input`)}
|
||||
onClick={() => setIsExpanded(true)}
|
||||
>
|
||||
<ExpandArrowsAltIcon />
|
||||
</Button>
|
||||
</SplitItem>
|
||||
</Split>
|
||||
</DetailName>
|
||||
@ -122,7 +151,7 @@ function VariablesDetail({ dataCy, helpText, value, label, rows, fullHeight }) {
|
||||
VariablesDetail.propTypes = {
|
||||
value: oneOfType([shape({}), arrayOf(string), string]).isRequired,
|
||||
label: node.isRequired,
|
||||
rows: number,
|
||||
rows: oneOfType(number, string),
|
||||
dataCy: string,
|
||||
helpText: string,
|
||||
};
|
||||
|
||||
@ -4,7 +4,8 @@ import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { useField } from 'formik';
|
||||
import styled from 'styled-components';
|
||||
import { Split, SplitItem } from '@patternfly/react-core';
|
||||
import { Split, SplitItem, Button, Modal } from '@patternfly/react-core';
|
||||
import { ExpandArrowsAltIcon } from '@patternfly/react-icons';
|
||||
import { CheckboxField } from '../FormField';
|
||||
import MultiButtonToggle from '../MultiButtonToggle';
|
||||
import { yamlToJson, jsonToYaml, isJsonString } from '../../util/yaml';
|
||||
@ -20,6 +21,7 @@ const FieldHeader = styled.div`
|
||||
|
||||
const StyledCheckboxField = styled(CheckboxField)`
|
||||
--pf-c-check__label--FontSize: var(--pf-c-form__label--FontSize);
|
||||
margin-left: auto;
|
||||
`;
|
||||
|
||||
function VariablesField({
|
||||
@ -31,10 +33,91 @@ function VariablesField({
|
||||
promptId,
|
||||
tooltip,
|
||||
}) {
|
||||
const [field, meta, helpers] = useField(name);
|
||||
const [field, meta] = useField(name);
|
||||
const [mode, setMode] = useState(
|
||||
isJsonString(field.value) ? JSON_MODE : YAML_MODE
|
||||
);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<VariablesFieldInternals
|
||||
i18n={i18n}
|
||||
id={id}
|
||||
name={name}
|
||||
label={label}
|
||||
readOnly={readOnly}
|
||||
promptId={promptId}
|
||||
tooltip={tooltip}
|
||||
onExpand={() => setIsExpanded(true)}
|
||||
mode={mode}
|
||||
setMode={setMode}
|
||||
/>
|
||||
<Modal
|
||||
variant="xlarge"
|
||||
title={label}
|
||||
isOpen={isExpanded}
|
||||
onClose={() => setIsExpanded(false)}
|
||||
actions={[
|
||||
<Button
|
||||
aria-label={i18n._(t`Done`)}
|
||||
key="select"
|
||||
variant="primary"
|
||||
onClick={() => setIsExpanded(false)}
|
||||
>
|
||||
{i18n._(t`Done`)}
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div className="pf-c-form">
|
||||
<VariablesFieldInternals
|
||||
i18n={i18n}
|
||||
id={`${id}-expanded`}
|
||||
name={name}
|
||||
label={label}
|
||||
readOnly={readOnly}
|
||||
promptId={promptId}
|
||||
tooltip={tooltip}
|
||||
fullHeight
|
||||
mode={mode}
|
||||
setMode={setMode}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
{meta.error ? (
|
||||
<div className="pf-c-form__helper-text pf-m-error" aria-live="polite">
|
||||
{meta.error}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
VariablesField.propTypes = {
|
||||
id: string.isRequired,
|
||||
name: string.isRequired,
|
||||
label: string.isRequired,
|
||||
readOnly: bool,
|
||||
promptId: string,
|
||||
};
|
||||
VariablesField.defaultProps = {
|
||||
readOnly: false,
|
||||
promptId: null,
|
||||
};
|
||||
|
||||
function VariablesFieldInternals({
|
||||
i18n,
|
||||
id,
|
||||
name,
|
||||
label,
|
||||
readOnly,
|
||||
promptId,
|
||||
tooltip,
|
||||
fullHeight,
|
||||
mode,
|
||||
setMode,
|
||||
onExpand,
|
||||
}) {
|
||||
const [field, meta, helpers] = useField(name);
|
||||
|
||||
return (
|
||||
<div className="pf-c-form__group">
|
||||
@ -75,6 +158,15 @@ function VariablesField({
|
||||
name="ask_variables_on_launch"
|
||||
/>
|
||||
)}
|
||||
{onExpand && (
|
||||
<Button
|
||||
variant="plain"
|
||||
aria-label={i18n._(t`Expand input`)}
|
||||
onClick={onExpand}
|
||||
>
|
||||
<ExpandArrowsAltIcon />
|
||||
</Button>
|
||||
)}
|
||||
</FieldHeader>
|
||||
<CodeEditor
|
||||
mode={mode}
|
||||
@ -83,26 +175,11 @@ function VariablesField({
|
||||
onChange={newVal => {
|
||||
helpers.setValue(newVal);
|
||||
}}
|
||||
fullHeight={fullHeight}
|
||||
hasErrors={!!meta.error}
|
||||
/>
|
||||
{meta.error ? (
|
||||
<div className="pf-c-form__helper-text pf-m-error" aria-live="polite">
|
||||
{meta.error}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
VariablesField.propTypes = {
|
||||
id: string.isRequired,
|
||||
name: string.isRequired,
|
||||
label: string.isRequired,
|
||||
readOnly: bool,
|
||||
promptId: string,
|
||||
};
|
||||
VariablesField.defaultProps = {
|
||||
readOnly: false,
|
||||
promptId: null,
|
||||
};
|
||||
|
||||
export default withI18n()(VariablesField);
|
||||
|
||||
@ -14,15 +14,7 @@ import { DetailName, DetailValue } from './Detail';
|
||||
import CodeEditor from '../CodeEditor';
|
||||
import Popover from '../Popover';
|
||||
|
||||
function CodeDetail({
|
||||
value,
|
||||
label,
|
||||
mode,
|
||||
rows,
|
||||
fullHeight,
|
||||
helpText,
|
||||
dataCy,
|
||||
}) {
|
||||
function CodeDetail({ value, label, mode, rows, helpText, dataCy }) {
|
||||
const labelCy = dataCy ? `${dataCy}-label` : null;
|
||||
const valueCy = dataCy ? `${dataCy}-value` : null;
|
||||
|
||||
@ -57,7 +49,6 @@ function CodeDetail({
|
||||
value={value}
|
||||
readOnly
|
||||
rows={rows}
|
||||
fullHeight={fullHeight}
|
||||
css="margin-top: 10px"
|
||||
/>
|
||||
</DetailValue>
|
||||
@ -69,7 +60,7 @@ CodeDetail.propTypes = {
|
||||
label: node.isRequired,
|
||||
dataCy: string,
|
||||
helpText: string,
|
||||
rows: number,
|
||||
rows: oneOfType(number, string),
|
||||
mode: oneOf(['javascript', 'yaml', 'jinja2']).isRequired,
|
||||
};
|
||||
CodeDetail.defaultProps = {
|
||||
|
||||
@ -36,7 +36,7 @@ function HostFacts({ i18n, host }) {
|
||||
return (
|
||||
<CardBody>
|
||||
<DetailList gutter="sm">
|
||||
<VariablesDetail label={i18n._(t`Facts`)} fullHeight value={facts} />
|
||||
<VariablesDetail label={i18n._(t`Facts`)} rows="auto" value={facts} />
|
||||
</DetailList>
|
||||
</CardBody>
|
||||
);
|
||||
|
||||
@ -35,7 +35,7 @@ function InventoryHostFacts({ i18n, host }) {
|
||||
return (
|
||||
<CardBody>
|
||||
<DetailList gutter="sm">
|
||||
<VariablesDetail label={i18n._(t`Facts`)} fullHeight value={result} />
|
||||
<VariablesDetail label={i18n._(t`Facts`)} rows="auto" value={result} />
|
||||
</DetailList>
|
||||
</CardBody>
|
||||
);
|
||||
|
||||
@ -286,7 +286,7 @@ const ObjectField = withI18n()(({ i18n, name, config, isRequired = false }) => {
|
||||
>
|
||||
<CodeEditor
|
||||
{...field}
|
||||
fullHeight
|
||||
rows="auto"
|
||||
id={name}
|
||||
mode="javascript"
|
||||
onChange={value => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user