mirror of
https://github.com/ansible/awx.git
synced 2026-01-13 02:50:02 -03: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:
commit
370440f63d
@ -1,317 +1,265 @@
|
||||
import React, { Component } from 'react';
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { CaretLeftIcon } from '@patternfly/react-icons';
|
||||
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 ContentError from '../../components/ContentError';
|
||||
import FullPage from '../../components/FullPage';
|
||||
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 {
|
||||
WorkflowJobTemplatesAPI,
|
||||
CredentialsAPI,
|
||||
OrganizationsAPI,
|
||||
} from '../../api';
|
||||
import { Schedules } from '../../components/Schedule';
|
||||
import { ResourceAccessList } from '../../components/ResourceAccessList';
|
||||
import WorkflowJobTemplateDetail from './WorkflowJobTemplateDetail';
|
||||
import WorkflowJobTemplateEdit from './WorkflowJobTemplateEdit';
|
||||
import { Visualizer } from './WorkflowJobTemplateVisualizer';
|
||||
import { WorkflowJobTemplatesAPI, OrganizationsAPI } from '../../api';
|
||||
import TemplateSurvey from './TemplateSurvey';
|
||||
import { Visualizer } from './WorkflowJobTemplateVisualizer';
|
||||
|
||||
class WorkflowJobTemplate extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
function WorkflowJobTemplate({ i18n, me, setBreadcrumb }) {
|
||||
const location = useLocation();
|
||||
const { id: templateId } = useParams();
|
||||
const match = useRouteMatch();
|
||||
|
||||
this.state = {
|
||||
contentError: null,
|
||||
hasContentLoading: true,
|
||||
template: null,
|
||||
isNotifAdmin: false,
|
||||
};
|
||||
this.createSchedule = this.createSchedule.bind(this);
|
||||
this.loadTemplate = this.loadTemplate.bind(this);
|
||||
this.loadSchedules = this.loadSchedules.bind(this);
|
||||
this.loadScheduleOptions = this.loadScheduleOptions.bind(this);
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
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),
|
||||
const {
|
||||
result: { isNotifAdmin, template },
|
||||
isLoading: hasRolesandTemplateLoading,
|
||||
error: rolesAndTemplateError,
|
||||
request: loadTemplateAndRoles,
|
||||
} = useRequest(
|
||||
useCallback(async () => {
|
||||
const [{ data }, actions, notifAdminRes] = await Promise.all([
|
||||
WorkflowJobTemplatesAPI.readDetail(templateId),
|
||||
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions(templateId),
|
||||
OrganizationsAPI.read({
|
||||
page_size: 1,
|
||||
role_level: 'notification_admin_role',
|
||||
}),
|
||||
]);
|
||||
let webhookKey;
|
||||
if (actions.PUT) {
|
||||
if (data?.webhook_service && data?.related?.webhook_key) {
|
||||
webhookKey = await WorkflowJobTemplatesAPI.readWebhookKey(id);
|
||||
|
||||
if (actions.data.actions.PUT) {
|
||||
if (data.webhook_service && data?.related?.webhook_key) {
|
||||
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);
|
||||
this.setState({
|
||||
template: { ...data, webhook_key: webhookKey?.data.webhook_key },
|
||||
|
||||
return {
|
||||
template: data,
|
||||
isNotifAdmin: notifAdminRes.data.results.length > 0,
|
||||
});
|
||||
} catch (err) {
|
||||
this.setState({ contentError: err });
|
||||
} finally {
|
||||
this.setState({ hasContentLoading: false });
|
||||
}
|
||||
}
|
||||
};
|
||||
}, [setBreadcrumb, templateId]),
|
||||
{ isNotifAdmin: false, template: null }
|
||||
);
|
||||
useEffect(() => {
|
||||
loadTemplateAndRoles();
|
||||
}, [loadTemplateAndRoles, location.pathname]);
|
||||
|
||||
createSchedule(data) {
|
||||
const { template } = this.state;
|
||||
return WorkflowJobTemplatesAPI.createSchedule(template.id, data);
|
||||
}
|
||||
const createSchedule = data => {
|
||||
return WorkflowJobTemplatesAPI.createSchedule(templateId, data);
|
||||
};
|
||||
|
||||
loadScheduleOptions() {
|
||||
const { template } = this.state;
|
||||
return WorkflowJobTemplatesAPI.readScheduleOptions(template.id);
|
||||
}
|
||||
const loadScheduleOptions = () => {
|
||||
return WorkflowJobTemplatesAPI.readScheduleOptions(templateId);
|
||||
};
|
||||
|
||||
loadSchedules(params) {
|
||||
const { template } = this.state;
|
||||
return WorkflowJobTemplatesAPI.readSchedules(template.id, params);
|
||||
}
|
||||
const loadSchedules = params => {
|
||||
return WorkflowJobTemplatesAPI.readSchedules(templateId, params);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { i18n, me, location, match, setBreadcrumb } = this.props;
|
||||
const {
|
||||
contentError,
|
||||
hasContentLoading,
|
||||
template,
|
||||
isNotifAdmin,
|
||||
} = this.state;
|
||||
const canSeeNotificationsTab = me.is_system_auditor || isNotifAdmin;
|
||||
const canAddAndEditSurvey =
|
||||
template?.summary_fields?.user_capabilities.edit ||
|
||||
template?.summary_fields?.user_capabilities.delete;
|
||||
|
||||
const canSeeNotificationsTab = me.is_system_auditor || isNotifAdmin;
|
||||
const canToggleNotifications = isNotifAdmin;
|
||||
const canAddAndEditSurvey =
|
||||
template?.summary_fields?.user_capabilities.edit ||
|
||||
template?.summary_fields?.user_capabilities.delete;
|
||||
|
||||
const tabsArray = [
|
||||
{
|
||||
name: (
|
||||
<>
|
||||
<CaretLeftIcon />
|
||||
{i18n._(t`Back to Templates`)}
|
||||
</>
|
||||
),
|
||||
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`,
|
||||
});
|
||||
}
|
||||
const tabsArray = [
|
||||
{
|
||||
name: (
|
||||
<>
|
||||
<CaretLeftIcon />
|
||||
{i18n._(t`Back to Templates`)}
|
||||
</>
|
||||
),
|
||||
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`,
|
||||
});
|
||||
}
|
||||
|
||||
tabsArray.push(
|
||||
{
|
||||
name: i18n._(t`Visualizer`),
|
||||
link: `${match.url}/visualizer`,
|
||||
});
|
||||
tabsArray.push({
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Completed Jobs`),
|
||||
link: `${match.url}/completed_jobs`,
|
||||
});
|
||||
tabsArray.push({
|
||||
},
|
||||
{
|
||||
name: canAddAndEditSurvey ? i18n._(t`Survey`) : i18n._(t`View Survey`),
|
||||
link: `${match.url}/survey`,
|
||||
});
|
||||
|
||||
tabsArray.forEach((tab, n) => {
|
||||
tab.id = n;
|
||||
});
|
||||
|
||||
if (hasContentLoading) {
|
||||
return (
|
||||
<PageSection>
|
||||
<Card>
|
||||
<ContentLoading />
|
||||
</Card>
|
||||
</PageSection>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
if (contentError) {
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
}
|
||||
tabsArray.forEach((tab, n) => {
|
||||
tab.id = n;
|
||||
});
|
||||
|
||||
let showCardHeader = true;
|
||||
let showCardHeader = true;
|
||||
|
||||
if (
|
||||
location.pathname.endsWith('edit') ||
|
||||
location.pathname.includes('schedules/')
|
||||
) {
|
||||
showCardHeader = false;
|
||||
}
|
||||
if (
|
||||
location.pathname.endsWith('edit') ||
|
||||
location.pathname.includes('schedules/')
|
||||
) {
|
||||
showCardHeader = false;
|
||||
}
|
||||
|
||||
const contentError = rolesAndTemplateError;
|
||||
if (!hasRolesandTemplateLoading && contentError) {
|
||||
return (
|
||||
<PageSection>
|
||||
<Card>
|
||||
{showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
|
||||
<Switch>
|
||||
<Redirect
|
||||
from="/templates/workflow_job_template/:id"
|
||||
to="/templates/workflow_job_template/:id/details"
|
||||
exact
|
||||
/>
|
||||
{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 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>
|
||||
);
|
||||
}
|
||||
|
||||
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="*">
|
||||
<ContentError isNotFound>
|
||||
{match.params.id && (
|
||||
<Link
|
||||
to={`/templates/workflow_job_template/${match.params.id}/details`}
|
||||
to={`/templates/${match.params.templateType}/${match.params.id}/details`}
|
||||
>
|
||||
{i18n._(t`View Template Details`)}
|
||||
</Link>
|
||||
)}
|
||||
</ContentError>
|
||||
</Route>
|
||||
</Switch>
|
||||
</Card>
|
||||
</PageSection>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</Switch>
|
||||
</Card>
|
||||
</PageSection>
|
||||
);
|
||||
}
|
||||
|
||||
export { WorkflowJobTemplate as _WorkflowJobTemplate };
|
||||
export default withI18n()(withRouter(WorkflowJobTemplate));
|
||||
export default withI18n()(WorkflowJobTemplate);
|
||||
|
||||
@ -1,192 +1,196 @@
|
||||
import React from 'react';
|
||||
import { Route } from 'react-router-dom';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { WorkflowJobTemplatesAPI, OrganizationsAPI } from '../../api';
|
||||
|
||||
import {
|
||||
mountWithContexts,
|
||||
waitForElement,
|
||||
} from '../../../testUtils/enzymeHelpers';
|
||||
import WorkflowJobTemplate from './WorkflowJobTemplate';
|
||||
import { sleep } from '../../../testUtils/testUtils';
|
||||
import {
|
||||
WorkflowJobTemplatesAPI,
|
||||
CredentialsAPI,
|
||||
OrganizationsAPI,
|
||||
} from '../../api';
|
||||
import mockWorkflowJobTemplateData from './shared/data.workflow_job_template.json';
|
||||
|
||||
jest.mock('../../api/models/WorkflowJobTemplates');
|
||||
jest.mock('../../api/models/Credentials');
|
||||
jest.mock('../../api/models/Organizations');
|
||||
|
||||
describe('<WorkflowJobTemplate/>', () => {
|
||||
const mockMe = {
|
||||
is_super_user: true,
|
||||
is_system_auditor: false,
|
||||
};
|
||||
const mockMe = {
|
||||
is_super_user: true,
|
||||
is_system_auditor: false,
|
||||
};
|
||||
describe('<WorkflowJobTemplate />', () => {
|
||||
let wrapper;
|
||||
let history;
|
||||
beforeAll(() => {
|
||||
beforeEach(() => {
|
||||
WorkflowJobTemplatesAPI.readDetail.mockResolvedValue({
|
||||
data: {
|
||||
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/',
|
||||
},
|
||||
},
|
||||
data: mockWorkflowJobTemplateData,
|
||||
});
|
||||
|
||||
WorkflowJobTemplatesAPI.readWebhookKey.mockResolvedValue({
|
||||
data: { webhook_key: 'WebHook Key' },
|
||||
});
|
||||
CredentialsAPI.readDetail.mockResolvedValue({
|
||||
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions.mockResolvedValue({
|
||||
data: {
|
||||
summary_fields: {
|
||||
credential_type: { name: 'Github Personal Access Token', id: 1 },
|
||||
},
|
||||
actions: { PUT: true },
|
||||
},
|
||||
});
|
||||
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(() => {
|
||||
jest.clearAllMocks();
|
||||
wrapper.unmount();
|
||||
});
|
||||
describe('User can PUT', () => {
|
||||
beforeEach(async () => {
|
||||
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions.mockResolvedValue({
|
||||
data: { actions: { PUT: {} } },
|
||||
});
|
||||
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}]`)));
|
||||
});
|
||||
test('initially renders succesfully', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<WorkflowJobTemplate setBreadcrumb={() => {}} me={mockMe} />
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('User cannot PUT', () => {
|
||||
beforeEach(async () => {
|
||||
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions.mockResolvedValueOnce(
|
||||
test('When component mounts API is called and the response is put in state', async () => {
|
||||
await act(async () => {
|
||||
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 act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<Route
|
||||
path="/templates/workflow_job_template/:id/details"
|
||||
component={() => (
|
||||
<WorkflowJobTemplate setBreadcrumb={() => {}} me={mockMe} />
|
||||
)}
|
||||
/>,
|
||||
{
|
||||
context: {
|
||||
router: {
|
||||
history,
|
||||
});
|
||||
|
||||
await waitForElement(wrapper, 'ContentError', el => el.length === 1);
|
||||
});
|
||||
test('should call to get webhook key', async () => {
|
||||
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',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
test('should not call for webhook key', async () => {
|
||||
expect(WorkflowJobTemplatesAPI.readWebhookKey).not.toBeCalled();
|
||||
expect(WorkflowJobTemplatesAPI.readWebhookKey).toHaveBeenCalled();
|
||||
});
|
||||
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
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user