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}