diff --git a/awx/ui_next/src/api/models/Jobs.js b/awx/ui_next/src/api/models/Jobs.js
index fc9bbb2334..db28e172b6 100644
--- a/awx/ui_next/src/api/models/Jobs.js
+++ b/awx/ui_next/src/api/models/Jobs.js
@@ -9,8 +9,8 @@ const getBaseURL = type => {
case 'project':
case 'project_update':
return '/project_updates/';
- case 'system':
- case 'system_job':
+ case 'management':
+ case 'management_job':
return '/system_jobs/';
case 'inventory':
case 'inventory_update':
diff --git a/awx/ui_next/src/api/models/SystemJobTemplates.js b/awx/ui_next/src/api/models/SystemJobTemplates.js
index 7520a3a3d3..5e8b395821 100644
--- a/awx/ui_next/src/api/models/SystemJobTemplates.js
+++ b/awx/ui_next/src/api/models/SystemJobTemplates.js
@@ -15,6 +15,10 @@ class SystemJobTemplates extends Mixins {
return this.http.get(path).then(({ data }) => data);
}
+
+ launch(id, data) {
+ return this.http.post(`${this.baseUrl}${id}/launch/`, data);
+ }
}
export default SystemJobTemplates;
diff --git a/awx/ui_next/src/constants.js b/awx/ui_next/src/constants.js
index 663814439e..f157c26d49 100644
--- a/awx/ui_next/src/constants.js
+++ b/awx/ui_next/src/constants.js
@@ -2,7 +2,7 @@
export const JOB_TYPE_URL_SEGMENTS = {
job: 'playbook',
project_update: 'project',
- system_job: 'system',
+ system_job: 'management',
inventory_update: 'inventory',
ad_hoc_command: 'command',
workflow_job: 'workflow',
diff --git a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx
index 89756a43ee..1949e04169 100644
--- a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx
+++ b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobList.jsx
@@ -1,19 +1,21 @@
-import React, { useEffect, useCallback } from 'react';
+import React, { useCallback, useEffect, useState } from 'react';
import { t } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { useLocation } from 'react-router-dom';
import { Card, PageSection } from '@patternfly/react-core';
import { SystemJobTemplatesAPI } from '../../../api';
-import { useConfig } from '../../../contexts/Config';
-import { getQSConfig, parseQueryString } from '../../../util/qs';
-import useRequest from '../../../util/useRequest';
+import AlertModal from '../../../components/AlertModal';
import DatalistToolbar from '../../../components/DataListToolbar';
+import ErrorDetail from '../../../components/ErrorDetail';
import PaginatedDataList from '../../../components/PaginatedDataList';
+import { useConfig } from '../../../contexts/Config';
+import { parseQueryString, getQSConfig } from '../../../util/qs';
+import useRequest from '../../../util/useRequest';
import ManagementJobListItem from './ManagementJobListItem';
-const QS_CONFIG = getQSConfig('management_jobs', {
+const QS_CONFIG = getQSConfig('system_job_templates', {
page: 1,
page_size: 20,
});
@@ -46,6 +48,7 @@ const loadManagementJobs = async search => {
function ManagementJobList({ i18n }) {
const { search } = useLocation();
const { me } = useConfig();
+ const [launchError, setLaunchError] = useState(null);
const {
request,
@@ -85,15 +88,26 @@ function ManagementJobList({ i18n }) {
)}
renderItem={({ id, name, description }) => (
)}
/>
+ setLaunchError(null)}
+ >
+ {i18n._(t`Failed to launch job.`)}
+
+
>
);
}
diff --git a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobListItem.jsx b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobListItem.jsx
index 7dd31d4ef0..02d898ca08 100644
--- a/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobListItem.jsx
+++ b/awx/ui_next/src/screens/ManagementJob/ManagementJobList/ManagementJobListItem.jsx
@@ -1,32 +1,55 @@
-import React from 'react';
+import React, { useState } from 'react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
-import { Link } from 'react-router-dom';
+import { Link, useHistory } from 'react-router-dom';
import {
Button,
DataListAction as _DataListAction,
+ DataListCell,
DataListItem,
DataListItemRow,
DataListItemCells,
Tooltip,
} from '@patternfly/react-core';
-import { PencilAltIcon } from '@patternfly/react-icons';
+import { PencilAltIcon, RocketIcon } from '@patternfly/react-icons';
import styled from 'styled-components';
-import DataListCell from '../../../components/DataListCell';
+import { SystemJobTemplatesAPI } from '../../../api';
const DataListAction = styled(_DataListAction)`
align-items: center;
display: grid;
grid-gap: 16px;
- grid-template-columns: 40px;
+ grid-template-columns: repeat(2, 40px);
`;
-function ManagementJobListItem({ i18n, isSuperUser, id, name, description }) {
+function ManagementJobListItem({
+ i18n,
+ onLaunchError,
+ isSuperUser,
+ id,
+ name,
+ description,
+}) {
const detailsUrl = `/management_jobs/${id}/details`;
const editUrl = `/management_jobs/${id}/edit`;
const labelId = `mgmt-job-action-${id}`;
+ const history = useHistory();
+ const [isLaunchLoading, setIsLaunchLoading] = useState(false);
+
+ const handleLaunch = async () => {
+ setIsLaunchLoading(true);
+ try {
+ const { data } = await SystemJobTemplatesAPI.launch(id);
+ history.push(`/jobs/management/${data.id}/output`);
+ } catch (error) {
+ onLaunchError(error);
+ } finally {
+ setIsLaunchLoading(false);
+ }
+ };
+
return (
@@ -54,16 +77,32 @@ function ManagementJobListItem({ i18n, isSuperUser, id, name, description }) {
id={labelId}
>
{isSuperUser ? (
-
-
-
+
+
+
+
+
+ >
) : null}