diff --git a/public/app/core/actions/appNotification.ts b/public/app/core/actions/appNotification.ts index 009e99b1245..b79b642eef1 100644 --- a/public/app/core/actions/appNotification.ts +++ b/public/app/core/actions/appNotification.ts @@ -22,7 +22,7 @@ export const clearAppNotification = (appNotificationId: number) => ({ payload: appNotificationId, }); -export const addAppNotification = (alert: AppNotification) => ({ +export const notifyApp = (appNotification: AppNotification) => ({ type: ActionTypes.AddAppNotification, - payload: alert, + payload: appNotification, }); diff --git a/public/app/core/actions/index.ts b/public/app/core/actions/index.ts index 451a13dae99..f7ce2dda945 100644 --- a/public/app/core/actions/index.ts +++ b/public/app/core/actions/index.ts @@ -1,4 +1,5 @@ import { updateLocation } from './location'; import { updateNavIndex, UpdateNavIndexAction } from './navModel'; +import { notifyApp, clearAppNotification } from './appNotification'; -export { updateLocation, updateNavIndex, UpdateNavIndexAction }; +export { updateLocation, updateNavIndex, UpdateNavIndexAction, notifyApp, clearAppNotification }; diff --git a/public/app/core/components/AppNotifications/AppNotificationItem.tsx b/public/app/core/components/AppNotifications/AppNotificationItem.tsx new file mode 100644 index 00000000000..5169c39e7a0 --- /dev/null +++ b/public/app/core/components/AppNotifications/AppNotificationItem.tsx @@ -0,0 +1,38 @@ +import React, { Component } from 'react'; +import { AppNotification } from 'app/types'; + +interface Props { + appNotification: AppNotification; + onClearNotification: (id) => void; +} + +export default class AppNotificationItem extends Component { + shouldComponentUpdate(nextProps) { + return this.props.appNotification.id !== nextProps.appNotification.id; + } + + componentDidMount() { + const { appNotification, onClearNotification } = this.props; + setTimeout(() => { + onClearNotification(appNotification.id); + }, appNotification.timeout); + } + + render() { + const { appNotification, onClearNotification } = this.props; + return ( +
+
+ +
+
+
{appNotification.title}
+
{appNotification.text}
+
+ +
+ ); + } +} diff --git a/public/app/core/components/AppNotifications/AppNotificationList.tsx b/public/app/core/components/AppNotifications/AppNotificationList.tsx index 53c88a41155..c91f8372384 100644 --- a/public/app/core/components/AppNotifications/AppNotificationList.tsx +++ b/public/app/core/components/AppNotifications/AppNotificationList.tsx @@ -1,53 +1,30 @@ import React, { PureComponent } from 'react'; import appEvents from 'app/core/app_events'; -import { addAppNotification, clearAppNotification } from '../../actions/appNotification'; +import AppNotificationItem from './AppNotificationItem'; +import { notifyApp, clearAppNotification } from 'app/core/actions'; import { connectWithStore } from 'app/core/utils/connectWithReduxStore'; -import { AppNotification, AppNotificationSeverity, StoreState } from 'app/types'; +import { AppNotification, StoreState } from 'app/types'; +import { + createErrorNotification, + createSuccessNotification, + createWarningNotification, +} from '../../copy/appNotification'; export interface Props { appNotifications: AppNotification[]; - addAppNotification: typeof addAppNotification; + notifyApp: typeof notifyApp; clearAppNotification: typeof clearAppNotification; } export class AppNotificationList extends PureComponent { componentDidMount() { - appEvents.on('alert-warning', options => this.addAppNotification(options[0], options[1], 'warning', 5000)); - appEvents.on('alert-success', options => this.addAppNotification(options[0], options[1], 'success', 3000)); - appEvents.on('alert-error', options => this.addAppNotification(options[0], options[1], 'error', 7000)); + const { notifyApp } = this.props; + + appEvents.on('alert-warning', options => notifyApp(createWarningNotification(options[0], options[1]))); + appEvents.on('alert-success', options => notifyApp(createSuccessNotification(options[0], options[1]))); + appEvents.on('alert-error', options => notifyApp(createErrorNotification(options[0], options[1]))); } - addAppNotification(title, text, severity, timeout) { - const id = Date.now(); - const newAlert = { - id: id, - title: title || '', - text: text || '', - severity: severity || AppNotificationSeverity.Info, - icon: this.getIconForSeverity(severity), - remove: this.clearAutomatically(id, timeout), - }; - - this.props.addAppNotification(newAlert); - } - - getIconForSeverity(severity) { - switch (severity) { - case AppNotificationSeverity.Success: - return 'fa fa-check'; - case AppNotificationSeverity.Error: - return 'fa fa-exclamation-triangle'; - default: - return 'fa fa-exclamation'; - } - } - - clearAutomatically = (id, timeout) => { - setTimeout(() => { - this.props.clearAppNotification(id); - }, timeout); - }; - onClearAppNotification = id => { this.props.clearAppNotification(id); }; @@ -59,22 +36,11 @@ export class AppNotificationList extends PureComponent {
{appNotifications.map((appNotification, index) => { return ( -
-
- -
-
-
{appNotification.title}
-
{appNotification.text}
-
- -
+ this.onClearAppNotification(id)} + /> ); })}
@@ -87,7 +53,7 @@ const mapStateToProps = (state: StoreState) => ({ }); const mapDispatchToProps = { - addAppNotification, + notifyApp, clearAppNotification, }; diff --git a/public/app/core/copy/appNotification.ts b/public/app/core/copy/appNotification.ts new file mode 100644 index 00000000000..c34480d7aad --- /dev/null +++ b/public/app/core/copy/appNotification.ts @@ -0,0 +1,46 @@ +import { AppNotification, AppNotificationSeverity, AppNotificationTimeout } from 'app/types'; + +const defaultSuccessNotification: AppNotification = { + title: '', + text: '', + severity: AppNotificationSeverity.Success, + icon: 'fa fa-check', + timeout: AppNotificationTimeout.Success, +}; + +const defaultWarningNotification: AppNotification = { + title: '', + text: '', + severity: AppNotificationSeverity.Warning, + icon: 'fa fa-exclamation', + timeout: AppNotificationTimeout.Warning, +}; + +const defaultErrorNotification: AppNotification = { + title: '', + text: '', + severity: AppNotificationSeverity.Error, + icon: 'fa fa-exclamation-triangle', + timeout: AppNotificationTimeout.Error, +}; + +export const createSuccessNotification = (title: string, text?: string): AppNotification => ({ + ...defaultSuccessNotification, + title: title, + text: text, + id: Date.now(), +}); + +export const createErrorNotification = (title: string, text?: string): AppNotification => ({ + ...defaultErrorNotification, + title: title, + text: text, + id: Date.now(), +}); + +export const createWarningNotification = (title: string, text?: string): AppNotification => ({ + ...defaultWarningNotification, + title: title, + text: text, + id: Date.now(), +}); diff --git a/public/app/core/reducers/appNotification.test.ts b/public/app/core/reducers/appNotification.test.ts index 5098abc9e74..183b699f5fc 100644 --- a/public/app/core/reducers/appNotification.test.ts +++ b/public/app/core/reducers/appNotification.test.ts @@ -1,6 +1,6 @@ import { appNotificationsReducer } from './appNotification'; import { ActionTypes } from '../actions/appNotification'; -import { AppNotificationSeverity } from 'app/types/index'; +import { AppNotificationSeverity, AppNotificationTimeout } from 'app/types/'; describe('clear alert', () => { it('should filter alert', () => { @@ -15,6 +15,7 @@ describe('clear alert', () => { icon: 'success', title: 'test', text: 'test alert', + timeout: AppNotificationTimeout.Success, }, { id: id2, @@ -22,6 +23,7 @@ describe('clear alert', () => { icon: 'warning', title: 'test2', text: 'test alert fail 2', + timeout: AppNotificationTimeout.Warning, }, ], }; @@ -39,6 +41,7 @@ describe('clear alert', () => { icon: 'success', title: 'test', text: 'test alert', + timeout: AppNotificationTimeout.Success, }, ], }; diff --git a/public/app/core/reducers/appNotification.ts b/public/app/core/reducers/appNotification.ts index 8812546356a..2c8bbbbd84d 100644 --- a/public/app/core/reducers/appNotification.ts +++ b/public/app/core/reducers/appNotification.ts @@ -1,4 +1,4 @@ -import { AppNotification, AppNotificationsState } from 'app/types/index'; +import { AppNotification, AppNotificationsState } from 'app/types/'; import { Action, ActionTypes } from '../actions/appNotification'; export const initialState: AppNotificationsState = { @@ -17,7 +17,3 @@ export const appNotificationsReducer = (state = initialState, action: Action): A } return state; }; - -export default { - appNotifications: appNotificationsReducer, -}; diff --git a/public/app/core/reducers/index.ts b/public/app/core/reducers/index.ts index be13528c91c..1c8670ed0d6 100644 --- a/public/app/core/reducers/index.ts +++ b/public/app/core/reducers/index.ts @@ -1,7 +1,9 @@ import { navIndexReducer as navIndex } from './navModel'; import { locationReducer as location } from './location'; +import { appNotificationsReducer as appNotifications } from './appNotification'; export default { navIndex, location, + appNotifications, }; diff --git a/public/app/store/configureStore.ts b/public/app/store/configureStore.ts index 6b3205dc53e..ccd027a0b6d 100644 --- a/public/app/store/configureStore.ts +++ b/public/app/store/configureStore.ts @@ -10,7 +10,6 @@ import dashboardReducers from 'app/features/dashboard/state/reducers'; import pluginReducers from 'app/features/plugins/state/reducers'; import dataSourcesReducers from 'app/features/datasources/state/reducers'; import usersReducers from 'app/features/users/state/reducers'; -import appNotificationReducers from 'app/core/reducers/appNotification'; const rootReducers = { ...sharedReducers, @@ -22,7 +21,6 @@ const rootReducers = { ...pluginReducers, ...dataSourcesReducers, ...usersReducers, - ...appNotificationReducers, }; export let store; diff --git a/public/app/types/appNotifications.ts b/public/app/types/appNotifications.ts index 1bbc66a4baa..81e6cfd55e1 100644 --- a/public/app/types/appNotifications.ts +++ b/public/app/types/appNotifications.ts @@ -4,6 +4,7 @@ export interface AppNotification { icon: string; title: string; text: string; + timeout: AppNotificationTimeout; } export enum AppNotificationSeverity { @@ -13,6 +14,12 @@ export enum AppNotificationSeverity { Info = 'info', } +export enum AppNotificationTimeout { + Warning = 5000, + Success = 3000, + Error = 7000, +} + export interface AppNotificationsState { appNotifications: AppNotification[]; } diff --git a/public/app/types/index.ts b/public/app/types/index.ts index b888ba83877..0cb1b196419 100644 --- a/public/app/types/index.ts +++ b/public/app/types/index.ts @@ -9,7 +9,12 @@ import { ApiKey, ApiKeysState, NewApiKey } from './apiKeys'; import { Invitee, OrgUser, User, UsersState } from './user'; import { DataSource, DataSourcesState } from './datasources'; import { PluginDashboard, PluginMeta, Plugin, PluginsState } from './plugins'; -import { AppNotification, AppNotificationSeverity, AppNotificationsState } from './appNotifications'; +import { + AppNotification, + AppNotificationSeverity, + AppNotificationsState, + AppNotificationTimeout, +} from './appNotifications'; export { Team, @@ -50,6 +55,7 @@ export { AppNotification, AppNotificationsState, AppNotificationSeverity, + AppNotificationTimeout, }; export interface StoreState {