mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-10-31 15:53:33 +00:00 
			
		
		
		
	Shell for UI pages, some placeholder dashboard stats
This commit is contained in:
		
							
								
								
									
										25
									
								
								src/backend/internal/report.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/backend/internal/report.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const _     = require('lodash'); | ||||||
|  | const error = require('../lib/error'); | ||||||
|  |  | ||||||
|  | const internalReport = { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param  {Access}   access | ||||||
|  |      * @return {Promise} | ||||||
|  |      */ | ||||||
|  |     getHostsReport: access => { | ||||||
|  |         return access.can('reports:hosts', 1) | ||||||
|  |             .then(() => { | ||||||
|  |                 return { | ||||||
|  |                     proxy:       12, | ||||||
|  |                     redirection: 2, | ||||||
|  |                     stream:      1, | ||||||
|  |                     '404':       0 | ||||||
|  |                 }; | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | module.exports = internalReport; | ||||||
							
								
								
									
										7
									
								
								src/backend/lib/access/reports-hosts.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/backend/lib/access/reports-hosts.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |   "anyOf": [ | ||||||
|  |     { | ||||||
|  |       "$ref": "roles#/definitions/user" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
| @@ -2,6 +2,7 @@ | |||||||
|  |  | ||||||
| const express = require('express'); | const express = require('express'); | ||||||
| const pjson   = require('../../../../package.json'); | const pjson   = require('../../../../package.json'); | ||||||
|  | const error   = require('../../lib/error'); | ||||||
|  |  | ||||||
| let router = express.Router({ | let router = express.Router({ | ||||||
|     caseSensitive: true, |     caseSensitive: true, | ||||||
| @@ -28,5 +29,16 @@ router.get('/', (req, res/*, next*/) => { | |||||||
|  |  | ||||||
| router.use('/tokens', require('./tokens')); | router.use('/tokens', require('./tokens')); | ||||||
| router.use('/users', require('./users')); | router.use('/users', require('./users')); | ||||||
|  | router.use('/reports', require('./reports')); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * API 404 for all other routes | ||||||
|  |  * | ||||||
|  |  * ALL /api/* | ||||||
|  |  */ | ||||||
|  | router.all(/(.+)/, function (req, res, next) { | ||||||
|  |     req.params.page = req.params['0']; | ||||||
|  |     next(new error.ItemNotFoundError(req.params.page)); | ||||||
|  | }); | ||||||
|  |  | ||||||
| module.exports = router; | module.exports = router; | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								src/backend/routes/api/reports.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/backend/routes/api/reports.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const express        = require('express'); | ||||||
|  | const jwtdecode      = require('../../lib/express/jwt-decode'); | ||||||
|  | const internalReport = require('../../internal/report'); | ||||||
|  |  | ||||||
|  | let router = express.Router({ | ||||||
|  |     caseSensitive: true, | ||||||
|  |     strict:        true, | ||||||
|  |     mergeParams:   true | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | router | ||||||
|  |     .route('/hosts') | ||||||
|  |     .options((req, res) => { | ||||||
|  |         res.sendStatus(204); | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * GET /reports/hosts | ||||||
|  |      */ | ||||||
|  |     .get(jwtdecode(), (req, res, next) => { | ||||||
|  |         internalReport.getHostsReport(res.locals.access) | ||||||
|  |             .then(data => { | ||||||
|  |                 res.status(200) | ||||||
|  |                     .send(data); | ||||||
|  |             }) | ||||||
|  |             .catch(next); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | module.exports = router; | ||||||
| @@ -225,5 +225,15 @@ module.exports = { | |||||||
|         loginAs: function (id) { |         loginAs: function (id) { | ||||||
|             return fetch('post', 'users/' + id + '/login'); |             return fetch('post', 'users/' + id + '/login'); | ||||||
|         } |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     Reports: { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * @returns {Promise} | ||||||
|  |          */ | ||||||
|  |         getHostStats: function () { | ||||||
|  |             return fetch('get', 'reports/hosts'); | ||||||
|  |         }, | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -94,6 +94,66 @@ module.exports = { | |||||||
|         }); |         }); | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Nginx Proxy Hosts | ||||||
|  |      */ | ||||||
|  |     showNginxProxy: function () { | ||||||
|  |         let controller = this; | ||||||
|  |  | ||||||
|  |         require(['./main', './nginx/proxy/main'], (App, View) => { | ||||||
|  |             controller.navigate('/nginx/proxy'); | ||||||
|  |             App.UI.showAppContent(new View()); | ||||||
|  |         }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Nginx Redirection Hosts | ||||||
|  |      */ | ||||||
|  |     showNginxRedirection: function () { | ||||||
|  |         let controller = this; | ||||||
|  |  | ||||||
|  |         require(['./main', './nginx/redirection/main'], (App, View) => { | ||||||
|  |             controller.navigate('/nginx/redirection'); | ||||||
|  |             App.UI.showAppContent(new View()); | ||||||
|  |         }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Nginx Stream Hosts | ||||||
|  |      */ | ||||||
|  |     showNginxStream: function () { | ||||||
|  |         let controller = this; | ||||||
|  |  | ||||||
|  |         require(['./main', './nginx/stream/main'], (App, View) => { | ||||||
|  |             controller.navigate('/nginx/stream'); | ||||||
|  |             App.UI.showAppContent(new View()); | ||||||
|  |         }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Nginx 404 Hosts | ||||||
|  |      */ | ||||||
|  |     showNginx404: function () { | ||||||
|  |         let controller = this; | ||||||
|  |  | ||||||
|  |         require(['./main', './nginx/404/main'], (App, View) => { | ||||||
|  |             controller.navigate('/nginx/404'); | ||||||
|  |             App.UI.showAppContent(new View()); | ||||||
|  |         }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Nginx Access | ||||||
|  |      */ | ||||||
|  |     showNginxAccess: function () { | ||||||
|  |         let controller = this; | ||||||
|  |  | ||||||
|  |         require(['./main', './nginx/access/main'], (App, View) => { | ||||||
|  |             controller.navigate('/nginx/access'); | ||||||
|  |             App.UI.showAppContent(new View()); | ||||||
|  |         }); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Dashboard |      * Dashboard | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -1 +1,57 @@ | |||||||
| Hi | <div class="page-header"> | ||||||
|  |     <h1 class="page-title">Hi <%- getUserName() %></h1> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <div class="row"> | ||||||
|  |     <div class="col-sm-6 col-lg-3"> | ||||||
|  |         <div class="card p-3"> | ||||||
|  |             <div class="d-flex align-items-center"> | ||||||
|  |                     <span class="stamp stamp-md bg-green mr-3"> | ||||||
|  |                       <i class="fe fe-zap"></i> | ||||||
|  |                     </span> | ||||||
|  |                 <div> | ||||||
|  |                     <h4 class="m-0"><a href="/nginx/proxy"><%- getHostStat('proxy') %> <small>Proxy Hosts</small></a></h4> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <div class="col-sm-6 col-lg-3"> | ||||||
|  |         <div class="card p-3"> | ||||||
|  |             <div class="d-flex align-items-center"> | ||||||
|  |                     <span class="stamp stamp-md bg-yellow mr-3"> | ||||||
|  |                       <i class="fe fe-shuffle"></i> | ||||||
|  |                     </span> | ||||||
|  |                 <div> | ||||||
|  |                     <h4 class="m-0"><a href="/nginx/redirection"><%- getHostStat('redirection') %> <small>Redirection Hosts</small></a></h4> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <div class="col-sm-6 col-lg-3"> | ||||||
|  |         <div class="card p-3"> | ||||||
|  |             <div class="d-flex align-items-center"> | ||||||
|  |                     <span class="stamp stamp-md bg-blue mr-3"> | ||||||
|  |                       <i class="fe fe-radio"></i> | ||||||
|  |                     </span> | ||||||
|  |                 <div> | ||||||
|  |                     <h4 class="m-0"><a href="/nginx/stream"><%- getHostStat('stream') %> <small> Streams</small></a></h4> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <div class="col-sm-6 col-lg-3"> | ||||||
|  |         <div class="card p-3"> | ||||||
|  |             <div class="d-flex align-items-center"> | ||||||
|  |                     <span class="stamp stamp-md bg-red mr-3"> | ||||||
|  |                       <i class="fe fe-zap-off"></i> | ||||||
|  |                     </span> | ||||||
|  |                 <div> | ||||||
|  |                     <h4 class="m-0"><a href="/nginx/404"><%- getHostStat('404') %> <small>404 Hosts</small></a></h4> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
| @@ -1,10 +1,61 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
| const Mn         = require('backbone.marionette'); | const Mn         = require('backbone.marionette'); | ||||||
|  | const Cache      = require('../cache'); | ||||||
|  | const Controller = require('../controller'); | ||||||
|  | const Api        = require('../api'); | ||||||
|  | const Helpers    = require('../../lib/helpers'); | ||||||
| const template   = require('./main.ejs'); | const template   = require('./main.ejs'); | ||||||
|  |  | ||||||
| module.exports = Mn.View.extend({ | module.exports = Mn.View.extend({ | ||||||
|     template: template, |     template: template, | ||||||
|     id:       'dashboard' |     id:       'dashboard', | ||||||
| }); |  | ||||||
|  |  | ||||||
|  |     stats: {}, | ||||||
|  |  | ||||||
|  |     ui: { | ||||||
|  |         links: 'a' | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     events: { | ||||||
|  |         'click @ui.links': function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             Controller.navigate($(e.currentTarget).attr('href'), true); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     templateContext: function () { | ||||||
|  |         let view = this; | ||||||
|  |  | ||||||
|  |         return { | ||||||
|  |             getUserName: function () { | ||||||
|  |                 return Cache.User.get('nickname') || Cache.User.get('name'); | ||||||
|  |             }, | ||||||
|  |  | ||||||
|  |             getHostStat: function (type) { | ||||||
|  |                 if (view.stats && typeof view.stats.hosts !== 'undefined' && typeof view.stats.hosts[type] !== 'undefined') { | ||||||
|  |                     return Helpers.niceNumber(view.stats.hosts[type]); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return '-'; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onRender: function () { | ||||||
|  |         let view = this; | ||||||
|  |  | ||||||
|  |         if (typeof view.stats.hosts === 'undefined') { | ||||||
|  |             Api.Reports.getHostStats() | ||||||
|  |                 .then(response => { | ||||||
|  |                     if (!view.isDestroyed()) { | ||||||
|  |                         view.stats.hosts = response; | ||||||
|  |                         view.render(); | ||||||
|  |                     } | ||||||
|  |                 }) | ||||||
|  |                 .catch(err => { | ||||||
|  |                     console.log(err); | ||||||
|  |                 }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }); | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								src/frontend/js/app/nginx/404/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/frontend/js/app/nginx/404/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | 404 | ||||||
							
								
								
									
										9
									
								
								src/frontend/js/app/nginx/404/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/frontend/js/app/nginx/404/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn       = require('backbone.marionette'); | ||||||
|  | const template = require('./main.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template: template, | ||||||
|  |     id:       'nginx-404' | ||||||
|  | }); | ||||||
							
								
								
									
										1
									
								
								src/frontend/js/app/nginx/access/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/frontend/js/app/nginx/access/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | access | ||||||
							
								
								
									
										9
									
								
								src/frontend/js/app/nginx/access/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/frontend/js/app/nginx/access/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn       = require('backbone.marionette'); | ||||||
|  | const template = require('./main.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template: template, | ||||||
|  |     id:       'nginx-access' | ||||||
|  | }); | ||||||
							
								
								
									
										1
									
								
								src/frontend/js/app/nginx/proxy/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/frontend/js/app/nginx/proxy/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | proxy | ||||||
							
								
								
									
										9
									
								
								src/frontend/js/app/nginx/proxy/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/frontend/js/app/nginx/proxy/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn       = require('backbone.marionette'); | ||||||
|  | const template = require('./main.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template: template, | ||||||
|  |     id:       'nginx-proxy' | ||||||
|  | }); | ||||||
							
								
								
									
										1
									
								
								src/frontend/js/app/nginx/redirection/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/frontend/js/app/nginx/redirection/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | redirection | ||||||
							
								
								
									
										9
									
								
								src/frontend/js/app/nginx/redirection/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/frontend/js/app/nginx/redirection/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn       = require('backbone.marionette'); | ||||||
|  | const template = require('./main.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template: template, | ||||||
|  |     id:       'nginx-redirection' | ||||||
|  | }); | ||||||
							
								
								
									
										1
									
								
								src/frontend/js/app/nginx/stream/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/frontend/js/app/nginx/stream/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | stream | ||||||
							
								
								
									
										9
									
								
								src/frontend/js/app/nginx/stream/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/frontend/js/app/nginx/stream/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const Mn       = require('backbone.marionette'); | ||||||
|  | const template = require('./main.ejs'); | ||||||
|  |  | ||||||
|  | module.exports = Mn.View.extend({ | ||||||
|  |     template: template, | ||||||
|  |     id:       'nginx-stream' | ||||||
|  | }); | ||||||
| @@ -8,6 +8,11 @@ module.exports = Mn.AppRouter.extend({ | |||||||
|         users:               'showUsers', |         users:               'showUsers', | ||||||
|         profile:             'showProfile', |         profile:             'showProfile', | ||||||
|         logout:              'logout', |         logout:              'logout', | ||||||
|  |         'nginx/proxy':       'showNginxProxy', | ||||||
|  |         'nginx/redirection': 'showNginxRedirection', | ||||||
|  |         'nginx/404':         'showNginx404', | ||||||
|  |         'nginx/stream':      'showNginxStream', | ||||||
|  |         'nginx/access':      'showNginxAccess', | ||||||
|         '*default':          'showDashboard' |         '*default':          'showDashboard' | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,6 +2,9 @@ | |||||||
|     <div class="row align-items-center"> |     <div class="row align-items-center"> | ||||||
|         <div class="col-lg order-lg-first"> |         <div class="col-lg order-lg-first"> | ||||||
|             <ul class="nav nav-tabs border-0 flex-column flex-lg-row"> |             <ul class="nav nav-tabs border-0 flex-column flex-lg-row"> | ||||||
|  |                 <li class="nav-item"> | ||||||
|  |                     <a href="/" class="nav-link"><i class="fe fe-home"></i> Dashboard</a> | ||||||
|  |                 </li> | ||||||
|                 <li class="nav-item dropdown"> |                 <li class="nav-item dropdown"> | ||||||
|                     <a href="#" class="nav-link" data-toggle="dropdown"><i class="fe fe-monitor"></i> Hosts</a> |                     <a href="#" class="nav-link" data-toggle="dropdown"><i class="fe fe-monitor"></i> Hosts</a> | ||||||
|                     <div class="dropdown-menu dropdown-menu-arrow"> |                     <div class="dropdown-menu dropdown-menu-arrow"> | ||||||
|   | |||||||
| @@ -12,22 +12,13 @@ module.exports = Mn.View.extend({ | |||||||
|     template:  template, |     template:  template, | ||||||
|  |  | ||||||
|     ui: { |     ui: { | ||||||
|         link: 'a' |         links: 'a' | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     events: { |     events: { | ||||||
|         'click @ui.link': function (e) { |         'click @ui.links': function (e) { | ||||||
|             e.preventDefault(); |             e.preventDefault(); | ||||||
|             let href = $(e.currentTarget).attr('href'); |             Controller.navigate($(e.currentTarget).attr('href'), true); | ||||||
|  |  | ||||||
|             switch (href) { |  | ||||||
|                 case '/': |  | ||||||
|                     Controller.showDashboard(); |  | ||||||
|                     break; |  | ||||||
|                 case '/users': |  | ||||||
|                     Controller.showUsers(); |  | ||||||
|                     break; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ | |||||||
|                     <div class="form-group"> |                     <div class="form-group"> | ||||||
|                         <label class="form-label">Email <span class="form-required">*</span></label> |                         <label class="form-label">Email <span class="form-required">*</span></label> | ||||||
|                         <input name="email" type="email" class="form-control" placeholder="joe@example.com" value="<%- email %>" required> |                         <input name="email" type="email" class="form-control" placeholder="joe@example.com" value="<%- email %>" required> | ||||||
|  |                         <div class="invalid-feedback secret-error"></div> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|                 <% if (!isSelf()) { %> |                 <% if (!isSelf()) { %> | ||||||
|   | |||||||
| @@ -18,13 +18,15 @@ module.exports = Mn.View.extend({ | |||||||
|         form:    'form', |         form:    'form', | ||||||
|         buttons: '.modal-footer button', |         buttons: '.modal-footer button', | ||||||
|         cancel:  'button.cancel', |         cancel:  'button.cancel', | ||||||
|         save:    'button.save' |         save:    'button.save', | ||||||
|  |         error:   '.secret-error' | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     events: { |     events: { | ||||||
|  |  | ||||||
|         'click @ui.save': function (e) { |         'click @ui.save': function (e) { | ||||||
|             e.preventDefault(); |             e.preventDefault(); | ||||||
|  |             this.ui.error.hide(); | ||||||
|             let view = this; |             let view = this; | ||||||
|             let data = this.ui.form.serializeJSON(); |             let data = this.ui.form.serializeJSON(); | ||||||
|  |  | ||||||
| @@ -59,7 +61,7 @@ module.exports = Mn.View.extend({ | |||||||
|                     App.UI.closeModal(); |                     App.UI.closeModal(); | ||||||
|                 }) |                 }) | ||||||
|                 .catch(err => { |                 .catch(err => { | ||||||
|                     alert(err.message); |                     this.ui.error.text(err.message).show(); | ||||||
|                     this.ui.buttons.prop('disabled', false).removeClass('btn-disabled'); |                     this.ui.buttons.prop('disabled', false).removeClass('btn-disabled'); | ||||||
|                 }); |                 }); | ||||||
|         } |         } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user