mirror of
https://github.com/ansible/awx.git
synced 2026-01-15 03:40:42 -03:30
add expandable rows to JobList
This commit is contained in:
parent
da16785201
commit
8bde6060c4
@ -234,7 +234,7 @@ function JobList({ i18n, defaultParams, showTypeColumn = false }) {
|
||||
},
|
||||
]}
|
||||
headerRow={
|
||||
<HeaderRow qsConfig={qsConfig}>
|
||||
<HeaderRow qsConfig={qsConfig} isExpandable>
|
||||
<HeaderCell sortKey="name">{i18n._(t`Name`)}</HeaderCell>
|
||||
<HeaderCell sortKey="status">{i18n._(t`Status`)}</HeaderCell>
|
||||
{showTypeColumn && <HeaderCell>{i18n._(t`Type`)}</HeaderCell>}
|
||||
|
||||
@ -1,16 +1,48 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { Button } from '@patternfly/react-core';
|
||||
import { Tr, Td } from '@patternfly/react-table';
|
||||
import { Button, Chip } from '@patternfly/react-core';
|
||||
import { Tr, Td, ExpandableRowContent } from '@patternfly/react-table';
|
||||
import { RocketIcon } from '@patternfly/react-icons';
|
||||
import { ActionsTd, ActionItem } from '../PaginatedTable';
|
||||
import LaunchButton from '../LaunchButton';
|
||||
import StatusLabel from '../StatusLabel';
|
||||
import { DetailList, Detail } from '../DetailList';
|
||||
import ChipGroup from '../ChipGroup';
|
||||
import CredentialChip from '../CredentialChip';
|
||||
import { formatDateString } from '../../util/dates';
|
||||
import { JOB_TYPE_URL_SEGMENTS } from '../../constants';
|
||||
|
||||
const getLaunchedByDetails = ({ summary_fields = {}, related = {} }) => {
|
||||
const {
|
||||
created_by: createdBy,
|
||||
job_template: jobTemplate,
|
||||
schedule,
|
||||
} = summary_fields;
|
||||
const { schedule: relatedSchedule } = related;
|
||||
|
||||
if (!createdBy && !schedule) {
|
||||
return {};
|
||||
}
|
||||
|
||||
let link;
|
||||
let value;
|
||||
|
||||
if (createdBy) {
|
||||
link = `/users/${createdBy.id}`;
|
||||
value = createdBy.username;
|
||||
} else if (relatedSchedule && jobTemplate) {
|
||||
link = `/templates/job_template/${jobTemplate.id}/schedules/${schedule.id}`;
|
||||
value = schedule.name;
|
||||
} else {
|
||||
link = null;
|
||||
value = schedule.name;
|
||||
}
|
||||
|
||||
return { link, value };
|
||||
};
|
||||
|
||||
function JobListItem({
|
||||
i18n,
|
||||
job,
|
||||
@ -20,6 +52,7 @@ function JobListItem({
|
||||
showTypeColumn = false,
|
||||
}) {
|
||||
const labelId = `check-action-${job.id}`;
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
const jobTypes = {
|
||||
project_update: i18n._(t`Source Control Update`),
|
||||
@ -30,57 +63,142 @@ function JobListItem({
|
||||
workflow_job: i18n._(t`Workflow Job`),
|
||||
};
|
||||
|
||||
const { value: launchedByValue, link: launchedByLink } =
|
||||
getLaunchedByDetails(job) || {};
|
||||
const { credentials, inventory, labels } = job.summary_fields;
|
||||
|
||||
return (
|
||||
<Tr id={`job-row-${job.id}`}>
|
||||
<Td
|
||||
select={{
|
||||
rowIndex,
|
||||
isSelected,
|
||||
onSelect,
|
||||
disable: false,
|
||||
}}
|
||||
/>
|
||||
<Td id={labelId} dataLabel={i18n._(t`Name`)}>
|
||||
<span>
|
||||
<Link to={`/jobs/${JOB_TYPE_URL_SEGMENTS[job.type]}/${job.id}`}>
|
||||
<b>
|
||||
{job.id} — {job.name}
|
||||
</b>
|
||||
</Link>
|
||||
</span>
|
||||
</Td>
|
||||
<Td dataLabel={i18n._(t`Status`)}>
|
||||
{job.status && <StatusLabel status={job.status} />}
|
||||
</Td>
|
||||
{showTypeColumn && (
|
||||
<Td dataLabel={i18n._(t`Type`)}>{jobTypes[job.type]}</Td>
|
||||
)}
|
||||
<Td dataLabel={i18n._(t`Start Time`)}>{formatDateString(job.started)}</Td>
|
||||
<Td dataLabel={i18n._(t`Finish Time`)}>
|
||||
{job.finished ? formatDateString(job.finished) : ''}
|
||||
</Td>
|
||||
<ActionsTd dataLabel={i18n._(t`Actions`)}>
|
||||
<ActionItem
|
||||
visible={
|
||||
job.type !== 'system_job' &&
|
||||
job.summary_fields?.user_capabilities?.start
|
||||
}
|
||||
tooltip={i18n._(t`Relaunch Job`)}
|
||||
>
|
||||
<LaunchButton resource={job}>
|
||||
{({ handleRelaunch }) => (
|
||||
<Button
|
||||
variant="plain"
|
||||
onClick={handleRelaunch}
|
||||
aria-label={i18n._(t`Relaunch`)}
|
||||
>
|
||||
<RocketIcon />
|
||||
</Button>
|
||||
)}
|
||||
</LaunchButton>
|
||||
</ActionItem>
|
||||
</ActionsTd>
|
||||
</Tr>
|
||||
<>
|
||||
<Tr id={`job-row-${job.id}`}>
|
||||
<Td
|
||||
expand={{
|
||||
rowIndex: job.id,
|
||||
isExpanded,
|
||||
onToggle: () => setIsExpanded(!isExpanded),
|
||||
}}
|
||||
/>
|
||||
<Td
|
||||
select={{
|
||||
rowIndex,
|
||||
isSelected,
|
||||
onSelect,
|
||||
disable: false,
|
||||
}}
|
||||
/>
|
||||
<Td id={labelId} dataLabel={i18n._(t`Name`)}>
|
||||
<span>
|
||||
<Link to={`/jobs/${JOB_TYPE_URL_SEGMENTS[job.type]}/${job.id}`}>
|
||||
<b>
|
||||
{job.id} — {job.name}
|
||||
</b>
|
||||
</Link>
|
||||
</span>
|
||||
</Td>
|
||||
<Td dataLabel={i18n._(t`Status`)}>
|
||||
{job.status && <StatusLabel status={job.status} />}
|
||||
</Td>
|
||||
{showTypeColumn && (
|
||||
<Td dataLabel={i18n._(t`Type`)}>{jobTypes[job.type]}</Td>
|
||||
)}
|
||||
<Td dataLabel={i18n._(t`Start Time`)}>
|
||||
{formatDateString(job.started)}
|
||||
</Td>
|
||||
<Td dataLabel={i18n._(t`Finish Time`)}>
|
||||
{job.finished ? formatDateString(job.finished) : ''}
|
||||
</Td>
|
||||
<ActionsTd dataLabel={i18n._(t`Actions`)}>
|
||||
<ActionItem
|
||||
visible={
|
||||
job.type !== 'system_job' &&
|
||||
job.summary_fields?.user_capabilities?.start
|
||||
}
|
||||
tooltip={i18n._(t`Relaunch Job`)}
|
||||
>
|
||||
<LaunchButton resource={job}>
|
||||
{({ handleRelaunch }) => (
|
||||
<Button
|
||||
variant="plain"
|
||||
onClick={handleRelaunch}
|
||||
aria-label={i18n._(t`Relaunch`)}
|
||||
>
|
||||
<RocketIcon />
|
||||
</Button>
|
||||
)}
|
||||
</LaunchButton>
|
||||
</ActionItem>
|
||||
</ActionsTd>
|
||||
</Tr>
|
||||
<Tr isExpanded={isExpanded}>
|
||||
<Td colSpan={2} />
|
||||
<Td colSpan={showTypeColumn ? 5 : 4}>
|
||||
<ExpandableRowContent>
|
||||
<DetailList>
|
||||
<Detail
|
||||
label={i18n._(t`Started`)}
|
||||
value={formatDateString(job.started)}
|
||||
/>
|
||||
<Detail
|
||||
label={i18n._(t`Finished`)}
|
||||
value={formatDateString(job.started)}
|
||||
/>
|
||||
<Detail
|
||||
label={i18n._(t`Launched By`)}
|
||||
value={
|
||||
launchedByLink ? (
|
||||
<Link to={`${launchedByLink}`}>{launchedByValue}</Link>
|
||||
) : (
|
||||
launchedByValue
|
||||
)
|
||||
}
|
||||
/>
|
||||
{credentials && credentials.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={i18n._(t`Credentials`)}
|
||||
value={
|
||||
<ChipGroup numChips={5} totalChips={credentials.length}>
|
||||
{credentials.map(c => (
|
||||
<CredentialChip key={c.id} credential={c} isReadOnly />
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{labels && labels.count > 0 && (
|
||||
<Detail
|
||||
label={i18n._(t`Labels`)}
|
||||
value={
|
||||
<ChipGroup numChips={5} totalChips={labels.results.length}>
|
||||
{labels.results.map(l => (
|
||||
<Chip key={l.id} isReadOnly>
|
||||
{l.name}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{inventory && (
|
||||
<Detail
|
||||
label={i18n._(t`Inventory`)}
|
||||
value={
|
||||
<Link
|
||||
to={
|
||||
inventory.kind === 'smart'
|
||||
? `/inventories/smart_inventory/${inventory.id}`
|
||||
: `/inventories/inventory/${inventory.id}`
|
||||
}
|
||||
>
|
||||
{inventory.name}
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</DetailList>
|
||||
</ExpandableRowContent>
|
||||
</Td>
|
||||
</Tr>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ const Th = styled(PFTh)`
|
||||
--pf-c-table--cell--Overflow: initial;
|
||||
`;
|
||||
|
||||
export default function HeaderRow({ qsConfig, children }) {
|
||||
export default function HeaderRow({ qsConfig, isExpandable, children }) {
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
|
||||
@ -46,6 +46,7 @@ export default function HeaderRow({ qsConfig, children }) {
|
||||
return (
|
||||
<Thead>
|
||||
<Tr>
|
||||
{isExpandable && <Th />}
|
||||
<Th />
|
||||
{React.Children.map(
|
||||
children,
|
||||
|
||||
@ -360,3 +360,4 @@ JobDetail.propTypes = {
|
||||
};
|
||||
|
||||
export default withI18n()(JobDetail);
|
||||
export { getLaunchedByDetails };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user