mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-10-31 07:43:33 +00:00 
			
		
		
		
	Frontend user list and modal dialog fixes
This commit is contained in:
		| @@ -163,17 +163,22 @@ module.exports = { | ||||
|         }, | ||||
|  | ||||
|         /** | ||||
|          * @param   {Integer}  [offset] | ||||
|          * @param   {Integer}  [limit] | ||||
|          * @param   {String}   [sort] | ||||
|          * @param   {Array}    [expand] | ||||
|          * @param   {String}   [query] | ||||
|          * @returns {Promise} | ||||
|          */ | ||||
|         getAll: function (offset, limit, sort, expand, query) { | ||||
|             return fetch('get', 'users?offset=' + (offset ? offset : 0) + '&limit=' + (limit ? limit : 20) + (sort ? '&sort=' + sort : '') + | ||||
|                 (typeof expand === 'object' && expand !== null && expand.length ? '&expand=' + makeExpansionString(expand) : '') + | ||||
|                 (typeof query === 'string' ? '&query=' + query : '')); | ||||
|         getAll: function (expand, query) { | ||||
|             let params = []; | ||||
|  | ||||
|             if (typeof expand === 'object' && expand !== null && expand.length) { | ||||
|                 params.push('expand=' + makeExpansionString(expand)); | ||||
|             } | ||||
|  | ||||
|             if (typeof query === 'string') { | ||||
|                 params.push('query=' + query); | ||||
|             } | ||||
|  | ||||
|             return fetch('get', 'users' + (params.length ? '?' + params.join('&') : '')); | ||||
|         }, | ||||
|  | ||||
|         /** | ||||
|   | ||||
| @@ -26,34 +26,30 @@ module.exports = { | ||||
|  | ||||
|     /** | ||||
|      * Users | ||||
|      * | ||||
|      * @param {Number}  [offset] | ||||
|      * @param {Number}  [limit] | ||||
|      * @param {String}  [sort] | ||||
|      */ | ||||
|     showUsers: function (offset, limit, sort) { | ||||
|         /* | ||||
|     showUsers: function () { | ||||
|         let controller = this; | ||||
|         if (Cache.User.isAdmin()) { | ||||
|             require(['./main', './users/main'], (App, View) => { | ||||
|                 controller.navigate('/users'); | ||||
|                 App.UI.showMainLoading(); | ||||
|                 let view = new View({ | ||||
|                     sort:   (typeof sort !== 'undefined' && sort ? sort : Cache.Session.Users.sort), | ||||
|                     offset: (typeof offset !== 'undefined' ? offset : Cache.Session.Users.offset), | ||||
|                     limit:  (typeof limit !== 'undefined' && limit ? limit : Cache.Session.Users.limit) | ||||
|                 }); | ||||
|  | ||||
|                 view.on('loaded', function () { | ||||
|                     App.UI.hideMainLoading(); | ||||
|                 }); | ||||
|  | ||||
|                 App.UI.showAppContent(view); | ||||
|                 App.UI.showAppContent(new View()); | ||||
|             }); | ||||
|         } else { | ||||
|             this.showRules(); | ||||
|             this.showDashboard(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|      * User Form | ||||
|      * | ||||
|      * @param model | ||||
|      */ | ||||
|     showUserForm: function (model) { | ||||
|         if (Cache.User.isAdmin()) { | ||||
|             require(['./main', './user/form'], function (App, View) { | ||||
|                 App.UI.showModalDialog(new View({model: model})); | ||||
|             }); | ||||
|         } | ||||
|         */ | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -12,13 +12,17 @@ const UI         = require('./ui/main'); | ||||
|  | ||||
| const App = Mn.Application.extend({ | ||||
|  | ||||
|     region:     '#app', | ||||
|     Cache:      Cache, | ||||
|     Api:        Api, | ||||
|     UI:         null, | ||||
|     Controller: Controller, | ||||
|     version:    null, | ||||
|  | ||||
|     region: { | ||||
|         el:             '#app', | ||||
|         replaceElement: true | ||||
|     }, | ||||
|  | ||||
|     onStart: function (app, options) { | ||||
|         console.log('Welcome to Nginx Proxy Manager'); | ||||
|  | ||||
|   | ||||
| @@ -9,6 +9,6 @@ | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="col-12 col-lg-auto mt-3 mt-lg-0 text-center"> | ||||
|         v<%- getVersion() %> © 2018 <a href="https://jc21.com?utm_source=docker-registry-ui" target="_blank">jc21.com</a>. Theme by <a href="https://github.com/tabler/tabler?utm_source=docker-registry-ui" target="_blank">Tabler</a> | ||||
|         v<%- getVersion() %> © 2018 <a href="https://jc21.com?utm_source=nginx-proxy-manager" target="_blank">jc21.com</a>. Theme by <a href="https://tabler.github.io/?utm_source=nginx-proxy-manager" target="_blank">Tabler</a> | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <div class="container"> | ||||
|     <div class="d-flex"> | ||||
|         <a class="navbar-brand" href="/"> | ||||
|             <img src="/images/favicons/favicon-32x32.png" border="0">   Docker Registry | ||||
|             <img src="/images/favicons/favicon-32x32.png" border="0">   Nginx Proxy Manager | ||||
|         </a> | ||||
|  | ||||
|         <div class="d-flex order-lg-2 ml-auto"> | ||||
| @@ -9,7 +9,7 @@ | ||||
|                 <a href="#" class="nav-link pr-0 leading-none" data-toggle="dropdown"> | ||||
|                     <span class="avatar" style="background-image: url(<%- getUserField('avatar', '/images/default-avatar.jpg') %>)"></span> | ||||
|                     <span class="ml-2 d-none d-lg-block"> | ||||
|                       <span class="text-default"><%- getUserField('name', 'Unknown User') %></span> | ||||
|                       <span class="text-default"><%- getUserField('nickname', null) || getUserField('name', 'Unknown User') %></span> | ||||
|                       <small class="text-muted d-block mt-1"><%- getRole() %></small> | ||||
|                     </span> | ||||
|                 </a> | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| <div class="page-main"> | ||||
|  | ||||
|     <div class="header" id="header"> | ||||
|         <!-- Header View --> | ||||
|     </div> | ||||
| @@ -15,4 +14,6 @@ | ||||
|  | ||||
| <footer class="footer"> | ||||
|     <!-- Footer View --> | ||||
| </footer> | ||||
| </footer> | ||||
|  | ||||
| <div class="modal fade" id="modal-dialog" tabindex="-1" role="dialog" aria-hidden="true"></div> | ||||
|   | ||||
| @@ -8,8 +8,16 @@ const FooterView = require('./footer/main'); | ||||
| const Cache      = require('../cache'); | ||||
|  | ||||
| module.exports = Mn.View.extend({ | ||||
|     className: 'page', | ||||
|     template:  template, | ||||
|     id:          'app', | ||||
|     className:   'page', | ||||
|     template:    template, | ||||
|     modal_setup: false, | ||||
|  | ||||
|     modal: null, | ||||
|  | ||||
|     ui: { | ||||
|         modal: '#modal-dialog' | ||||
|     }, | ||||
|  | ||||
|     regions: { | ||||
|         header_region:      { | ||||
| @@ -21,13 +29,60 @@ module.exports = Mn.View.extend({ | ||||
|             replaceElement: true | ||||
|         }, | ||||
|         footer_region:      '.footer', | ||||
|         app_content_region: '#app-content' | ||||
|         app_content_region: '#app-content', | ||||
|         modal_region:       '#modal-dialog' | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|      * @param {Object}  view | ||||
|      */ | ||||
|     showAppContent: function (view) { | ||||
|         this.showChildView('app_content_region', view); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|      * @param {Object}    view | ||||
|      * @param {Function}  [show_callback] | ||||
|      * @param {Function}  [shown_callback] | ||||
|      */ | ||||
|     showModalDialog: function (view, show_callback, shown_callback) { | ||||
|         this.showChildView('modal_region', view); | ||||
|         let modal = this.getRegion('modal_region').$el.modal('show'); | ||||
|  | ||||
|         modal.on('hidden.bs.modal', function (/*e*/) { | ||||
|             if (show_callback) { | ||||
|                 modal.off('show.bs.modal', show_callback); | ||||
|             } | ||||
|  | ||||
|             if (shown_callback) { | ||||
|                 modal.off('shown.bs.modal', shown_callback); | ||||
|             } | ||||
|  | ||||
|             modal.off('hidden.bs.modal'); | ||||
|             view.destroy(); | ||||
|         }); | ||||
|  | ||||
|         if (show_callback) { | ||||
|             modal.on('show.bs.modal', show_callback); | ||||
|         } | ||||
|  | ||||
|         if (shown_callback) { | ||||
|             modal.on('shown.bs.modal', shown_callback); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|      * | ||||
|      * @param {Function}  [hidden_callback] | ||||
|      */ | ||||
|     closeModal: function (hidden_callback) { | ||||
|         let modal = this.getRegion('modal_region').$el.modal('hide'); | ||||
|  | ||||
|         if (hidden_callback) { | ||||
|             modal.on('hidden.bs.modal', hidden_callback); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     onRender: function () { | ||||
|         this.showChildView('header_region', new HeaderView({ | ||||
|             model: Cache.User | ||||
| @@ -40,5 +95,6 @@ module.exports = Mn.View.extend({ | ||||
|     reset: function () { | ||||
|         this.getRegion('header_region').reset(); | ||||
|         this.getRegion('footer_region').reset(); | ||||
|         this.getRegion('modal_region').reset(); | ||||
|     } | ||||
| }); | ||||
|   | ||||
| @@ -3,10 +3,15 @@ | ||||
|         <div class="col-lg order-lg-first"> | ||||
|             <ul class="nav nav-tabs border-0 flex-column flex-lg-row"> | ||||
|                 <li class="nav-item"> | ||||
|                     <a href="../index.html" class="nav-link"><i class="fe fe-home"></i> Home</a> | ||||
|                     <a href="/" class="nav-link"><i class="fe fe-home"></i> Home</a> | ||||
|                 </li> | ||||
|                 <% if (showUsers()) { %> | ||||
|                 <li class="nav-item"> | ||||
|                     <a href="javascript:void(0)" class="nav-link" data-toggle="dropdown"><i class="fe fe-box"></i> Interface</a> | ||||
|                     <a href="/users" class="nav-link"><i class="fe fe-users"></i> Users</a> | ||||
|                 </li> | ||||
|                 <% } %> | ||||
|                 <li class="nav-item"> | ||||
|                     <a href="#" class="nav-link" data-toggle="dropdown"><i class="fe fe-box"></i> Interface</a> | ||||
|                     <div class="dropdown-menu dropdown-menu-arrow"> | ||||
|                         <a href="../cards.html" class="dropdown-item ">Cards design</a> | ||||
|                         <a href="../charts.html" class="dropdown-item ">Charts</a> | ||||
| @@ -14,7 +19,7 @@ | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 <li class="nav-item dropdown"> | ||||
|                     <a href="javascript:void(0)" class="nav-link" data-toggle="dropdown"><i class="fe fe-calendar"></i> Components</a> | ||||
|                     <a href="#" class="nav-link" data-toggle="dropdown"><i class="fe fe-calendar"></i> Components</a> | ||||
|                     <div class="dropdown-menu dropdown-menu-arrow"> | ||||
|                         <a href="../maps.html" class="dropdown-item ">Maps</a> | ||||
|                         <a href="../icons.html" class="dropdown-item ">Icons</a> | ||||
| @@ -24,7 +29,7 @@ | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 <li class="nav-item dropdown"> | ||||
|                     <a href="javascript:void(0)" class="nav-link" data-toggle="dropdown"><i class="fe fe-file"></i> Pages</a> | ||||
|                     <a href="#" class="nav-link" data-toggle="dropdown"><i class="fe fe-file"></i> Pages</a> | ||||
|                     <div class="dropdown-menu dropdown-menu-arrow"> | ||||
|                         <a href="../profile.html" class="dropdown-item ">Profile</a> | ||||
|                         <a href="../login.html" class="dropdown-item ">Login</a> | ||||
|   | ||||
| @@ -1,10 +1,39 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const Mn       = require('backbone.marionette'); | ||||
| const template = require('./main.ejs'); | ||||
| const $          = require('jquery'); | ||||
| const Mn         = require('backbone.marionette'); | ||||
| const Controller = require('../../controller'); | ||||
| const Cache      = require('../../cache'); | ||||
| const template   = require('./main.ejs'); | ||||
|  | ||||
| module.exports = Mn.View.extend({ | ||||
|     id:        'menu', | ||||
|     className: 'header collapse d-lg-flex p-0', | ||||
|     template:  template | ||||
|     template:  template, | ||||
|  | ||||
|     ui: { | ||||
|         link: 'a' | ||||
|     }, | ||||
|  | ||||
|     events: { | ||||
|         'click @ui.link': function (e) { | ||||
|             e.preventDefault(); | ||||
|             let href = $(e.currentTarget).attr('href'); | ||||
|  | ||||
|             switch (href) { | ||||
|                 case '/': | ||||
|                     Controller.showDashboard(); | ||||
|                     break; | ||||
|                 case '/users': | ||||
|                     Controller.showUsers(); | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     templateContext: { | ||||
|         showUsers: function () { | ||||
|             return Cache.User.isAdmin(); | ||||
|         } | ||||
|     } | ||||
| }); | ||||
|   | ||||
							
								
								
									
										53
									
								
								src/frontend/js/app/user/form.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/frontend/js/app/user/form.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| <div class="modal-content"> | ||||
|     <div class="modal-header"> | ||||
|         <h5 class="modal-title"><% if (typeof id !== 'undefined') { %>Edit<% } else { %>New<% } %> User</h5> | ||||
|         <button type="button" class="close cancel" aria-label="Close" data-dismiss="modal"> </button> | ||||
|     </div> | ||||
|     <div class="modal-body"> | ||||
|         <form> | ||||
|             <div class="row"> | ||||
|                 <div class="col-sm-6 col-md-6"> | ||||
|                     <div class="form-group"> | ||||
|                         <label class="form-label">Full Name <span class="form-required">*</span></label> | ||||
|                         <input name="name" type="text" class="form-control" placeholder="Joe Citizen" value="<%- name %>" required> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <div class="col-sm-6 col-md-6"> | ||||
|                     <div class="form-group"> | ||||
|                         <label class="form-label">Nickname</label> | ||||
|                         <input name="nickname" type="text" class="form-control" placeholder="Joe" value="<%- nickname %>"> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <div class="col-sm-12 col-md-12"> | ||||
|                     <div class="form-group"> | ||||
|                         <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> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <% if (!isSelf()) { %> | ||||
|                 <div class="col-sm-12 col-md-12"> | ||||
|                     <div class="form-group"> | ||||
|                         <div class="form-label">Switches</div> | ||||
|                         <div class="custom-switches-stacked"> | ||||
|                             <label class="custom-switch"> | ||||
|                                 <input type="checkbox" class="custom-switch-input" name="is_admin" value="1"<%- isAdmin() ? ' checked' : '' %>> | ||||
|                                 <span class="custom-switch-indicator"></span> | ||||
|                                 <span class="custom-switch-description">Administrator</span> | ||||
|                             </label> | ||||
|                             <label class="custom-switch"> | ||||
|                                 <input type="checkbox" class="custom-switch-input" name="is_disabled" value="1"<%- is_disabled ? ' checked' : '' %>> | ||||
|                                 <span class="custom-switch-indicator"></span> | ||||
|                                 <span class="custom-switch-description">Disabled</span> | ||||
|                             </label> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <% } %> | ||||
|             </div> | ||||
|         </form> | ||||
|     </div> | ||||
|     <div class="modal-footer"> | ||||
|         <button type="button" class="btn btn-secondary cancel" data-dismiss="modal">Cancel</button> | ||||
|         <button type="button" class="btn btn-teal save">Save</button> | ||||
|     </div> | ||||
| </div> | ||||
							
								
								
									
										99
									
								
								src/frontend/js/app/user/form.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/frontend/js/app/user/form.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const Mn         = require('backbone.marionette'); | ||||
| const template   = require('./form.ejs'); | ||||
| const Controller = require('../controller'); | ||||
| const Cache      = require('../cache'); | ||||
| const Api        = require('../api'); | ||||
| const App        = require('../main'); | ||||
| const UserModel  = require('../../models/user'); | ||||
|  | ||||
| require('jquery-serializejson'); | ||||
|  | ||||
| module.exports = Mn.View.extend({ | ||||
|     template:  template, | ||||
|     className: 'modal-dialog', | ||||
|  | ||||
|     ui: { | ||||
|         form:    'form', | ||||
|         buttons: '.modal-footer button', | ||||
|         cancel:  'button.cancel', | ||||
|         save:    'button.save' | ||||
|     }, | ||||
|  | ||||
|     events: { | ||||
|         /* | ||||
|         'click @ui.cancel': function (e) { | ||||
|             e.preventDefault(); | ||||
|             App.UI.closeModal(); | ||||
|         }, | ||||
|         */ | ||||
|  | ||||
|         'submit @ui.form': function (e) { | ||||
|             e.preventDefault(); | ||||
|             let view = this; | ||||
|             let data = this.ui.form.serializeJSON(); | ||||
|  | ||||
|             // Manipulate | ||||
|             data.roles = []; | ||||
|             if ( | ||||
|                 (this.model.get('id') === Cache.User.get('id') && this.model.isAdmin()) || | ||||
|                 (typeof data.is_admin !== 'undefined' && data.is_admin)) { | ||||
|                 data.roles.push('admin'); | ||||
|                 delete data.is_admin; | ||||
|             } | ||||
|  | ||||
|             data.is_disabled = typeof data.is_disabled !== 'undefined' ? !!data.is_disabled : false; | ||||
|             this.ui.buttons.prop('disabled', true).addClass('btn-disabled'); | ||||
|             let method = Api.Users.create; | ||||
|  | ||||
|             if (this.model.get('id')) { | ||||
|                 // edit | ||||
|                 method  = Api.Users.update; | ||||
|                 data.id = this.model.get('id'); | ||||
|             } | ||||
|  | ||||
|             method(data) | ||||
|                 .then(result => { | ||||
|                     if (result.id === Cache.User.get('id')) { | ||||
|                         Cache.User.set(result); | ||||
|                     } | ||||
|  | ||||
|                     view.model.set(result); | ||||
|                     App.UI.closeModal(); | ||||
|  | ||||
|                     if (view.model.get('id') !== Cache.User.get('id')) { | ||||
|                         Controller.showUsers(); | ||||
|                     } | ||||
|                 }) | ||||
|                 .catch(err => { | ||||
|                     alert(err.message); | ||||
|                     this.ui.buttons.prop('disabled', false).removeClass('btn-disabled'); | ||||
|                 }); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     templateContext: function () { | ||||
|         let view = this; | ||||
|  | ||||
|         return { | ||||
|             isSelf: function () { | ||||
|                 return view.model.get('id') === Cache.User.get('id'); | ||||
|             }, | ||||
|  | ||||
|             isAdmin: function () { | ||||
|                 return view.model.isAdmin(); | ||||
|             }, | ||||
|  | ||||
|             isDisabled: function () { | ||||
|                 return view.model.isDisabled(); | ||||
|             } | ||||
|         }; | ||||
|     }, | ||||
|  | ||||
|     initialize: function (options) { | ||||
|         if (typeof options.model === 'undefined' || !options.model) { | ||||
|             this.model = new UserModel.Model(); | ||||
|         } | ||||
|     } | ||||
| }); | ||||
							
								
								
									
										31
									
								
								src/frontend/js/app/users/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/frontend/js/app/users/list/item.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| <td class="text-center"> | ||||
|     <div class="avatar d-block" style="background-image: url(<%- avatar || '/images/default-avatar.jpg' %>)"> | ||||
|         <span class="avatar-status <%- is_disabled ? 'bg-red' : 'bg-green' %>"></span> | ||||
|     </div> | ||||
| </td> | ||||
| <td> | ||||
|     <div><%- name %></div> | ||||
|     <div class="small text-muted"> | ||||
|         Created: Mar 19, 2018 | ||||
|     </div> | ||||
| </td> | ||||
| <td> | ||||
|     <div><%- email %></div> | ||||
| </td> | ||||
| <td> | ||||
|     <div><%- roles.join(', ') %></div> | ||||
| </td> | ||||
| <td class="text-center"> | ||||
|     <div class="item-action dropdown"> | ||||
|         <a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a> | ||||
|         <div class="dropdown-menu dropdown-menu-right"> | ||||
|             <a href="#" class="edit-user dropdown-item"><i class="dropdown-icon fe fe-edit"></i> Edit User</a> | ||||
|             <a href="#" class="set-password dropdown-item"><i class="dropdown-icon fe fe-shield"></i> Set Password</a> | ||||
|             <% if (!isSelf()) { %> | ||||
|             <a href="#" class="login dropdown-item"><i class="dropdown-icon fe fe-log-in"></i> Sign in as User</a> | ||||
|             <div class="dropdown-divider"></div> | ||||
|             <a href="#" class="delete-user dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> Delete User</a> | ||||
|             <% } %> | ||||
|         </div> | ||||
|     </div> | ||||
| </td> | ||||
							
								
								
									
										66
									
								
								src/frontend/js/app/users/list/item.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/frontend/js/app/users/list/item.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const Mn         = require('backbone.marionette'); | ||||
| const Controller = require('../../controller'); | ||||
| const Api        = require('../../api'); | ||||
| const Cache      = require('../../cache'); | ||||
| const Tokens     = require('../../tokens'); | ||||
| const template   = require('./item.ejs'); | ||||
|  | ||||
| module.exports = Mn.View.extend({ | ||||
|     template: template, | ||||
|     tagName:  'tr', | ||||
|  | ||||
|     ui: { | ||||
|         edit:             'a.edit-user', | ||||
|         password:         'a.set-password', | ||||
|         login:            'a.login', | ||||
|         delete:           'a.delete-user' | ||||
|     }, | ||||
|  | ||||
|     events: { | ||||
|         'click @ui.edit': function (e) { | ||||
|             e.preventDefault(); | ||||
|             Controller.showUserForm(this.model); | ||||
|         }, | ||||
|  | ||||
|         'click @ui.password': function (e) { | ||||
|             e.preventDefault(); | ||||
|             //Controller.showUserPasswordForm(this.model); | ||||
|         }, | ||||
|  | ||||
|         'click @ui.delete': function (e) { | ||||
|             e.preventDefault(); | ||||
|             //Controller.showUserDeleteConfirm(this.model); | ||||
|         }, | ||||
|  | ||||
|         'click @ui.login': function (e) { | ||||
|             e.preventDefault(); | ||||
|  | ||||
|             if (Cache.User.get('id') !== this.model.get('id')) { | ||||
|                 this.ui.login.prop('disabled', true).addClass('btn-disabled'); | ||||
|  | ||||
|                 Api.Users.loginAs(this.model.get('id')) | ||||
|                     .then(res => { | ||||
|                         Tokens.addToken(res.token, res.user.nickname || res.user.name); | ||||
|                         window.location = '/'; | ||||
|                         window.location.reload(); | ||||
|                     }) | ||||
|                     .catch(err => { | ||||
|                         alert(err.message); | ||||
|                         this.ui.login.prop('disabled', false).removeClass('btn-disabled'); | ||||
|                     }); | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     templateContext: { | ||||
|         isSelf: function () { | ||||
|             return Cache.User.get('id') === this.id; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     initialize: function () { | ||||
|         this.listenTo(this.model, 'change', this.render); | ||||
|     } | ||||
| }); | ||||
							
								
								
									
										10
									
								
								src/frontend/js/app/users/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/frontend/js/app/users/list/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| <thead> | ||||
|     <th width="30"> </th> | ||||
|     <th>Name</th> | ||||
|     <th>Email</th> | ||||
|     <th>Roles</th> | ||||
|     <th> </th> | ||||
| </thead> | ||||
| <tbody> | ||||
|     <!-- items --> | ||||
| </tbody> | ||||
							
								
								
									
										29
									
								
								src/frontend/js/app/users/list/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/frontend/js/app/users/list/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const Mn         = require('backbone.marionette'); | ||||
| const ItemView   = require('./item'); | ||||
| const template   = require('./main.ejs'); | ||||
|  | ||||
| const TableBody = Mn.CollectionView.extend({ | ||||
|     tagName:   'tbody', | ||||
|     childView: ItemView | ||||
| }); | ||||
|  | ||||
| module.exports = Mn.View.extend({ | ||||
|     tagName:   'table', | ||||
|     className: 'table table-hover table-outline table-vcenter text-nowrap card-table', | ||||
|     template:  template, | ||||
|  | ||||
|     regions: { | ||||
|         body: { | ||||
|             el:             'tbody', | ||||
|             replaceElement: true | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     onRender: function () { | ||||
|         this.showChildView('body', new TableBody({ | ||||
|             collection: this.collection | ||||
|         })); | ||||
|     } | ||||
| }); | ||||
							
								
								
									
										17
									
								
								src/frontend/js/app/users/main.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/frontend/js/app/users/main.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| <div class="card"> | ||||
|     <div class="card-header"> | ||||
|         <h3 class="card-title">Users</h3> | ||||
|         <div class="card-options"> | ||||
|             <a href="#" class="btn btn-outline-teal btn-sm ml-2 add-user">Add User</a> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="card-body no-padding min-100"> | ||||
|         <div class="dimmer active"> | ||||
|             <div class="loader"></div> | ||||
|             <div class="dimmer-content list-region"> | ||||
|                 <!-- List Region --> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|     </div> | ||||
| </div> | ||||
							
								
								
									
										51
									
								
								src/frontend/js/app/users/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/frontend/js/app/users/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const Mn         = require('backbone.marionette'); | ||||
| const UserModel  = require('../../models/user'); | ||||
| const Api        = require('../api'); | ||||
| const Controller = require('../controller'); | ||||
| const ListView   = require('./list/main'); | ||||
| const template   = require('./main.ejs'); | ||||
|  | ||||
| module.exports = Mn.View.extend({ | ||||
|     id:        'users', | ||||
|     template:  template, | ||||
|  | ||||
|     ui: { | ||||
|         list_region: '.list-region', | ||||
|         add_user:    '.add-user', | ||||
|         dimmer:      '.dimmer' | ||||
|     }, | ||||
|  | ||||
|     regions: { | ||||
|         list_region: '@ui.list_region' | ||||
|     }, | ||||
|  | ||||
|     events: { | ||||
|         'click @ui.add_user': function (e) { | ||||
|             e.preventDefault(); | ||||
|             Controller.showUserForm(new UserModel.Model()); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     onRender: function () { | ||||
|         let view = this; | ||||
|  | ||||
|         Api.Users.getAll() | ||||
|             .then(response => { | ||||
|                 if (!view.isDestroyed() && response && response.length) { | ||||
|                     view.showChildView('list_region', new ListView({ | ||||
|                         collection: new UserModel.Collection(response) | ||||
|                     })); | ||||
|  | ||||
|                     // Remove loader | ||||
|                     view.ui.dimmer.removeClass('active'); | ||||
|                 } | ||||
|             }) | ||||
|             .catch(err => { | ||||
|                 console.log(err); | ||||
|                 //Controller.showError(err, 'Could not fetch Users'); | ||||
|                 //view.trigger('loaded'); | ||||
|             }); | ||||
|     } | ||||
| }); | ||||
							
								
								
									
										25
									
								
								src/frontend/scss/custom.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/frontend/scss/custom.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| $primary-color: #2bcbba; | ||||
|  | ||||
| .loader { | ||||
|     color: $primary-color; | ||||
| } | ||||
|  | ||||
| a { | ||||
|     color: $primary-color; | ||||
| } | ||||
|  | ||||
| a:hover { | ||||
|     color: darken($primary-color, 10%); | ||||
| } | ||||
|  | ||||
| .dropdown-item.active, .dropdown-item:active { | ||||
|     background-color: $primary-color; | ||||
| } | ||||
|  | ||||
| .custom-switch-input:checked ~ .custom-switch-indicator { | ||||
|     background: $primary-color; | ||||
| } | ||||
|  | ||||
| .min-100 { | ||||
|     min-height: 100px; | ||||
| } | ||||
| @@ -1,4 +1,6 @@ | ||||
| @import "~tabler-ui/dist/assets/css/dashboard"; | ||||
| @import "tabler-extra"; | ||||
| @import "custom"; | ||||
|  | ||||
| /* Before any JS content is loaded */ | ||||
| #app > .loader, #login > .loader, .container > .loader { | ||||
| @@ -10,4 +12,4 @@ | ||||
|  | ||||
| .no-js-warning { | ||||
|     margin-top: 100px; | ||||
| } | ||||
| } | ||||
|   | ||||
							
								
								
									
										26
									
								
								src/frontend/scss/tabler-extra.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/frontend/scss/tabler-extra.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| $teal: #2bcbba; | ||||
|  | ||||
| /* For Card bodies where I don't want padding */ | ||||
| .card-body.no-padding { | ||||
|     padding: 0; | ||||
| } | ||||
|  | ||||
| /* Teal Outline Buttons */ | ||||
| .btn-outline-teal { | ||||
|     color: $teal; | ||||
|     background-color: transparent; | ||||
|     background-image: none; | ||||
|     border-color: $teal; | ||||
| } | ||||
|  | ||||
| .btn-outline-teal:hover { | ||||
|     color: #fff; | ||||
|     background-color: $teal; | ||||
|     border-color: $teal; | ||||
| } | ||||
|  | ||||
| .btn-outline-teal:not(:disabled):not(.disabled):active, .btn-outline-teal:not(:disabled):not(.disabled).active, .show > .btn-outline-teal.dropdown-toggle { | ||||
|     color: #fff; | ||||
|     background-color: $teal; | ||||
|     border-color: $teal; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user