mirror of
https://github.com/ansible/awx.git
synced 2026-01-20 22:18:01 -03:30
Add project manual scm type subform
This commit is contained in:
parent
922723cf39
commit
e4721d7722
@ -97,7 +97,13 @@ class App extends Component {
|
||||
MeAPI.read(),
|
||||
]);
|
||||
const {
|
||||
data: { ansible_version, custom_virtualenvs, version },
|
||||
data: {
|
||||
ansible_version,
|
||||
custom_virtualenvs,
|
||||
project_base_dir,
|
||||
project_local_paths,
|
||||
version,
|
||||
},
|
||||
} = configRes;
|
||||
const {
|
||||
data: {
|
||||
@ -105,7 +111,14 @@ class App extends Component {
|
||||
},
|
||||
} = meRes;
|
||||
|
||||
this.setState({ ansible_version, custom_virtualenvs, version, me });
|
||||
this.setState({
|
||||
ansible_version,
|
||||
custom_virtualenvs,
|
||||
project_base_dir,
|
||||
project_local_paths,
|
||||
version,
|
||||
me,
|
||||
});
|
||||
} catch (err) {
|
||||
this.setState({ configError: err });
|
||||
}
|
||||
@ -115,6 +128,8 @@ class App extends Component {
|
||||
const {
|
||||
ansible_version,
|
||||
custom_virtualenvs,
|
||||
project_base_dir,
|
||||
project_local_paths,
|
||||
isAboutModalOpen,
|
||||
isNavOpen,
|
||||
me,
|
||||
@ -169,7 +184,14 @@ class App extends Component {
|
||||
<Fragment>
|
||||
<Page usecondensed="True" header={header} sidebar={sidebar}>
|
||||
<ConfigProvider
|
||||
value={{ ansible_version, custom_virtualenvs, me, version }}
|
||||
value={{
|
||||
ansible_version,
|
||||
custom_virtualenvs,
|
||||
project_base_dir,
|
||||
project_local_paths,
|
||||
me,
|
||||
version,
|
||||
}}
|
||||
>
|
||||
{render({ routeGroups })}
|
||||
</ConfigProvider>
|
||||
|
||||
@ -189,10 +189,6 @@
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.pf-c-alert__icon {
|
||||
--pf-c-alert__icon--Color: white;
|
||||
}
|
||||
|
||||
.at-u-textRight {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@ -23,6 +23,9 @@ function ProjectAdd({ history, i18n }) {
|
||||
const [formSubmitError, setFormSubmitError] = useState(null);
|
||||
|
||||
const handleSubmit = async values => {
|
||||
if (values.scm_type === 'manual') {
|
||||
values.scm_type = '';
|
||||
}
|
||||
setFormSubmitError(null);
|
||||
try {
|
||||
const {
|
||||
|
||||
@ -16,6 +16,7 @@ describe('<ProjectAdd />', () => {
|
||||
scm_url: 'https://foo.bar',
|
||||
scm_clean: true,
|
||||
credential: 100,
|
||||
local_path: '',
|
||||
organization: 2,
|
||||
scm_update_on_launch: true,
|
||||
scm_update_cache_timeout: 3,
|
||||
@ -116,9 +117,15 @@ describe('<ProjectAdd />', () => {
|
||||
});
|
||||
|
||||
test('handleSubmit should throw an error', async () => {
|
||||
const config = {
|
||||
project_local_paths: ['foobar', 'qux'],
|
||||
project_base_dir: 'dir/foo/bar',
|
||||
};
|
||||
ProjectsAPI.create.mockImplementation(() => Promise.reject(new Error()));
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(<ProjectAdd />);
|
||||
wrapper = mountWithContexts(<ProjectAdd />, {
|
||||
context: { config },
|
||||
});
|
||||
});
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
const formik = wrapper.find('Formik').instance();
|
||||
@ -127,6 +134,7 @@ describe('<ProjectAdd />', () => {
|
||||
{
|
||||
values: {
|
||||
...projectData,
|
||||
scm_type: 'manual',
|
||||
},
|
||||
},
|
||||
() => resolve()
|
||||
|
||||
@ -5,9 +5,11 @@ import { t } from '@lingui/macro';
|
||||
import styled from 'styled-components';
|
||||
import { Project } from '@types';
|
||||
import { formatDateString } from '@util/dates';
|
||||
import { Config } from '@contexts/Config';
|
||||
import { Button, CardBody, List, ListItem } from '@patternfly/react-core';
|
||||
import { DetailList, Detail } from '@components/DetailList';
|
||||
import { CredentialChip } from '@components/Chip';
|
||||
import { toTitleCase } from '@util/strings';
|
||||
|
||||
const ActionButtonWrapper = styled.div`
|
||||
display: flex;
|
||||
@ -25,6 +27,7 @@ function ProjectDetail({ project, i18n }) {
|
||||
custom_virtualenv,
|
||||
description,
|
||||
id,
|
||||
local_path,
|
||||
modified,
|
||||
name,
|
||||
scm_branch,
|
||||
@ -93,10 +96,21 @@ function ProjectDetail({ project, i18n }) {
|
||||
{summary_fields.organization && (
|
||||
<Detail
|
||||
label={i18n._(t`Organization`)}
|
||||
value={summary_fields.organization.name}
|
||||
value={
|
||||
<Link
|
||||
to={`/organizations/${summary_fields.organization.id}/details`}
|
||||
>
|
||||
{summary_fields.organization.name}
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Detail label={i18n._(t`SCM Type`)} value={scm_type} />
|
||||
<Detail
|
||||
label={i18n._(t`SCM Type`)}
|
||||
value={
|
||||
scm_type === '' ? i18n._(t`Manual`) : toTitleCase(project.scm_type)
|
||||
}
|
||||
/>
|
||||
<Detail label={i18n._(t`SCM URL`)} value={scm_url} />
|
||||
<Detail label={i18n._(t`SCM Branch`)} value={scm_branch} />
|
||||
<Detail label={i18n._(t`SCM Refspec`)} value={scm_refspec} />
|
||||
@ -123,6 +137,15 @@ function ProjectDetail({ project, i18n }) {
|
||||
label={i18n._(t`Ansible Environment`)}
|
||||
value={custom_virtualenv}
|
||||
/>
|
||||
<Config>
|
||||
{({ project_base_dir }) => (
|
||||
<Detail
|
||||
label={i18n._(t`Project Base Path`)}
|
||||
value={project_base_dir}
|
||||
/>
|
||||
)}
|
||||
</Config>
|
||||
<Detail label={i18n._(t`Playbook Directory`)} value={local_path} />
|
||||
{/* TODO: Link to user in users */}
|
||||
<Detail label={i18n._(t`Created`)} value={createdBy} />
|
||||
{/* TODO: Link to user in users */}
|
||||
|
||||
@ -85,7 +85,7 @@ describe('<ProjectDetail />', () => {
|
||||
assertDetail('Name', mockProject.name);
|
||||
assertDetail('Description', mockProject.description);
|
||||
assertDetail('Organization', mockProject.summary_fields.organization.name);
|
||||
assertDetail('SCM Type', mockProject.scm_type);
|
||||
assertDetail('SCM Type', 'Git');
|
||||
assertDetail('SCM URL', mockProject.scm_url);
|
||||
assertDetail('SCM Branch', mockProject.scm_branch);
|
||||
assertDetail('SCM Refspec', mockProject.scm_refspec);
|
||||
|
||||
@ -22,6 +22,9 @@ function ProjectEdit({ project, history, i18n }) {
|
||||
const [formSubmitError, setFormSubmitError] = useState(null);
|
||||
|
||||
const handleSubmit = async values => {
|
||||
if (values.scm_type === 'manual') {
|
||||
values.scm_type = '';
|
||||
}
|
||||
try {
|
||||
const {
|
||||
data: { id },
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<ProjectEdit />', () => {
|
||||
scm_url: 'https://foo.bar',
|
||||
scm_clean: true,
|
||||
credential: 100,
|
||||
local_path: '',
|
||||
organization: 2,
|
||||
scm_update_on_launch: true,
|
||||
scm_update_cache_timeout: 3,
|
||||
@ -115,9 +116,18 @@ describe('<ProjectEdit />', () => {
|
||||
});
|
||||
|
||||
test('handleSubmit should throw an error', async () => {
|
||||
const config = {
|
||||
project_local_paths: [],
|
||||
project_base_dir: 'foo/bar',
|
||||
};
|
||||
ProjectsAPI.update.mockImplementation(() => Promise.reject(new Error()));
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(<ProjectEdit project={projectData} />);
|
||||
wrapper = mountWithContexts(
|
||||
<ProjectEdit project={{ ...projectData, scm_type: 'manual' }} />,
|
||||
{
|
||||
context: { config },
|
||||
}
|
||||
);
|
||||
});
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
await act(async () => {
|
||||
|
||||
@ -19,6 +19,7 @@ import ListActionButton from '@components/ListActionButton';
|
||||
import ProjectSyncButton from '../shared/ProjectSyncButton';
|
||||
import { StatusIcon } from '@components/Sparkline';
|
||||
import VerticalSeparator from '@components/VerticalSeparator';
|
||||
import { toTitleCase } from '@util/strings';
|
||||
import { Project } from '@types';
|
||||
|
||||
class ProjectListItem extends React.Component {
|
||||
@ -97,7 +98,9 @@ class ProjectListItem extends React.Component {
|
||||
</Link>
|
||||
</DataListCell>,
|
||||
<DataListCell key="type">
|
||||
{project.scm_type.toUpperCase()}
|
||||
{project.scm_type === ''
|
||||
? i18n._(t`Manual`)
|
||||
: toTitleCase(project.scm_type)}
|
||||
</DataListCell>,
|
||||
<DataListCell key="revision">
|
||||
{project.scm_revision.substring(0, 7)}
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
SvnSubForm,
|
||||
InsightsSubForm,
|
||||
SubFormTitle,
|
||||
ManualSubForm,
|
||||
} from './ProjectSubForms';
|
||||
|
||||
const ScmTypeFormRow = styled(FormRow)`
|
||||
@ -173,199 +174,224 @@ function ProjectForm({ project, ...props }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Formik
|
||||
initialValues={{
|
||||
allow_override: project.allow_override || false,
|
||||
credential: project.credential || '',
|
||||
custom_virtualenv: project.custom_virtualenv || '',
|
||||
description: project.description || '',
|
||||
name: project.name || '',
|
||||
organization: project.organization || '',
|
||||
scm_branch: project.scm_branch || '',
|
||||
scm_clean: project.scm_clean || false,
|
||||
scm_delete_on_update: project.scm_delete_on_update || false,
|
||||
scm_refspec: project.scm_refspec || '',
|
||||
scm_type:
|
||||
project.scm_type === ''
|
||||
? 'manual'
|
||||
: project.scm_type === undefined
|
||||
? ''
|
||||
: project.scm_type,
|
||||
scm_update_cache_timeout: project.scm_update_cache_timeout || 0,
|
||||
scm_update_on_launch: project.scm_update_on_launch || false,
|
||||
scm_url: project.scm_url || '',
|
||||
}}
|
||||
onSubmit={handleSubmit}
|
||||
render={formik => (
|
||||
<Form
|
||||
autoComplete="off"
|
||||
onSubmit={formik.handleSubmit}
|
||||
css="padding: 0 24px"
|
||||
>
|
||||
<FormRow>
|
||||
<FormField
|
||||
id="project-name"
|
||||
label={i18n._(t`Name`)}
|
||||
name="name"
|
||||
type="text"
|
||||
validate={required(null, i18n)}
|
||||
isRequired
|
||||
/>
|
||||
<FormField
|
||||
id="project-description"
|
||||
label={i18n._(t`Description`)}
|
||||
name="description"
|
||||
type="text"
|
||||
/>
|
||||
<Field
|
||||
name="organization"
|
||||
validate={required(
|
||||
i18n._(t`Select a value for this field`),
|
||||
i18n
|
||||
)}
|
||||
render={({ form }) => (
|
||||
<OrganizationLookup
|
||||
helperTextInvalid={form.errors.organization}
|
||||
isValid={
|
||||
!form.touched.organization || !form.errors.organization
|
||||
}
|
||||
onBlur={() => form.setFieldTouched('organization')}
|
||||
onChange={value => {
|
||||
form.setFieldValue('organization', value.id);
|
||||
setOrganization(value);
|
||||
}}
|
||||
value={organization}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Field
|
||||
name="scm_type"
|
||||
validate={required(
|
||||
i18n._(t`Select a value for this field`),
|
||||
i18n
|
||||
)}
|
||||
render={({ field, form }) => (
|
||||
<FormGroup
|
||||
fieldId="project-scm-type"
|
||||
helperTextInvalid={form.errors.scm_type}
|
||||
<Config>
|
||||
{({ project_base_dir, project_local_paths }) => (
|
||||
<Formik
|
||||
initialValues={{
|
||||
allow_override: project.allow_override || false,
|
||||
base_dir: project_base_dir || '',
|
||||
credential: project.credential || '',
|
||||
custom_virtualenv: project.custom_virtualenv || '',
|
||||
description: project.description || '',
|
||||
local_path: project.local_path || null,
|
||||
name: project.name || '',
|
||||
organization: project.organization || '',
|
||||
scm_branch: project.scm_branch || '',
|
||||
scm_clean: project.scm_clean || false,
|
||||
scm_delete_on_update: project.scm_delete_on_update || false,
|
||||
scm_refspec: project.scm_refspec || '',
|
||||
scm_type:
|
||||
project.scm_type === ''
|
||||
? 'manual'
|
||||
: project.scm_type === undefined
|
||||
? ''
|
||||
: project.scm_type,
|
||||
scm_update_cache_timeout: project.scm_update_cache_timeout || 0,
|
||||
scm_update_on_launch: project.scm_update_on_launch || false,
|
||||
scm_url: project.scm_url || '',
|
||||
}}
|
||||
onSubmit={handleSubmit}
|
||||
render={formik => (
|
||||
<Form
|
||||
autoComplete="off"
|
||||
onSubmit={formik.handleSubmit}
|
||||
css="padding: 0 24px"
|
||||
>
|
||||
<FormRow>
|
||||
<FormField
|
||||
id="project-name"
|
||||
label={i18n._(t`Name`)}
|
||||
name="name"
|
||||
type="text"
|
||||
validate={required(null, i18n)}
|
||||
isRequired
|
||||
isValid={!form.touched.scm_type || !form.errors.scm_type}
|
||||
label={i18n._(t`SCM Type`)}
|
||||
>
|
||||
<AnsibleSelect
|
||||
{...field}
|
||||
id="scm_type"
|
||||
data={[
|
||||
/>
|
||||
<FormField
|
||||
id="project-description"
|
||||
label={i18n._(t`Description`)}
|
||||
name="description"
|
||||
type="text"
|
||||
/>
|
||||
<Field
|
||||
name="organization"
|
||||
validate={required(
|
||||
i18n._(t`Select a value for this field`),
|
||||
i18n
|
||||
)}
|
||||
render={({ form }) => (
|
||||
<OrganizationLookup
|
||||
helperTextInvalid={form.errors.organization}
|
||||
isValid={
|
||||
!form.touched.organization || !form.errors.organization
|
||||
}
|
||||
onBlur={() => form.setFieldTouched('organization')}
|
||||
onChange={value => {
|
||||
form.setFieldValue('organization', value.id);
|
||||
setOrganization(value);
|
||||
}}
|
||||
value={organization}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Field
|
||||
name="scm_type"
|
||||
validate={required(
|
||||
i18n._(t`Select a value for this field`),
|
||||
i18n
|
||||
)}
|
||||
render={({ field, form }) => (
|
||||
<FormGroup
|
||||
fieldId="project-scm-type"
|
||||
helperTextInvalid={form.errors.scm_type}
|
||||
isRequired
|
||||
isValid={!form.touched.scm_type || !form.errors.scm_type}
|
||||
label={i18n._(t`SCM Type`)}
|
||||
>
|
||||
<AnsibleSelect
|
||||
{...field}
|
||||
id="scm_type"
|
||||
data={[
|
||||
{
|
||||
value: '',
|
||||
key: '',
|
||||
label: i18n._(t`Choose an SCM Type`),
|
||||
isDisabled: true,
|
||||
},
|
||||
...scmTypeOptions.map(([value, label]) => {
|
||||
if (label === 'Manual') {
|
||||
value = 'manual';
|
||||
}
|
||||
return {
|
||||
label,
|
||||
value,
|
||||
key: value,
|
||||
};
|
||||
}),
|
||||
]}
|
||||
onChange={(event, value) => {
|
||||
form.setFieldValue('scm_type', value);
|
||||
resetScmTypeFields(value, form);
|
||||
}}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
/>
|
||||
{formik.values.scm_type !== '' && (
|
||||
<ScmTypeFormRow>
|
||||
<SubFormTitle size="md">
|
||||
{i18n._(t`Type Details`)}
|
||||
</SubFormTitle>
|
||||
{
|
||||
{
|
||||
value: '',
|
||||
key: '',
|
||||
label: i18n._(t`Choose an SCM Type`),
|
||||
isDisabled: true,
|
||||
},
|
||||
...scmTypeOptions.map(([value, label]) => {
|
||||
if (label === 'Manual') {
|
||||
value = 'manual';
|
||||
}
|
||||
return {
|
||||
label,
|
||||
value,
|
||||
key: value,
|
||||
};
|
||||
}),
|
||||
]}
|
||||
onChange={(event, value) => {
|
||||
form.setFieldValue('scm_type', value);
|
||||
resetScmTypeFields(value, form);
|
||||
}}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
/>
|
||||
{formik.values.scm_type !== '' && (
|
||||
<ScmTypeFormRow>
|
||||
<SubFormTitle size="md">{i18n._(t`Type Details`)}</SubFormTitle>
|
||||
{
|
||||
{
|
||||
git: (
|
||||
<GitSubForm
|
||||
credential={credentials.scm}
|
||||
onCredentialSelection={handleCredentialSelection}
|
||||
scmUpdateOnLaunch={formik.values.scm_update_on_launch}
|
||||
manual: (
|
||||
<ManualSubForm
|
||||
localPath={formik.initialValues.local_path}
|
||||
project_base_dir={project_base_dir}
|
||||
project_local_paths={project_local_paths}
|
||||
/>
|
||||
),
|
||||
git: (
|
||||
<GitSubForm
|
||||
credential={credentials.scm}
|
||||
onCredentialSelection={handleCredentialSelection}
|
||||
scmUpdateOnLaunch={
|
||||
formik.values.scm_update_on_launch
|
||||
}
|
||||
/>
|
||||
),
|
||||
hg: (
|
||||
<HgSubForm
|
||||
credential={credentials.scm}
|
||||
onCredentialSelection={handleCredentialSelection}
|
||||
scmUpdateOnLaunch={
|
||||
formik.values.scm_update_on_launch
|
||||
}
|
||||
/>
|
||||
),
|
||||
svn: (
|
||||
<SvnSubForm
|
||||
credential={credentials.scm}
|
||||
onCredentialSelection={handleCredentialSelection}
|
||||
scmUpdateOnLaunch={
|
||||
formik.values.scm_update_on_launch
|
||||
}
|
||||
/>
|
||||
),
|
||||
insights: (
|
||||
<InsightsSubForm
|
||||
credential={credentials.insights}
|
||||
onCredentialSelection={handleCredentialSelection}
|
||||
scmUpdateOnLaunch={
|
||||
formik.values.scm_update_on_launch
|
||||
}
|
||||
/>
|
||||
),
|
||||
}[formik.values.scm_type]
|
||||
}
|
||||
</ScmTypeFormRow>
|
||||
)}
|
||||
<Config>
|
||||
{({ custom_virtualenvs }) =>
|
||||
custom_virtualenvs &&
|
||||
custom_virtualenvs.length > 1 && (
|
||||
<Field
|
||||
name="custom_virtualenv"
|
||||
render={({ field }) => (
|
||||
<FormGroup
|
||||
fieldId="project-custom-virtualenv"
|
||||
label={i18n._(t`Ansible Environment`)}
|
||||
>
|
||||
<FieldTooltip
|
||||
content={i18n._(t`Select the playbook to be executed by
|
||||
this job.`)}
|
||||
/>
|
||||
<AnsibleSelect
|
||||
id="project-custom-virtualenv"
|
||||
data={[
|
||||
{
|
||||
label: i18n._(
|
||||
t`Use Default Ansible Environment`
|
||||
),
|
||||
value: '/venv/ansible/',
|
||||
key: 'default',
|
||||
},
|
||||
...custom_virtualenvs
|
||||
.filter(datum => datum !== '/venv/ansible/')
|
||||
.map(datum => ({
|
||||
label: datum,
|
||||
value: datum,
|
||||
key: datum,
|
||||
})),
|
||||
]}
|
||||
{...field}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
/>
|
||||
),
|
||||
hg: (
|
||||
<HgSubForm
|
||||
credential={credentials.scm}
|
||||
onCredentialSelection={handleCredentialSelection}
|
||||
scmUpdateOnLaunch={formik.values.scm_update_on_launch}
|
||||
/>
|
||||
),
|
||||
svn: (
|
||||
<SvnSubForm
|
||||
credential={credentials.scm}
|
||||
onCredentialSelection={handleCredentialSelection}
|
||||
scmUpdateOnLaunch={formik.values.scm_update_on_launch}
|
||||
/>
|
||||
),
|
||||
insights: (
|
||||
<InsightsSubForm
|
||||
credential={credentials.insights}
|
||||
onCredentialSelection={handleCredentialSelection}
|
||||
scmUpdateOnLaunch={formik.values.scm_update_on_launch}
|
||||
/>
|
||||
),
|
||||
}[formik.values.scm_type]
|
||||
}
|
||||
</ScmTypeFormRow>
|
||||
)}
|
||||
<Config>
|
||||
{({ custom_virtualenvs }) =>
|
||||
custom_virtualenvs &&
|
||||
custom_virtualenvs.length > 1 && (
|
||||
<Field
|
||||
name="custom_virtualenv"
|
||||
render={({ field }) => (
|
||||
<FormGroup
|
||||
fieldId="project-custom-virtualenv"
|
||||
label={i18n._(t`Ansible Environment`)}
|
||||
>
|
||||
<FieldTooltip
|
||||
content={i18n._(t`Select the playbook to be executed by
|
||||
this job.`)}
|
||||
/>
|
||||
<AnsibleSelect
|
||||
id="project-custom-virtualenv"
|
||||
data={[
|
||||
{
|
||||
label: i18n._(t`Use Default Ansible Environment`),
|
||||
value: '/venv/ansible/',
|
||||
key: 'default',
|
||||
},
|
||||
...custom_virtualenvs
|
||||
.filter(datum => datum !== '/venv/ansible/')
|
||||
.map(datum => ({
|
||||
label: datum,
|
||||
value: datum,
|
||||
key: datum,
|
||||
})),
|
||||
]}
|
||||
{...field}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</Config>
|
||||
</FormRow>
|
||||
<FormActionGroup
|
||||
onCancel={handleCancel}
|
||||
onSubmit={formik.handleSubmit}
|
||||
/>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
</Config>
|
||||
</FormRow>
|
||||
<FormActionGroup
|
||||
onCancel={handleCancel}
|
||||
onSubmit={formik.handleSubmit}
|
||||
/>
|
||||
</Form>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Config>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@ describe('<ProjectAdd />', () => {
|
||||
id: 100,
|
||||
credential_type_id: 4,
|
||||
kind: 'scm',
|
||||
name: 'alpha',
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -216,6 +217,59 @@ describe('<ProjectAdd />', () => {
|
||||
expect(formik.state.values.credential).toEqual(123);
|
||||
});
|
||||
|
||||
test('manual subform should display expected fields', async () => {
|
||||
const config = {
|
||||
project_local_paths: ['foobar', 'qux'],
|
||||
project_base_dir: 'dir/foo/bar',
|
||||
};
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<ProjectForm
|
||||
handleSubmit={jest.fn()}
|
||||
handleCancel={jest.fn()}
|
||||
project={{ scm_type: '', local_path: '/_foo__bar' }}
|
||||
/>,
|
||||
{
|
||||
context: { config },
|
||||
}
|
||||
);
|
||||
});
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
const playbookDirectorySelect = wrapper.find(
|
||||
'FormGroup[label="Playbook Directory"] FormSelect'
|
||||
);
|
||||
await act(async () => {
|
||||
playbookDirectorySelect
|
||||
.props()
|
||||
.onChange('foobar', { target: { name: 'foobar' } });
|
||||
});
|
||||
expect(wrapper.find('FormGroup[label="Project Base Path"]').length).toBe(1);
|
||||
expect(wrapper.find('FormGroup[label="Playbook Directory"]').length).toBe(
|
||||
1
|
||||
);
|
||||
});
|
||||
|
||||
test('manual subform should display warning message when playbook directory is empty', async () => {
|
||||
const config = {
|
||||
project_local_paths: [],
|
||||
project_base_dir: 'dir/foo/bar',
|
||||
};
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<ProjectForm
|
||||
handleSubmit={jest.fn()}
|
||||
handleCancel={jest.fn()}
|
||||
project={{ scm_type: '', local_path: '' }}
|
||||
/>,
|
||||
{
|
||||
context: { config },
|
||||
}
|
||||
);
|
||||
});
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
expect(wrapper.find('ManualSubForm Alert').length).toBe(1);
|
||||
});
|
||||
|
||||
test('should reset scm subform values when scm type changes', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
|
||||
@ -0,0 +1,103 @@
|
||||
import React from 'react';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { Field } from 'formik';
|
||||
import AnsibleSelect from '@components/AnsibleSelect';
|
||||
import FormField, { FieldTooltip } from '@components/FormField';
|
||||
import { FormGroup, Alert } from '@patternfly/react-core';
|
||||
import { BrandName } from '../../../../variables';
|
||||
|
||||
// Setting BrandName to a variable here is necessary to get the jest tests
|
||||
// passing. Attempting to use BrandName in the template literal results
|
||||
// in failing tests.
|
||||
const brandName = BrandName;
|
||||
|
||||
const ManualSubForm = ({
|
||||
i18n,
|
||||
localPath,
|
||||
project_base_dir,
|
||||
project_local_paths,
|
||||
}) => {
|
||||
const localPaths = [...new Set([...project_local_paths, localPath])];
|
||||
const options = [
|
||||
{
|
||||
value: '',
|
||||
key: '',
|
||||
label: i18n._(t`Choose a Playbook Directory`),
|
||||
},
|
||||
...localPaths
|
||||
.filter(path => path)
|
||||
.map(path => ({
|
||||
value: path,
|
||||
key: path,
|
||||
label: path,
|
||||
})),
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{options.length === 1 && (
|
||||
<Alert
|
||||
title={i18n._(t`WARNING: `)}
|
||||
css="grid-column: 1/-1"
|
||||
variant="warning"
|
||||
isInline
|
||||
>
|
||||
{i18n._(t`
|
||||
There are no available playbook directories in ${project_base_dir}.
|
||||
Either that directory is empty, or all of the contents are already
|
||||
assigned to other projects. Create a new directory there and make
|
||||
sure the playbook files can be read by the "awx" system user,
|
||||
or have ${brandName} directly retrieve your playbooks from
|
||||
source control using the SCM Type option above.`)}
|
||||
</Alert>
|
||||
)}
|
||||
<FormField
|
||||
id="project-base-dir"
|
||||
label={i18n._(t`Project Base Path`)}
|
||||
name="base_dir"
|
||||
type="text"
|
||||
isReadOnly
|
||||
tooltip={
|
||||
<span>
|
||||
{i18n._(t`Base path used for locating playbooks. Directories
|
||||
found inside this path will be listed in the playbook directory drop-down.
|
||||
Together the base path and selected playbook directory provide the full
|
||||
path used to locate playbooks.`)}
|
||||
<br />
|
||||
<br />
|
||||
{i18n._(t`Change PROJECTS_ROOT when deploying
|
||||
${brandName} to change this location.`)}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
{options.length !== 1 && (
|
||||
<Field
|
||||
name="local_path"
|
||||
render={({ field, form }) => (
|
||||
<FormGroup
|
||||
fieldId="project-local-path"
|
||||
label={i18n._(t`Playbook Directory`)}
|
||||
>
|
||||
<FieldTooltip
|
||||
content={i18n._(t`Select from the list of directories found in
|
||||
the Project Base Path. Together the base path and the playbook
|
||||
directory provide the full path used to locate playbooks.`)}
|
||||
/>
|
||||
<AnsibleSelect
|
||||
{...field}
|
||||
id="local_path"
|
||||
data={options}
|
||||
onChange={(event, value) => {
|
||||
form.setFieldValue('local_path', value);
|
||||
}}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default withI18n()(ManualSubForm);
|
||||
@ -1,5 +1,6 @@
|
||||
export { SubFormTitle } from './SharedFields';
|
||||
export { default as GitSubForm } from './GitSubForm';
|
||||
export { default as HgSubForm } from './HgSubForm';
|
||||
export { default as SvnSubForm } from './SvnSubForm';
|
||||
export { default as InsightsSubForm } from './InsightsSubForm';
|
||||
export { SubFormTitle } from './SharedFields';
|
||||
export { default as ManualSubForm } from './ManualSubForm';
|
||||
export { default as SvnSubForm } from './SvnSubForm';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user