From 194f45263b5a56205045becd17ef3682143ed788 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 28 Feb 2019 07:33:03 -0300 Subject: [PATCH] [Feature] Migrate Alerts List Page to React (#3505) --- .../assets/less/redash/redash-newstyle.less | 6 +- client/app/pages/alerts-list/alerts-list.html | 35 ----- client/app/pages/alerts-list/index.js | 50 ------- client/app/pages/alerts/AlertsList.jsx | 139 ++++++++++++++++++ 4 files changed, 142 insertions(+), 88 deletions(-) delete mode 100644 client/app/pages/alerts-list/alerts-list.html delete mode 100644 client/app/pages/alerts-list/index.js create mode 100644 client/app/pages/alerts/AlertsList.jsx 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) => ( +
+ {alert.name} +
+ ), { + 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;