diff --git a/awx/ui_next/src/api/models/Credentials.js b/awx/ui_next/src/api/models/Credentials.js index 2e3634b4e5..9b31506956 100644 --- a/awx/ui_next/src/api/models/Credentials.js +++ b/awx/ui_next/src/api/models/Credentials.js @@ -4,6 +4,14 @@ class Credentials extends Base { constructor(http) { super(http); this.baseUrl = '/api/v2/credentials/'; + + this.readAccessList = this.readAccessList.bind(this); + } + + readAccessList(id, params) { + return this.http.get(`${this.baseUrl}${id}/access_list/`, { + params, + }); } } diff --git a/awx/ui_next/src/components/CodeMirrorInput/VariablesField.jsx b/awx/ui_next/src/components/CodeMirrorInput/VariablesField.jsx index 79bd41a826..91818e84c7 100644 --- a/awx/ui_next/src/components/CodeMirrorInput/VariablesField.jsx +++ b/awx/ui_next/src/components/CodeMirrorInput/VariablesField.jsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import { string, bool } from 'prop-types'; -import { Field, useFormikContext } from 'formik'; +import { useField } from 'formik'; import { Split, SplitItem } from '@patternfly/react-core'; import { yamlToJson, jsonToYaml, isJson } from '@util/yaml'; import CodeMirrorInput from './CodeMirrorInput'; @@ -8,58 +8,50 @@ import YamlJsonToggle from './YamlJsonToggle'; import { JSON_MODE, YAML_MODE } from './constants'; function VariablesField({ id, name, label, readOnly }) { - const { values } = useFormikContext(); - const value = values[name]; - const [mode, setMode] = useState(isJson(value) ? JSON_MODE : YAML_MODE); + const [field, meta, helpers] = useField(name); + const [mode, setMode] = useState(isJson(field.value) ? JSON_MODE : YAML_MODE); return ( - - {({ field, form }) => ( -
- - - - - - { - try { - const newVal = - newMode === YAML_MODE - ? jsonToYaml(field.value) - : yamlToJson(field.value); - form.setFieldValue(name, newVal); - setMode(newMode); - } catch (err) { - form.setFieldError(name, err.message); - } - }} - /> - - - + + + + + + { - form.setFieldValue(name, newVal); + onChange={newMode => { + try { + const newVal = + newMode === YAML_MODE + ? jsonToYaml(field.value) + : yamlToJson(field.value); + helpers.setValue(newVal); + setMode(newMode); + } catch (err) { + helpers.setError(err.message); + } }} - hasErrors={!!form.errors[field.name]} /> - {form.errors[field.name] ? ( -
- {form.errors[field.name]} -
- ) : null} +
+
+ { + helpers.setValue(newVal); + }} + hasErrors={!!meta.error} + /> + {meta.error ? ( +
+ {meta.error}
- )} - + ) : null} + ); } VariablesField.propTypes = { diff --git a/awx/ui_next/src/components/CollapsibleSection/ExpandingContainer.jsx b/awx/ui_next/src/components/CollapsibleSection/ExpandingContainer.jsx index 35804d324d..b89ce94d7b 100644 --- a/awx/ui_next/src/components/CollapsibleSection/ExpandingContainer.jsx +++ b/awx/ui_next/src/components/CollapsibleSection/ExpandingContainer.jsx @@ -19,7 +19,7 @@ function ExpandingContainer({ isExpanded, children }) { }); useEffect(() => { setContentHeight(ref.current.scrollHeight); - }, [setContentHeight]); + }, [setContentHeight, children]); const height = isExpanded ? contentHeight : '0'; return ( ( `} `; -const DetailValue = styled(({ fullWidth, ...props }) => ( +const DetailValue = styled(({ fullWidth, isEncrypted, ...props }) => ( ))` word-break: break-all; @@ -23,6 +23,12 @@ const DetailValue = styled(({ fullWidth, ...props }) => ( ` grid-column: 2 / -1; `} + ${props => + props.isEncrypted && + ` + text-transform: uppercase + color: var(--pf-global--Color--400); + `} `; const Detail = ({ @@ -32,6 +38,7 @@ const Detail = ({ className, dataCy, alwaysVisible, + isEncrypted, }) => { if (!value && typeof value !== 'number' && !alwaysVisible) { return null; @@ -55,6 +62,7 @@ const Detail = ({ component={TextListItemVariants.dd} fullWidth={fullWidth} data-cy={valueCy} + isEncrypted={isEncrypted} > {value} diff --git a/awx/ui_next/src/components/FormActionGroup/FormActionGroup.jsx b/awx/ui_next/src/components/FormActionGroup/FormActionGroup.jsx index bae4fe0772..203de01483 100644 --- a/awx/ui_next/src/components/FormActionGroup/FormActionGroup.jsx +++ b/awx/ui_next/src/components/FormActionGroup/FormActionGroup.jsx @@ -9,6 +9,8 @@ const ActionGroup = styled(PFActionGroup)` display: flex; justify-content: flex-end; --pf-c-form__group--m-action--MarginTop: 0; + grid-column: 1 / -1; + margin-right: calc(var(--pf-c-form__actions--MarginRight) * -1); .pf-c-form__actions { & > button { diff --git a/awx/ui_next/src/components/FormField/CheckboxField.jsx b/awx/ui_next/src/components/FormField/CheckboxField.jsx index 9e854d803a..a04a78b02c 100644 --- a/awx/ui_next/src/components/FormField/CheckboxField.jsx +++ b/awx/ui_next/src/components/FormField/CheckboxField.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { string, func } from 'prop-types'; -import { Field } from 'formik'; +import { useField } from 'formik'; import { Checkbox, Tooltip } from '@patternfly/react-core'; import { QuestionCircleIcon as PFQuestionCircleIcon } from '@patternfly/react-icons'; import styled from 'styled-components'; @@ -10,32 +10,29 @@ const QuestionCircleIcon = styled(PFQuestionCircleIcon)` `; function CheckboxField({ id, name, label, tooltip, validate, ...rest }) { + const [field] = useField({ name, validate }); return ( - - {({ field }) => ( - - {label} -   - {tooltip && ( - - - - )} - - } - id={id} - {...rest} - isChecked={field.value} - {...field} - onChange={(value, event) => { - field.onChange(event); - }} - /> - )} - + + {label} +   + {tooltip && ( + + + + )} + + } + id={id} + {...rest} + isChecked={field.value} + {...field} + onChange={(value, event) => { + field.onChange(event); + }} + /> ); } CheckboxField.propTypes = { diff --git a/awx/ui_next/src/components/FormField/FormField.jsx b/awx/ui_next/src/components/FormField/FormField.jsx index f55eabb131..19b1b8a0af 100644 --- a/awx/ui_next/src/components/FormField/FormField.jsx +++ b/awx/ui_next/src/components/FormField/FormField.jsx @@ -1,7 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Field } from 'formik'; -import { FormGroup, TextInput, Tooltip } from '@patternfly/react-core'; +import { useField } from 'formik'; +import { + FormGroup, + TextInput, + TextArea, + Tooltip, +} from '@patternfly/react-core'; import { QuestionCircleIcon as PFQuestionCircleIcon } from '@patternfly/react-icons'; import styled from 'styled-components'; @@ -18,53 +23,81 @@ function FormField(props) { tooltipMaxWidth, validate, isRequired, + type, ...rest } = props; - return ( - - {({ field, form }) => { - const isValid = - form && (!form.touched[field.name] || !form.errors[field.name]); + const [field, meta] = useField({ name, validate }); + const isValid = !(meta.touched && meta.error); - return ( - + {(type === 'textarea' && ( + + {tooltip && ( + + + + )} +