diff --git a/client/app/assets/less/redash/redash-newstyle.less b/client/app/assets/less/redash/redash-newstyle.less
index 78de0e937f..dee33dacb1 100644
--- a/client/app/assets/less/redash/redash-newstyle.less
+++ b/client/app/assets/less/redash/redash-newstyle.less
@@ -60,7 +60,7 @@ body {
// Fixed width layout for specific pages
@media (min-width: 768px) {
- settings-screen, home-page, page-dashboard-list, page-queries-list, alerts-list-page, alert-page, queries-search-results-page, .fixed-container {
+ settings-screen, home-page, page-dashboard-list, page-queries-list, page-alerts-list, alert-page, queries-search-results-page, .fixed-container {
.container {
width: 750px;
}
@@ -68,7 +68,7 @@ body {
}
@media (min-width: 992px) {
- settings-screen, home-page, page-dashboard-list, page-queries-list, alerts-list-page, alert-page, queries-search-results-page, .fixed-container {
+ settings-screen, home-page, page-dashboard-list, page-queries-list, page-alerts-list, alert-page, queries-search-results-page, .fixed-container {
.container {
width: 970px;
}
@@ -76,7 +76,7 @@ body {
}
@media (min-width: 1200px) {
- settings-screen, home-page, page-dashboard-list, page-queries-list, alerts-list-page, alert-page, queries-search-results-page, .fixed-container {
+ settings-screen, home-page, page-dashboard-list, page-queries-list, page-alerts-list, alert-page, queries-search-results-page, .fixed-container {
.container {
width: 1170px;
}
diff --git a/client/app/pages/alerts-list/alerts-list.html b/client/app/pages/alerts-list/alerts-list.html
deleted file mode 100644
index 2c6c49ba3b..0000000000
--- a/client/app/pages/alerts-list/alerts-list.html
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
- Name |
- Created By |
- State |
- Created At |
-
-
-
-
- {{row.name}} |
- {{row.created_by}} |
- {{row.state | uppercase}} since |
- |
-
-
-
-
-
-
-
diff --git a/client/app/pages/alerts-list/index.js b/client/app/pages/alerts-list/index.js
deleted file mode 100644
index 5c27223b62..0000000000
--- a/client/app/pages/alerts-list/index.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { Paginator } from '@/lib/pagination';
-import template from './alerts-list.html';
-
-const stateClass = {
- ok: 'label label-success',
- triggered: 'label label-danger',
- unknown: 'label label-warning',
-};
-
-class AlertsListCtrl {
- constructor(Alert) {
- this.showEmptyState = false;
- this.showList = false;
-
- this.alerts = new Paginator([], { itemsPerPage: 20 });
- Alert.query((alerts) => {
- if (alerts.length > 0) {
- this.showList = true;
- } else {
- this.showEmptyState = true;
- }
-
- this.alerts.updateRows(alerts.map(alert => ({
- id: alert.id,
- name: alert.name,
- state: alert.state,
- class: stateClass[alert.state],
- created_by: alert.user.name,
- created_at: alert.created_at,
- updated_at: alert.updated_at,
- })));
- });
- }
-}
-
-export default function init(ngModule) {
- ngModule.component('alertsListPage', {
- template,
- controller: AlertsListCtrl,
- });
-
- return {
- '/alerts': {
- template: '',
- title: 'Alerts',
- },
- };
-}
-
-init.init = true;
diff --git a/client/app/pages/alerts/AlertsList.jsx b/client/app/pages/alerts/AlertsList.jsx
new file mode 100644
index 0000000000..41031d5b12
--- /dev/null
+++ b/client/app/pages/alerts/AlertsList.jsx
@@ -0,0 +1,139 @@
+import React from 'react';
+import { react2angular } from 'react2angular';
+
+import { toUpper } from 'lodash';
+import { PageHeader } from '@/components/PageHeader';
+import { Paginator } from '@/components/Paginator';
+import { EmptyState } from '@/components/empty-state/EmptyState';
+
+import { wrap as liveItemsList, ControllerType } from '@/components/items-list/ItemsList';
+import { ResourceItemsSource } from '@/components/items-list/classes/ItemsSource';
+import { StateStorage } from '@/components/items-list/classes/StateStorage';
+
+import LoadingState from '@/components/items-list/components/LoadingState';
+import ItemsTable, { Columns } from '@/components/items-list/components/ItemsTable';
+
+import { Alert } from '@/services/alert';
+import navigateTo from '@/services/navigateTo';
+import { routesToAngularRoutes } from '@/lib/utils';
+
+const STATE_CLASS = {
+ unknown: 'label-warning',
+ ok: 'label-success',
+ triggered: 'label-danger',
+};
+
+class AlertsList extends React.Component {
+ static propTypes = {
+ controller: ControllerType.isRequired,
+ };
+
+ onTableRowClick = (event, item) => navigateTo('alerts/' + item.id);
+
+ listColumns = [
+ Columns.custom.sortable((text, alert) => (
+
+ ), {
+ title: 'Name',
+ field: 'name',
+ }),
+ Columns.custom.sortable((text, alert) => (
+
+ {toUpper(alert.state)}
+
+ ), {
+ title: 'State',
+ field: 'state',
+ width: '1%',
+ }),
+ Columns.timeAgo.sortable({ title: 'Last Updated At',
+ field: 'updated_at',
+ className: 'text-nowrap',
+ width: '1%' }),
+ Columns.avatar({ field: 'user', className: 'p-l-0 p-r-0' }, name => `Created by ${name}`),
+ Columns.dateTime.sortable({ title: 'Created At',
+ field: 'created_at',
+ className: 'text-nowrap',
+ width: '1%' }),
+ ];
+
+ render() {
+ const { controller } = this.props;
+
+ return (
+
+
+
+ {!controller.isLoaded &&
}
+ {controller.isLoaded && controller.isEmpty && (
+
+ )}
+ {
+ controller.isLoaded && !controller.isEmpty && (
+
+
+
controller.updatePagination({ page })}
+ />
+
+ )
+ }
+
+
+ );
+ }
+}
+
+export default function init(ngModule) {
+ ngModule.component('pageAlertsList', react2angular(liveItemsList(
+ AlertsList,
+ new ResourceItemsSource({
+ isPlainList: true,
+ getRequest() {
+ return {};
+ },
+ getResource() {
+ return Alert.query.bind(Alert);
+ },
+ getItemProcessor() {
+ return (item => new Alert(item));
+ },
+ }),
+ new StateStorage({ orderByField: 'created_at', orderByReverse: true, itemsPerPage: 20 }),
+ )));
+ return routesToAngularRoutes([
+ {
+ path: '/alerts',
+ title: 'Alerts',
+ key: 'alerts',
+ },
+ ], {
+ reloadOnSearch: false,
+ template: '',
+ controller($scope, $exceptionHandler) {
+ 'ngInject';
+
+ $scope.handleError = $exceptionHandler;
+ },
+ });
+}
+
+init.init = true;