diff --git a/awx/ui/src/components/DetailList/LaunchedByDetail.js b/awx/ui/src/components/DetailList/LaunchedByDetail.js
index 099d2385a7..6f542231c5 100644
--- a/awx/ui/src/components/DetailList/LaunchedByDetail.js
+++ b/awx/ui/src/components/DetailList/LaunchedByDetail.js
@@ -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`;
diff --git a/awx/ui/src/components/JobList/JobListItem.js b/awx/ui/src/components/JobList/JobListItem.js
index 9967b1b154..364b4279c0 100644
--- a/awx/ui/src/components/JobList/JobListItem.js
+++ b/awx/ui/src/components/JobList/JobListItem.js
@@ -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({
/>
)}
+ {job.launch_type === 'scheduled' &&
+ (schedule ? (
+ {schedule.name}
+ }
+ />
+ ) : (
+
+ ))}
{job_template && (
', () => {
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('', () => {
expect(wrapper.find('Td[dataLabel="Type"]').length).toBe(1);
});
+ test('should not show schedule detail in expanded view', () => {
+ wrapper = mountWithContexts(
+
+ );
+ expect(wrapper.find('Detail[label="Schedule"] dt').length).toBe(1);
+ });
+
test('should not display EE for canceled jobs', () => {
wrapper = mountWithContexts(
diff --git a/awx/ui/src/screens/Job/JobDetail/JobDetail.test.js b/awx/ui/src/screens/Job/JobDetail/JobDetail.test.js
index da8b7048fe..33487f687d 100644
--- a/awx/ui/src/screens/Job/JobDetail/JobDetail.test.js
+++ b/awx/ui/src/screens/Job/JobDetail/JobDetail.test.js
@@ -189,6 +189,7 @@ describe('', () => {
{
+ 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'
+ );
+ });
+});