mirror of
https://github.com/ansible/awx.git
synced 2026-03-20 10:27:34 -02:30
Merge pull request #8526 from mabashian/convert-WorkflowJobTemplatejsx-functional
Convert WorkflowJobTemplate.jsx to functional component Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
@@ -1,317 +1,265 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { useEffect, useCallback } from 'react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { CaretLeftIcon } from '@patternfly/react-icons';
|
import { CaretLeftIcon } from '@patternfly/react-icons';
|
||||||
import { Card, PageSection } from '@patternfly/react-core';
|
import { Card, PageSection } from '@patternfly/react-core';
|
||||||
import { Switch, Route, Redirect, withRouter, Link } from 'react-router-dom';
|
import {
|
||||||
|
Switch,
|
||||||
|
Route,
|
||||||
|
Redirect,
|
||||||
|
Link,
|
||||||
|
useLocation,
|
||||||
|
useParams,
|
||||||
|
useRouteMatch,
|
||||||
|
} from 'react-router-dom';
|
||||||
|
import RoutedTabs from '../../components/RoutedTabs';
|
||||||
|
import useRequest from '../../util/useRequest';
|
||||||
import AppendBody from '../../components/AppendBody';
|
import AppendBody from '../../components/AppendBody';
|
||||||
import ContentError from '../../components/ContentError';
|
import ContentError from '../../components/ContentError';
|
||||||
import FullPage from '../../components/FullPage';
|
import FullPage from '../../components/FullPage';
|
||||||
import JobList from '../../components/JobList';
|
import JobList from '../../components/JobList';
|
||||||
import RoutedTabs from '../../components/RoutedTabs';
|
|
||||||
import { Schedules } from '../../components/Schedule';
|
|
||||||
import ContentLoading from '../../components/ContentLoading';
|
|
||||||
import { ResourceAccessList } from '../../components/ResourceAccessList';
|
|
||||||
import NotificationList from '../../components/NotificationList';
|
import NotificationList from '../../components/NotificationList';
|
||||||
import {
|
import { Schedules } from '../../components/Schedule';
|
||||||
WorkflowJobTemplatesAPI,
|
import { ResourceAccessList } from '../../components/ResourceAccessList';
|
||||||
CredentialsAPI,
|
|
||||||
OrganizationsAPI,
|
|
||||||
} from '../../api';
|
|
||||||
import WorkflowJobTemplateDetail from './WorkflowJobTemplateDetail';
|
import WorkflowJobTemplateDetail from './WorkflowJobTemplateDetail';
|
||||||
import WorkflowJobTemplateEdit from './WorkflowJobTemplateEdit';
|
import WorkflowJobTemplateEdit from './WorkflowJobTemplateEdit';
|
||||||
import { Visualizer } from './WorkflowJobTemplateVisualizer';
|
import { WorkflowJobTemplatesAPI, OrganizationsAPI } from '../../api';
|
||||||
import TemplateSurvey from './TemplateSurvey';
|
import TemplateSurvey from './TemplateSurvey';
|
||||||
|
import { Visualizer } from './WorkflowJobTemplateVisualizer';
|
||||||
|
|
||||||
class WorkflowJobTemplate extends Component {
|
function WorkflowJobTemplate({ i18n, me, setBreadcrumb }) {
|
||||||
constructor(props) {
|
const location = useLocation();
|
||||||
super(props);
|
const { id: templateId } = useParams();
|
||||||
|
const match = useRouteMatch();
|
||||||
|
|
||||||
this.state = {
|
const {
|
||||||
contentError: null,
|
result: { isNotifAdmin, template },
|
||||||
hasContentLoading: true,
|
isLoading: hasRolesandTemplateLoading,
|
||||||
template: null,
|
error: rolesAndTemplateError,
|
||||||
isNotifAdmin: false,
|
request: loadTemplateAndRoles,
|
||||||
};
|
} = useRequest(
|
||||||
this.createSchedule = this.createSchedule.bind(this);
|
useCallback(async () => {
|
||||||
this.loadTemplate = this.loadTemplate.bind(this);
|
const [{ data }, actions, notifAdminRes] = await Promise.all([
|
||||||
this.loadSchedules = this.loadSchedules.bind(this);
|
WorkflowJobTemplatesAPI.readDetail(templateId),
|
||||||
this.loadScheduleOptions = this.loadScheduleOptions.bind(this);
|
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions(templateId),
|
||||||
}
|
OrganizationsAPI.read({
|
||||||
|
page_size: 1,
|
||||||
async componentDidMount() {
|
role_level: 'notification_admin_role',
|
||||||
await this.loadTemplate();
|
}),
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate(prevProps) {
|
|
||||||
const { location } = this.props;
|
|
||||||
if (location !== prevProps.location) {
|
|
||||||
await this.loadTemplate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadTemplate() {
|
|
||||||
const { setBreadcrumb, match } = this.props;
|
|
||||||
const { id } = match.params;
|
|
||||||
|
|
||||||
this.setState({ contentError: null });
|
|
||||||
try {
|
|
||||||
const [
|
|
||||||
{ data },
|
|
||||||
{
|
|
||||||
data: { actions },
|
|
||||||
},
|
|
||||||
] = await Promise.all([
|
|
||||||
WorkflowJobTemplatesAPI.readDetail(id),
|
|
||||||
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions(id),
|
|
||||||
]);
|
]);
|
||||||
let webhookKey;
|
|
||||||
if (actions.PUT) {
|
if (actions.data.actions.PUT) {
|
||||||
if (data?.webhook_service && data?.related?.webhook_key) {
|
if (data.webhook_service && data?.related?.webhook_key) {
|
||||||
webhookKey = await WorkflowJobTemplatesAPI.readWebhookKey(id);
|
const {
|
||||||
|
data: { webhook_key },
|
||||||
|
} = await WorkflowJobTemplatesAPI.readWebhookKey(templateId);
|
||||||
|
|
||||||
|
data.webhook_key = webhook_key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data?.summary_fields?.webhook_credential) {
|
|
||||||
const {
|
|
||||||
data: {
|
|
||||||
summary_fields: {
|
|
||||||
credential_type: { name },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} = await CredentialsAPI.readDetail(
|
|
||||||
data.summary_fields.webhook_credential.id
|
|
||||||
);
|
|
||||||
data.summary_fields.webhook_credential.kind = name;
|
|
||||||
}
|
|
||||||
const notifAdminRes = await OrganizationsAPI.read({
|
|
||||||
page_size: 1,
|
|
||||||
role_level: 'notification_admin_role',
|
|
||||||
});
|
|
||||||
setBreadcrumb(data);
|
setBreadcrumb(data);
|
||||||
this.setState({
|
|
||||||
template: { ...data, webhook_key: webhookKey?.data.webhook_key },
|
return {
|
||||||
|
template: data,
|
||||||
isNotifAdmin: notifAdminRes.data.results.length > 0,
|
isNotifAdmin: notifAdminRes.data.results.length > 0,
|
||||||
});
|
};
|
||||||
} catch (err) {
|
}, [setBreadcrumb, templateId]),
|
||||||
this.setState({ contentError: err });
|
{ isNotifAdmin: false, template: null }
|
||||||
} finally {
|
);
|
||||||
this.setState({ hasContentLoading: false });
|
useEffect(() => {
|
||||||
}
|
loadTemplateAndRoles();
|
||||||
}
|
}, [loadTemplateAndRoles, location.pathname]);
|
||||||
|
|
||||||
createSchedule(data) {
|
const createSchedule = data => {
|
||||||
const { template } = this.state;
|
return WorkflowJobTemplatesAPI.createSchedule(templateId, data);
|
||||||
return WorkflowJobTemplatesAPI.createSchedule(template.id, data);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
loadScheduleOptions() {
|
const loadScheduleOptions = () => {
|
||||||
const { template } = this.state;
|
return WorkflowJobTemplatesAPI.readScheduleOptions(templateId);
|
||||||
return WorkflowJobTemplatesAPI.readScheduleOptions(template.id);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
loadSchedules(params) {
|
const loadSchedules = params => {
|
||||||
const { template } = this.state;
|
return WorkflowJobTemplatesAPI.readSchedules(templateId, params);
|
||||||
return WorkflowJobTemplatesAPI.readSchedules(template.id, params);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
const canSeeNotificationsTab = me.is_system_auditor || isNotifAdmin;
|
||||||
const { i18n, me, location, match, setBreadcrumb } = this.props;
|
const canAddAndEditSurvey =
|
||||||
const {
|
template?.summary_fields?.user_capabilities.edit ||
|
||||||
contentError,
|
template?.summary_fields?.user_capabilities.delete;
|
||||||
hasContentLoading,
|
|
||||||
template,
|
|
||||||
isNotifAdmin,
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const canSeeNotificationsTab = me.is_system_auditor || isNotifAdmin;
|
const tabsArray = [
|
||||||
const canToggleNotifications = isNotifAdmin;
|
{
|
||||||
const canAddAndEditSurvey =
|
name: (
|
||||||
template?.summary_fields?.user_capabilities.edit ||
|
<>
|
||||||
template?.summary_fields?.user_capabilities.delete;
|
<CaretLeftIcon />
|
||||||
|
{i18n._(t`Back to Templates`)}
|
||||||
const tabsArray = [
|
</>
|
||||||
{
|
),
|
||||||
name: (
|
link: `/templates`,
|
||||||
<>
|
id: 99,
|
||||||
<CaretLeftIcon />
|
},
|
||||||
{i18n._(t`Back to Templates`)}
|
{ name: i18n._(t`Details`), link: `${match.url}/details` },
|
||||||
</>
|
{ name: i18n._(t`Access`), link: `${match.url}/access` },
|
||||||
),
|
];
|
||||||
link: `/templates`,
|
|
||||||
id: 99,
|
|
||||||
},
|
|
||||||
{ name: i18n._(t`Details`), link: `${match.url}/details` },
|
|
||||||
{ name: i18n._(t`Access`), link: `${match.url}/access` },
|
|
||||||
];
|
|
||||||
|
|
||||||
if (canSeeNotificationsTab) {
|
|
||||||
tabsArray.push({
|
|
||||||
name: i18n._(t`Notifications`),
|
|
||||||
link: `${match.url}/notifications`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (template) {
|
|
||||||
tabsArray.push({
|
|
||||||
name: i18n._(t`Schedules`),
|
|
||||||
link: `${match.url}/schedules`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (canSeeNotificationsTab) {
|
||||||
tabsArray.push({
|
tabsArray.push({
|
||||||
|
name: i18n._(t`Notifications`),
|
||||||
|
link: `${match.url}/notifications`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (template) {
|
||||||
|
tabsArray.push({
|
||||||
|
name: i18n._(t`Schedules`),
|
||||||
|
link: `${match.url}/schedules`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tabsArray.push(
|
||||||
|
{
|
||||||
name: i18n._(t`Visualizer`),
|
name: i18n._(t`Visualizer`),
|
||||||
link: `${match.url}/visualizer`,
|
link: `${match.url}/visualizer`,
|
||||||
});
|
},
|
||||||
tabsArray.push({
|
{
|
||||||
name: i18n._(t`Completed Jobs`),
|
name: i18n._(t`Completed Jobs`),
|
||||||
link: `${match.url}/completed_jobs`,
|
link: `${match.url}/completed_jobs`,
|
||||||
});
|
},
|
||||||
tabsArray.push({
|
{
|
||||||
name: canAddAndEditSurvey ? i18n._(t`Survey`) : i18n._(t`View Survey`),
|
name: canAddAndEditSurvey ? i18n._(t`Survey`) : i18n._(t`View Survey`),
|
||||||
link: `${match.url}/survey`,
|
link: `${match.url}/survey`,
|
||||||
});
|
|
||||||
|
|
||||||
tabsArray.forEach((tab, n) => {
|
|
||||||
tab.id = n;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (hasContentLoading) {
|
|
||||||
return (
|
|
||||||
<PageSection>
|
|
||||||
<Card>
|
|
||||||
<ContentLoading />
|
|
||||||
</Card>
|
|
||||||
</PageSection>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (contentError) {
|
tabsArray.forEach((tab, n) => {
|
||||||
return (
|
tab.id = n;
|
||||||
<PageSection>
|
});
|
||||||
<Card>
|
|
||||||
<ContentError error={contentError}>
|
|
||||||
{contentError.response.status === 404 && (
|
|
||||||
<span>
|
|
||||||
{i18n._(t`Template not found.`)}{' '}
|
|
||||||
<Link to="/templates">{i18n._(t`View all Templates.`)}</Link>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</ContentError>
|
|
||||||
</Card>
|
|
||||||
</PageSection>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let showCardHeader = true;
|
let showCardHeader = true;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
location.pathname.endsWith('edit') ||
|
location.pathname.endsWith('edit') ||
|
||||||
location.pathname.includes('schedules/')
|
location.pathname.includes('schedules/')
|
||||||
) {
|
) {
|
||||||
showCardHeader = false;
|
showCardHeader = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const contentError = rolesAndTemplateError;
|
||||||
|
if (!hasRolesandTemplateLoading && contentError) {
|
||||||
return (
|
return (
|
||||||
<PageSection>
|
<PageSection>
|
||||||
<Card>
|
<Card>
|
||||||
{showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
|
<ContentError error={contentError}>
|
||||||
<Switch>
|
{contentError.response.status === 404 && (
|
||||||
<Redirect
|
<span>
|
||||||
from="/templates/workflow_job_template/:id"
|
{i18n._(t`Template not found.`)}{' '}
|
||||||
to="/templates/workflow_job_template/:id/details"
|
<Link to="/templates">{i18n._(t`View all Templates.`)}</Link>
|
||||||
exact
|
</span>
|
||||||
/>
|
|
||||||
{template && (
|
|
||||||
<Route
|
|
||||||
key="wfjt-details"
|
|
||||||
path="/templates/workflow_job_template/:id/details"
|
|
||||||
>
|
|
||||||
<WorkflowJobTemplateDetail template={template} />
|
|
||||||
</Route>
|
|
||||||
)}
|
|
||||||
{template && (
|
|
||||||
<Route path="/templates/workflow_job_template/:id/access">
|
|
||||||
<ResourceAccessList
|
|
||||||
resource={template}
|
|
||||||
apiModel={WorkflowJobTemplatesAPI}
|
|
||||||
/>
|
|
||||||
</Route>
|
|
||||||
)}
|
|
||||||
{canSeeNotificationsTab && (
|
|
||||||
<Route path="/templates/workflow_job_template/:id/notifications">
|
|
||||||
<NotificationList
|
|
||||||
id={Number(match.params.id)}
|
|
||||||
canToggleNotifications={canToggleNotifications}
|
|
||||||
apiModel={WorkflowJobTemplatesAPI}
|
|
||||||
showApprovalsToggle
|
|
||||||
/>
|
|
||||||
</Route>
|
|
||||||
)}
|
|
||||||
{template && (
|
|
||||||
<Route
|
|
||||||
key="wfjt-edit"
|
|
||||||
path="/templates/workflow_job_template/:id/edit"
|
|
||||||
>
|
|
||||||
<WorkflowJobTemplateEdit template={template} />
|
|
||||||
</Route>
|
|
||||||
)}
|
|
||||||
{template && (
|
|
||||||
<Route
|
|
||||||
key="wfjt-visualizer"
|
|
||||||
path="/templates/workflow_job_template/:id/visualizer"
|
|
||||||
>
|
|
||||||
<AppendBody>
|
|
||||||
<FullPage>
|
|
||||||
<Visualizer template={template} />
|
|
||||||
</FullPage>
|
|
||||||
</AppendBody>
|
|
||||||
</Route>
|
|
||||||
)}
|
|
||||||
{template?.id && (
|
|
||||||
<Route path="/templates/workflow_job_template/:id/completed_jobs">
|
|
||||||
<JobList
|
|
||||||
defaultParams={{
|
|
||||||
workflow_job__workflow_job_template: template.id,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Route>
|
|
||||||
)}
|
|
||||||
{template?.id && (
|
|
||||||
<Route path="/templates/workflow_job_template/:id/schedules">
|
|
||||||
<Schedules
|
|
||||||
setBreadcrumb={setBreadcrumb}
|
|
||||||
unifiedJobTemplate={template}
|
|
||||||
createSchedule={this.createSchedule}
|
|
||||||
loadSchedules={this.loadSchedules}
|
|
||||||
loadScheduleOptions={this.loadScheduleOptions}
|
|
||||||
/>
|
|
||||||
</Route>
|
|
||||||
)}
|
|
||||||
{template && (
|
|
||||||
<Route path="/templates/:templateType/:id/survey">
|
|
||||||
<TemplateSurvey
|
|
||||||
template={template}
|
|
||||||
canEdit={canAddAndEditSurvey}
|
|
||||||
/>
|
|
||||||
</Route>
|
|
||||||
)}
|
)}
|
||||||
|
</ContentError>
|
||||||
|
</Card>
|
||||||
|
</PageSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageSection>
|
||||||
|
<Card>
|
||||||
|
{showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
|
||||||
|
<Switch>
|
||||||
|
<Redirect
|
||||||
|
from="/templates/:templateType/:id"
|
||||||
|
to="/templates/:templateType/:id/details"
|
||||||
|
exact
|
||||||
|
/>
|
||||||
|
{template && (
|
||||||
|
<Route key="details" path="/templates/:templateType/:id/details">
|
||||||
|
<WorkflowJobTemplateDetail template={template} />
|
||||||
|
</Route>
|
||||||
|
)}
|
||||||
|
{template && (
|
||||||
|
<Route key="edit" path="/templates/:templateType/:id/edit">
|
||||||
|
<WorkflowJobTemplateEdit template={template} />
|
||||||
|
</Route>
|
||||||
|
)}
|
||||||
|
{template && (
|
||||||
|
<Route key="access" path="/templates/:templateType/:id/access">
|
||||||
|
<ResourceAccessList
|
||||||
|
resource={template}
|
||||||
|
apiModel={WorkflowJobTemplatesAPI}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
)}
|
||||||
|
{template && (
|
||||||
|
<Route
|
||||||
|
key="schedules"
|
||||||
|
path="/templates/:templateType/:id/schedules"
|
||||||
|
>
|
||||||
|
<Schedules
|
||||||
|
createSchedule={createSchedule}
|
||||||
|
setBreadcrumb={setBreadcrumb}
|
||||||
|
unifiedJobTemplate={template}
|
||||||
|
loadSchedules={loadSchedules}
|
||||||
|
loadScheduleOptions={loadScheduleOptions}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
)}
|
||||||
|
{canSeeNotificationsTab && (
|
||||||
|
<Route path="/templates/:templateType/:id/notifications">
|
||||||
|
<NotificationList
|
||||||
|
id={Number(templateId)}
|
||||||
|
canToggleNotifications={isNotifAdmin}
|
||||||
|
apiModel={WorkflowJobTemplatesAPI}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
)}
|
||||||
|
{template && (
|
||||||
|
<Route
|
||||||
|
key="wfjt-visualizer"
|
||||||
|
path="/templates/workflow_job_template/:id/visualizer"
|
||||||
|
>
|
||||||
|
<AppendBody>
|
||||||
|
<FullPage>
|
||||||
|
<Visualizer template={template} />
|
||||||
|
</FullPage>
|
||||||
|
</AppendBody>
|
||||||
|
</Route>
|
||||||
|
)}
|
||||||
|
{template?.id && (
|
||||||
|
<Route path="/templates/:templateType/:id/completed_jobs">
|
||||||
|
<JobList
|
||||||
|
defaultParams={{
|
||||||
|
workflow_job__workflow_job_template: template.id,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
)}
|
||||||
|
{template && (
|
||||||
|
<Route path="/templates/:templateType/:id/survey">
|
||||||
|
<TemplateSurvey
|
||||||
|
template={template}
|
||||||
|
canEdit={canAddAndEditSurvey}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
)}
|
||||||
|
{!hasRolesandTemplateLoading && (
|
||||||
<Route key="not-found" path="*">
|
<Route key="not-found" path="*">
|
||||||
<ContentError isNotFound>
|
<ContentError isNotFound>
|
||||||
{match.params.id && (
|
{match.params.id && (
|
||||||
<Link
|
<Link
|
||||||
to={`/templates/workflow_job_template/${match.params.id}/details`}
|
to={`/templates/${match.params.templateType}/${match.params.id}/details`}
|
||||||
>
|
>
|
||||||
{i18n._(t`View Template Details`)}
|
{i18n._(t`View Template Details`)}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</ContentError>
|
</ContentError>
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
)}
|
||||||
</Card>
|
</Switch>
|
||||||
</PageSection>
|
</Card>
|
||||||
);
|
</PageSection>
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { WorkflowJobTemplate as _WorkflowJobTemplate };
|
export { WorkflowJobTemplate as _WorkflowJobTemplate };
|
||||||
export default withI18n()(withRouter(WorkflowJobTemplate));
|
export default withI18n()(WorkflowJobTemplate);
|
||||||
|
|||||||
@@ -1,192 +1,196 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Route } from 'react-router-dom';
|
|
||||||
import { createMemoryHistory } from 'history';
|
import { createMemoryHistory } from 'history';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
|
import { WorkflowJobTemplatesAPI, OrganizationsAPI } from '../../api';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
mountWithContexts,
|
mountWithContexts,
|
||||||
waitForElement,
|
waitForElement,
|
||||||
} from '../../../testUtils/enzymeHelpers';
|
} from '../../../testUtils/enzymeHelpers';
|
||||||
import WorkflowJobTemplate from './WorkflowJobTemplate';
|
import WorkflowJobTemplate from './WorkflowJobTemplate';
|
||||||
import { sleep } from '../../../testUtils/testUtils';
|
import mockWorkflowJobTemplateData from './shared/data.workflow_job_template.json';
|
||||||
import {
|
|
||||||
WorkflowJobTemplatesAPI,
|
|
||||||
CredentialsAPI,
|
|
||||||
OrganizationsAPI,
|
|
||||||
} from '../../api';
|
|
||||||
|
|
||||||
jest.mock('../../api/models/WorkflowJobTemplates');
|
jest.mock('../../api/models/WorkflowJobTemplates');
|
||||||
jest.mock('../../api/models/Credentials');
|
|
||||||
jest.mock('../../api/models/Organizations');
|
jest.mock('../../api/models/Organizations');
|
||||||
|
|
||||||
describe('<WorkflowJobTemplate/>', () => {
|
const mockMe = {
|
||||||
const mockMe = {
|
is_super_user: true,
|
||||||
is_super_user: true,
|
is_system_auditor: false,
|
||||||
is_system_auditor: false,
|
};
|
||||||
};
|
describe('<WorkflowJobTemplate />', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
let history;
|
beforeEach(() => {
|
||||||
beforeAll(() => {
|
|
||||||
WorkflowJobTemplatesAPI.readDetail.mockResolvedValue({
|
WorkflowJobTemplatesAPI.readDetail.mockResolvedValue({
|
||||||
data: {
|
data: mockWorkflowJobTemplateData,
|
||||||
id: 1,
|
|
||||||
name: 'Foo',
|
|
||||||
description: 'Bar',
|
|
||||||
created: '2015-07-07T17:21:26.429745Z',
|
|
||||||
modified: '2019-08-11T19:47:37.980466Z',
|
|
||||||
extra_vars: '',
|
|
||||||
webhook_service: 'github',
|
|
||||||
summary_fields: {
|
|
||||||
webhook_credential: { id: 1234567, name: 'Foo Webhook Credential' },
|
|
||||||
created_by: { id: 1, username: 'Athena' },
|
|
||||||
modified_by: { id: 1, username: 'Apollo' },
|
|
||||||
recent_jobs: [
|
|
||||||
{ id: 1, status: 'run' },
|
|
||||||
{ id: 2, status: 'run' },
|
|
||||||
{ id: 3, status: 'run' },
|
|
||||||
],
|
|
||||||
labels: {
|
|
||||||
results: [
|
|
||||||
{ name: 'Label 1', id: 1 },
|
|
||||||
{ name: 'Label 2', id: 2 },
|
|
||||||
{ name: 'Label 3', id: 3 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
user_capabilities: {},
|
|
||||||
},
|
|
||||||
related: {
|
|
||||||
webhook_key: '/api/v2/workflow_job_templates/57/webhook_key/',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions.mockResolvedValue({
|
||||||
WorkflowJobTemplatesAPI.readWebhookKey.mockResolvedValue({
|
|
||||||
data: { webhook_key: 'WebHook Key' },
|
|
||||||
});
|
|
||||||
CredentialsAPI.readDetail.mockResolvedValue({
|
|
||||||
data: {
|
data: {
|
||||||
summary_fields: {
|
actions: { PUT: true },
|
||||||
credential_type: { name: 'Github Personal Access Token', id: 1 },
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
OrganizationsAPI.read.mockResolvedValue({
|
OrganizationsAPI.read.mockResolvedValue({
|
||||||
data: { results: [{ id: 1, name: 'Org Foo' }] },
|
data: {
|
||||||
|
count: 1,
|
||||||
|
next: null,
|
||||||
|
previous: null,
|
||||||
|
results: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
WorkflowJobTemplatesAPI.readWebhookKey.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
webhook_key: 'key',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
describe('User can PUT', () => {
|
test('initially renders succesfully', async () => {
|
||||||
beforeEach(async () => {
|
await act(async () => {
|
||||||
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions.mockResolvedValue({
|
wrapper = mountWithContexts(
|
||||||
data: { actions: { PUT: {} } },
|
<WorkflowJobTemplate setBreadcrumb={() => {}} me={mockMe} />
|
||||||
});
|
);
|
||||||
history = createMemoryHistory({
|
|
||||||
initialEntries: ['/templates/workflow_job_template/1/details'],
|
|
||||||
});
|
|
||||||
await act(async () => {
|
|
||||||
wrapper = mountWithContexts(
|
|
||||||
<Route
|
|
||||||
path="/templates/workflow_job_template/:id/details"
|
|
||||||
component={() => (
|
|
||||||
<WorkflowJobTemplate setBreadcrumb={() => {}} me={mockMe} />
|
|
||||||
)}
|
|
||||||
/>,
|
|
||||||
{
|
|
||||||
context: {
|
|
||||||
router: {
|
|
||||||
history,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test('calls api to get workflow job template data', async () => {
|
|
||||||
expect(wrapper.find('WorkflowJobTemplate').length).toBe(1);
|
|
||||||
expect(WorkflowJobTemplatesAPI.readDetail).toBeCalledWith('1');
|
|
||||||
wrapper.update();
|
|
||||||
await sleep(0);
|
|
||||||
expect(WorkflowJobTemplatesAPI.readWebhookKey).toBeCalledWith('1');
|
|
||||||
expect(
|
|
||||||
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions
|
|
||||||
).toBeCalled();
|
|
||||||
|
|
||||||
expect(CredentialsAPI.readDetail).toBeCalledWith(1234567);
|
|
||||||
expect(OrganizationsAPI.read).toBeCalledWith({
|
|
||||||
page_size: 1,
|
|
||||||
role_level: 'notification_admin_role',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('renders proper tabs', async () => {
|
|
||||||
const tabs = [
|
|
||||||
'Details',
|
|
||||||
'Access',
|
|
||||||
'Notifications',
|
|
||||||
'Schedules',
|
|
||||||
'Visualizer',
|
|
||||||
'Completed Jobs',
|
|
||||||
'Survey',
|
|
||||||
];
|
|
||||||
waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
|
|
||||||
wrapper.update();
|
|
||||||
wrapper.find('TabContainer').forEach(tc => {
|
|
||||||
tabs.forEach(t => expect(tc.prop(`aria-label=[${t}]`)));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Does not render Notifications tab', async () => {
|
|
||||||
OrganizationsAPI.read.mockResolvedValue({
|
|
||||||
data: { results: [] },
|
|
||||||
});
|
|
||||||
const tabs = [
|
|
||||||
'Details',
|
|
||||||
'Access',
|
|
||||||
'Schedules',
|
|
||||||
'Visualizer',
|
|
||||||
'Completed Jobs',
|
|
||||||
'Survey',
|
|
||||||
];
|
|
||||||
waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
|
|
||||||
wrapper.update();
|
|
||||||
wrapper.find('TabContainer').forEach(tc => {
|
|
||||||
tabs.forEach(t => expect(tc.prop(`aria-label=[${t}]`)));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('User cannot PUT', () => {
|
test('When component mounts API is called and the response is put in state', async () => {
|
||||||
beforeEach(async () => {
|
await act(async () => {
|
||||||
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions.mockResolvedValueOnce(
|
wrapper = mountWithContexts(
|
||||||
|
<WorkflowJobTemplate setBreadcrumb={() => {}} me={mockMe} />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
expect(WorkflowJobTemplatesAPI.readDetail).toBeCalled();
|
||||||
|
expect(OrganizationsAPI.read).toBeCalled();
|
||||||
|
});
|
||||||
|
test('notifications tab shown for admins', async done => {
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<WorkflowJobTemplate setBreadcrumb={() => {}} me={mockMe} />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const tabs = await waitForElement(
|
||||||
|
wrapper,
|
||||||
|
'.pf-c-tabs__item',
|
||||||
|
el => el.length === 8
|
||||||
|
);
|
||||||
|
expect(tabs.at(3).text()).toEqual('Notifications');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
test('notifications tab hidden with reduced permissions', async done => {
|
||||||
|
OrganizationsAPI.read.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
count: 0,
|
||||||
|
next: null,
|
||||||
|
previous: null,
|
||||||
|
results: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<WorkflowJobTemplate setBreadcrumb={() => {}} me={mockMe} />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const tabs = await waitForElement(
|
||||||
|
wrapper,
|
||||||
|
'.pf-c-tabs__item',
|
||||||
|
el => el.length === 7
|
||||||
|
);
|
||||||
|
tabs.forEach(tab => expect(tab.text()).not.toEqual('Notifications'));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show content error when user attempts to navigate to erroneous route', async () => {
|
||||||
|
const history = createMemoryHistory({
|
||||||
|
initialEntries: ['/templates/workflow_job_template/1/foobar'],
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<WorkflowJobTemplate setBreadcrumb={() => {}} me={mockMe} />,
|
||||||
{
|
{
|
||||||
data: { actions: {} },
|
context: {
|
||||||
|
router: {
|
||||||
|
history,
|
||||||
|
route: {
|
||||||
|
location: history.location,
|
||||||
|
match: {
|
||||||
|
params: { id: 1 },
|
||||||
|
url: '/templates/workflow_job_template/1/foobar',
|
||||||
|
path: '/templates/workflow_job_template/1/foobar',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
history = createMemoryHistory({
|
});
|
||||||
initialEntries: ['/templates/workflow_job_template/1/details'],
|
|
||||||
});
|
await waitForElement(wrapper, 'ContentError', el => el.length === 1);
|
||||||
await act(async () => {
|
});
|
||||||
wrapper = mountWithContexts(
|
test('should call to get webhook key', async () => {
|
||||||
<Route
|
const history = createMemoryHistory({
|
||||||
path="/templates/workflow_job_template/:id/details"
|
initialEntries: ['/templates/workflow_job_template/1/foobar'],
|
||||||
component={() => (
|
});
|
||||||
<WorkflowJobTemplate setBreadcrumb={() => {}} me={mockMe} />
|
await act(async () => {
|
||||||
)}
|
wrapper = mountWithContexts(
|
||||||
/>,
|
<WorkflowJobTemplate setBreadcrumb={() => {}} me={mockMe} />,
|
||||||
{
|
{
|
||||||
context: {
|
context: {
|
||||||
router: {
|
router: {
|
||||||
history,
|
history,
|
||||||
|
route: {
|
||||||
|
location: history.location,
|
||||||
|
match: {
|
||||||
|
params: { id: 1 },
|
||||||
|
url: '/templates/workflow_job_template/1/foobar',
|
||||||
|
path: '/templates/workflow_job_template/1/foobar',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
}
|
||||||
});
|
);
|
||||||
});
|
});
|
||||||
test('should not call for webhook key', async () => {
|
expect(WorkflowJobTemplatesAPI.readWebhookKey).toHaveBeenCalled();
|
||||||
expect(WorkflowJobTemplatesAPI.readWebhookKey).not.toBeCalled();
|
});
|
||||||
|
test('should not call to get webhook key', async () => {
|
||||||
|
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions.mockResolvedValueOnce(
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
actions: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const history = createMemoryHistory({
|
||||||
|
initialEntries: ['/templates/workflow_job_template/1/foobar'],
|
||||||
});
|
});
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<WorkflowJobTemplate setBreadcrumb={() => {}} me={mockMe} />,
|
||||||
|
{
|
||||||
|
context: {
|
||||||
|
router: {
|
||||||
|
history,
|
||||||
|
route: {
|
||||||
|
location: history.location,
|
||||||
|
match: {
|
||||||
|
params: { id: 1 },
|
||||||
|
url: '/templates/workflow_job_template/1/foobar',
|
||||||
|
path: '/templates/workflow_job_template/1/foobar',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
expect(WorkflowJobTemplatesAPI.readWebhookKey).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
{
|
||||||
|
"id": 15,
|
||||||
|
"type": "workflow_job_template",
|
||||||
|
"url": "/api/v2/workflow_job_templates/15/",
|
||||||
|
"related": {
|
||||||
|
"named_url": "/api/v2/workflow_job_templates/A workflow++/",
|
||||||
|
"created_by": "/api/v2/users/1/",
|
||||||
|
"modified_by": "/api/v2/users/1/",
|
||||||
|
"workflow_jobs": "/api/v2/workflow_job_templates/15/workflow_jobs/",
|
||||||
|
"schedules": "/api/v2/workflow_job_templates/15/schedules/",
|
||||||
|
"launch": "/api/v2/workflow_job_templates/15/launch/",
|
||||||
|
"webhook_key": "/api/v2/workflow_job_templates/15/webhook_key/",
|
||||||
|
"webhook_receiver": "/api/v2/workflow_job_templates/15/github/",
|
||||||
|
"workflow_nodes": "/api/v2/workflow_job_templates/15/workflow_nodes/",
|
||||||
|
"labels": "/api/v2/workflow_job_templates/15/labels/",
|
||||||
|
"activity_stream": "/api/v2/workflow_job_templates/15/activity_stream/",
|
||||||
|
"notification_templates_started": "/api/v2/workflow_job_templates/15/notification_templates_started/",
|
||||||
|
"notification_templates_success": "/api/v2/workflow_job_templates/15/notification_templates_success/",
|
||||||
|
"notification_templates_error": "/api/v2/workflow_job_templates/15/notification_templates_error/",
|
||||||
|
"notification_templates_approvals": "/api/v2/workflow_job_templates/15/notification_templates_approvals/",
|
||||||
|
"access_list": "/api/v2/workflow_job_templates/15/access_list/",
|
||||||
|
"object_roles": "/api/v2/workflow_job_templates/15/object_roles/",
|
||||||
|
"survey_spec": "/api/v2/workflow_job_templates/15/survey_spec/",
|
||||||
|
"copy": "/api/v2/workflow_job_templates/15/copy/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"created_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"modified_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"object_roles": {
|
||||||
|
"admin_role": {
|
||||||
|
"description": "Can manage all aspects of the workflow job template",
|
||||||
|
"name": "Admin",
|
||||||
|
"id": 68
|
||||||
|
},
|
||||||
|
"execute_role": {
|
||||||
|
"description": "May run the workflow job template",
|
||||||
|
"name": "Execute",
|
||||||
|
"id": 69
|
||||||
|
},
|
||||||
|
"read_role": {
|
||||||
|
"description": "May view settings for the workflow job template",
|
||||||
|
"name": "Read",
|
||||||
|
"id": 70
|
||||||
|
},
|
||||||
|
"approval_role": {
|
||||||
|
"description": "Can approve or deny a workflow approval node",
|
||||||
|
"name": "Approve",
|
||||||
|
"id": 71
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_capabilities": {
|
||||||
|
"edit": true,
|
||||||
|
"delete": true,
|
||||||
|
"start": true,
|
||||||
|
"schedule": true,
|
||||||
|
"copy": true
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"count": 0,
|
||||||
|
"results": []
|
||||||
|
},
|
||||||
|
"recent_jobs": []
|
||||||
|
},
|
||||||
|
"created": "2020-10-30T14:29:59.728159Z",
|
||||||
|
"modified": "2020-11-03T14:48:50.519450Z",
|
||||||
|
"name": "A workflow",
|
||||||
|
"description": "",
|
||||||
|
"last_job_run": null,
|
||||||
|
"last_job_failed": false,
|
||||||
|
"next_job_run": null,
|
||||||
|
"status": "never updated",
|
||||||
|
"extra_vars": "",
|
||||||
|
"organization": null,
|
||||||
|
"survey_enabled": false,
|
||||||
|
"allow_simultaneous": false,
|
||||||
|
"ask_variables_on_launch": false,
|
||||||
|
"inventory": null,
|
||||||
|
"limit": "",
|
||||||
|
"scm_branch": "",
|
||||||
|
"ask_inventory_on_launch": false,
|
||||||
|
"ask_scm_branch_on_launch": false,
|
||||||
|
"ask_limit_on_launch": false,
|
||||||
|
"webhook_service": "github",
|
||||||
|
"webhook_credential": null
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user