mirror of
https://github.com/ansible/awx.git
synced 2026-01-14 03:10:42 -03:30
Merge pull request #11792 from marshmalien/8321-job-list-schedule-name
Add schedule detail to job list expanded view
This commit is contained in:
commit
d07c2973e0
@ -1,45 +1,16 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { t } from '@lingui/macro';
|
||||
import getScheduleUrl from 'util/getScheduleUrl';
|
||||
import Detail from './Detail';
|
||||
|
||||
function getScheduleURL(template, scheduleId, inventoryId = null) {
|
||||
let scheduleUrl;
|
||||
|
||||
switch (template.unified_job_type) {
|
||||
case 'inventory_update':
|
||||
scheduleUrl =
|
||||
inventoryId &&
|
||||
`/inventories/inventory/${inventoryId}/sources/${template.id}/schedules/${scheduleId}/details`;
|
||||
break;
|
||||
case 'job':
|
||||
scheduleUrl = `/templates/job_template/${template.id}/schedules/${scheduleId}/details`;
|
||||
break;
|
||||
case 'project_update':
|
||||
scheduleUrl = `/projects/${template.id}/schedules/${scheduleId}/details`;
|
||||
break;
|
||||
case 'system_job':
|
||||
scheduleUrl = `/management_jobs/${template.id}/schedules/${scheduleId}/details`;
|
||||
break;
|
||||
case 'workflow_job':
|
||||
scheduleUrl = `/templates/workflow_job_template/${template.id}/schedules/${scheduleId}/details`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return scheduleUrl;
|
||||
}
|
||||
|
||||
const getLaunchedByDetails = ({ summary_fields = {}, launch_type }) => {
|
||||
const getLaunchedByDetails = (job) => {
|
||||
const {
|
||||
created_by: createdBy,
|
||||
job_template: jobTemplate,
|
||||
unified_job_template: unifiedJT,
|
||||
workflow_job_template: workflowJT,
|
||||
inventory,
|
||||
schedule,
|
||||
} = summary_fields;
|
||||
} = job.summary_fields;
|
||||
|
||||
if (!createdBy && !schedule) {
|
||||
return {};
|
||||
@ -48,7 +19,7 @@ const getLaunchedByDetails = ({ summary_fields = {}, launch_type }) => {
|
||||
let link;
|
||||
let value;
|
||||
|
||||
switch (launch_type) {
|
||||
switch (job.launch_type) {
|
||||
case 'webhook':
|
||||
value = t`Webhook`;
|
||||
link =
|
||||
@ -58,7 +29,7 @@ const getLaunchedByDetails = ({ summary_fields = {}, launch_type }) => {
|
||||
break;
|
||||
case 'scheduled':
|
||||
value = schedule.name;
|
||||
link = getScheduleURL(unifiedJT, schedule.id, inventory?.id);
|
||||
link = getScheduleUrl(job);
|
||||
break;
|
||||
case 'manual':
|
||||
link = `/users/${createdBy.id}/details`;
|
||||
|
||||
@ -8,10 +8,16 @@ import { RocketIcon } from '@patternfly/react-icons';
|
||||
import styled from 'styled-components';
|
||||
import { formatDateString } from 'util/dates';
|
||||
import { isJobRunning } from 'util/jobs';
|
||||
import getScheduleUrl from 'util/getScheduleUrl';
|
||||
import { ActionsTd, ActionItem, TdBreakWord } from '../PaginatedTable';
|
||||
import { LaunchButton, ReLaunchDropDown } from '../LaunchButton';
|
||||
import StatusLabel from '../StatusLabel';
|
||||
import { DetailList, Detail, LaunchedByDetail } from '../DetailList';
|
||||
import {
|
||||
DetailList,
|
||||
Detail,
|
||||
DeletedDetail,
|
||||
LaunchedByDetail,
|
||||
} from '../DetailList';
|
||||
import ChipGroup from '../ChipGroup';
|
||||
import CredentialChip from '../CredentialChip';
|
||||
import ExecutionEnvironmentDetail from '../ExecutionEnvironmentDetail';
|
||||
@ -48,6 +54,7 @@ function JobListItem({
|
||||
job_template,
|
||||
labels,
|
||||
project,
|
||||
schedule,
|
||||
source_workflow_job,
|
||||
workflow_job_template,
|
||||
} = job.summary_fields;
|
||||
@ -167,6 +174,18 @@ function JobListItem({
|
||||
/>
|
||||
)}
|
||||
<LaunchedByDetail job={job} />
|
||||
{job.launch_type === 'scheduled' &&
|
||||
(schedule ? (
|
||||
<Detail
|
||||
dataCy="job-schedule"
|
||||
label={t`Schedule`}
|
||||
value={
|
||||
<Link to={getScheduleUrl(job)}>{schedule.name}</Link>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<DeletedDetail label={t`Schedule`} />
|
||||
))}
|
||||
{job_template && (
|
||||
<Detail
|
||||
label={t`Job Template`}
|
||||
|
||||
@ -14,11 +14,20 @@ const mockJob = {
|
||||
delete: true,
|
||||
start: true,
|
||||
},
|
||||
schedule: {
|
||||
name: 'mock schedule',
|
||||
id: 999,
|
||||
},
|
||||
unified_job_template: {
|
||||
unified_job_type: 'job',
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
created: '2019-08-08T19:24:05.344276Z',
|
||||
modified: '2019-08-08T19:24:18.162949Z',
|
||||
name: 'Demo Job Template',
|
||||
job_type: 'run',
|
||||
launch_type: 'scheduled',
|
||||
started: '2019-08-08T19:24:18.329589Z',
|
||||
finished: '2019-08-08T19:24:50.119995Z',
|
||||
status: 'successful',
|
||||
@ -51,7 +60,11 @@ describe('<JobListItem />', () => {
|
||||
|
||||
test('initially renders successfully', () => {
|
||||
expect(wrapper.find('JobListItem').length).toBe(1);
|
||||
});
|
||||
|
||||
test('should display expected details', () => {
|
||||
assertDetail('Job Slice', '1/3');
|
||||
assertDetail('Schedule', 'mock schedule');
|
||||
});
|
||||
|
||||
test('launch button shown to users with launch capabilities', () => {
|
||||
@ -129,6 +142,25 @@ describe('<JobListItem />', () => {
|
||||
expect(wrapper.find('Td[dataLabel="Type"]').length).toBe(1);
|
||||
});
|
||||
|
||||
test('should not show schedule detail in expanded view', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<table>
|
||||
<tbody>
|
||||
<JobListItem
|
||||
job={{
|
||||
...mockJob,
|
||||
summary_fields: {},
|
||||
}}
|
||||
showTypeColumn
|
||||
isSelected
|
||||
onSelect={() => {}}
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
expect(wrapper.find('Detail[label="Schedule"] dt').length).toBe(1);
|
||||
});
|
||||
|
||||
test('should not display EE for canceled jobs', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<table>
|
||||
|
||||
@ -189,6 +189,7 @@ describe('<JobDetail />', () => {
|
||||
<JobDetail
|
||||
job={{
|
||||
...mockJobData,
|
||||
type: 'workflow_job',
|
||||
launch_type: 'scheduled',
|
||||
summary_fields: {
|
||||
user_capabilities: {},
|
||||
|
||||
32
awx/ui/src/util/getScheduleUrl.js
Normal file
32
awx/ui/src/util/getScheduleUrl.js
Normal file
@ -0,0 +1,32 @@
|
||||
export default function getScheduleUrl(job) {
|
||||
const templateId = job.summary_fields.unified_job_template.id;
|
||||
const scheduleId = job.summary_fields.schedule.id;
|
||||
const inventoryId = job.summary_fields.inventory
|
||||
? job.summary_fields.inventory.id
|
||||
: null;
|
||||
let scheduleUrl;
|
||||
|
||||
switch (job.type) {
|
||||
case 'inventory_update':
|
||||
scheduleUrl =
|
||||
inventoryId &&
|
||||
`/inventories/inventory/${inventoryId}/sources/${templateId}/schedules/${scheduleId}/details`;
|
||||
break;
|
||||
case 'job':
|
||||
scheduleUrl = `/templates/job_template/${templateId}/schedules/${scheduleId}/details`;
|
||||
break;
|
||||
case 'project_update':
|
||||
scheduleUrl = `/projects/${templateId}/schedules/${scheduleId}/details`;
|
||||
break;
|
||||
case 'system_job':
|
||||
scheduleUrl = `/management_jobs/${templateId}/schedules/${scheduleId}/details`;
|
||||
break;
|
||||
case 'workflow_job':
|
||||
scheduleUrl = `/templates/workflow_job_template/${templateId}/schedules/${scheduleId}/details`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return scheduleUrl;
|
||||
}
|
||||
103
awx/ui/src/util/getScheduleUrl.test.js
Normal file
103
awx/ui/src/util/getScheduleUrl.test.js
Normal file
@ -0,0 +1,103 @@
|
||||
import getScheduleUrl from './getScheduleUrl';
|
||||
|
||||
describe('getScheduleUrl', () => {
|
||||
test('should return expected schedule URL for inventory update job', () => {
|
||||
const invSrcJob = {
|
||||
type: 'inventory_update',
|
||||
summary_fields: {
|
||||
inventory: {
|
||||
id: 1,
|
||||
name: 'mock inv',
|
||||
},
|
||||
schedule: {
|
||||
name: 'mock schedule',
|
||||
id: 3,
|
||||
},
|
||||
unified_job_template: {
|
||||
unified_job_type: 'inventory_update',
|
||||
name: 'mock inv src',
|
||||
id: 2,
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(getScheduleUrl(invSrcJob)).toEqual(
|
||||
'/inventories/inventory/1/sources/2/schedules/3/details'
|
||||
);
|
||||
});
|
||||
test('should return expected schedule URL for job', () => {
|
||||
const templateJob = {
|
||||
type: 'job',
|
||||
summary_fields: {
|
||||
schedule: {
|
||||
name: 'mock schedule',
|
||||
id: 5,
|
||||
},
|
||||
unified_job_template: {
|
||||
unified_job_type: 'job',
|
||||
name: 'mock job',
|
||||
id: 4,
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(getScheduleUrl(templateJob)).toEqual(
|
||||
'/templates/job_template/4/schedules/5/details'
|
||||
);
|
||||
});
|
||||
test('should return expected schedule URL for project update job', () => {
|
||||
const projectUpdateJob = {
|
||||
type: 'project_update',
|
||||
summary_fields: {
|
||||
schedule: {
|
||||
name: 'mock schedule',
|
||||
id: 7,
|
||||
},
|
||||
unified_job_template: {
|
||||
unified_job_type: 'project_update',
|
||||
name: 'mock job',
|
||||
id: 6,
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(getScheduleUrl(projectUpdateJob)).toEqual(
|
||||
'/projects/6/schedules/7/details'
|
||||
);
|
||||
});
|
||||
test('should return expected schedule URL for system job', () => {
|
||||
const systemJob = {
|
||||
type: 'system_job',
|
||||
summary_fields: {
|
||||
schedule: {
|
||||
name: 'mock schedule',
|
||||
id: 10,
|
||||
},
|
||||
unified_job_template: {
|
||||
unified_job_type: 'system_job',
|
||||
name: 'mock job',
|
||||
id: 9,
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(getScheduleUrl(systemJob)).toEqual(
|
||||
'/management_jobs/9/schedules/10/details'
|
||||
);
|
||||
});
|
||||
test('should return expected schedule URL for workflow job', () => {
|
||||
const workflowJob = {
|
||||
type: 'workflow_job',
|
||||
summary_fields: {
|
||||
schedule: {
|
||||
name: 'mock schedule',
|
||||
id: 12,
|
||||
},
|
||||
unified_job_template: {
|
||||
unified_job_type: 'job',
|
||||
name: 'mock job',
|
||||
id: 11,
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(getScheduleUrl(workflowJob)).toEqual(
|
||||
'/templates/workflow_job_template/11/schedules/12/details'
|
||||
);
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user