mirror of
https://github.com/ansible/awx.git
synced 2026-03-01 08:48:46 -03:30
Merge pull request #9585 from keithjgrant/8031-variables-expand-2
Add Expand button to variables fields SUMMARY Adds expand button to variables fields and details. Clicking it opens the code editor & YAML/JSON toggles in a large modal Addresses #8031 ISSUE TYPE Feature Pull Request COMPONENT NAME UI ADDITIONAL INFORMATION Reviewed-by: Kersom <None> Reviewed-by: Mat Wilson <mawilson@redhat.com>
This commit is contained in:
@@ -77,7 +77,8 @@
|
|||||||
"resizeOrientation",
|
"resizeOrientation",
|
||||||
"src",
|
"src",
|
||||||
"theme",
|
"theme",
|
||||||
"gridColumns"
|
"gridColumns",
|
||||||
|
"rows"
|
||||||
],
|
],
|
||||||
"ignore": ["Ansible", "Tower", "JSON", "YAML", "lg"],
|
"ignore": ["Ansible", "Tower", "JSON", "YAML", "lg"],
|
||||||
"ignoreComponent": [
|
"ignoreComponent": [
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useRef, useCallback } from 'react';
|
import React, { useEffect, useRef, useCallback } from 'react';
|
||||||
import { oneOf, bool, number, string, func } from 'prop-types';
|
import { oneOf, bool, number, string, func, oneOfType } from 'prop-types';
|
||||||
import ReactAce from 'react-ace';
|
import ReactAce from 'react-ace';
|
||||||
import 'ace-builds/src-noconflict/mode-json';
|
import 'ace-builds/src-noconflict/mode-json';
|
||||||
import 'ace-builds/src-noconflict/mode-javascript';
|
import 'ace-builds/src-noconflict/mode-javascript';
|
||||||
@@ -77,6 +77,13 @@ function CodeEditor({
|
|||||||
className,
|
className,
|
||||||
i18n,
|
i18n,
|
||||||
}) {
|
}) {
|
||||||
|
if (rows && 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 wrapper = useRef(null);
|
||||||
const editor = useRef(null);
|
const editor = useRef(null);
|
||||||
|
|
||||||
@@ -117,7 +124,8 @@ function CodeEditor({
|
|||||||
jinja2: 'django',
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -132,7 +140,7 @@ function CodeEditor({
|
|||||||
editorProps={{ $blockScrolling: true }}
|
editorProps={{ $blockScrolling: true }}
|
||||||
fontSize={16}
|
fontSize={16}
|
||||||
width="100%"
|
width="100%"
|
||||||
height={`${numRows * LINE_HEIGHT + PADDING}px`}
|
height={height}
|
||||||
hasErrors={hasErrors}
|
hasErrors={hasErrors}
|
||||||
setOptions={{
|
setOptions={{
|
||||||
readOnly,
|
readOnly,
|
||||||
@@ -178,7 +186,7 @@ CodeEditor.propTypes = {
|
|||||||
readOnly: bool,
|
readOnly: bool,
|
||||||
hasErrors: bool,
|
hasErrors: bool,
|
||||||
fullHeight: bool,
|
fullHeight: bool,
|
||||||
rows: number,
|
rows: oneOfType([number, string]),
|
||||||
className: string,
|
className: string,
|
||||||
};
|
};
|
||||||
CodeEditor.defaultProps = {
|
CodeEditor.defaultProps = {
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
import 'styled-components/macro';
|
import 'styled-components/macro';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { node, number, oneOfType, shape, string, arrayOf } from 'prop-types';
|
import { node, number, oneOfType, shape, string, arrayOf } from 'prop-types';
|
||||||
import { Trans, withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { Split, SplitItem, TextListItemVariants } from '@patternfly/react-core';
|
import { t } from '@lingui/macro';
|
||||||
|
import {
|
||||||
|
Split,
|
||||||
|
SplitItem,
|
||||||
|
TextListItemVariants,
|
||||||
|
Button,
|
||||||
|
Modal,
|
||||||
|
} from '@patternfly/react-core';
|
||||||
|
import { ExpandArrowsAltIcon } from '@patternfly/react-icons';
|
||||||
import { DetailName, DetailValue } from '../DetailList';
|
import { DetailName, DetailValue } from '../DetailList';
|
||||||
import MultiButtonToggle from '../MultiButtonToggle';
|
import MultiButtonToggle from '../MultiButtonToggle';
|
||||||
import Popover from '../Popover';
|
import Popover from '../Popover';
|
||||||
@@ -29,13 +37,14 @@ function getValueAsMode(value, mode) {
|
|||||||
return mode === YAML_MODE ? jsonToYaml(value) : yamlToJson(value);
|
return mode === YAML_MODE ? jsonToYaml(value) : yamlToJson(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function VariablesDetail({ dataCy, helpText, value, label, rows, fullHeight }) {
|
function VariablesDetail({ dataCy, helpText, value, label, rows, i18n }) {
|
||||||
const [mode, setMode] = useState(
|
const [mode, setMode] = useState(
|
||||||
isJsonObject(value) || isJsonString(value) ? JSON_MODE : YAML_MODE
|
isJsonObject(value) || isJsonString(value) ? JSON_MODE : YAML_MODE
|
||||||
);
|
);
|
||||||
const [currentValue, setCurrentValue] = useState(
|
const [currentValue, setCurrentValue] = useState(
|
||||||
isJsonObject(value) ? JSON.stringify(value, null, 2) : value || '---'
|
isJsonObject(value) ? JSON.stringify(value, null, 2) : value || '---'
|
||||||
);
|
);
|
||||||
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -60,7 +69,112 @@ function VariablesDetail({ dataCy, helpText, value, label, rows, fullHeight }) {
|
|||||||
fullWidth
|
fullWidth
|
||||||
css="grid-column: 1 / -1"
|
css="grid-column: 1 / -1"
|
||||||
>
|
>
|
||||||
<Split hasGutter>
|
<ModeToggle
|
||||||
|
label={label}
|
||||||
|
helpText={helpText}
|
||||||
|
dataCy={dataCy}
|
||||||
|
mode={mode}
|
||||||
|
setMode={setMode}
|
||||||
|
currentValue={currentValue}
|
||||||
|
setCurrentValue={setCurrentValue}
|
||||||
|
setError={setError}
|
||||||
|
onExpand={() => setIsExpanded(true)}
|
||||||
|
i18n={i18n}
|
||||||
|
/>
|
||||||
|
</DetailName>
|
||||||
|
<DetailValue
|
||||||
|
data-cy={valueCy}
|
||||||
|
component={TextListItemVariants.dd}
|
||||||
|
fullWidth
|
||||||
|
css="grid-column: 1 / -1; margin-top: -20px"
|
||||||
|
>
|
||||||
|
<CodeEditor
|
||||||
|
mode={mode}
|
||||||
|
value={currentValue}
|
||||||
|
readOnly
|
||||||
|
rows={rows}
|
||||||
|
css="margin-top: 10px"
|
||||||
|
/>
|
||||||
|
{error && (
|
||||||
|
<div
|
||||||
|
css="color: var(--pf-global--danger-color--100);
|
||||||
|
font-size: var(--pf-global--FontSize--sm"
|
||||||
|
>
|
||||||
|
{i18n._(t`Error:`)} {error.message}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</DetailValue>
|
||||||
|
<Modal
|
||||||
|
variant="xlarge"
|
||||||
|
title={label}
|
||||||
|
isOpen={isExpanded}
|
||||||
|
onClose={() => setIsExpanded(false)}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
aria-label={i18n._(t`Done`)}
|
||||||
|
key="select"
|
||||||
|
variant="primary"
|
||||||
|
onClick={() => setIsExpanded(false)}
|
||||||
|
ouiaId={`${dataCy}-unexpand`}
|
||||||
|
>
|
||||||
|
{i18n._(t`Done`)}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<div className="pf-c-form">
|
||||||
|
<ModeToggle
|
||||||
|
label={label}
|
||||||
|
helpText={helpText}
|
||||||
|
dataCy={dataCy}
|
||||||
|
mode={mode}
|
||||||
|
setMode={setMode}
|
||||||
|
currentValue={currentValue}
|
||||||
|
setCurrentValue={setCurrentValue}
|
||||||
|
setError={setError}
|
||||||
|
i18n={i18n}
|
||||||
|
/>
|
||||||
|
<CodeEditor
|
||||||
|
mode={mode}
|
||||||
|
value={currentValue}
|
||||||
|
readOnly
|
||||||
|
rows={rows}
|
||||||
|
fullHeight
|
||||||
|
css="margin-top: 10px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
VariablesDetail.propTypes = {
|
||||||
|
value: oneOfType([shape({}), arrayOf(string), string]).isRequired,
|
||||||
|
label: node.isRequired,
|
||||||
|
rows: oneOfType([number, string]),
|
||||||
|
dataCy: string,
|
||||||
|
helpText: string,
|
||||||
|
};
|
||||||
|
VariablesDetail.defaultProps = {
|
||||||
|
rows: null,
|
||||||
|
dataCy: '',
|
||||||
|
helpText: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
function ModeToggle({
|
||||||
|
label,
|
||||||
|
helpText,
|
||||||
|
dataCy,
|
||||||
|
currentValue,
|
||||||
|
setCurrentValue,
|
||||||
|
mode,
|
||||||
|
setMode,
|
||||||
|
setError,
|
||||||
|
onExpand,
|
||||||
|
i18n,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Split hasGutter>
|
||||||
|
<SplitItem isFilled>
|
||||||
|
<Split hasGutter css="align-items: baseline">
|
||||||
<SplitItem>
|
<SplitItem>
|
||||||
<div className="pf-c-form__label">
|
<div className="pf-c-form__label">
|
||||||
<span
|
<span
|
||||||
@@ -92,44 +206,21 @@ function VariablesDetail({ dataCy, helpText, value, label, rows, fullHeight }) {
|
|||||||
/>
|
/>
|
||||||
</SplitItem>
|
</SplitItem>
|
||||||
</Split>
|
</Split>
|
||||||
</DetailName>
|
</SplitItem>
|
||||||
<DetailValue
|
{onExpand && (
|
||||||
data-cy={valueCy}
|
<SplitItem>
|
||||||
component={TextListItemVariants.dd}
|
<Button
|
||||||
fullWidth
|
variant="plain"
|
||||||
css="grid-column: 1 / -1; margin-top: -20px"
|
aria-label={i18n._(t`Expand input`)}
|
||||||
>
|
onClick={onExpand}
|
||||||
<CodeEditor
|
ouiaId={`${dataCy}-expand`}
|
||||||
mode={mode}
|
|
||||||
value={currentValue}
|
|
||||||
readOnly
|
|
||||||
rows={rows}
|
|
||||||
fullHeight={fullHeight}
|
|
||||||
css="margin-top: 10px"
|
|
||||||
/>
|
|
||||||
{error && (
|
|
||||||
<div
|
|
||||||
css="color: var(--pf-global--danger-color--100);
|
|
||||||
font-size: var(--pf-global--FontSize--sm"
|
|
||||||
>
|
>
|
||||||
<Trans>Error:</Trans> {error.message}
|
<ExpandArrowsAltIcon />
|
||||||
</div>
|
</Button>
|
||||||
)}
|
</SplitItem>
|
||||||
</DetailValue>
|
)}
|
||||||
</>
|
</Split>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
VariablesDetail.propTypes = {
|
|
||||||
value: oneOfType([shape({}), arrayOf(string), string]).isRequired,
|
|
||||||
label: node.isRequired,
|
|
||||||
rows: number,
|
|
||||||
dataCy: string,
|
|
||||||
helpText: string,
|
|
||||||
};
|
|
||||||
VariablesDetail.defaultProps = {
|
|
||||||
rows: null,
|
|
||||||
dataCy: '',
|
|
||||||
helpText: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default withI18n()(VariablesDetail);
|
export default withI18n()(VariablesDetail);
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { withI18n } from '@lingui/react';
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { useField } from 'formik';
|
import { useField } from 'formik';
|
||||||
import styled from 'styled-components';
|
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 { CheckboxField } from '../FormField';
|
||||||
import MultiButtonToggle from '../MultiButtonToggle';
|
import MultiButtonToggle from '../MultiButtonToggle';
|
||||||
import { yamlToJson, jsonToYaml, isJsonString } from '../../util/yaml';
|
import { yamlToJson, jsonToYaml, isJsonString } from '../../util/yaml';
|
||||||
@@ -20,6 +21,7 @@ const FieldHeader = styled.div`
|
|||||||
|
|
||||||
const StyledCheckboxField = styled(CheckboxField)`
|
const StyledCheckboxField = styled(CheckboxField)`
|
||||||
--pf-c-check__label--FontSize: var(--pf-c-form__label--FontSize);
|
--pf-c-check__label--FontSize: var(--pf-c-form__label--FontSize);
|
||||||
|
margin-left: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function VariablesField({
|
function VariablesField({
|
||||||
@@ -31,10 +33,92 @@ function VariablesField({
|
|||||||
promptId,
|
promptId,
|
||||||
tooltip,
|
tooltip,
|
||||||
}) {
|
}) {
|
||||||
const [field, meta, helpers] = useField(name);
|
const [field, meta] = useField(name);
|
||||||
const [mode, setMode] = useState(
|
const [mode, setMode] = useState(
|
||||||
isJsonString(field.value) ? JSON_MODE : YAML_MODE
|
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)}
|
||||||
|
ouiaId={`${id}-variables-unexpand`}
|
||||||
|
>
|
||||||
|
{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 (
|
return (
|
||||||
<div className="pf-c-form__group">
|
<div className="pf-c-form__group">
|
||||||
@@ -75,6 +159,16 @@ function VariablesField({
|
|||||||
name="ask_variables_on_launch"
|
name="ask_variables_on_launch"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{onExpand && (
|
||||||
|
<Button
|
||||||
|
variant="plain"
|
||||||
|
aria-label={i18n._(t`Expand input`)}
|
||||||
|
onClick={onExpand}
|
||||||
|
ouiaId={`${id}-variables-expand`}
|
||||||
|
>
|
||||||
|
<ExpandArrowsAltIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</FieldHeader>
|
</FieldHeader>
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
mode={mode}
|
mode={mode}
|
||||||
@@ -83,26 +177,11 @@ function VariablesField({
|
|||||||
onChange={newVal => {
|
onChange={newVal => {
|
||||||
helpers.setValue(newVal);
|
helpers.setValue(newVal);
|
||||||
}}
|
}}
|
||||||
|
fullHeight={fullHeight}
|
||||||
hasErrors={!!meta.error}
|
hasErrors={!!meta.error}
|
||||||
/>
|
/>
|
||||||
{meta.error ? (
|
|
||||||
<div className="pf-c-form__helper-text pf-m-error" aria-live="polite">
|
|
||||||
{meta.error}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</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);
|
export default withI18n()(VariablesField);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ describe('VariablesField', () => {
|
|||||||
</Formik>
|
</Formik>
|
||||||
);
|
);
|
||||||
const buttons = wrapper.find('Button');
|
const buttons = wrapper.find('Button');
|
||||||
expect(buttons).toHaveLength(2);
|
expect(buttons).toHaveLength(3);
|
||||||
expect(buttons.at(0).prop('variant')).toEqual('primary');
|
expect(buttons.at(0).prop('variant')).toEqual('primary');
|
||||||
expect(buttons.at(1).prop('variant')).toEqual('secondary');
|
expect(buttons.at(1).prop('variant')).toEqual('secondary');
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -136,4 +136,27 @@ describe('VariablesField', () => {
|
|||||||
|
|
||||||
expect(wrapper.find('CodeEditor').prop('mode')).toEqual('javascript');
|
expect(wrapper.find('CodeEditor').prop('mode')).toEqual('javascript');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should open modal when expanded', async () => {
|
||||||
|
const value = '---';
|
||||||
|
const wrapper = mountWithContexts(
|
||||||
|
<Formik initialValues={{ variables: value }} onSubmit={jest.fn()}>
|
||||||
|
{formik => (
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<VariablesField id="the-field" name="variables" label="Variables" />
|
||||||
|
<button type="submit" id="submit">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
);
|
||||||
|
expect(wrapper.find('Modal').prop('isOpen')).toEqual(false);
|
||||||
|
|
||||||
|
wrapper.find('Button[variant="plain"]').invoke('onClick')();
|
||||||
|
wrapper.update();
|
||||||
|
|
||||||
|
expect(wrapper.find('Modal').prop('isOpen')).toEqual(true);
|
||||||
|
expect(wrapper.find('Modal CodeEditor')).toHaveLength(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,15 +14,7 @@ import { DetailName, DetailValue } from './Detail';
|
|||||||
import CodeEditor from '../CodeEditor';
|
import CodeEditor from '../CodeEditor';
|
||||||
import Popover from '../Popover';
|
import Popover from '../Popover';
|
||||||
|
|
||||||
function CodeDetail({
|
function CodeDetail({ value, label, mode, rows, helpText, dataCy }) {
|
||||||
value,
|
|
||||||
label,
|
|
||||||
mode,
|
|
||||||
rows,
|
|
||||||
fullHeight,
|
|
||||||
helpText,
|
|
||||||
dataCy,
|
|
||||||
}) {
|
|
||||||
const labelCy = dataCy ? `${dataCy}-label` : null;
|
const labelCy = dataCy ? `${dataCy}-label` : null;
|
||||||
const valueCy = dataCy ? `${dataCy}-value` : null;
|
const valueCy = dataCy ? `${dataCy}-value` : null;
|
||||||
|
|
||||||
@@ -57,7 +49,6 @@ function CodeDetail({
|
|||||||
value={value}
|
value={value}
|
||||||
readOnly
|
readOnly
|
||||||
rows={rows}
|
rows={rows}
|
||||||
fullHeight={fullHeight}
|
|
||||||
css="margin-top: 10px"
|
css="margin-top: 10px"
|
||||||
/>
|
/>
|
||||||
</DetailValue>
|
</DetailValue>
|
||||||
@@ -69,7 +60,7 @@ CodeDetail.propTypes = {
|
|||||||
label: node.isRequired,
|
label: node.isRequired,
|
||||||
dataCy: string,
|
dataCy: string,
|
||||||
helpText: string,
|
helpText: string,
|
||||||
rows: number,
|
rows: oneOfType(number, string),
|
||||||
mode: oneOf(['javascript', 'yaml', 'jinja2']).isRequired,
|
mode: oneOf(['javascript', 'yaml', 'jinja2']).isRequired,
|
||||||
};
|
};
|
||||||
CodeDetail.defaultProps = {
|
CodeDetail.defaultProps = {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ function HostFacts({ i18n, host }) {
|
|||||||
return (
|
return (
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<DetailList gutter="sm">
|
<DetailList gutter="sm">
|
||||||
<VariablesDetail label={i18n._(t`Facts`)} fullHeight value={facts} />
|
<VariablesDetail label={i18n._(t`Facts`)} rows="auto" value={facts} />
|
||||||
</DetailList>
|
</DetailList>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -72,11 +72,12 @@ describe('<InventoryGroupDetail />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should open delete modal and then call api to delete the group', async () => {
|
test('should open delete modal and then call api to delete the group', async () => {
|
||||||
|
expect(wrapper.find('Modal').length).toBe(1); // variables modal already mounted
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('button[aria-label="Delete"]').simulate('click');
|
wrapper.find('button[aria-label="Delete"]').simulate('click');
|
||||||
});
|
});
|
||||||
await waitForElement(wrapper, 'Modal', el => el.length === 1);
|
wrapper.update();
|
||||||
expect(wrapper.find('Modal').length).toBe(1);
|
expect(wrapper.find('Modal').length).toBe(2);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('Radio[id="radio-delete"]').invoke('onChange')();
|
wrapper.find('Radio[id="radio-delete"]').invoke('onChange')();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ function InventoryHostFacts({ i18n, host }) {
|
|||||||
return (
|
return (
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<DetailList gutter="sm">
|
<DetailList gutter="sm">
|
||||||
<VariablesDetail label={i18n._(t`Facts`)} fullHeight value={result} />
|
<VariablesDetail label={i18n._(t`Facts`)} rows="auto" value={result} />
|
||||||
</DetailList>
|
</DetailList>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ const ObjectField = withI18n()(({ i18n, name, config, isRequired = false }) => {
|
|||||||
>
|
>
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
{...field}
|
{...field}
|
||||||
fullHeight
|
rows="auto"
|
||||||
id={name}
|
id={name}
|
||||||
mode="javascript"
|
mode="javascript"
|
||||||
onChange={value => {
|
onChange={value => {
|
||||||
|
|||||||
@@ -371,6 +371,7 @@ function JobTemplateDetail({ i18n, template }) {
|
|||||||
value={extra_vars}
|
value={extra_vars}
|
||||||
rows={4}
|
rows={4}
|
||||||
label={i18n._(t`Variables`)}
|
label={i18n._(t`Variables`)}
|
||||||
|
dataCy={`jt-details-${template.id}`}
|
||||||
/>
|
/>
|
||||||
</DetailList>
|
</DetailList>
|
||||||
<CardActionsRow>
|
<CardActionsRow>
|
||||||
|
|||||||
Reference in New Issue
Block a user