add FieldTooltip component, some JobTemplateForm cleanup

This commit is contained in:
Keith Grant
2019-09-23 10:59:19 -07:00
parent ec3edb07e8
commit 362339d89c
6 changed files with 152 additions and 113 deletions

View File

@@ -0,0 +1,26 @@
import React from 'react';
import { node } from 'prop-types';
import { Tooltip } from '@patternfly/react-core';
import { QuestionCircleIcon as PFQuestionCircleIcon } from '@patternfly/react-icons';
import styled from 'styled-components';
const QuestionCircleIcon = styled(PFQuestionCircleIcon)`
margin-left: 10px;
`;
function FieldTooltip({ content }) {
return (
<Tooltip
position="right"
content={content}
trigger="click mouseenter focus"
>
<QuestionCircleIcon />
</Tooltip>
);
}
FieldTooltip.propTypes = {
content: node.isRequired,
};
export default FieldTooltip;

View File

@@ -1,2 +1,3 @@
export { default } from './FormField'; export { default } from './FormField';
export { default as CheckboxField } from './CheckboxField'; export { default as CheckboxField } from './CheckboxField';
export { default as FieldTooltip } from './FieldTooltip';

View File

@@ -112,6 +112,7 @@ class ListHeader extends React.Component {
columns, columns,
onSearch: this.handleSearch, onSearch: this.handleSearch,
onSort: this.handleSort, onSort: this.handleSort,
qsConfig,
})} })}
<FilterTags <FilterTags
itemCount={itemCount} itemCount={itemCount}

View File

@@ -2,17 +2,11 @@ import React from 'react';
import { string, func, bool } from 'prop-types'; import { string, func, bool } from 'prop-types';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { FormGroup, Tooltip } from '@patternfly/react-core'; import { FormGroup } from '@patternfly/react-core';
import { QuestionCircleIcon as PFQuestionCircleIcon } from '@patternfly/react-icons';
import styled from 'styled-components';
import { InventoriesAPI } from '@api'; import { InventoriesAPI } from '@api';
import { Inventory } from '@types'; import { Inventory } from '@types';
import Lookup from '@components/Lookup'; import Lookup from '@components/Lookup';
import { FieldTooltip } from '@components/FormField';
const QuestionCircleIcon = styled(PFQuestionCircleIcon)`
margin-left: 10px;
`;
const getInventories = async params => InventoriesAPI.read(params); const getInventories = async params => InventoriesAPI.read(params);
@@ -26,11 +20,7 @@ class InventoryLookup extends React.Component {
isRequired={required} isRequired={required}
fieldId="inventory-lookup" fieldId="inventory-lookup"
> >
{tooltip && ( {tooltip && <FieldTooltip content={tooltip} />}
<Tooltip position="right" content={tooltip}>
<QuestionCircleIcon />
</Tooltip>
)}
<Lookup <Lookup
id="inventory-lookup" id="inventory-lookup"
lookupHeader={i18n._(t`Inventory`)} lookupHeader={i18n._(t`Inventory`)}

View File

@@ -383,6 +383,24 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
} }
onSearch={[Function]} onSearch={[Function]}
onSort={[Function]} onSort={[Function]}
qsConfig={
Object {
"dateFields": Array [
"modified",
"created",
],
"defaultParams": Object {
"order_by": "name",
"page": 1,
"page_size": 5,
},
"integerFields": Array [
"page",
"page_size",
],
"namespace": "notification",
}
}
sortOrder="ascending" sortOrder="ascending"
sortedColumnKey="name" sortedColumnKey="name"
> >
@@ -423,6 +441,24 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
onSearch={[Function]} onSearch={[Function]}
onSelectAll={null} onSelectAll={null}
onSort={[Function]} onSort={[Function]}
qsConfig={
Object {
"dateFields": Array [
"modified",
"created",
],
"defaultParams": Object {
"order_by": "name",
"page": 1,
"page_size": 5,
},
"integerFields": Array [
"page",
"page_size",
],
"namespace": "notification",
}
}
showSelectAll={false} showSelectAll={false}
sortOrder="ascending" sortOrder="ascending"
sortedColumnKey="name" sortedColumnKey="name"
@@ -590,6 +626,24 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
] ]
} }
onSearch={[Function]} onSearch={[Function]}
qsConfig={
Object {
"dateFields": Array [
"modified",
"created",
],
"defaultParams": Object {
"order_by": "name",
"page": 1,
"page_size": 5,
},
"integerFields": Array [
"page",
"page_size",
],
"namespace": "notification",
}
}
sortedColumnKey="name" sortedColumnKey="name"
> >
<I18n <I18n
@@ -621,6 +675,24 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
} }
i18n={"/i18n/"} i18n={"/i18n/"}
onSearch={[Function]} onSearch={[Function]}
qsConfig={
Object {
"dateFields": Array [
"modified",
"created",
],
"defaultParams": Object {
"order_by": "name",
"page": 1,
"page_size": 5,
},
"integerFields": Array [
"page",
"page_size",
],
"namespace": "notification",
}
}
sortedColumnKey="name" sortedColumnKey="name"
> >
<Form <Form

