diff --git a/client/app/components/alerts/AlertSubscriptions.jsx b/client/app/components/alerts/AlertSubscriptions.jsx
new file mode 100644
index 0000000000..f7e522a141
--- /dev/null
+++ b/client/app/components/alerts/AlertSubscriptions.jsx
@@ -0,0 +1,154 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { react2angular } from 'react2angular';
+import Select from 'antd/lib/select';
+import { includes, without, compact } from 'lodash';
+
+import Destination from './Destination';
+
+class AlertSubscriptions extends React.Component {
+ static propTypes = {
+ alertId: PropTypes.number.isRequired,
+ }
+ constructor(props) {
+ super(props);
+ this.props.$q
+ .all([
+ this.props.Destination.query().$promise,
+ this.props.AlertSubscription.query({ alertId: this.props.alertId }).$promise,
+ ])
+ .then((responses) => {
+ let destinations = responses[0];
+ const subscribers = responses[1];
+
+ const mapF = s => s.destination && s.destination.id;
+ const subscribedDestinations = compact(subscribers.map(mapF));
+
+ const subscribedUsers = compact(subscribers.map(s => !s.destination && s.user.id));
+
+ destinations = destinations.filter(d => !includes(subscribedDestinations, d.id));
+
+ if (!includes(subscribedUsers, this.props.currentUser.id)) {
+ destinations.unshift({
+ name: this.props.currentUser.name + ' (Email)',
+ id: null,
+ icon: 'fa-envelope',
+ });
+ }
+ this.setState({
+ subscribers,
+ destinations,
+ });
+ });
+ }
+
+ state = {
+ selection: null,
+ subscribers: [],
+ destinations: [],
+ }
+
+ saveSubscriber = () => {
+ const sub = new this.props.AlertSubscription({ alert_id: this.props.alertId });
+ if (this.state.selection) {
+ sub.destination_id = this.state.selection;
+ }
+
+ sub.$save(
+ () => {
+ this.props.toastr.success('Subscribed.');
+ const destinations = this.state.destinations.filter(d => d.id !== this.state.selection);
+ this.setState({
+ subscribers: this.state.subscribers.concat(sub),
+ destinations,
+ selection: destinations.length ? destinations[0].id : null,
+ });
+ },
+ () => {
+ this.props.toastr.error('Failed saving subscription.');
+ },
+ );
+ }
+
+ unsubscribe = (subscriber) => {
+ const destination = subscriber.destination;
+ const user = subscriber.user;
+
+ subscriber.$delete(
+ () => {
+ this.props.toastr.success('Unsubscribed');
+ let destinations;
+ const subscribers = without(this.state.subscribers, subscriber);
+ if (destination) {
+ destinations = this.state.destinations.concat(destination);
+ } else if (user.id === this.props.currentUser.id) {
+ destinations = this.state.destinations.concat({
+ id: null,
+ name: this.props.currentUser.name + ' (Email)',
+ icon: 'fa-envelope',
+ });
+ }
+ const newState = { subscribers, destinations };
+ if (destinations.length === 1) {
+ newState.selection = destinations[0].id;
+ }
+ this.setState(newState);
+ },
+ () => {
+ this.props.toastr.error('Failed unsubscribing.');
+ },
+ );
+ }
+
+ updateSelection = selection => this.setState({ selection })
+
+ render() {
+ return (
+
+
Notifications
+
+
+
+
+
+
+ {this.state.subscribers.map(s => (
+
+
+ {this.props.currentUser.isAdmin ||
+ this.props.currentUser.id === s.user.id ?
+ : ''
+ }
+
+ ))}
+
+
+ );
+ }
+}
+
+export default function init(ngModule) {
+ ngModule.component('alertSubscriptions', react2angular(AlertSubscriptions, null, ['currentUser', '$q', 'Destination', 'AlertSubscription', 'toastr']));
+}
+init.init = true;
diff --git a/client/app/components/alerts/Destination.jsx b/client/app/components/alerts/Destination.jsx
new file mode 100644
index 0000000000..38412a1f8b
--- /dev/null
+++ b/client/app/components/alerts/Destination.jsx
@@ -0,0 +1,34 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function Destination(props) {
+ let icon;
+ let name;
+ if (props.destination.destination) {
+ icon = props.destination.destination.icon;
+ name = props.destination.destination.name;
+ } else if (props.destination.user) {
+ name = `${props.destination.user.name} (Email)`;
+ icon = 'fa-envelope';
+ } else {
+ name = props.destination.name;
+ icon = props.destination.icon;
+ }
+ return (
+
+ {name}
+
+ );
+}
+
+Destination.propTypes = {
+ destination: PropTypes.shape({
+ destination: PropTypes.shape({
+ icon: PropTypes.string,
+ name: PropTypes.string,
+ }),
+ user: PropTypes.shape({
+ name: PropTypes.string,
+ }),
+ }).isRequired,
+};
diff --git a/client/app/components/alerts/alert-subscriptions/alert-subscriptions.html b/client/app/components/alerts/alert-subscriptions/alert-subscriptions.html
deleted file mode 100644
index 4d3d0a246e..0000000000
--- a/client/app/components/alerts/alert-subscriptions/alert-subscriptions.html
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
Notifications
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/client/app/components/alerts/alert-subscriptions/index.js b/client/app/components/alerts/alert-subscriptions/index.js
deleted file mode 100644
index e0dc5793e4..0000000000
--- a/client/app/components/alerts/alert-subscriptions/index.js
+++ /dev/null
@@ -1,116 +0,0 @@
-import { includes, without, compact } from 'lodash';
-import template from './alert-subscriptions.html';
-
-function controller($scope, $q, $sce, currentUser, AlertSubscription, Destination, toastr) {
- 'ngInject';
-
- $scope.newSubscription = {};
- $scope.subscribers = [];
- $scope.destinations = [];
- $scope.currentUser = currentUser;
-
- $q
- .all([
- Destination.query().$promise,
- AlertSubscription.query({ alertId: $scope.alertId }).$promise,
- ])
- .then((responses) => {
- const destinations = responses[0];
- const subscribers = responses[1];
-
- const mapF = s => s.destination && s.destination.id;
- const subscribedDestinations = compact(subscribers.map(mapF));
-
- const subscribedUsers = compact(subscribers.map(s => !s.destination && s.user.id));
-
- $scope.destinations = destinations.filter(d => !includes(subscribedDestinations, d.id));
-
- if (!includes(subscribedUsers, currentUser.id)) {
- $scope.destinations.unshift({ user: { name: currentUser.name } });
- }
-
- $scope.newSubscription.destination = $scope.destinations[0];
- $scope.subscribers = subscribers;
- });
-
- $scope.destinationsDisplay = (d) => {
- if (!d) {
- return '';
- }
-
- let destination = d;
- if (d.destination) {
- destination = destination.destination;
- } else if (destination.user) {
- destination = {
- name: `${d.user.name} (Email)`,
- icon: 'fa-envelope',
- type: 'user',
- };
- }
-
- return $sce.trustAsHtml(` ${destination.name}`);
- };
-
- $scope.saveSubscriber = () => {
- const sub = new AlertSubscription({ alert_id: $scope.alertId });
- if ($scope.newSubscription.destination.id) {
- sub.destination_id = $scope.newSubscription.destination.id;
- }
-
- sub.$save(
- () => {
- toastr.success('Subscribed.');
- $scope.subscribers.push(sub);
- $scope.destinations = without($scope.destinations, $scope.newSubscription.destination);
- if ($scope.destinations.length > 0) {
- $scope.newSubscription.destination = $scope.destinations[0];
- } else {
- $scope.newSubscription.destination = undefined;
- }
- },
- () => {
- toastr.error('Failed saving subscription.');
- },
- );
- };
-
- $scope.unsubscribe = (subscriber) => {
- const destination = subscriber.destination;
- const user = subscriber.user;
-
- subscriber.$delete(
- () => {
- toastr.success('Unsubscribed');
- $scope.subscribers = without($scope.subscribers, subscriber);
- if (destination) {
- $scope.destinations.push(destination);
- } else if (user.id === currentUser.id) {
- $scope.destinations.push({ user: { name: currentUser.name } });
- }
-
- if ($scope.destinations.length === 1) {
- $scope.newSubscription.destination = $scope.destinations[0];
- }
- },
- () => {
- toastr.error('Failed unsubscribing.');
- },
- );
- };
-}
-
-export default function init(ngModule) {
- ngModule.directive('alertSubscriptions', () => ({
- restrict: 'E',
- replace: true,
- scope: {
- alertId: '=',
- },
- template,
- controller,
- }));
-}
-
-init.init = true;
-