mirror of
https://github.com/ansible/awx.git
synced 2026-04-07 02:59:21 -02:30
Add routing system for mgmt jobs
This commit is contained in:
@@ -29,6 +29,7 @@ import Root from './models/Root';
|
|||||||
import Schedules from './models/Schedules';
|
import Schedules from './models/Schedules';
|
||||||
import Settings from './models/Settings';
|
import Settings from './models/Settings';
|
||||||
import SystemJobs from './models/SystemJobs';
|
import SystemJobs from './models/SystemJobs';
|
||||||
|
import SystemJobTemplates from './models/SystemJobTemplates';
|
||||||
import Teams from './models/Teams';
|
import Teams from './models/Teams';
|
||||||
import Tokens from './models/Tokens';
|
import Tokens from './models/Tokens';
|
||||||
import UnifiedJobTemplates from './models/UnifiedJobTemplates';
|
import UnifiedJobTemplates from './models/UnifiedJobTemplates';
|
||||||
@@ -71,6 +72,7 @@ const RootAPI = new Root();
|
|||||||
const SchedulesAPI = new Schedules();
|
const SchedulesAPI = new Schedules();
|
||||||
const SettingsAPI = new Settings();
|
const SettingsAPI = new Settings();
|
||||||
const SystemJobsAPI = new SystemJobs();
|
const SystemJobsAPI = new SystemJobs();
|
||||||
|
const SystemJobTemplatesAPI = new SystemJobTemplates();
|
||||||
const TeamsAPI = new Teams();
|
const TeamsAPI = new Teams();
|
||||||
const TokensAPI = new Tokens();
|
const TokensAPI = new Tokens();
|
||||||
const UnifiedJobTemplatesAPI = new UnifiedJobTemplates();
|
const UnifiedJobTemplatesAPI = new UnifiedJobTemplates();
|
||||||
@@ -114,6 +116,7 @@ export {
|
|||||||
SchedulesAPI,
|
SchedulesAPI,
|
||||||
SettingsAPI,
|
SettingsAPI,
|
||||||
SystemJobsAPI,
|
SystemJobsAPI,
|
||||||
|
SystemJobTemplatesAPI,
|
||||||
TeamsAPI,
|
TeamsAPI,
|
||||||
TokensAPI,
|
TokensAPI,
|
||||||
UnifiedJobTemplatesAPI,
|
UnifiedJobTemplatesAPI,
|
||||||
|
|||||||
14
awx/ui_next/src/api/models/SystemJobTemplates.js
Normal file
14
awx/ui_next/src/api/models/SystemJobTemplates.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import Base from '../Base';
|
||||||
|
|
||||||
|
class SystemJobTemplates extends Base {
|
||||||
|
constructor(http) {
|
||||||
|
super(http);
|
||||||
|
this.baseUrl = '/api/v2/system_job_templates/';
|
||||||
|
}
|
||||||
|
|
||||||
|
readDetail(id) {
|
||||||
|
return this.http.get(`${this.baseUrl}${id}/`).then(({ data }) => data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SystemJobTemplates;
|
||||||
147
awx/ui_next/src/screens/ManagementJob/ManagementJob.jsx
Normal file
147
awx/ui_next/src/screens/ManagementJob/ManagementJob.jsx
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import React, { useEffect, useCallback } from 'react';
|
||||||
|
import {
|
||||||
|
Link,
|
||||||
|
Redirect,
|
||||||
|
Route,
|
||||||
|
Switch,
|
||||||
|
useLocation,
|
||||||
|
useParams,
|
||||||
|
} from 'react-router-dom';
|
||||||
|
import { withI18n } from '@lingui/react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import { CaretLeftIcon } from '@patternfly/react-icons';
|
||||||
|
import { Card, PageSection } from '@patternfly/react-core';
|
||||||
|
import { useRouteMatch } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { SystemJobTemplatesAPI } from '../../api';
|
||||||
|
|
||||||
|
import ContentError from '../../components/ContentError';
|
||||||
|
import ContentLoading from '../../components/ContentLoading';
|
||||||
|
import RoutedTabs from '../../components/RoutedTabs';
|
||||||
|
import { useConfig } from '../../contexts/Config';
|
||||||
|
import useRequest from '../../util/useRequest';
|
||||||
|
|
||||||
|
import ManagementJobDetails from './ManagementJobDetails';
|
||||||
|
import ManagementJobEdit from './ManagementJobEdit';
|
||||||
|
import ManagementJobNotifications from './ManagementJobNotifications';
|
||||||
|
import ManagementJobSchedules from './ManagementJobSchedules';
|
||||||
|
|
||||||
|
function ManagementJob({ i18n, setBreadcrumb }) {
|
||||||
|
const segment = '/management_jobs';
|
||||||
|
|
||||||
|
const match = useRouteMatch();
|
||||||
|
const { id } = useParams();
|
||||||
|
const { pathname } = useLocation();
|
||||||
|
const { me, isNotificationAdmin } = useConfig();
|
||||||
|
|
||||||
|
const { isLoading, error, request, result } = useRequest(
|
||||||
|
useCallback(async () => SystemJobTemplatesAPI.readDetail(id), [id])
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
request();
|
||||||
|
}, [request, pathname]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!result) return;
|
||||||
|
|
||||||
|
setBreadcrumb(result);
|
||||||
|
}, [result, setBreadcrumb]);
|
||||||
|
|
||||||
|
const tabsArray = [
|
||||||
|
{
|
||||||
|
id: 99,
|
||||||
|
link: segment,
|
||||||
|
name: (
|
||||||
|
<>
|
||||||
|
<CaretLeftIcon />
|
||||||
|
{i18n._(t`Back to management jobs`)}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
link: `${segment}/${id}/details`,
|
||||||
|
name: i18n._(t`Details`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: i18n._(t`Schedules`),
|
||||||
|
link: `${match.url}/schedules`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (me?.is_system_auditor || isNotificationAdmin) {
|
||||||
|
tabsArray.push({
|
||||||
|
id: 2,
|
||||||
|
name: i18n._(t`Notifications`),
|
||||||
|
link: `${match.url}/notifications`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const LoadingScreen = (
|
||||||
|
<PageSection>
|
||||||
|
<Card>
|
||||||
|
{pathname.endsWith('edit') ? null : (
|
||||||
|
<RoutedTabs tabsArray={tabsArray} />
|
||||||
|
)}
|
||||||
|
<ContentLoading />
|
||||||
|
</Card>
|
||||||
|
</PageSection>
|
||||||
|
);
|
||||||
|
|
||||||
|
const ErrorScreen = (
|
||||||
|
<PageSection>
|
||||||
|
<Card>
|
||||||
|
<ContentError error={error}>
|
||||||
|
{error?.response?.status === 404 && (
|
||||||
|
<span>
|
||||||
|
{i18n._(t`Management job not found.`)}
|
||||||
|
{''}
|
||||||
|
<Link to={segment}>{i18n._(t`View all management jobs`)}</Link>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</ContentError>
|
||||||
|
</Card>
|
||||||
|
</PageSection>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return ErrorScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return LoadingScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageSection>
|
||||||
|
<Card>
|
||||||
|
{pathname.endsWith('edit') ? null : (
|
||||||
|
<RoutedTabs tabsArray={tabsArray} />
|
||||||
|
)}
|
||||||
|
<Switch>
|
||||||
|
<Redirect
|
||||||
|
exact
|
||||||
|
from={`${segment}/:id`}
|
||||||
|
to={`${segment}/:id/details`}
|
||||||
|
/>
|
||||||
|
<Route path={`${segment}/:id/details`}>
|
||||||
|
<ManagementJobDetails managementJob={result} />
|
||||||
|
</Route>
|
||||||
|
<Route path={`${segment}/:id/edit`}>
|
||||||
|
<ManagementJobEdit managementJob={result} />
|
||||||
|
</Route>
|
||||||
|
<Route path={`${segment}/:id/notifications`}>
|
||||||
|
<ManagementJobNotifications managementJob={result} />
|
||||||
|
</Route>
|
||||||
|
<Route path={`${segment}/:id/schedules`}>
|
||||||
|
<ManagementJobSchedules managementJob={result} />
|
||||||
|
</Route>
|
||||||
|
</Switch>
|
||||||
|
</Card>
|
||||||
|
</PageSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withI18n()(ManagementJob);
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { withI18n } from '@lingui/react';
|
||||||
|
|
||||||
|
import { CardBody } from '../../../components/Card';
|
||||||
|
|
||||||
|
function ManagementJobDetails() {
|
||||||
|
return <CardBody>Management Job Details</CardBody>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withI18n()(ManagementJobDetails);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from './ManagementJobDetails';
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { CardBody } from '../../../components/Card';
|
||||||
|
|
||||||
|
function ManagementJobEdit() {
|
||||||
|
return <CardBody>Management Job Edit</CardBody>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ManagementJobEdit;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from './ManagementJobEdit';
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { withI18n } from '@lingui/react';
|
||||||
|
import { Card, PageSection } from '@patternfly/react-core';
|
||||||
|
|
||||||
|
function ManagementJobDetails() {
|
||||||
|
return (
|
||||||
|
<PageSection>
|
||||||
|
<Card>Management Job List </Card>
|
||||||
|
</PageSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withI18n()(ManagementJobDetails);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from './ManagementJobList';
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { CardBody } from '../../../components/Card';
|
||||||
|
|
||||||
|
function ManagementJobNotifications({ managementJob }) {
|
||||||
|
return <CardBody>Management Job Notifications</CardBody>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ManagementJobNotifications;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from './ManagementJobNotifications';
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { CardBody } from '../../../components/Card';
|
||||||
|
import { Schedules } from '../../../components/Schedule';
|
||||||
|
|
||||||
|
function ManagementJobSchedules({ managementJob }) {
|
||||||
|
return <CardBody>Management Job Schedules</CardBody>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ManagementJobSchedules;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from './ManagementJobSchedules';
|
||||||
@@ -1,17 +1,51 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { useState, useCallback } from 'react';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
import { Route, Switch } from 'react-router-dom';
|
||||||
|
|
||||||
import ScreenHeader from '../../components/ScreenHeader';
|
import ScreenHeader from '../../components/ScreenHeader';
|
||||||
|
import ManagementJob from './ManagementJob';
|
||||||
|
import ManagementJobList from './ManagementJobList';
|
||||||
|
|
||||||
function ManagementJobs({ i18n }) {
|
function ManagementJobs({ i18n }) {
|
||||||
|
const basePath = '/management_jobs';
|
||||||
|
|
||||||
|
const [breadcrumbConfig, setBreadcrumbConfig] = useState({
|
||||||
|
[basePath]: i18n._(t`Management jobs`),
|
||||||
|
});
|
||||||
|
|
||||||
|
const buildBreadcrumbConfig = useCallback(
|
||||||
|
({ id, name }, nested) => {
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
setBreadcrumbConfig({
|
||||||
|
[basePath]: i18n._(t`Management job`),
|
||||||
|
[`${basePath}/${id}`]: name,
|
||||||
|
[`${basePath}/${id}/details`]: i18n._(t`Details`),
|
||||||
|
[`${basePath}/${id}/edit`]: i18n._(t`Edit details`),
|
||||||
|
[`${basePath}/${id}/notifications`]: i18n._(t`Notifications`),
|
||||||
|
[`${basePath}/schedules`]: i18n._(t`Schedules`),
|
||||||
|
[`${basePath}/schedules/add`]: i18n._(t`Create New Schedule`),
|
||||||
|
[`${basePath}/schedules/${nested?.id}`]: `${nested?.name}`,
|
||||||
|
[`${basePath}/schedules/${nested?.id}/details`]: i18n._(t`Details`),
|
||||||
|
[`${basePath}/schedules/${nested?.id}/edit`]: i18n._(t`Edit Details`),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[i18n]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<>
|
||||||
<ScreenHeader
|
<ScreenHeader streamType="none" breadcrumbConfig={breadcrumbConfig} />
|
||||||
streamType="none"
|
<Switch>
|
||||||
breadcrumbConfig={{ '/management_jobs': i18n._(t`Management Jobs`) }}
|
<Route path={`${basePath}/:id`}>
|
||||||
/>
|
<ManagementJob setBreadcrumb={buildBreadcrumbConfig} />
|
||||||
</Fragment>
|
</Route>
|
||||||
|
<Route path={basePath}>
|
||||||
|
<ManagementJobList setBreadcrumb={buildBreadcrumbConfig} />
|
||||||
|
</Route>
|
||||||
|
</Switch>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,17 +10,20 @@ jest.mock('react-router-dom', () => ({
|
|||||||
|
|
||||||
describe('<ManagementJobs />', () => {
|
describe('<ManagementJobs />', () => {
|
||||||
let pageWrapper;
|
let pageWrapper;
|
||||||
|
let pageSections;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
pageWrapper = mountWithContexts(<ManagementJobs />);
|
pageWrapper = mountWithContexts(<ManagementJobs />);
|
||||||
|
pageSections = pageWrapper.find('PageSection');
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
pageWrapper.unmount();
|
pageWrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('initially renders without crashing', () => {
|
test('renders ok', () => {
|
||||||
expect(pageWrapper.length).toBe(1);
|
expect(pageWrapper.length).toBe(1);
|
||||||
expect(pageWrapper.find('ScreenHeader').length).toBe(1);
|
expect(pageWrapper.find('ScreenHeader').length).toBe(1);
|
||||||
|
expect(pageSections.length).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user