Refactor job template detail into functional component

This commit is contained in:
Marliana Lara 2020-01-23 13:52:29 -05:00
parent c983b6a755
commit 10131432b5
No known key found for this signature in database
GPG Key ID: 38C73B40DFA809EE

View File

@ -1,5 +1,5 @@
import React, { Component, Fragment } from 'react';
import { Link, withRouter } from 'react-router-dom';
import React, { Fragment, useState, useEffect } from 'react';
import { Link, useParams } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import {
Button,
@ -13,10 +13,10 @@ import { t } from '@lingui/macro';
import { CardBody, CardActionsRow } from '@components/Card';
import ContentError from '@components/ContentError';
import LaunchButton from '@components/LaunchButton';
import ContentLoading from '@components/ContentLoading';
import { ChipGroup, Chip, CredentialChip } from '@components/Chip';
import { DetailList, Detail, UserDateDetail } from '@components/DetailList';
import LaunchButton from '@components/LaunchButton';
import { JobTemplatesAPI } from '@api';
const MissingDetail = styled(Detail)`
@ -25,319 +25,290 @@ const MissingDetail = styled(Detail)`
}
`;
class JobTemplateDetail extends Component {
constructor(props) {
super(props);
this.state = {
contentError: null,
hasContentLoading: true,
instanceGroups: [],
};
this.readInstanceGroups = this.readInstanceGroups.bind(this);
}
function JobTemplateDetail({ i18n, template }) {
const {
ask_inventory_on_launch,
allow_simultaneous,
become_enabled,
created,
description,
diff_mode,
forks,
host_config_key,
job_slice_count,
job_tags,
job_type,
name,
limit,
modified,
playbook,
skip_tags,
timeout,
summary_fields,
use_fact_cache,
url,
verbosity,
} = template;
const [contentError, setContentError] = useState(null);
const [hasContentLoading, setHasContentLoading] = useState(false);
const [instanceGroups, setInstanceGroups] = useState([]);
const { id: templateId } = useParams();
componentDidMount() {
this.readInstanceGroups();
}
useEffect(() => {
(async () => {
setContentError(null);
setHasContentLoading(true);
try {
const {
data: { results = [] },
} = await JobTemplatesAPI.readInstanceGroups(templateId);
setInstanceGroups(results);
} catch (error) {
setContentError(error);
} finally {
setHasContentLoading(false);
}
})();
}, [templateId]);
async readInstanceGroups() {
const { match } = this.props;
try {
const { data } = await JobTemplatesAPI.readInstanceGroups(
match.params.id
);
this.setState({ instanceGroups: [...data.results] });
} catch (err) {
this.setState({ contentError: err });
} finally {
this.setState({ hasContentLoading: false });
}
}
const canLaunch =
summary_fields.user_capabilities && summary_fields.user_capabilities.start;
const verbosityOptions = [
{ verbosity: 0, details: i18n._(t`0 (Normal)`) },
{ verbosity: 1, details: i18n._(t`1 (Verbose)`) },
{ verbosity: 2, details: i18n._(t`2 (More Verbose)`) },
{ verbosity: 3, details: i18n._(t`3 (Debug)`) },
{ verbosity: 4, details: i18n._(t`4 (Connection Debug)`) },
{ verbosity: 5, details: i18n._(t`5 (WinRM Debug)`) },
];
const verbosityDetails = verbosityOptions.filter(
option => option.verbosity === verbosity
);
const generateCallBackUrl = `${window.location.origin + url}callback/`;
const renderOptionsField =
become_enabled || host_config_key || allow_simultaneous || use_fact_cache;
render() {
const {
template: {
ask_inventory_on_launch,
allow_simultaneous,
become_enabled,
created,
description,
diff_mode,
forks,
host_config_key,
job_slice_count,
job_tags,
job_type,
name,
limit,
modified,
playbook,
skip_tags,
timeout,
summary_fields,
use_fact_cache,
url,
verbosity,
},
hasTemplateLoading,
template,
i18n,
match,
} = this.props;
const canLaunch = summary_fields.user_capabilities.start;
const { instanceGroups, hasContentLoading, contentError } = this.state;
const verbosityOptions = [
{ verbosity: 0, details: i18n._(t`0 (Normal)`) },
{ verbosity: 1, details: i18n._(t`1 (Verbose)`) },
{ verbosity: 2, details: i18n._(t`2 (More Verbose)`) },
{ verbosity: 3, details: i18n._(t`3 (Debug)`) },
{ verbosity: 4, details: i18n._(t`4 (Connection Debug)`) },
{ verbosity: 5, details: i18n._(t`5 (WinRM Debug)`) },
];
const verbosityDetails = verbosityOptions.filter(
option => option.verbosity === verbosity
);
const generateCallBackUrl = `${window.location.origin + url}callback/`;
const isInitialized = !hasTemplateLoading && !hasContentLoading;
const renderOptions = (
<TextList component={TextListVariants.ul}>
{become_enabled && (
<TextListItem component={TextListItemVariants.li}>
{i18n._(t`Enable Privilege Escalation`)}
</TextListItem>
)}
{host_config_key && (
<TextListItem component={TextListItemVariants.li}>
{i18n._(t`Allow Provisioning Callbacks`)}
</TextListItem>
)}
{allow_simultaneous && (
<TextListItem component={TextListItemVariants.li}>
{i18n._(t`Enable Concurrent Jobs`)}
</TextListItem>
)}
{use_fact_cache && (
<TextListItem component={TextListItemVariants.li}>
{i18n._(t`Use Fact Cache`)}
</TextListItem>
)}
</TextList>
);
const renderOptionsField =
become_enabled || host_config_key || allow_simultaneous || use_fact_cache;
const renderMissingDataDetail = value => (
<MissingDetail label={value} value={i18n._(t`Deleted`)} />
);
const renderOptions = (
<TextList component={TextListVariants.ul}>
{become_enabled && (
<TextListItem component={TextListItemVariants.li}>
{i18n._(t`Enable Privilege Escalation`)}
</TextListItem>
)}
{host_config_key && (
<TextListItem component={TextListItemVariants.li}>
{i18n._(t`Allow Provisioning Callbacks`)}
</TextListItem>
)}
{allow_simultaneous && (
<TextListItem component={TextListItemVariants.li}>
{i18n._(t`Enable Concurrent Jobs`)}
</TextListItem>
)}
{use_fact_cache && (
<TextListItem component={TextListItemVariants.li}>
{i18n._(t`Use Fact Cache`)}
</TextListItem>
)}
</TextList>
);
const inventoryValue = (kind, id) => {
const inventorykind = kind === 'smart' ? 'smart_inventory' : 'inventory';
const renderMissingDataDetail = value => (
<MissingDetail label={value} value={i18n._(t`Deleted`)} />
);
const inventoryValue = (kind, id) => {
const inventorykind =
kind === 'smart' ? (kind = 'smart_inventory') : (kind = 'inventory');
return ask_inventory_on_launch ? (
<Fragment>
<Link to={`/inventories/${inventorykind}/${id}/details`}>
{summary_fields.inventory.name}
</Link>
<span> {i18n._(t`(Prompt on Launch)`)}</span>
</Fragment>
) : (
return ask_inventory_on_launch ? (
<Fragment>
<Link to={`/inventories/${inventorykind}/${id}/details`}>
{summary_fields.inventory.name}
</Link>
);
};
<span> {i18n._(t`(Prompt on Launch)`)}</span>
</Fragment>
) : (
<Link to={`/inventories/${inventorykind}/${id}/details`}>
{summary_fields.inventory.name}
</Link>
);
};
if (contentError) {
return <ContentError error={contentError} />;
}
if (contentError) {
return <ContentError error={contentError} />;
}
if (hasContentLoading) {
return <ContentLoading />;
}
if (hasContentLoading) {
return <ContentLoading />;
}
return (
isInitialized && (
<CardBody>
<DetailList gutter="sm">
<Detail
label={i18n._(t`Name`)}
value={name}
dataCy="jt-detail-name"
/>
<Detail label={i18n._(t`Description`)} value={description} />
<Detail label={i18n._(t`Job Type`)} value={job_type} />
{summary_fields.inventory ? (
<Detail
label={i18n._(t`Inventory`)}
value={inventoryValue(
summary_fields.inventory.kind,
summary_fields.inventory.id
)}
/>
) : (
!ask_inventory_on_launch &&
renderMissingDataDetail(i18n._(t`Inventory`))
return (
<CardBody>
<DetailList gutter="sm">
<Detail label={i18n._(t`Name`)} value={name} dataCy="jt-detail-name" />
<Detail label={i18n._(t`Description`)} value={description} />
<Detail label={i18n._(t`Job Type`)} value={job_type} />
{summary_fields.inventory ? (
<Detail
label={i18n._(t`Inventory`)}
value={inventoryValue(
summary_fields.inventory.kind,
summary_fields.inventory.id
)}
{summary_fields.project ? (
<Detail
label={i18n._(t`Project`)}
value={
<Link to={`/projects/${summary_fields.project.id}/details`}>
{summary_fields.project
? summary_fields.project.name
: i18n._(t`Deleted`)}
</Link>
}
/>
) : (
renderMissingDataDetail(i18n._(t`Project`))
)}
<Detail label={i18n._(t`SCM Branch`)} value={template.scm_branch} />
<Detail label={i18n._(t`Playbook`)} value={playbook} />
<Detail label={i18n._(t`Forks`)} value={forks || '0'} />
<Detail label={i18n._(t`Limit`)} value={limit} />
/>
) : (
!ask_inventory_on_launch &&
renderMissingDataDetail(i18n._(t`Inventory`))
)}
{summary_fields.project ? (
<Detail
label={i18n._(t`Project`)}
value={
<Link to={`/projects/${summary_fields.project.id}/details`}>
{summary_fields.project.name}
</Link>
}
/>
) : (
renderMissingDataDetail(i18n._(t`Project`))
)}
<Detail label={i18n._(t`SCM Branch`)} value={template.scm_branch} />
<Detail label={i18n._(t`Playbook`)} value={playbook} />
<Detail label={i18n._(t`Forks`)} value={forks || '0'} />
<Detail label={i18n._(t`Limit`)} value={limit} />
<Detail
label={i18n._(t`Verbosity`)}
value={verbosityDetails[0].details}
/>
<Detail label={i18n._(t`Timeout`)} value={timeout || '0'} />
<UserDateDetail
label={i18n._(t`Created`)}
date={created}
user={summary_fields.created_by}
/>
<UserDateDetail
label={i18n._(t`Last Modified`)}
date={modified}
user={summary_fields.modified_by}
/>
<Detail
label={i18n._(t`Show Changes`)}
value={diff_mode ? 'On' : 'Off'}
/>
<Detail label={i18n._(t` Job Slicing`)} value={job_slice_count} />
{host_config_key && (
<React.Fragment>
<Detail
label={i18n._(t`Verbosity`)}
value={verbosityDetails[0].details}
/>
<Detail label={i18n._(t`Timeout`)} value={timeout || '0'} />
<UserDateDetail
label={i18n._(t`Created`)}
date={created}
user={summary_fields.created_by}
/>
<UserDateDetail
label={i18n._(t`Last Modified`)}
date={modified}
user={summary_fields.modified_by}
label={i18n._(t`Host Config Key`)}
value={host_config_key}
/>
<Detail
label={i18n._(t`Show Changes`)}
value={diff_mode ? 'On' : 'Off'}
label={i18n._(t`Provisioning Callback URL`)}
value={generateCallBackUrl}
/>
<Detail label={i18n._(t` Job Slicing`)} value={job_slice_count} />
{host_config_key && (
<React.Fragment>
<Detail
label={i18n._(t`Host Config Key`)}
value={host_config_key}
/>
<Detail
label={i18n._(t`Provisioning Callback URL`)}
value={generateCallBackUrl}
/>
</React.Fragment>
)}
{renderOptionsField && (
<Detail label={i18n._(t`Options`)} value={renderOptions} />
)}
{summary_fields.credentials &&
summary_fields.credentials.length > 0 && (
<Detail
fullWidth
label={i18n._(t`Credentials`)}
value={
<ChipGroup numChips={5}>
{summary_fields.credentials.map(c => (
<CredentialChip key={c.id} credential={c} isReadOnly />
))}
</ChipGroup>
}
/>
)}
{summary_fields.labels && summary_fields.labels.results.length > 0 && (
<Detail
fullWidth
label={i18n._(t`Labels`)}
value={
<ChipGroup numChips={5}>
{summary_fields.labels.results.map(l => (
<Chip key={l.id} isReadOnly>
{l.name}
</Chip>
))}
</ChipGroup>
}
/>
)}
{instanceGroups.length > 0 && (
<Detail
fullWidth
label={i18n._(t`Instance Groups`)}
value={
<ChipGroup numChips={5}>
{instanceGroups.map(ig => (
<Chip key={ig.id} isReadOnly>
{ig.name}
</Chip>
))}
</ChipGroup>
}
/>
)}
{job_tags && job_tags.length > 0 && (
<Detail
fullWidth
label={i18n._(t`Job tags`)}
value={
<ChipGroup numChips={5}>
{job_tags.split(',').map(jobTag => (
<Chip key={jobTag} isReadOnly>
{jobTag}
</Chip>
))}
</ChipGroup>
}
/>
)}
{skip_tags && skip_tags.length > 0 && (
<Detail
fullWidth
label={i18n._(t`Skip tags`)}
value={
<ChipGroup numChips={5}>
{skip_tags.split(',').map(skipTag => (
<Chip key={skipTag} isReadOnly>
{skipTag}
</Chip>
))}
</ChipGroup>
}
/>
)}
</DetailList>
<CardActionsRow>
{summary_fields.user_capabilities.edit && (
<Button
component={Link}
to={`/templates/job_template/${match.params.id}/edit`}
aria-label={i18n._(t`Edit`)}
>
{i18n._(t`Edit`)}
</React.Fragment>
)}
{renderOptionsField && (
<Detail label={i18n._(t`Options`)} value={renderOptions} />
)}
{summary_fields.credentials && summary_fields.credentials.length > 0 && (
<Detail
fullWidth
label={i18n._(t`Credentials`)}
value={
<ChipGroup numChips={5}>
{summary_fields.credentials.map(c => (
<CredentialChip key={c.id} credential={c} isReadOnly />
))}
</ChipGroup>
}
/>
)}
{summary_fields.labels && summary_fields.labels.results.length > 0 && (
<Detail
fullWidth
label={i18n._(t`Labels`)}
value={
<ChipGroup numChips={5}>
{summary_fields.labels.results.map(l => (
<Chip key={l.id} isReadOnly>
{l.name}
</Chip>
))}
</ChipGroup>
}
/>
)}
{instanceGroups.length > 0 && (
<Detail
fullWidth
label={i18n._(t`Instance Groups`)}
value={
<ChipGroup numChips={5}>
{instanceGroups.map(ig => (
<Chip key={ig.id} isReadOnly>
{ig.name}
</Chip>
))}
</ChipGroup>
}
/>
)}
{job_tags && job_tags.length > 0 && (
<Detail
fullWidth
label={i18n._(t`Job tags`)}
value={
<ChipGroup numChips={5}>
{job_tags.split(',').map(jobTag => (
<Chip key={jobTag} isReadOnly>
{jobTag}
</Chip>
))}
</ChipGroup>
}
/>
)}
{skip_tags && skip_tags.length > 0 && (
<Detail
fullWidth
label={i18n._(t`Skip tags`)}
value={
<ChipGroup numChips={5}>
{skip_tags.split(',').map(skipTag => (
<Chip key={skipTag} isReadOnly>
{skipTag}
</Chip>
))}
</ChipGroup>
}
/>
)}
</DetailList>
<CardActionsRow>
{summary_fields.user_capabilities &&
summary_fields.user_capabilities.edit && (
<Button
component={Link}
to={`/templates/job_template/${templateId}/edit`}
aria-label={i18n._(t`Edit`)}
>
{i18n._(t`Edit`)}
</Button>
)}
{canLaunch && (
<LaunchButton resource={template} aria-label={i18n._(t`Launch`)}>
{({ handleLaunch }) => (
<Button variant="secondary" type="submit" onClick={handleLaunch}>
{i18n._(t`Launch`)}
</Button>
)}
{canLaunch && (
<LaunchButton resource={template} aria-label={i18n._(t`Launch`)}>
{({ handleLaunch }) => (
<Button
variant="secondary"
type="submit"
onClick={handleLaunch}
>
{i18n._(t`Launch`)}
</Button>
)}
</LaunchButton>
)}
</CardActionsRow>
</CardBody>
)
);
}
</LaunchButton>
)}
</CardActionsRow>
</CardBody>
);
}
export { JobTemplateDetail as _JobTemplateDetail };
export default withI18n()(withRouter(JobTemplateDetail));
export default withI18n()(JobTemplateDetail);