diff --git a/awx/ui_next/.eslintrc b/awx/ui_next/.eslintrc index f82900134e..b7c86c305a 100644 --- a/awx/ui_next/.eslintrc +++ b/awx/ui_next/.eslintrc @@ -77,7 +77,8 @@ "resizeOrientation", "src", "theme", - "gridColumns" + "gridColumns", + "rows" ], "ignore": ["Ansible", "Tower", "JSON", "YAML", "lg"], "ignoreComponent": [ diff --git a/awx/ui_next/src/components/CodeEditor/CodeEditor.jsx b/awx/ui_next/src/components/CodeEditor/CodeEditor.jsx index 0218a83c3c..981cf01610 100644 --- a/awx/ui_next/src/components/CodeEditor/CodeEditor.jsx +++ b/awx/ui_next/src/components/CodeEditor/CodeEditor.jsx @@ -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 = { diff --git a/awx/ui_next/src/components/CodeEditor/VariablesDetail.jsx b/awx/ui_next/src/components/CodeEditor/VariablesDetail.jsx index f5cfd91373..602ef6695f 100644 --- a/awx/ui_next/src/components/CodeEditor/VariablesDetail.jsx +++ b/awx/ui_next/src/components/CodeEditor/VariablesDetail.jsx @@ -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" > - -
- - {label} - - {helpText && ( - - )} -
+ + + +
+ + {label} + + {helpText && ( + + )} +
+
+ + { + try { + setCurrentValue(getValueAsMode(currentValue, newMode)); + setMode(newMode); + } catch (err) { + setError(err); + } + }} + /> + +
- { - try { - setCurrentValue(getValueAsMode(currentValue, newMode)); - setMode(newMode); - } catch (err) { - setError(err); - } - }} - /> +
@@ -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, }; diff --git a/awx/ui_next/src/components/CodeEditor/VariablesField.jsx b/awx/ui_next/src/components/CodeEditor/VariablesField.jsx index 8fbf1e4bfa..35756132e8 100644 --- a/awx/ui_next/src/components/CodeEditor/VariablesField.jsx +++ b/awx/ui_next/src/components/CodeEditor/VariablesField.jsx @@ -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 ( + <> + setIsExpanded(true)} + mode={mode} + setMode={setMode} + /> + setIsExpanded(false)} + actions={[ + , + ]} + > +
+ +
+
+ {meta.error ? ( +
+ {meta.error} +
+ ) : 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 (
@@ -75,6 +158,15 @@ function VariablesField({ name="ask_variables_on_launch" /> )} + {onExpand && ( + + )} { helpers.setValue(newVal); }} + fullHeight={fullHeight} hasErrors={!!meta.error} /> - {meta.error ? ( -
- {meta.error} -
- ) : null}
); } -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); diff --git a/awx/ui_next/src/components/DetailList/CodeDetail.jsx b/awx/ui_next/src/components/DetailList/CodeDetail.jsx index 08c935b18e..90edb259e8 100644 --- a/awx/ui_next/src/components/DetailList/CodeDetail.jsx +++ b/awx/ui_next/src/components/DetailList/CodeDetail.jsx @@ -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" /> @@ -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 = { diff --git a/awx/ui_next/src/screens/Host/HostFacts/HostFacts.jsx b/awx/ui_next/src/screens/Host/HostFacts/HostFacts.jsx index f33c989f5b..08b447a991 100644 --- a/awx/ui_next/src/screens/Host/HostFacts/HostFacts.jsx +++ b/awx/ui_next/src/screens/Host/HostFacts/HostFacts.jsx @@ -36,7 +36,7 @@ function HostFacts({ i18n, host }) { return ( - + ); diff --git a/awx/ui_next/src/screens/Inventory/InventoryHostFacts/InventoryHostFacts.jsx b/awx/ui_next/src/screens/Inventory/InventoryHostFacts/InventoryHostFacts.jsx index 6bffd37ba4..4d93ce58c3 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryHostFacts/InventoryHostFacts.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryHostFacts/InventoryHostFacts.jsx @@ -35,7 +35,7 @@ function InventoryHostFacts({ i18n, host }) { return ( - + ); diff --git a/awx/ui_next/src/screens/Setting/shared/SharedFields.jsx b/awx/ui_next/src/screens/Setting/shared/SharedFields.jsx index b5e118088a..96dc973de5 100644 --- a/awx/ui_next/src/screens/Setting/shared/SharedFields.jsx +++ b/awx/ui_next/src/screens/Setting/shared/SharedFields.jsx @@ -286,7 +286,7 @@ const ObjectField = withI18n()(({ i18n, name, config, isRequired = false }) => { > {