diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplate.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplate.jsx
index 4b6692f72c..7b8516f787 100644
--- a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplate.jsx
+++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplate.jsx
@@ -2,14 +2,27 @@ import React, { useEffect, useCallback } from 'react';
import { t } from '@lingui/macro';
import { withI18n } from '@lingui/react';
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 RoutedTabs from '../../components/RoutedTabs';
import ContentError from '../../components/ContentError';
import { NotificationTemplatesAPI } from '../../api';
import NotificationTemplateDetail from './NotificationTemplateDetail';
+import NotificationTemplateEdit from './NotificationTemplateEdit';
-function NotificationTemplate({ i18n, setBreadcrumb }) {
+function NotificationTemplate({ setBreadcrumb, i18n }) {
const { id: templateId } = useParams();
+ const match = useRouteMatch();
+ const location = useLocation();
const {
result: template,
isLoading,
@@ -47,15 +60,51 @@ function NotificationTemplate({ i18n, setBreadcrumb }) {
);
}
+ const showCardHeader = !isLoading && !location.pathname.endsWith('edit');
+ const tabs = [
+ {
+ name: (
+ <>
+
+ {i18n._(t`Back to Notifications`)}
+ >
+ ),
+ link: `/notification_templates`,
+ id: 99,
+ },
+ {
+ name: i18n._(t`Details`),
+ link: `${match.url}/details`,
+ id: 0,
+ },
+ ];
return (
- {template && (
- }
+
+
- )}
+ {template && (
+ <>
+
+
+
+
+
+
+ >
+ )}
+
);
diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx
index 77cadb74cd..18f45a4c21 100644
--- a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx
+++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.jsx
@@ -1,5 +1,5 @@
-import React, { Fragment, useState, useEffect, useCallback } from 'react';
-import { Link, useHistory, useParams } from 'react-router-dom';
+import React, { useState, useEffect, useCallback } from 'react';
+import { Link, useHistory } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import {
Button,
@@ -28,26 +28,27 @@ import DeleteButton from '../../../components/DeleteButton';
import ErrorDetail from '../../../components/ErrorDetail';
import LaunchButton from '../../../components/LaunchButton';
import { VariablesDetail } from '../../../components/CodeMirrorInput';
-import { JobTemplatesAPI } from '../../../api';
+import { NotificationTemplatesAPI } from '../../../api';
import useRequest, { useDismissableError } from '../../../util/useRequest';
-
-const TYPES = {
- email: 'Email',
- grafana: 'Grafana',
- irc: 'IRC',
- mattermost: 'Mattermost',
- pagerduty: 'Pagerduty',
- rocketchat: 'Rocket.Chat',
- slack: 'Slack',
- twilio: 'Twilio',
- webhook: 'Webhook',
-};
+import { NOTIFICATION_TYPES } from '../constants';
function NotificationTemplateDetail({ i18n, template }) {
+ const history = useHistory();
+
const {
notification_configuration: configuration,
summary_fields,
} = 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 (
@@ -78,7 +79,8 @@ function NotificationTemplateDetail({ i18n, template }) {
@@ -265,7 +267,107 @@ function NotificationTemplateDetail({ i18n, template }) {
/>
>
)}
+ {template.notification_type === 'slack' && (
+ <>
+
+
+ >
+ )}
+ {template.notification_type === 'twilio' && (
+ <>
+
+
+
+ >
+ )}
+ {template.notification_type === 'webhook' && (
+ <>
+
+
+
+
+ {/* */}
+ >
+ )}
+
+ {summary_fields.user_capabilities &&
+ summary_fields.user_capabilities.edit && (
+
+ )}
+ {summary_fields.user_capabilities &&
+ summary_fields.user_capabilities.delete && (
+
+ {i18n._(t`Delete`)}
+
+ )}
+
+ {error && (
+
+ {i18n._(t`Failed to delete notification.`)}
+
+
+ )}
);
}
diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateEdit/NotificationTemplateEdit.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateEdit/NotificationTemplateEdit.jsx
new file mode 100644
index 0000000000..b089b6b89f
--- /dev/null
+++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateEdit/NotificationTemplateEdit.jsx
@@ -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 (
+
+
+ {({ me }) => (
+
+ )}
+
+
+ );
+}
+
+NotificationTemplateEdit.propTypes = {
+ template: PropTypes.shape().isRequired,
+};
+
+NotificationTemplateEdit.contextTypes = {
+ custom_virtualenvs: PropTypes.arrayOf(PropTypes.string),
+};
+
+export { NotificationTemplateEdit as _NotificationTemplateEdit };
+export default NotificationTemplateEdit;
diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateEdit/index.js b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateEdit/index.js
new file mode 100644
index 0000000000..be9b40a69c
--- /dev/null
+++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateEdit/index.js
@@ -0,0 +1,3 @@
+import NotificationTemplateEdit from './NotificationTemplateEdit';
+
+export default NotificationTemplateEdit;
diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.jsx
index bf2ea92fb8..f5bf5f8be4 100644
--- a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.jsx
+++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.jsx
@@ -14,6 +14,7 @@ import {
} from '@patternfly/react-core';
import { PencilAltIcon, BellIcon } from '@patternfly/react-icons';
import DataListCell from '../../../components/DataListCell';
+import { NOTIFICATION_TYPES } from '../constants';
const DataListAction = styled(_DataListAction)`
align-items: center;
@@ -49,7 +50,8 @@ function NotificationTemplateListItem({
,
- {template.notification_type}
+ {NOTIFICATION_TYPES[template.notification_type] ||
+ template.notification_type}
,
]}
/>
diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/index.js b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/index.js
index 06c347d889..335e76dd6c 100644
--- a/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/index.js
+++ b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplateList/index.js
@@ -1,4 +1,4 @@
-import NotificationTemplatesList from './NotificationTemplateList';
+import NotificationTemplateList from './NotificationTemplateList';
-export default NotificationTemplatesList;
-export { default as NotificationTemplatesListItem } from './NotificationTemplateListItem';
+export default NotificationTemplateList;
+export { default as NotificationTemplateListItem } from './NotificationTemplateListItem';
diff --git a/awx/ui_next/src/screens/NotificationTemplate/constants.js b/awx/ui_next/src/screens/NotificationTemplate/constants.js
new file mode 100644
index 0000000000..5937e48743
--- /dev/null
+++ b/awx/ui_next/src/screens/NotificationTemplate/constants.js
@@ -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',
+};
diff --git a/awx/ui_next/src/screens/NotificationTemplate/shared/NotificationTemplateForm.jsx b/awx/ui_next/src/screens/NotificationTemplate/shared/NotificationTemplateForm.jsx
new file mode 100644
index 0000000000..c08caaa3e5
--- /dev/null
+++ b/awx/ui_next/src/screens/NotificationTemplate/shared/NotificationTemplateForm.jsx
@@ -0,0 +1,3 @@
+export default function NotificationTemplateForm() {
+ //
+}