View File

@@ -7,19 +7,17 @@ import { withFormik, Field } from 'formik';
import { import {
Form, Form,
FormGroup, FormGroup,
Tooltip,
Card, Card,
Switch, Switch,
Checkbox, Checkbox,
TextInput, TextInput,
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import { QuestionCircleIcon as PFQuestionCircleIcon } from '@patternfly/react-icons';
import ContentError from '@components/ContentError'; import ContentError from '@components/ContentError';
import ContentLoading from '@components/ContentLoading'; import ContentLoading from '@components/ContentLoading';
import AnsibleSelect from '@components/AnsibleSelect'; import AnsibleSelect from '@components/AnsibleSelect';
import MultiSelect, { TagMultiSelect } from '@components/MultiSelect'; import MultiSelect, { TagMultiSelect } from '@components/MultiSelect';
import FormActionGroup from '@components/FormActionGroup'; import FormActionGroup from '@components/FormActionGroup';
import FormField, { CheckboxField } from '@components/FormField'; import FormField, { CheckboxField, FieldTooltip } from '@components/FormField';
import FormRow from '@components/FormRow'; import FormRow from '@components/FormRow';
import CollapsibleSection from '@components/CollapsibleSection'; import CollapsibleSection from '@components/CollapsibleSection';
import { required } from '@util/validators'; import { required } from '@util/validators';
@@ -29,10 +27,6 @@ import { InventoryLookup, InstanceGroupsLookup } from '@components/Lookup';
import ProjectLookup from './ProjectLookup'; import ProjectLookup from './ProjectLookup';
import { JobTemplatesAPI, LabelsAPI, ProjectsAPI } from '@api'; import { JobTemplatesAPI, LabelsAPI, ProjectsAPI } from '@api';
const QuestionCircleIcon = styled(PFQuestionCircleIcon)`
margin-left: 10px;
`;
const GridFormGroup = styled(FormGroup)` const GridFormGroup = styled(FormGroup)`
& > label { & > label {
grid-column: 1 / -1; grid-column: 1 / -1;
@@ -374,15 +368,12 @@ class JobTemplateForm extends Component {
isValid={isValid} isValid={isValid}
label={i18n._(t`Job Type`)} label={i18n._(t`Job Type`)}
> >
<Tooltip <FieldTooltip
position="right"
content={i18n._(t`For job templates, select run to execute content={i18n._(t`For job templates, select run to execute
the playbook. Select check to only check playbook syntax, the playbook. Select check to only check playbook syntax,
test environment setup, and report problems without test environment setup, and report problems without
executing the playbook.`)} executing the playbook.`)}
> />
<QuestionCircleIcon />
</Tooltip>
<AnsibleSelect <AnsibleSelect
isValid={isValid} isValid={isValid}
id="template-job-type" id="template-job-type"
@@ -443,14 +434,11 @@ class JobTemplateForm extends Component {
isValid={isValid} isValid={isValid}
label={i18n._(t`Playbook`)} label={i18n._(t`Playbook`)}
> >
<Tooltip <FieldTooltip
position="right"
content={i18n._( content={i18n._(
t`Select the playbook to be executed by this job.` t`Select the playbook to be executed by this job.`
)} )}
> />
<QuestionCircleIcon />
</Tooltip>
<AnsibleSelect <AnsibleSelect
id="template-playbook" id="template-playbook"
data={playbookOptions} data={playbookOptions}
@@ -465,14 +453,11 @@ class JobTemplateForm extends Component {
</FormRow> </FormRow>
<FormRow> <FormRow>
<FormGroup label={i18n._(t`Labels`)} fieldId="template-labels"> <FormGroup label={i18n._(t`Labels`)} fieldId="template-labels">
<Tooltip <FieldTooltip
position="right"
content={i18n._( content={i18n._(
t`Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs.` t`Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs.`
)} )}
> />
<QuestionCircleIcon />
</Tooltip>
<MultiSelect <MultiSelect
onAddNewItem={this.handleNewLabel} onAddNewItem={this.handleNewLabel}
onRemoveItem={this.removeLabel} onRemoveItem={this.removeLabel}
@@ -519,13 +504,10 @@ class JobTemplateForm extends Component {
fieldId="template-verbosity" fieldId="template-verbosity"
label={i18n._(t`Verbosity`)} label={i18n._(t`Verbosity`)}
> >
<Tooltip <FieldTooltip
position="right"
content={i18n._(t`Control the level of output ansible will content={i18n._(t`Control the level of output ansible will
produce as the playbook executes.`)} produce as the playbook executes.`)}
> />
<QuestionCircleIcon />
</Tooltip>
<AnsibleSelect <AnsibleSelect
id="template-verbosity" id="template-verbosity"
data={verbosityOptions} data={verbosityOptions}
@@ -561,14 +543,11 @@ class JobTemplateForm extends Component {
fieldId="template-show-changes" fieldId="template-show-changes"
label={i18n._(t`Show Changes`)} label={i18n._(t`Show Changes`)}
> >
<Tooltip <FieldTooltip
position="right"
content={i18n._(t`If enabled, show the changes made by content={i18n._(t`If enabled, show the changes made by
Ansible tasks, where supported. This is equivalent Ansible tasks, where supported. This is equivalent
to Ansible&#x2019s --diff mode.`)} to Ansible&#x2019s --diff mode.`)}
> />
<QuestionCircleIcon />
</Tooltip>
<div> <div>
<Switch <Switch
id="template-show-changes" id="template-show-changes"
@@ -599,16 +578,13 @@ class JobTemplateForm extends Component {
css="margin-top: 20px" css="margin-top: 20px"
fieldId="template-job-tags" fieldId="template-job-tags"
> >
<Tooltip <FieldTooltip
position="right"
content={i18n._(t`Tags are useful when you have a large content={i18n._(t`Tags are useful when you have a large
playbook, and you want to run a specific part of a playbook, and you want to run a specific part of a
play or task. Use commas to separate multiple tags. play or task. Use commas to separate multiple tags.
Refer to Ansible Tower documentation for details on Refer to Ansible Tower documentation for details on
the usage of tags.`)} the usage of tags.`)}
> />
<QuestionCircleIcon />
</Tooltip>
<TagMultiSelect <TagMultiSelect
value={field.value} value={field.value}
onChange={value => form.setFieldValue(field.name, value)} onChange={value => form.setFieldValue(field.name, value)}
@@ -624,16 +600,13 @@ class JobTemplateForm extends Component {
css="margin-top: 20px" css="margin-top: 20px"
fieldId="template-skip-tags" fieldId="template-skip-tags"
> >
<Tooltip <FieldTooltip
position="right"
content={i18n._(t`Skip tags are useful when you have a content={i18n._(t`Skip tags are useful when you have a
large playbook, and you want to skip specific parts of a large playbook, and you want to skip specific parts of a
play or task. Use commas to separate multiple tags. Refer play or task. Use commas to separate multiple tags. Refer
to Ansible Tower documentation for details on the usage to Ansible Tower documentation for details on the usage
of tags.`)} of tags.`)}
> />
<QuestionCircleIcon />
</Tooltip>
<TagMultiSelect <TagMultiSelect
value={field.value} value={field.value}
onChange={value => form.setFieldValue(field.name, value)} onChange={value => form.setFieldValue(field.name, value)}
@@ -661,16 +634,13 @@ class JobTemplateForm extends Component {
<span> <span>
{i18n._(t`Provisioning Callbacks`)} {i18n._(t`Provisioning Callbacks`)}
&nbsp; &nbsp;
<Tooltip <FieldTooltip
position="right"
content={i18n._( content={i18n._(
t`Enables creation of a provisioning callback URL. Using t`Enables creation of a provisioning callback URL. Using
the URL a host can contact BRAND_NAME and request a the URL a host can contact BRAND_NAME and request a
configuration update using this job template.` configuration update using this job template.`
)} )}
> />
<QuestionCircleIcon />
</Tooltip>
</span> </span>
} }
id="option-callbacks" id="option-callbacks"
@@ -735,50 +705,29 @@ class JobTemplateForm extends Component {
const FormikApp = withFormik({ const FormikApp = withFormik({
mapPropsToValues(props) { mapPropsToValues(props) {
const { template = {} } = props; const { template = {} } = props;
const { const { summary_fields = { labels: { results: [] } } } = template;
name = '',
description = '',
job_type = 'run',
inventory = '',
project = '',
playbook = '',
forks,
limit,
verbosity,
job_slice_count,
timeout,
diff_mode,
job_tags,
skip_tags,
become_enabled,
allow_callbacks,
allow_simultaneous,
use_fact_cache,
host_config_key,
summary_fields = { labels: { results: [] } },
} = { ...template };
return { return {
name: name || '', name: template.name || '',
description: description || '', description: template.description || '',
job_type: job_type || '', job_type: template.job_type || 'run',
inventory: inventory || '', inventory: template.inventory || '',
project: project || '', project: template.project || '',
playbook: playbook || '', playbook: template.playbook || '',
labels: summary_fields.labels.results, labels: summary_fields.labels.results,
forks: forks || 0, forks: template.forks || 0,
limit: limit || '', limit: template.limit || '',
verbosity: verbosity || '0', verbosity: template.verbosity || '0',
job_slice_count: job_slice_count || 1, job_slice_count: template.job_slice_count || 1,
timeout: timeout || 0, timeout: template.timeout || 0,
diff_mode: diff_mode || false, diff_mode: template.diff_mode || false,
job_tags: job_tags || '', job_tags: template.job_tags || '',
skip_tags: skip_tags || '', skip_tags: template.skip_tags || '',
become_enabled: become_enabled || false, become_enabled: template.become_enabled || false,
allow_callbacks: allow_callbacks || false, allow_callbacks: template.allow_callbacks || false,
allow_simultaneous: allow_simultaneous || false, allow_simultaneous: template.allow_simultaneous || false,
use_fact_cache: use_fact_cache || false, use_fact_cache: template.use_fact_cache || false,
host_config_key: host_config_key || '', host_config_key: template.host_config_key || '',
}; };
}, },
handleSubmit: (values, bag) => bag.props.handleSubmit(values), handleSubmit: (values, bag) => bag.props.handleSubmit(values),