mirror of
				https://github.com/ohwgiles/laminar.git
				synced 2025-06-13 12:54:29 +00:00 
			
		
		
		
	resolves #23: In-browser notification
This implements web notifications on job completion. Opt-in by default, the preference is saved in js localStorage and can be toggled directly on any page
This commit is contained in:
		
							parent
							
								
									93b428529e
								
							
						
					
					
						commit
						3b0efcac9d
					
				| @ -25,6 +25,9 @@ | |||||||
|   a.navbar-btn.active { color: #fff; } |   a.navbar-btn.active { color: #fff; } | ||||||
|   a.navbar-btn:hover { color: #fff; text-decoration: none; } |   a.navbar-btn:hover { color: #fff; text-decoration: none; } | ||||||
|   a.navbar-btn:focus { color: #fff; } |   a.navbar-btn:focus { color: #fff; } | ||||||
|  |   .bell { margin: 8px 15px; color: #9d9d9d; } | ||||||
|  |   .bell:hover { text-decoration: none; color: #9d9d9d; cursor: pointer; } | ||||||
|  |   .bell.active { color: #333; } | ||||||
|   dt,dd { line-height: 2; } |   dt,dd { line-height: 2; } | ||||||
|   canvas { |   canvas { | ||||||
|    width: 100% !important; |    width: 100% !important; | ||||||
| @ -219,13 +222,12 @@ | |||||||
| 
 | 
 | ||||||
|  <div id="app"> |  <div id="app"> | ||||||
|   <nav class="navbar navbar-inverse"> |   <nav class="navbar navbar-inverse"> | ||||||
|    <div class="container-fluid"> |  | ||||||
|    <div> |    <div> | ||||||
|     <router-link to="/" class="navbar-brand"><img src="/icon.png">{{title}}</router-link> |     <router-link to="/" class="navbar-brand"><img src="/icon.png">{{title}}</router-link> | ||||||
|     <router-link to="/jobs" class="btn navbar-btn pull-right">Jobs</router-link> |     <router-link to="/jobs" class="btn navbar-btn pull-right">Jobs</router-link> | ||||||
|    </div> |    </div> | ||||||
|    </div> |  | ||||||
|   </nav> |   </nav> | ||||||
|  |   <a v-on:click="toggleNotifications(!notify)" v-show="supportsNotifications" class="bell pull-right" :class="{'active':notify}" :title="(notify?'Disable':'Enable')+' notifications'">🔔</a> | ||||||
|   <router-view></router-view> |   <router-view></router-view> | ||||||
|   <div v-show="!connected" id="popup-connecting"><img src="/spin.gif"> Connecting...</div> |   <div v-show="!connected" id="popup-connecting"><img src="/spin.gif"> Connecting...</div> | ||||||
|  </div> |  </div> | ||||||
|  | |||||||
| @ -32,9 +32,12 @@ const WebsocketHandler = function() { | |||||||
|         // at this point, the component must be defined
 |         // at this point, the component must be defined
 | ||||||
|         if (!this.comp) |         if (!this.comp) | ||||||
|           return console.error("Page component was undefined"); |           return console.error("Page component was undefined"); | ||||||
|         else if (typeof this.comp[msg.type] === 'function') |         else { | ||||||
|  |           this.comp.$root.showNotify(msg.type, msg.data); | ||||||
|  |           if(typeof this.comp[msg.type] === 'function') | ||||||
|             this.comp[msg.type](msg.data); |             this.comp[msg.type](msg.data); | ||||||
|         } |         } | ||||||
|  |       } | ||||||
|     }; |     }; | ||||||
|     ws.onclose = function(ev) { |     ws.onclose = function(ev) { | ||||||
|       // if this.comp isn't set, this connection has never been used
 |       // if this.comp isn't set, this connection has never been used
 | ||||||
| @ -513,7 +516,28 @@ new Vue({ | |||||||
|   el: '#app', |   el: '#app', | ||||||
|   data: { |   data: { | ||||||
|     title: '', // populated by status ws message
 |     title: '', // populated by status ws message
 | ||||||
|     connected: false |     connected: false, | ||||||
|  |     notify: 'localStorage' in window && localStorage.getItem('showNotifications') == 1 | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     supportsNotifications() { | ||||||
|  |       return 'Notification' in window && Notification.permission !== 'denied'; | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     toggleNotifications(en) { | ||||||
|  |       if(Notification.permission !== 'granted') | ||||||
|  |         Notification.requestPermission(p => this.notify = (p === 'granted')) | ||||||
|  |       else | ||||||
|  |         this.notify = en; | ||||||
|  |     }, | ||||||
|  |     showNotify(msg, data) { | ||||||
|  |       if(this.notify && msg === 'job_completed') | ||||||
|  |         new Notification(data.name + ' ' + '#' + data.number +' completed'); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     notify(e) { localStorage.setItem('showNotifications', e ? 1 : 0); } | ||||||
|   }, |   }, | ||||||
|   router: new VueRouter({ |   router: new VueRouter({ | ||||||
|     mode: 'history', |     mode: 'history', | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user