mirror of
https://github.com/ansible/awx.git
synced 2026-03-03 17:51:06 -03:30
more template details; add template delete button
This commit is contained in:
@@ -2,14 +2,27 @@ 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 { Card, PageSection } from '@patternfly/react-core';
|
import { Card, PageSection } from '@patternfly/react-core';
|
||||||
import { Link, useParams } from 'react-router-dom';
|
import { CaretLeftIcon } from '@patternfly/react-icons';
|
||||||
|
import {
|
||||||
|
Link,
|
||||||
|
Switch,
|
||||||
|
Route,
|
||||||
|
Redirect,
|
||||||
|
useParams,
|
||||||
|
useRouteMatch,
|
||||||
|
useLocation,
|
||||||
|
} from 'react-router-dom';
|
||||||
import useRequest from '../../util/useRequest';
|
import useRequest from '../../util/useRequest';
|
||||||
|
import RoutedTabs from '../../components/RoutedTabs';
|
||||||
import ContentError from '../../components/ContentError';
|
import ContentError from '../../components/ContentError';
|
||||||
import { NotificationTemplatesAPI } from '../../api';
|
import { NotificationTemplatesAPI } from '../../api';
|
||||||
import NotificationTemplateDetail from './NotificationTemplateDetail';
|
import NotificationTemplateDetail from './NotificationTemplateDetail';
|
||||||
|
import NotificationTemplateEdit from './NotificationTemplateEdit';
|
||||||
|
|
||||||
function NotificationTemplate({ i18n, setBreadcrumb }) {
|
function NotificationTemplate({ setBreadcrumb, i18n }) {
|
||||||
const { id: templateId } = useParams();
|
const { id: templateId } = useParams();
|
||||||
|
const match = useRouteMatch();
|
||||||
|
const location = useLocation();
|
||||||
const {
|
const {
|
||||||
result: template,
|
result: template,
|
||||||
isLoading,
|
isLoading,
|
||||||
@@ -47,15 +60,51 @@ function NotificationTemplate({ i18n, setBreadcrumb }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const showCardHeader = !isLoading && !location.pathname.endsWith('edit');
|
||||||
|
const tabs = [
|
||||||
|
{
|
||||||
|
name: (
|
||||||
|
<>
|
||||||
|
<CaretLeftIcon />
|
||||||
|
{i18n._(t`Back to Notifications`)}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
link: `/notification_templates`,
|
||||||
|
id: 99,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n._(t`Details`),
|
||||||
|
link: `${match.url}/details`,
|
||||||
|
id: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
return (
|
return (
|
||||||
<PageSection>
|
<PageSection>
|
||||||
<Card>
|
<Card>
|
||||||
{template && (
|
{showCardHeader && <RoutedTabs tabsArray={tabs} />}
|
||||||
<NotificationTemplateDetail
|
<Switch>
|
||||||
template={template}
|
<Redirect
|
||||||
isLoading={isLoading}
|
from="/notification_templates/:id"
|
||||||
|
to="/notification_templates/:id/details"
|
||||||
|
exact
|
||||||
/>
|
/>
|
||||||
)}
|
{template && (
|
||||||
|
<>
|
||||||
|
<Route path="/notification_templates/:id/edit">
|
||||||
|
<NotificationTemplateEdit
|
||||||
|
template={template}
|
||||||
|
isLoading={isLoading}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
<Route path="/notification_templates/:id/details">
|
||||||
|
<NotificationTemplateDetail
|
||||||
|
template={template}
|
||||||
|
isLoading={isLoading}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Switch>
|
||||||
</Card>
|
</Card>
|
||||||
</PageSection>
|
</PageSection>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { Fragment, useState, useEffect, useCallback } from 'react';
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
import { Link, useHistory, useParams } from 'react-router-dom';
|
import { Link, useHistory } from 'react-router-dom';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -28,26 +28,27 @@ import DeleteButton from '../../../components/DeleteButton';
|
|||||||
import ErrorDetail from '../../../components/ErrorDetail';
|
import ErrorDetail from '../../../components/ErrorDetail';
|
||||||
import LaunchButton from '../../../components/LaunchButton';
|
import LaunchButton from '../../../components/LaunchButton';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
||||||
import { JobTemplatesAPI } from '../../../api';
|
import { NotificationTemplatesAPI } from '../../../api';
|
||||||
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
||||||
|
import { NOTIFICATION_TYPES } from '../constants';
|
||||||
const TYPES = {
|
|
||||||
email: 'Email',
|
|
||||||
grafana: 'Grafana',
|
|
||||||
irc: 'IRC',
|
|
||||||
mattermost: 'Mattermost',
|
|
||||||
pagerduty: 'Pagerduty',
|
|
||||||
rocketchat: 'Rocket.Chat',
|
|
||||||
slack: 'Slack',
|
|
||||||
twilio: 'Twilio',
|
|
||||||
webhook: 'Webhook',
|
|
||||||
};
|
|
||||||
|
|
||||||
function NotificationTemplateDetail({ i18n, template }) {
|
function NotificationTemplateDetail({ i18n, template }) {
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
notification_configuration: configuration,
|
notification_configuration: configuration,
|
||||||
summary_fields,
|
summary_fields,
|
||||||
} = template;
|
} = template;
|
||||||
|
|
||||||
|
const { request: deleteTemplate, isLoading, error: deleteError } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await NotificationTemplatesAPI.destroy(template.id);
|
||||||
|
history.push(`/notification_templates`);
|
||||||
|
}, [template.id, history])
|
||||||
|
);
|
||||||
|
|
||||||
|
const { error, dismissError } = useDismissableError(deleteError);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<DetailList gutter="sm">
|
<DetailList gutter="sm">
|
||||||
@@ -78,7 +79,8 @@ function NotificationTemplateDetail({ i18n, template }) {
|
|||||||
<Detail
|
<Detail
|
||||||
label={i18n._(t`Notification Type`)}
|
label={i18n._(t`Notification Type`)}
|
||||||
value={
|
value={
|
||||||
TYPES[template.notification_type] || template.notification_type
|
NOTIFICATION_TYPES[template.notification_type] ||
|
||||||
|
template.notification_type
|
||||||
}
|
}
|
||||||
dataCy="nt-detail-type"
|
dataCy="nt-detail-type"
|
||||||
/>
|
/>
|
||||||
@@ -265,7 +267,107 @@ function NotificationTemplateDetail({ i18n, template }) {
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{template.notification_type === 'slack' && (
|
||||||
|
<>
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Destination Channels`)}
|
||||||
|
value={configuration.channels} // array
|
||||||
|
dataCy="nt-detail-slack-channels"
|
||||||
|
/>
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Notification Color`)}
|
||||||
|
value={configuration.hex_color}
|
||||||
|
dataCy="nt-detail-slack-color"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{template.notification_type === 'twilio' && (
|
||||||
|
<>
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Source Phone Number`)}
|
||||||
|
value={configuration.from_number}
|
||||||
|
dataCy="nt-detail-twilio-source-phone"
|
||||||
|
/>
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Destination SMS Number`)}
|
||||||
|
value={configuration.to_numbers} // array
|
||||||
|
dataCy="nt-detail-twilio-destination-numbers"
|
||||||
|
/>
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Account SID`)}
|
||||||
|
value={configuration.account_sid}
|
||||||
|
dataCy="nt-detail-twilio-account-sid"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{template.notification_type === 'webhook' && (
|
||||||
|
<>
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Username`)}
|
||||||
|
value={configuration.username}
|
||||||
|
dataCy="nt-detail-webhook-password"
|
||||||
|
/>
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Target URL`)}
|
||||||
|
value={configuration.url}
|
||||||
|
dataCy="nt-detail-webhook-url"
|
||||||
|
/>
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Disable SSL Verification`)}
|
||||||
|
value={
|
||||||
|
configuration.disable_ssl_verification
|
||||||
|
? i18n._(t`True`)
|
||||||
|
: i18n._(t`False`)
|
||||||
|
}
|
||||||
|
dataCy="nt-detail-disable-ssl"
|
||||||
|
/>
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`HTTP Method`)}
|
||||||
|
value={configuration.http_method}
|
||||||
|
dataCy="nt-detail-webhook-http-method"
|
||||||
|
/>
|
||||||
|
{/* <Detail
|
||||||
|
label={i18n._(t`HTTP Headers`)}
|
||||||
|
value={configuration.headers}
|
||||||
|
dataCy="nt-detail-webhook-headers"
|
||||||
|
/> */}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</DetailList>
|
</DetailList>
|
||||||
|
<CardActionsRow>
|
||||||
|
{summary_fields.user_capabilities &&
|
||||||
|
summary_fields.user_capabilities.edit && (
|
||||||
|
<Button
|
||||||
|
component={Link}
|
||||||
|
to={`/notification_templates/${template.id}/edit`}
|
||||||
|
aria-label={i18n._(t`Edit`)}
|
||||||
|
>
|
||||||
|
{i18n._(t`Edit`)}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{summary_fields.user_capabilities &&
|
||||||
|
summary_fields.user_capabilities.delete && (
|
||||||
|
<DeleteButton
|
||||||
|
name={template.name}
|
||||||
|
modalTitle={i18n._(t`Delete Notification`)}
|
||||||
|
onConfirm={deleteTemplate}
|
||||||
|
isDisabled={isLoading}
|
||||||
|
>
|
||||||
|
{i18n._(t`Delete`)}
|
||||||
|
</DeleteButton>
|
||||||
|
)}
|
||||||
|
</CardActionsRow>
|
||||||
|
{error && (
|
||||||
|
<AlertModal
|
||||||
|
isOpen={error}
|
||||||
|
variant="error"
|
||||||
|
title={i18n._(t`Error!`)}
|
||||||
|
onClose={dismissError}
|
||||||
|
>
|
||||||
|
{i18n._(t`Failed to delete notification.`)}
|
||||||
|
<ErrorDetail error={error} />
|
||||||
|
</AlertModal>
|
||||||
|
)}
|
||||||
</CardBody>
|
</CardBody>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { CardBody } from '../../../components/Card';
|
||||||
|
import { OrganizationsAPI } from '../../../api';
|
||||||
|
import { Config } from '../../../contexts/Config';
|
||||||
|
|
||||||
|
import NotificationTemplateForm from '../shared/NotificationTemplateForm';
|
||||||
|
|
||||||
|
function NotificationTemplateEdit({ template }) {
|
||||||
|
const detailsUrl = `/notification_templates/${template.id}/details`;
|
||||||
|
const history = useHistory();
|
||||||
|
const [formError, setFormError] = useState(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (
|
||||||
|
values,
|
||||||
|
groupsToAssociate,
|
||||||
|
groupsToDisassociate
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
await OrganizationsAPI.update(template.id, values);
|
||||||
|
await Promise.all(
|
||||||
|
groupsToAssociate.map(id =>
|
||||||
|
OrganizationsAPI.associateInstanceGroup(template.id, id)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
await Promise.all(
|
||||||
|
groupsToDisassociate.map(id =>
|
||||||
|
OrganizationsAPI.disassociateInstanceGroup(template.id, id)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
history.push(detailsUrl);
|
||||||
|
} catch (error) {
|
||||||
|
setFormError(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
history.push(detailsUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CardBody>
|
||||||
|
<Config>
|
||||||
|
{({ me }) => (
|
||||||
|
<NotificationTemplateForm
|
||||||
|
template={template}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
me={me || {}}
|
||||||
|
submitError={formError}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Config>
|
||||||
|
</CardBody>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationTemplateEdit.propTypes = {
|
||||||
|
template: PropTypes.shape().isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
NotificationTemplateEdit.contextTypes = {
|
||||||
|
custom_virtualenvs: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
};
|
||||||
|
|
||||||
|
export { NotificationTemplateEdit as _NotificationTemplateEdit };
|
||||||
|
export default NotificationTemplateEdit;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import NotificationTemplateEdit from './NotificationTemplateEdit';
|
||||||
|
|
||||||
|
export default NotificationTemplateEdit;
|
||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
} from '@patternfly/react-core';
|
} from '@patternfly/react-core';
|
||||||
import { PencilAltIcon, BellIcon } from '@patternfly/react-icons';
|
import { PencilAltIcon, BellIcon } from '@patternfly/react-icons';
|
||||||
import DataListCell from '../../../components/DataListCell';
|
import DataListCell from '../../../components/DataListCell';
|
||||||
|
import { NOTIFICATION_TYPES } from '../constants';
|
||||||
|
|
||||||
const DataListAction = styled(_DataListAction)`
|
const DataListAction = styled(_DataListAction)`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -49,7 +50,8 @@ function NotificationTemplateListItem({
|
|||||||
</Link>
|
</Link>
|
||||||
</DataListCell>,
|
</DataListCell>,
|
||||||
<DataListCell key="type">
|
<DataListCell key="type">
|
||||||
{template.notification_type}
|
{NOTIFICATION_TYPES[template.notification_type] ||
|
||||||
|
template.notification_type}
|
||||||
</DataListCell>,
|
</DataListCell>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import NotificationTemplatesList from './NotificationTemplateList';
|
import NotificationTemplateList from './NotificationTemplateList';
|
||||||
|
|
||||||
export default NotificationTemplatesList;
|
export default NotificationTemplateList;
|
||||||
export { default as NotificationTemplatesListItem } from './NotificationTemplateListItem';
|
export { default as NotificationTemplateListItem } from './NotificationTemplateListItem';
|
||||||
|
|||||||
12
awx/ui_next/src/screens/NotificationTemplate/constants.js
Normal file
12
awx/ui_next/src/screens/NotificationTemplate/constants.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/* eslint-disable-next-line import/prefer-default-export */
|
||||||
|
export const NOTIFICATION_TYPES = {
|
||||||
|
email: 'Email',
|
||||||
|
grafana: 'Grafana',
|
||||||
|
irc: 'IRC',
|
||||||
|
mattermost: 'Mattermost',
|
||||||
|
pagerduty: 'Pagerduty',
|
||||||
|
rocketchat: 'Rocket.Chat',
|
||||||
|
slack: 'Slack',
|
||||||
|
twilio: 'Twilio',
|
||||||
|
webhook: 'Webhook',
|
||||||
|
};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export default function NotificationTemplateForm() {
|
||||||
|
//
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user