diff --git a/ui/src/admin/actions/chronograf.js b/ui/src/admin/actions/chronograf.js index d0dd65f5a7..c5857f5e62 100644 --- a/ui/src/admin/actions/chronograf.js +++ b/ui/src/admin/actions/chronograf.js @@ -18,6 +18,12 @@ import { import {publishNotification} from 'shared/actions/notifications' import {errorThrown} from 'shared/actions/errors' +import { + mappingDeletedNotification, + updateUserSuccessNotification, + deleteOrgSuccessNotification, + userRemovedFromOrgNotification, +} from 'shared/copy/notificationsCopy' import {REVERT_STATE_DELAY} from 'shared/constants' @@ -178,12 +184,9 @@ export const deleteMappingAsync = mapping => async dispatch => { try { await deleteMappingAJAX(mapping) dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: `Mapping deleted: ${mapping.id} ${mapping.scheme}`, - }) + publishNotification( + mappingDeletedNotification(mapping.id, mapping.scheme) + ) ) } catch (error) { dispatch(errorThrown(error)) @@ -240,14 +243,7 @@ export const updateUserAsync = ( provider: null, scheme: null, }) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: successMessage, - }) - ) + dispatch(publishNotification(updateUserSuccessNotification(successMessage))) // it's not necessary to syncUser again but it's useful for good // measure and for the clarity of insight in the redux story dispatch(syncUser(user, data)) @@ -266,10 +262,7 @@ export const deleteUserAsync = ( await deleteUserAJAX(user) dispatch( publishNotification( - 'success', - `${user.name} has been removed from ${isAbsoluteDelete - ? 'all organizations and deleted' - : 'the current organization'}` + userRemovedFromOrgNotification(user.name, isAbsoluteDelete) ) ) } catch (error) { @@ -323,12 +316,7 @@ export const deleteOrganizationAsync = organization => async dispatch => { try { await deleteOrganizationAJAX(organization) dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: `Organization deleted: ${organization.name}`, - }) + publishNotification(deleteOrgSuccessNotification(organization.name)) ) } catch (error) { dispatch(errorThrown(error)) diff --git a/ui/src/admin/actions/influxdb.js b/ui/src/admin/actions/influxdb.js index 553e52175b..4fe92bc17c 100644 --- a/ui/src/admin/actions/influxdb.js +++ b/ui/src/admin/actions/influxdb.js @@ -21,6 +21,13 @@ import {killQuery as killQueryProxy} from 'shared/apis/metaQuery' import {publishNotification} from 'shared/actions/notifications' import {errorThrown} from 'shared/actions/errors' +import {dbAdminNotifications} from 'shared/copy/notificationsCopy' +const { + createNotification, + updateNotification, + deleteNotification, +} = dbAdminNotifications + import {REVERT_STATE_DELAY} from 'shared/constants' import _ from 'lodash' @@ -276,17 +283,12 @@ export const loadDBsAndRPsAsync = url => async dispatch => { export const createUserAsync = (url, user) => async dispatch => { try { const {data} = await createUserAJAX(url, user) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'User created successfully', - }) - ) + dispatch(publishNotification(createNotification(true, 'user'))) dispatch(syncUser(user, data)) } catch (error) { - dispatch(errorThrown(error, `Failed to create user: ${error.data.message}`)) + dispatch( + errorThrown(error, createNotification(false, 'user', error.data.message)) + ) // undo optimistic update setTimeout(() => dispatch(deleteUser(user)), REVERT_STATE_DELAY) } @@ -295,17 +297,12 @@ export const createUserAsync = (url, user) => async dispatch => { export const createRoleAsync = (url, role) => async dispatch => { try { const {data} = await createRoleAJAX(url, role) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'Role created successfully', - }) - ) + dispatch(publishNotification(createNotification(true, 'role'))) dispatch(syncRole(role, data)) } catch (error) { - dispatch(errorThrown(error, `Failed to create role: ${error.data.message}`)) + dispatch( + errorThrown(error, createNotification(false, 'role', error.data.message)) + ) // undo optimistic update setTimeout(() => dispatch(deleteRole(role)), REVERT_STATE_DELAY) } @@ -315,17 +312,13 @@ export const createDatabaseAsync = (url, database) => async dispatch => { try { const {data} = await createDatabaseAJAX(url, database) dispatch(syncDatabase(database, data)) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'Database created successfully', - }) - ) + dispatch(publishNotification(createNotification(true, 'database'))) } catch (error) { dispatch( - errorThrown(error, `Failed to create database: ${error.data.message}`) + errorThrown( + error, + createNotification(false, 'database', error.data.message) + ) ) // undo optimistic update setTimeout(() => dispatch(removeDatabase(database)), REVERT_STATE_DELAY) @@ -341,20 +334,12 @@ export const createRetentionPolicyAsync = ( database.links.retentionPolicies, retentionPolicy ) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'Retention policy created successfully', - }) - ) + dispatch(publishNotification(createNotification(true, 'retention policy'))) dispatch(syncRetentionPolicy(database, retentionPolicy, data)) } catch (error) { dispatch( errorThrown( - error, - `Failed to create retention policy: ${error.data.message}` + createNotification(false, 'retention policy', error.data.message) ) ) // undo optimistic update @@ -374,20 +359,13 @@ export const updateRetentionPolicyAsync = ( dispatch(editRetentionPolicyRequested(database, oldRP, newRP)) const {data} = await updateRetentionPolicyAJAX(oldRP.links.self, newRP) dispatch(editRetentionPolicyCompleted(database, oldRP, data)) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'Retention policy updated successfully', - }) - ) + dispatch(publishNotification(updateNotification(true, 'retention policy'))) } catch (error) { dispatch(editRetentionPolicyFailed(database, oldRP)) dispatch( errorThrown( error, - `Failed to update retention policy: ${error.data.message}` + updateNotification(false, 'retention policy', error.data.message) ) ) } @@ -410,16 +388,14 @@ export const deleteRoleAsync = role => async dispatch => { dispatch(deleteRole(role)) try { await deleteRoleAJAX(role.links.self) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'Role deleted', - }) - ) + dispatch(publishNotification(deleteNotification(true, 'role', role.name))) } catch (error) { - dispatch(errorThrown(error, `Failed to delete role: ${error.data.message}`)) + dispatch( + errorThrown( + error, + deleteNotification(false, 'role', null, error.data.message) + ) + ) } } @@ -427,16 +403,14 @@ export const deleteUserAsync = user => async dispatch => { dispatch(deleteUser(user)) try { await deleteUserAJAX(user.links.self) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'User deleted', - }) - ) + dispatch(publishNotification(deleteNotification(true, 'user', user.name))) } catch (error) { - dispatch(errorThrown(error, `Failed to delete user: ${error.data.message}`)) + dispatch( + errorThrown( + error, + deleteNotification(false, 'user', null, error.data.message) + ) + ) } } @@ -445,16 +419,14 @@ export const deleteDatabaseAsync = database => async dispatch => { try { await deleteDatabaseAJAX(database.links.self) dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'Database deleted', - }) + publishNotification(deleteNotification(true, 'database', database.name)) ) } catch (error) { dispatch( - errorThrown(error, `Failed to delete database: ${error.data.message}`) + errorThrown( + error, + deleteNotification(false, 'database', null, error.data.message) + ) ) } } @@ -467,18 +439,15 @@ export const deleteRetentionPolicyAsync = ( try { await deleteRetentionPolicyAJAX(retentionPolicy.links.self) dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: `Retention policy ${retentionPolicy.name} deleted`, - }) + publishNotification( + deleteNotification(true, 'retention policy', retentionPolicy.name) + ) ) } catch (error) { dispatch( errorThrown( error, - `Failed to delete retentionPolicy: ${error.data.message}` + deleteNotification(false, 'retention policy', null, error.data.message) ) ) } @@ -491,17 +460,12 @@ export const updateRoleUsersAsync = (role, users) => async dispatch => { users, role.permissions ) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'Role users updated', - }) - ) + dispatch(publishNotification(updateNotification(true, 'role users'))) dispatch(syncRole(role, data)) } catch (error) { - dispatch(errorThrown(error, `Failed to update role: ${error.data.message}`)) + dispatch( + errorThrown(error, updateNotification(false, 'role', error.data.message)) + ) } } @@ -515,18 +479,11 @@ export const updateRolePermissionsAsync = ( role.users, permissions ) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'Role permissions updated', - }) - ) + dispatch(publishNotification(updateNotification(true, 'role permissions'))) dispatch(syncRole(role, data)) } catch (error) { dispatch( - errorThrown(error, `Failed to update role: ${error.data.message}`) + errorThrown(error, updateNotification(false, 'role', error.data.message)) ) } } @@ -537,18 +494,11 @@ export const updateUserPermissionsAsync = ( ) => async dispatch => { try { const {data} = await updateUserAJAX(user.links.self, {permissions}) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'User permissions updated', - }) - ) + dispatch(publishNotification(updateNotification(true, 'user permissions'))) dispatch(syncUser(user, data)) } catch (error) { dispatch( - errorThrown(error, `Failed to update user: ${error.data.message}`) + errorThrown(error, updateNotification(false, 'user', error.data.message)) ) } } @@ -556,18 +506,11 @@ export const updateUserPermissionsAsync = ( export const updateUserRolesAsync = (user, roles) => async dispatch => { try { const {data} = await updateUserAJAX(user.links.self, {roles}) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'User roles updated', - }) - ) + dispatch(publishNotification(updateNotification(true, 'user roles'))) dispatch(syncUser(user, data)) } catch (error) { dispatch( - errorThrown(error, `Failed to update user: ${error.data.message}`) + errorThrown(error, updateNotification(false, 'user', error.data.message)) ) } } @@ -575,18 +518,11 @@ export const updateUserRolesAsync = (user, roles) => async dispatch => { export const updateUserPasswordAsync = (user, password) => async dispatch => { try { const {data} = await updateUserAJAX(user.links.self, {password}) - dispatch( - publishNotification({ - type: 'success', - icon: 'checkmark', - duration: 5000, - message: 'User password updated', - }) - ) + dispatch(publishNotification(updateNotification(true, 'user password'))) dispatch(syncUser(user, data)) } catch (error) { dispatch( - errorThrown(error, `Failed to update user: ${error.data.message}`) + errorThrown(error, updateNotification(false, 'user', error.data.message)) ) } } diff --git a/ui/src/admin/components/chronograf/AllUsersTable.js b/ui/src/admin/components/chronograf/AllUsersTable.js index f392c20d0e..7c4dd9aeb4 100644 --- a/ui/src/admin/components/chronograf/AllUsersTable.js +++ b/ui/src/admin/components/chronograf/AllUsersTable.js @@ -16,6 +16,11 @@ const { colActions, } = ALL_USERS_TABLE +import { + userAddedToOrgMessage, + userRemovedFromOrgMessage, +} from 'shared/copy/notificationsCopy' + class AllUsersTable extends Component { constructor(props) { super(props) @@ -47,7 +52,7 @@ class AllUsersTable extends Component { this.props.onUpdateUserRoles( user, newRoles, - `${user.name} has been added to ${organization.name}` + userAddedToOrgMessage(user.name, organization.name) ) } @@ -61,7 +66,7 @@ class AllUsersTable extends Component { this.props.onUpdateUserRoles( user, newRoles, - `${user.name} has been removed from ${name}` + userRemovedFromOrgMessage(user.name, name) ) } diff --git a/ui/src/shared/copy/notificationsCopy.js b/ui/src/shared/copy/notificationsCopy.js new file mode 100644 index 0000000000..f59941c659 --- /dev/null +++ b/ui/src/shared/copy/notificationsCopy.js @@ -0,0 +1,102 @@ +// All copy for notifications should be stored here for easy editing and comparison + +// Text Formatting helper +const toTitleCase = str => { + return str.replace(/\w\S*/g, function(txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase() + }) +} + +// App Wide Notifications +export const enterPresentationModeNotification = { + type: 'primary', + icon: 'expand-b', + duration: 7500, + message: 'Press ESC to exit Presentation Mode.', +} + +// Chronograf Admin Notifications +export const mappingDeletedNotification = (id, scheme) => { + return { + type: 'success', + icon: 'checkmark', + duration: 5000, + message: `Mapping deleted: ${id} ${scheme}`, + } +} + +export const userAddedToOrgMessage = (user, organization) => { + return `${user} has been added to ${organization}` +} + +export const userRemovedFromOrgMessage = (user, organization) => { + return `${user} has been removed from ${organization}` +} + +export const userRemovedFromOrgNotification = (user, isAbsoluteDelete) => { + return { + type: 'success', + icon: 'checkmark', + duration: 5000, + message: `${user} has been removed from ${isAbsoluteDelete + ? 'all organizations and deleted' + : 'the current organization'}`, + } +} + +export const updateUserSuccessNotification = message => { + return { + type: 'success', + icon: 'checkmark', + duration: 5000, + message, + } +} + +export const deleteOrgSuccessNotification = orgName => { + return { + type: 'success', + icon: 'checkmark', + duration: 5000, + message: `Organization deleted: ${orgName}`, + } +} + +// InfluxDB Admin Notifications +const dbAdminCreate = (success, objectType, errorMessage) => { + return success + ? { + type: 'success', + icon: 'checkmark', + duration: 5000, + message: `${toTitleCase(objectType)} created successfully`, + } + : `Failed to create ${toTitleCase(objectType)}: ${errorMessage}` +} + +const dbAdminUpdate = (success, objectType, errorMessage) => { + return success + ? { + type: 'success', + icon: 'checkmark', + duration: 5000, + message: `${toTitleCase(objectType)} updated successfully`, + } + : `Failed to update ${toTitleCase(objectType)}: ${errorMessage}` +} + +const dbAdminDelete = (success, objectType, name, errorMessage) => { + return success + ? { + type: 'success', + icon: 'checkmark', + duration: 5000, + message: `${toTitleCase(objectType)} ${name} deleted successfully`, + } + : `Failed to delete ${toTitleCase(objectType)}: ${errorMessage}` +} +export const dbAdminNotifications = { + createNotification: dbAdminCreate, + updateNotification: dbAdminUpdate, + deleteNotification: dbAdminDelete, +} diff --git a/ui/src/shared/dispatchers/index.js b/ui/src/shared/dispatchers/index.js index 6d8fe0d647..679fc4ae1c 100644 --- a/ui/src/shared/dispatchers/index.js +++ b/ui/src/shared/dispatchers/index.js @@ -1,14 +1,8 @@ import {publishNotification} from 'shared/actions/notifications' import {delayEnablePresentationMode} from 'shared/actions/app' +import {enterPresentationModeNotification} from 'shared/copy/notificationsCopy' export const presentationButtonDispatcher = dispatch => () => { dispatch(delayEnablePresentationMode()) - dispatch( - publishNotification({ - type: 'primary', - icon: 'expand-b', - duration: 7500, - message: 'Press ESC to exit Presentation Mode.', - }) - ) + dispatch(publishNotification(enterPresentationModeNotification)) }