update forms from FormRow to using FormLayout components

This commit is contained in:
John Mitchell
2020-02-18 14:35:41 -05:00
parent ff823c9fdb
commit df13a8fea9
17 changed files with 655 additions and 608 deletions

View File

@@ -3,6 +3,7 @@ import { string, bool } from 'prop-types';
import { useField } from 'formik';
import { Split, SplitItem } from '@patternfly/react-core';
import { yamlToJson, jsonToYaml, isJson } from '@util/yaml';
import { FormFullWidthLayout } from '@components/FormLayout';
import CodeMirrorInput from './CodeMirrorInput';
import YamlJsonToggle from './YamlJsonToggle';
import { JSON_MODE, YAML_MODE } from './constants';
@@ -12,9 +13,7 @@ function VariablesField({ id, name, label, readOnly }) {
const [mode, setMode] = useState(isJson(field.value) ? JSON_MODE : YAML_MODE);
return (
<Field name={name}>
{({ field, form }) => (
<div className="pf-c-form__group">
<FormFullWidthLayout>
<Split gutter="sm">
<SplitItem>
<label htmlFor={id} className="pf-c-form__label">
@@ -53,9 +52,7 @@ function VariablesField({ id, name, label, readOnly }) {
{meta.error}
</div>
) : null}
</div>
)}
</Field>
</FormFullWidthLayout>
);
}
VariablesField.propTypes = {

View File

@@ -9,6 +9,7 @@ const ActionGroup = styled(PFActionGroup)`
display: flex;
justify-content: flex-end;
--pf-c-form__group--m-action--MarginTop: 0;
grid-column: 1 / -1;
.pf-c-form__actions {
& > button {

View File

@@ -0,0 +1,44 @@
import styled from 'styled-components';
export const FormColumnLayout = styled.div`
width: 100%;
grid-column: 1 / 4;
display: grid;
grid-gap: 20px;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
@media (min-width: 1210px) {
grid-template-columns: repeat(3, 1fr);
}
`;
export const FormFullWidthLayout = styled.div`
grid-column: 1 / -1;
display: grid;
grid-template-columns: 1fr;
grid-gap: 20px;
`;
export const FormCheckboxLayout = styled.div`
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
& > * {
margin-right: 30px;
margin-bottom: 10px;
}
`;
export const SubFormLayout = styled.div`
grid-column: 1 / -1;
background-color: #f5f5f5;
margin: 0 -24px;
padding: 24px;
& > .pf-c-title {
--pf-c-title--m-md--FontWeight: 700;
grid-column: 1 / -1;
margin-bottom: 20px;
}
`;

View File

@@ -0,0 +1,6 @@
export {
FormColumnLayout,
FormFullWidthLayout,
FormCheckboxLayout,
SubFormLayout,
} from './FormLayout';

View File

@@ -1,11 +0,0 @@
import React from 'react';
import styled from 'styled-components';
const Row = styled.div`
display: grid;
grid-gap: 20px;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
`;
export default function FormRow({ children, className }) {
return <Row className={className}>{children}</Row>;
}

View File

@@ -1,11 +0,0 @@
import React from 'react';
import { mount } from 'enzyme';
import FormRow from './FormRow';
describe('FormRow', () => {
test('renders the expected content', () => {
const wrapper = mount(<FormRow />);
expect(wrapper).toHaveLength(1);
});
});

View File

@@ -1 +0,0 @@
export { default } from './FormRow';

View File

@@ -8,12 +8,12 @@ import { t } from '@lingui/macro';
import { Form } from '@patternfly/react-core';
import FormRow from '@components/FormRow';
import FormField, { FormSubmitError } from '@components/FormField';
import FormActionGroup from '@components/FormActionGroup/FormActionGroup';
import { VariablesField } from '@components/CodeMirrorInput';
import { required } from '@util/validators';
import { InventoryLookup } from '@components/Lookup';
import { FormColumnLayout } from '@components/FormLayout';
function HostFormFields({ host, i18n }) {
const [inventory, setInventory] = useState(
@@ -84,12 +84,14 @@ function HostForm({ handleSubmit, host, submitError, handleCancel, ...rest }) {
>
{formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormColumnLayout>
<HostFormFields host={host} {...rest} />
<FormSubmitError error={submitError} />
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
/>
</FormColumnLayout>
</Form>
)}
</Formik>

View File

@@ -12,6 +12,7 @@ import { required } from '@util/validators';
import InstanceGroupsLookup from '@components/Lookup/InstanceGroupsLookup';
import OrganizationLookup from '@components/Lookup/OrganizationLookup';
import CredentialLookup from '@components/Lookup/CredentialLookup';
import { FormColumnLayout } from '@components/FormLayout';
function InventoryFormFields({ i18n, credentialTypeId }) {
const [organizationField, organizationMeta, organizationHelpers] = useField({
@@ -108,13 +109,14 @@ function InventoryForm({
>
{formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormColumnLayout>
<InventoryFormFields {...rest} />
<FormSubmitError error={submitError} />
<FormActionGroup
onCancel={onCancel}
onSubmit={formik.handleSubmit}
/>
</FormRow>
</FormColumnLayout>
</Form>
)}
</Formik>

View File

@@ -6,11 +6,11 @@ import { Form, Card } from '@patternfly/react-core';
import { t } from '@lingui/macro';
import { CardBody } from '@components/Card';
import FormRow from '@components/FormRow';
import FormField from '@components/FormField';
import FormActionGroup from '@components/FormActionGroup/FormActionGroup';
import { VariablesField } from '@components/CodeMirrorInput';
import { required } from '@util/validators';
import { FormColumnLayout } from '@components/FormLayout';
function InventoryGroupForm({
i18n,
@@ -31,7 +31,7 @@ function InventoryGroupForm({
<Formik initialValues={initialValues} onSubmit={handleSubmit}>
{formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormRow css="grid-template-columns: repeat(auto-fit, minmax(300px, 500px));">
<FormColumnLayout>
<FormField
id="inventoryGroup-name"
name="name"
@@ -46,19 +46,17 @@ function InventoryGroupForm({
type="text"
label={i18n._(t`Description`)}
/>
</FormRow>
<FormRow>
<VariablesField
id="host-variables"
name="variables"
label={i18n._(t`Variables`)}
/>
</FormRow>
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
/>
{error ? <div>error</div> : null}
</FormColumnLayout>
</Form>
)}
</Formik>

View File

@@ -11,12 +11,12 @@ import { ConfigContext } from '@contexts/Config';
import AnsibleSelect from '@components/AnsibleSelect';
import ContentError from '@components/ContentError';
import ContentLoading from '@components/ContentLoading';
import FormRow from '@components/FormRow';
import FormField, { FormSubmitError } from '@components/FormField';
import FormActionGroup from '@components/FormActionGroup/FormActionGroup';
import { InstanceGroupsLookup } from '@components/Lookup/';
import { getAddedAndRemoved } from '@util/lists';
import { required, minMaxValue } from '@util/validators';
import { FormColumnLayout } from '@components/FormLayout';
function OrganizationFormFields({
i18n,
@@ -166,6 +166,7 @@ function OrganizationForm({
>
{formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormColumnLayout>
<OrganizationFormFields
instanceGroups={instanceGroups}
setInstanceGroups={setInstanceGroups}
@@ -176,6 +177,7 @@ function OrganizationForm({
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
/>
</FormColumnLayout>
</Form>
)}
</Formik>

View File

@@ -14,11 +14,10 @@ import FormField, {
FieldTooltip,
FormSubmitError,
} from '@components/FormField';
import FormRow from '@components/FormRow';
import OrganizationLookup from '@components/Lookup/OrganizationLookup';
import { CredentialTypesAPI, ProjectsAPI } from '@api';
import { required } from '@util/validators';
import styled from 'styled-components';
import { FormColumnLayout, SubFormLayout } from '@components/FormLayout';
import {
GitSubForm,
HgSubForm,
@@ -206,10 +205,9 @@ function ProjectFormFields({
/>
</FormGroup>
{formik.values.scm_type !== '' && (
<ScmTypeFormRow>
<SubFormTitle size="md">
{i18n._(t`Type Details`)}
</SubFormTitle>
<SubFormLayout>
<Title size="md">{i18n._(t`Type Details`)}</Title>
<FormColumnLayout>
{
{
manual: (
@@ -249,14 +247,13 @@ function ProjectFormFields({
),
}[formik.values.scm_type]
}
</ScmTypeFormRow>
</FormColumnLayout>
</SubFormLayout>
)}
<Config>
{({ custom_virtualenvs }) =>
custom_virtualenvs &&
custom_virtualenvs.length > 1 && (
<Field name="custom_virtualenv">
{({ field }) => (
<FormGroup
fieldId="project-custom-virtualenv"
label={i18n._(t`Ansible Environment`)}
@@ -373,6 +370,7 @@ function ProjectForm({ i18n, project, submitError, ...props }) {
onSubmit={formik.handleSubmit}
css="padding: 0 24px"
>
<FormColumnLayout>
<ProjectFormFields
project_base_dir={project_base_dir}
project_local_paths={project_local_paths}
@@ -391,6 +389,7 @@ function ProjectForm({ i18n, project, submitError, ...props }) {
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
/>
</FormColumnLayout>
</Form>
)}
</Formik>

View File

@@ -6,12 +6,10 @@ import CredentialLookup from '@components/Lookup/CredentialLookup';
import FormField, { CheckboxField } from '@components/FormField';
import { required } from '@util/validators';
import { FormGroup, Title } from '@patternfly/react-core';
import styled from 'styled-components';
export const SubFormTitle = styled(Title)`
--pf-c-title--m-md--FontWeight: 700;
grid-column: 1 / -1;
`;
import {
FormCheckboxLayout,
FormFullWidthLayout,
} from '@components/FormLayout';
export const UrlFormField = withI18n()(({ i18n, tooltip }) => (
<FormField
@@ -59,13 +57,9 @@ export const ScmCredentialFormField = withI18n()(
export const ScmTypeOptions = withI18n()(
({ i18n, scmUpdateOnLaunch, hideAllowOverride }) => (
<>
<FormGroup
css="grid-column: 1/-1"
fieldId="project-option-checkboxes"
label={i18n._(t`Options`)}
>
<FormRow>
<FormFullWidthLayout>
<FormGroup fieldId="project-option-checkboxes" label={i18n._(t`Options`)}>
<FormCheckboxLayout>
<CheckboxField
id="option-scm-clean"
name="scm_clean"
@@ -105,11 +99,12 @@ export const ScmTypeOptions = withI18n()(
)}
/>
)}
</FormRow>
</FormCheckboxLayout>
</FormGroup>
{scmUpdateOnLaunch && (
<>
<SubFormTitle size="md">{i18n._(t`Option Details`)}</SubFormTitle>
<Title size="md">{i18n._(t`Option Details`)}</Title>
<FormField
id="project-cache-timeout"
name="scm_update_cache_timeout"
@@ -125,6 +120,6 @@ export const ScmTypeOptions = withI18n()(
/>
</>
)}
</>
</FormFullWidthLayout>
)
);

View File

@@ -1,4 +1,3 @@
export { SubFormTitle } from './SharedFields';
export { default as GitSubForm } from './GitSubForm';
export { default as HgSubForm } from './HgSubForm';
export { default as InsightsSubForm } from './InsightsSubForm';

View File

@@ -8,6 +8,7 @@ import FormActionGroup from '@components/FormActionGroup/FormActionGroup';
import FormField, { FormSubmitError } from '@components/FormField';
import OrganizationLookup from '@components/Lookup/OrganizationLookup';
import { required } from '@util/validators';
import { FormColumnLayout } from '@components/FormLayout';
function TeamFormFields(props) {
const { team, i18n } = props;
@@ -68,14 +69,15 @@ function TeamForm(props) {
<Form
autoComplete="off"
onSubmit={formik.handleSubmit}
css="padding: 0 24px"
>
<FormColumnLayout>
<TeamFormFields team={team} {...rest} />
<FormSubmitError error={submitError} />
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
/>
</FormColumnLayout>
</Form>
)}
</Formik>

View File

@@ -22,10 +22,13 @@ import FormField, {
FormSubmitError,
} from '@components/FormField';
import FieldWithPrompt from '@components/FieldWithPrompt';
import FormRow from '@components/FormRow';
import {
FormColumnLayout,
FormFullWidthLayout,
FormCheckboxLayout,
} from '@components/FormLayout';
import CollapsibleSection from '@components/CollapsibleSection';
import { required } from '@util/validators';
import styled from 'styled-components';
import { JobTemplate } from '@types';
import {
InventoryLookup,
@@ -37,17 +40,6 @@ import { JobTemplatesAPI, ProjectsAPI } from '@api';
import LabelSelect from './LabelSelect';
import PlaybookSelect from './PlaybookSelect';
const GridFormGroup = styled(FormGroup)`
& > label {
grid-column: 1 / -1;
}
&& {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
`;
class JobTemplateForm extends Component {
static propTypes = {
template: JobTemplate,
@@ -211,9 +203,10 @@ class JobTemplateForm extends Component {
}
const AdvancedFieldsWrapper = template.isNew ? CollapsibleSection : 'div';
return (
<Form autoComplete="off" onSubmit={handleSubmit}>
<FormRow>
<FormColumnLayout>
<FormField
id="template-name"
name="name"
@@ -334,8 +327,7 @@ class JobTemplateForm extends Component {
);
}}
</Field>
</FormRow>
<FormRow>
<FormFullWidthLayout>
<Field name="labels">
{({ field }) => (
<FormGroup label={i18n._(t`Labels`)} fieldId="template-labels">
@@ -352,8 +344,6 @@ class JobTemplateForm extends Component {
</FormGroup>
)}
</Field>
</FormRow>
<FormRow>
<Field name="credentials" fieldId="template-credentials">
{({ field }) => (
<MultiCredentialsLookup
@@ -368,9 +358,8 @@ class JobTemplateForm extends Component {
/>
)}
</Field>
</FormRow>
<AdvancedFieldsWrapper label="Advanced">
<FormRow>
<FormColumnLayout>
<FormField
id="template-forks"
name="forks"
@@ -462,13 +451,14 @@ class JobTemplateForm extends Component {
</FormGroup>
)}
</Field>
</FormRow>
<FormFullWidthLayout>
<Field name="instanceGroups">
{({ field, form }) => (
<InstanceGroupsLookup
css="margin-top: 20px"
value={field.value}
onChange={value => form.setFieldValue(field.name, value)}
onChange={value =>
form.setFieldValue(field.name, value)
}
tooltip={i18n._(t`Select the Instance Groups for this Organization
to run on.`)}
/>
@@ -478,7 +468,6 @@ class JobTemplateForm extends Component {
{({ field, form }) => (
<FormGroup
label={i18n._(t`Job Tags`)}
css="margin-top: 20px"
fieldId="template-job-tags"
>
<FieldTooltip
@@ -490,7 +479,9 @@ class JobTemplateForm extends Component {
/>
<TagMultiSelect
value={field.value}
onChange={value => form.setFieldValue(field.name, value)}
onChange={value =>
form.setFieldValue(field.name, value)
}
/>
</FormGroup>
)}
@@ -499,7 +490,6 @@ class JobTemplateForm extends Component {
{({ field, form }) => (
<FormGroup
label={i18n._(t`Skip Tags`)}
css="margin-top: 20px"
fieldId="template-skip-tags"
>
<FieldTooltip
@@ -511,17 +501,19 @@ class JobTemplateForm extends Component {
/>
<TagMultiSelect
value={field.value}
onChange={value => form.setFieldValue(field.name, value)}
onChange={value =>
form.setFieldValue(field.name, value)
}
/>
</FormGroup>
)}
</Field>
<GridFormGroup
<FormGroup
fieldId="template-option-checkboxes"
isInline
label={i18n._(t`Options`)}
css="margin-top: 20px"
>
<FormCheckboxLayout>
<CheckboxField
id="option-privilege-escalation"
name="become_enabled"
@@ -563,14 +555,11 @@ class JobTemplateForm extends Component {
tooltip={i18n._(t`If enabled, use cached facts if available
and store discovered facts in the cache.`)}
/>
</GridFormGroup>
<div
css={`
${allowCallbacks ? '' : 'display: none'}
margin-top: 20px;
`}
>
<FormRow>
</FormCheckboxLayout>
</FormGroup>
</FormFullWidthLayout>
{allowCallbacks && (
<>
{callbackUrl && (
<FormGroup
label={i18n._(t`Provisioning Callback URL`)}
@@ -589,11 +578,14 @@ class JobTemplateForm extends Component {
label={i18n._(t`Host Config Key`)}
validate={allowCallbacks ? required(null, i18n) : null}
/>
</FormRow>
</div>
</>
)}
</FormColumnLayout>
</AdvancedFieldsWrapper>
</FormFullWidthLayout>
<FormSubmitError error={submitError} />
<FormActionGroup onCancel={handleCancel} onSubmit={handleSubmit} />
</FormColumnLayout>
</Form>
);
}

View File

@@ -10,9 +10,9 @@ import FormField, {
PasswordField,
FormSubmitError,
} from '@components/FormField';
import FormRow from '@components/FormRow';
import OrganizationLookup from '@components/Lookup/OrganizationLookup';
import { required, requiredEmail } from '@util/validators';
import { FormColumnLayout } from '@components/FormLayout';
function UserFormFields({ user, i18n }) {
const [organization, setOrganization] = useState(null);
@@ -99,6 +99,7 @@ function UserFormFields({ user, i18n }) {
type="text"
/>
{!user.id && (
<<<<<<< HEAD
<OrganizationLookup
helperTextInvalid={organizationMeta.error}
isValid={!organizationMeta.touched || !organizationMeta.error}
@@ -125,6 +126,34 @@ function UserFormFields({ user, i18n }) {
{...userTypeField}
/>
</FormGroup>
=======
<OrganizationLookup
helperTextInvalid={organizationMeta.error}
isValid={!organizationMeta.touched || !organizationMeta.error}
onBlur={() => organizationHelpers.setTouched()}
onChange={value => {
organizationHelpers.setValue(value.id);
setOrganization(value);
}}
value={organization}
required
/>
)}
<FormGroup
fieldId="user-type"
helperTextInvalid={userTypeMeta.error}
isRequired
isValid={!userTypeMeta.touched || !userTypeMeta.error}
label={i18n._(t`User Type`)}
>
<AnsibleSelect
isValid={!userTypeMeta.touched || !userTypeMeta.error}
id="user-type"
data={userTypeOptions}
{...userTypeField}
/>
</FormGroup>
>>>>>>> update forms from FormRow to using FormLayout components
</>
);
}
@@ -173,12 +202,14 @@ function UserForm({ user, handleCancel, handleSubmit, submitError, i18n }) {
>
{formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormColumnLayout>
<UserFormFields user={user} i18n={i18n} />
<FormSubmitError error={submitError} />
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
/>
</FormColumnLayout>
</Form>
)}
</Formik>