-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ui: Add a global notification component
plugins/notify is a new locally developed vue + vuetify + vuex plugin implementing a global notification service. * <Notifications /> displays notifications sent to the user. * Vue.$notify.{ success, info, warning, error } allow easy addition of messages from anywhere with access to the Vue object (often via `this` in a .vue component). * The 'notify' vuex module can be called directly to send notices from a vuex context. * Notifications stay on-screen until manually dismissed by default. * An optional timeout can be provided to automatically dismiss success and info notifications. This plugin is installed and the Notifications component has been added to the root App. Notifications are displayed using v-alert vutify components in a container attached to the bottom of the user's viewport. This commit also converts the AuditLogs view and its associated vuex store to use the new system rather than it's own error tracking and display code. Follow up commits should convert other views. Bug: T272185 Change-Id: I30e3aeb9bd7450d393ca48d7b511393f988a2cc8
- Loading branch information
Showing
15 changed files
with
565 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,4 @@ | |
/docs/htmlcov | ||
/node_modules/ | ||
/vue/dist/ | ||
/vue/dist-tests/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<template> | ||
<v-container id="notifications"> | ||
<v-row> | ||
<v-col cols="12"> | ||
<v-alert | ||
v-for="message in messages" | ||
:key="message.id" | ||
:type="message.type" | ||
:prominent="message.prominent" | ||
:dense="message.prominent" | ||
border="left" | ||
class="mx-auto" | ||
dismissible | ||
transition="fade-transition" | ||
:close-label="$t( 'message-close' )" | ||
@input="close( message )" | ||
> | ||
{{ message.message }} | ||
</v-alert> | ||
</v-col> | ||
</v-row> | ||
</v-container> | ||
</template> | ||
|
||
<script> | ||
import { mapState, mapMutations } from 'vuex'; | ||
export default { | ||
computed: { | ||
...mapState( 'notify', [ 'messages' ] ) | ||
}, | ||
methods: { | ||
...mapMutations( 'notify', [ 'onClearMessage' ] ), | ||
/** | ||
* Remove a message. | ||
* | ||
* @param {Object} payload - Message object | ||
* @param {string} payload.id = Message id | ||
*/ | ||
close( payload ) { | ||
this.onClearMessage( payload.id ); | ||
} | ||
} | ||
}; | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import module from './vuex'; | ||
import Notifications from './component'; | ||
|
||
export let $store; | ||
|
||
export function setStore( store ) { | ||
$store = store; | ||
} | ||
|
||
export const methods = { | ||
/** | ||
* Signal a successful action. | ||
* | ||
* @param {string} message - Content | ||
* @param {number} [timeout=0] - Time in milliseconds to display | ||
* @return {number} Message id | ||
*/ | ||
success( message, timeout = 0 ) { | ||
return $store.dispatch( 'notify/success', { message, timeout } ); | ||
}, | ||
|
||
/** | ||
* Present information to the user. | ||
* | ||
* @param {string} message - Content | ||
* @param {number} [timeout=0] - Time in milliseconds to display | ||
* @return {number} Message id | ||
*/ | ||
info( message, timeout = 0 ) { | ||
return $store.dispatch( 'notify/info', { message, timeout } ); | ||
}, | ||
|
||
/** | ||
* Raise a warning. | ||
* | ||
* @param {string} msg - Warning | ||
* @return {number} Message id | ||
*/ | ||
warning( msg ) { | ||
return $store.dispatch( 'notify/warning', msg ); | ||
}, | ||
|
||
/** | ||
* Signal an error. | ||
* | ||
* @param {string} msg - Error message | ||
* @return {number} Message id | ||
*/ | ||
error( msg ) { | ||
return $store.dispatch( 'notify/error', msg ); | ||
}, | ||
|
||
/** | ||
* Remove a notification. | ||
* | ||
* @param {number} messageId - Message id | ||
* @return {undefined} | ||
*/ | ||
clear( messageId ) { | ||
return $store.dispatch( 'notify/clearMessage', messageId ); | ||
} | ||
}; | ||
|
||
/** | ||
* Install this plugin. | ||
* | ||
* @param {Object} Vue - Vue instance installing plugin | ||
* @param {Object} options - Plugin options | ||
* @param {Object} options.store - Vuex store | ||
*/ | ||
export function install( Vue, options ) { | ||
if ( install.installed ) { | ||
return; | ||
} | ||
if ( !options.store ) { | ||
throw new Error( 'Required options.store Vuex instance missing.' ); | ||
} | ||
|
||
install.installed = true; | ||
setStore( options.store ); | ||
|
||
options.store.registerModule( 'notify', module ); | ||
Vue.component( 'Notifications', Notifications ); | ||
Vue.prototype.$notify = methods; | ||
} | ||
|
||
export default { | ||
install | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
'use strict'; | ||
import chai from 'chai'; | ||
import sinon from 'sinon'; | ||
|
||
chai.use( require( 'sinon-chai' ) ); | ||
const expect = chai.expect; | ||
/* eslint-disable no-unused-expressions */ | ||
|
||
import { setStore, methods, install } from './index'; | ||
|
||
let $store; | ||
|
||
describe( 'notify/index', () => { | ||
beforeEach( () => { | ||
$store = { dispatch: sinon.spy() }; | ||
setStore( $store ); | ||
} ); | ||
|
||
describe( 'methods', () => { | ||
it( 'success', () => { | ||
methods.success( 'success message' ); | ||
|
||
expect( $store.dispatch ).to.have.been.calledOnce; | ||
expect( $store.dispatch ).to.have.been.calledWithExactly( | ||
'notify/success', { message: 'success message', timeout: 0 } | ||
); | ||
} ); | ||
|
||
it( 'info', () => { | ||
methods.info( 'info message' ); | ||
|
||
expect( $store.dispatch ).to.have.been.calledOnce; | ||
expect( $store.dispatch ).to.have.been.calledWithExactly( | ||
'notify/info', { message: 'info message', timeout: 0 } | ||
); | ||
} ); | ||
|
||
it( 'warning', () => { | ||
methods.warning( 'warning message' ); | ||
|
||
expect( $store.dispatch ).to.have.been.calledOnce; | ||
expect( $store.dispatch ).to.have.been.calledWithExactly( | ||
'notify/warning', 'warning message' | ||
); | ||
} ); | ||
|
||
it( 'error', () => { | ||
methods.error( 'error message' ); | ||
|
||
expect( $store.dispatch ).to.have.been.calledOnce; | ||
expect( $store.dispatch ).to.have.been.calledWithExactly( | ||
'notify/error', 'error message' | ||
); | ||
} ); | ||
|
||
it( 'clear', () => { | ||
methods.clear( 31337 ); | ||
|
||
expect( $store.dispatch ).to.have.been.calledOnce; | ||
expect( $store.dispatch ).to.have.been.calledWithExactly( | ||
'notify/clearMessage', 31337 | ||
); | ||
} ); | ||
} ); | ||
|
||
describe( 'install', () => { | ||
it( 'happy path', () => { | ||
const vue = { component: sinon.spy(), prototype: sinon.spy() }; | ||
const store = { registerModule: sinon.spy() }; | ||
|
||
install( vue, { store: store } ); | ||
|
||
expect( install.installed ).to.be.a( 'boolean' ).that.is.true; | ||
expect( store.registerModule ).to.have.been.calledOnce; | ||
expect( vue.component ).to.have.been.calledOnce; | ||
expect( vue.prototype.$notify ).to.be.an( 'object' ); | ||
} ); | ||
} ); | ||
|
||
} ); |
Oops, something went wrong.