1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-21 06:09:42 +02:00

user admin UX

This commit is contained in:
Harvey Kandola 2017-11-29 10:31:00 +00:00
parent 79531e01b3
commit 95bb440a65
9 changed files with 194 additions and 315 deletions

View file

@ -9,9 +9,8 @@
//
// https://documize.com
import { debounce } from '@ember/runloop';
import Component from '@ember/component';
import { schedule, debounce } from '@ember/runloop';
import AuthProvider from '../../mixins/auth';
import DropdownMixin from '../../mixins/dropdown';
@ -24,6 +23,7 @@ export default Component.extend(AuthProvider, DropdownMixin, {
filteredUsers: [],
selectedUsers: [],
hasSelectedUsers: false,
showDeleteDialog: false,
didReceiveAttrs() {
this._super(...arguments);
@ -39,11 +39,6 @@ export default Component.extend(AuthProvider, DropdownMixin, {
this.set('filteredUsers', users);
},
willDestroyElement() {
this._super(...arguments);
this.destroyDropdown();
},
onKeywordChange: function () {
debounce(this, this.filterUsers, 350);
}.observes('filter'),
@ -101,76 +96,45 @@ export default Component.extend(AuthProvider, DropdownMixin, {
this.attrs.onSave(user);
},
edit(id) {
let self = this;
onShowEdit(id) {
let user = this.users.findBy("id", id);
let userCopy = user.getProperties('id', 'created', 'revised', 'firstname', 'lastname', 'email', 'initials', 'active', 'editor', 'admin', 'viewUsers', 'accounts');
this.set('editUser', userCopy);
this.set('password', {
password: "",
confirmation: ""
});
$(".edit-user-dialog").css("display", "block");
$("input").removeClass("error");
this.closeDropdown();
let dropOptions = Object.assign(this.get('dropDefaults'), {
target: $(".edit-button-" + id)[0],
content: $(".edit-user-dialog")[0],
classes: 'drop-theme-basic',
position: "bottom right",
remove: false});
let drop = new Drop(dropOptions);
self.set('dropdown', drop);
drop.on('open', function () {
self.$("#edit-firstname").focus();
$('#edit-user-modal').on('show.bs.modal', function(event) { // eslint-disable-line no-unused-vars
schedule('afterRender', () => {
$("#edit-firstname").focus();
});
});
$('#edit-user-modal').modal('dispose');
$('#edit-user-modal').modal({show: true});
},
confirmDelete(id) {
let user = this.users.findBy("id", id);
this.set('deleteUser', user);
$(".delete-user-dialog").css("display", "block");
this.closeDropdown();
let dropOptions = Object.assign(this.get('dropDefaults'), {
target: $(".delete-button-" + id)[0],
content: $(".delete-user-dialog")[0],
classes: 'drop-theme-basic',
position: "bottom right",
remove: false});
let drop = new Drop(dropOptions);
this.set('dropdown', drop);
},
cancel() {
this.closeDropdown();
},
save() {
onUpdate() {
let user = this.get('editUser');
let password = this.get('password');
if (is.empty(user.firstname)) {
$("#edit-firstname").addClass("error").focus();
$("#edit-firstname").addClass("is-invalid").focus();
return;
}
if (is.empty(user.lastname)) {
$("#edit-lastname").addClass("error").focus();
$("#edit-lastname").addClass("is-invalid").focus();
return;
}
if (is.empty(user.email)) {
$("#edit-email").addClass("error").focus();
if (is.empty(user.email) || is.not.email(user.email)) {
$("#edit-email").addClass("is-invalid").focus();
return;
}
this.closeDropdown();
$('#edit-user-modal').modal('hide');
$('#edit-user-modal').modal('dispose');
this.attrs.onSave(user);
@ -180,12 +144,19 @@ export default Component.extend(AuthProvider, DropdownMixin, {
}
},
delete() {
this.closeDropdown();
onShowDelete(id) {
this.set('deleteUser', this.users.findBy("id", id));
this.set('showDeleteDialog', true);
},
onDelete() {
this.set('showDeleteDialog', false);
this.set('selectedUsers', []);
this.set('hasSelectedUsers', false);
this.attrs.onDelete(this.get('deleteUser.id'));
return true;
},
onBulkDelete() {

View file

@ -10,7 +10,6 @@
// https://documize.com
import { empty, and } from '@ember/object/computed';
import Component from '@ember/component';
import { isEmpty } from '@ember/utils';
import { get, set } from '@ember/object';

View file

@ -10,12 +10,10 @@
// https://documize.com
import { set } from '@ember/object';
import { inject as service } from '@ember/service';
import Controller from '@ember/controller';
import NotifierMixin from '../../../mixins/notifier';
export default Controller.extend(NotifierMixin, {
export default Controller.extend({
userService: service('user'),
newUser: { firstname: "", lastname: "", email: "", active: true },
@ -26,7 +24,6 @@ export default Controller.extend(NotifierMixin, {
return this.get('userService')
.add(this.get('newUser'))
.then((user) => {
this.showNotification('Added');
this.get('model').pushObject(user);
})
.catch(function (error) {
@ -38,8 +35,6 @@ export default Controller.extend(NotifierMixin, {
onDelete(userId) {
let self = this;
this.get('userService').remove(userId).then(function () {
self.showNotification('Deleted');
self.get('userService').getComplete().then(function (users) {
self.set('model', users);
});
@ -49,7 +44,6 @@ export default Controller.extend(NotifierMixin, {
onSave(user) {
let self = this;
this.get('userService').save(user).then(function () {
self.showNotification('Saved');
self.get('userService').getComplete().then(function (users) {
self.set('model', users);
@ -59,7 +53,6 @@ export default Controller.extend(NotifierMixin, {
onPassword(user, password) {
this.get('userService').updatePassword(user.id, password);
this.showNotification('Password changed');
}
}
});

View file

@ -1,3 +1,12 @@
<div class="row">
<div class="col">
<div class="view-customize">
<h1 class="admin-heading">Users</h1>
<h2 class="sub-heading">Set basic information, passwords and permissions for {{model.length}} users</h2>
</div>
</div>
</div>
{{customize/user-settings add=(action 'add')}}
{{customize/user-admin users=model onDelete=(action "onDelete") onSave=(action "onSave") onPassword=(action "onPassword")}}

View file

@ -10,71 +10,18 @@
color: $color-gray;
}
> .user-admin {
margin: 30px 0;
> .heading {
font-size: 1.2rem;
color: $color-off-black;
font-weight: bold;
margin: 0 0 20px 0;
}
> .basic-table {
background-color: $color-white;
border: none !important;
font-size: 1rem;
color: $color-off-black;
> thead {
> tr {
> th {
height: 40px;
font-weight: bold;
color: $color-gray;
}
> th:first-child {
font-weight: normal;
}
> th:last-child {
text-align: center;
}
}
}
> tbody {
> tr {
> td {
vertical-align: middle;
text-align: center;
> .selector {
> i {
color: $color-off-black;
}
}
> .name {
.user-table {
.name {
font-size: 1rem;
color: $color-off-black;
margin: 0 0 0 30px;
}
> .email {
.email {
font-size: 0.9rem;
color: $color-gray;
margin: 0 0 0 30px;
}
}
> td:first-child, td:last-child {
text-align: left;
}
}
}
}
.inactive-user
{
@ -95,10 +42,6 @@
}
}
.edit-user-dialog, .delete-user-dialog {
display: none;
}
> .space-list {
padding: 0;
margin: 0;

View file

@ -26,8 +26,10 @@
<div class="form-group row">
<label class="col-sm-2 col-form-label">Anonymous Access</label>
<div class="col-sm-10">
<input type="checkbox" id="allowAnonymousAccess" checked={{model.general.allowAnonymousAccess}} />
<small class="form-text text-muted">Content within "Everyone" will be made available to anonymous users</small>
<label class="form-check-label">
<input type="checkbox" class="form-check-input" id="allowAnonymousAccess" checked={{model.general.allowAnonymousAccess}} />
Make content marked as "Everyone" available to anonymous users
</label>
</div>
</div>
<div class="form-group row">

View file

@ -1,8 +1,8 @@
<div class="row">
<div class="col">
<div class="view-customize">
<h1 class="admin-heading">SMTP Settings</h1>
<h2 class="sub-heading">Used for sending email notifications</h2>
<h1 class="admin-heading">SMTP Server</h1>
<h2 class="sub-heading">For sending email notifications</h2>
</div>
</div>
</div>
@ -10,35 +10,35 @@
<div class="view-customize">
<form class="mt-5">
<div class="form-group row">
<label for="smtp-host" class="col-sm-2 col-form-label">SMTP Host</label>
<label for="smtp-host" class="col-sm-2 col-form-label">Host</label>
<div class="col-sm-10">
{{focus-input id="smtp-host" type="text" value=model.smtp.host class=(if SMTPHostEmptyError 'form-control is-invalid' 'form-control')}}
<small class="form-text text-muted">e.g. my.host.com</small>
</div>
</div>
<div class="form-group row">
<label for="smtp-port" class="col-sm-2 col-form-label">SMTP Port</label>
<label for="smtp-port" class="col-sm-2 col-form-label">Port</label>
<div class="col-sm-10">
{{input id="smtp-port" type="text" value=model.smtp.port class=(if SMTPPortEmptyError 'form-control is-invalid' 'form-control')}}
<small class="form-text text-muted">e.g. 587</small>
</div>
</div>
<div class="form-group row">
<label for="smtp-sender" class="col-sm-2 col-form-label">SMTP Sender</label>
<label for="smtp-sender" class="col-sm-2 col-form-label">Sender</label>
<div class="col-sm-10">
{{input id="smtp-sender" type="text" value=model.smtp.sender class=(if SMTPSenderEmptyError 'form-control is-invalid' 'form-control')}}
<small class="form-text text-muted">e.g. user@some-domain.com</small>
</div>
</div>
<div class="form-group row">
<label for="smtp-userid" class="col-sm-2 col-form-label">SMTP Username</label>
<label for="smtp-userid" class="col-sm-2 col-form-label">Username</label>
<div class="col-sm-10">
{{input id="smtp-userid" type="text" value=model.smtp.userid class=(if SMTPUserIdEmptyError 'form-control is-invalid' 'form-control')}}
<small class="form-text text-muted">e.g. Login username for SMTP server</small>
</div>
</div>
<div class="form-group row">
<label for="smtp-password" class="col-sm-2 col-form-label">SMTP Password</label>
<label for="smtp-password" class="col-sm-2 col-form-label">Password</label>
<div class="col-sm-10">
{{input id="smtp-password" type="password" value=model.smtp.password class=(if SMTPPasswordEmptyError 'form-control is-invalid' 'form-control')}}
<small class="form-text text-muted">e.g. Login password for SMTP server</small>

View file

@ -1,27 +1,16 @@
<div class="page-customize">
<div class="user-admin">
<div class="form-header">
<div class="title">User Management</div>
<div class="tip">Set basic information, passwords and permissions for {{users.length}} users</div>
</div>
<table class="basic-table">
<div class="view-customize mb-5">
<h3>Users</h3>
<table class="table table-hover table-responsive user-table">
<thead>
<tr>
<th class="">
<div class="input-inline input-transparent">
{{focus-input type="text" placeholder="< type here to filter users >" value=filter}}
</div>
</th>
<th>{{input type="text" class="form-control" placeholder="filter users" value=filter}}</th>
<th class="no-width">Add Space</th>
<th class="no-width">View Users</th>
<th class="no-width">Admin</th>
<th class="no-width">Active</th>
<th class="no-width">
{{#if hasSelectedUsers}}
<div class="round-button round-button-small button-red" id="bulk-delete-users">
<i class="material-icons">delete</i>
</div>
<button id="bulk-delete-users" type="button" class="btn btn-danger btn-sm">Delete</button>
{{#dropdown-dialog target="bulk-delete-users" position="bottom right" button="Delete" color="flat-red" onAction=(action 'onBulkDelete')}}
<p>Are you sure you want to delete selected users?</p>
{{/dropdown-dialog}}
@ -30,10 +19,10 @@
</tr>
</thead>
<tbody>
{{#each users key="id" as |user|}}
{{#each filteredUsers key="id" as |user|}}
<tr>
<td class="{{unless user.active 'inactive-user'}} {{if user.admin 'admin-user'}}">
<div class="selector pull-left">
<div class="d-inline-block align-top">
{{#if user.me}}
<i class="material-icons color-gray">check_box_outline_blank</i>
{{else if user.selected}}
@ -42,8 +31,10 @@
<i class="material-icons checkbox" {{action 'toggleSelect' user}}>check_box_outline_blank</i>
{{/if}}
</div>
<div class="name">{{ user.fullname }}</div>
<div class="d-inline-block">
<div class="name d-inline-block">{{ user.fullname }}</div>
<div class="email">{{ user.email }}</div>
</div>
</td>
<td class="no-width text-center">
{{#if user.editor}}
@ -79,15 +70,15 @@
</td>
<td class="no-width text-center">
{{#if user.me}}
<div class="edit-button-{{user.id}} round-button-mono" title="Edit" {{action "edit" user.id}}>
<div class="edit-button-{{user.id}} button-icon-gray" title="Edit" {{action "onShowEdit" user.id}}>
<i class="material-icons">edit</i>
</div>
{{else}}
<div class="edit-button-{{user.id}} round-button-mono" title="Edit" {{action "edit" user.id}}>
<div class="edit-button-{{user.id}} button-icon-gray" title="Edit" {{action "onShowEdit" user.id}}>
<i class="material-icons">edit</i>
</div>
<div class="button-gap"></div>
<div class="delete-button-{{user.id}} round-button-mono" title="Delete" {{action "confirmDelete" user.id}}>
<div class="button-icon-gap"></div>
<div class="delete-button-{{user.id}} button-icon-danger" title="Delete" {{action "onShowDelete" user.id}}>
<i class="material-icons">delete</i>
</div>
{{/if}}
@ -98,74 +89,53 @@
</table>
</div>
<div class="dropdown-dialog edit-user-dialog">
<div class="content">
<div id="edit-user-modal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">User {{editUser.firstname}} {{editUser.lastname}}</div>
<div class="modal-body">
<form>
<div class="row">
<div class="col-md-6">
<div class="input-control">
<label>Firstname</label>
{{input id="edit-firstname" type="text" value=editUser.firstname}}
</div>
</div>
<div class="col-md-6">
<div class="input-control">
<label>Lastname</label>
{{input id="edit-lastname" type="text" value=editUser.lastname}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="input-control">
<label>Email</label>
{{input id="edit-email" type="text" value=editUser.email}}
<div class="form-group">
<label for="edit-firstname">Firstname</label>
{{input id="edit-firstname" class="form-control" type="text" value=editUser.firstname}}
</div>
<div class="form-group">
<label for="edit-lastname">Lastname</label>
{{input id="edit-lastname" type="text" class="form-control" value=editUser.lastname}}
</div>
<div class="form-group">
<label for="edit-email">Email</label>
{{input id="edit-email" type="text" class="form-control" value=editUser.email}}
</div>
{{#if isAuthProviderDocumize}}
<div class="row">
<div class="col-md-6">
<div class="input-control">
<label>Password</label>
<div class="form-group">
<label for="edit-password">Password</label>
<div class="tip">Optional new password</div>
{{input id="edit-password" type="password" value=password.password}}
{{input id="edit-password" type="password" class="form-control" value=password.password}}
</div>
</div>
<div class="col-md-6">
<div class="input-control">
<label>Confirm Password</label>
<div class="form-group">
<label for="edit-confirmPassword">Confirm Password</label>
<div class="tip">Confirm new password</div>
{{input id="edit-confirmPassword" type="password" value=password.confirmation}}
{{input id="edit-confirmPassword" type="password" class="form-control" value=password.confirmation}}
</div>
</div>
</div>
{{/if}}
</form>
</div>
<div class="actions">
<div class="flat-button" {{action 'cancel'}}>
cancel
</div>
<div class="flat-button flat-blue" {{action 'save'}}>
save
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-outline-success" onclick={{action 'onUpdate'}}>Save</button>
</div>
</div>
</div>
<div class="clearfix"></div>
</div>
<div class="dropdown-dialog delete-user-dialog">
<div class="content">
<p>Are you sure you want to delete user <span class="font-weight-bold">{{deleteUser.fullname}}?</span></p>
</div>
<div class="actions">
<div class="flat-button" {{action 'cancel'}}>
cancel
</div>
<div class="flat-button flat-red" {{action 'delete'}}>
delete
</div>
</div>
<div class="clearfix"></div>
</div>
</div>
{{#ui/ui-dialog title="Delete User" confirmCaption="Delete" buttonType="btn-danger" show=showDeleteDialog onAction=(action 'onDelete')}}
<p>Are you sure you want to delete {{deleteUser.fullname}}?</p>
{{/ui/ui-dialog}}

View file

@ -1,25 +1,17 @@
{{#if isAuthProviderDocumize}}
<div class="page-customize">
<div class="add-user">
<form>
<div class="form-header">
<div class="title">New User</div>
<div class="tip">Newly added users receive an invitation email with a random password</div>
</div>
<div class="input-control">
<label>Firstname</label>
{{focus-input id="newUserFirstname" type="text" value=newUser.firstname class=(if hasFirstnameEmptyError 'error')}}
</div>
<div class="input-control">
<label>Lastname</label>
{{input id="newUserLastname" type="text" value=newUser.lastname class=(if hasLastnameEmptyError 'error')}}
</div>
<div class="input-control">
<label>Email</label>
{{input id="newUserEmail" type="text" value=newUser.email class=(if hasEmailEmptyError 'error')}}
</div>
<div class="regular-button button-blue" {{ action 'add' }}>Add</div>
<div class="view-customize mt-5 mb-5">
<h3>Add User</h3>
<form class="form-inline">
<label class="sr-only" for="newUserFirstname">Firstname</label>
{{focus-input id="newUserFirstname" type="text" value=newUser.firstname placeholder="Firstname" class=(if hasFirstnameEmptyError 'form-control mb-2 mr-sm-4 mb-sm-0 is-invalid' 'form-control mb-2 mr-sm-4 mb-sm-0')}}
<label class="sr-only" for="newUserLastname">Lastname</label>
{{input id="newUserLastname" type="text" value=newUser.lastname placeholder="Lastname" class=(if hasLastnameEmptyError 'form-control mb-2 mr-sm-4 mb-sm-0 is-invalid' 'form-control mb-2 mr-sm-4 mb-sm-0')}}
<label class="sr-only" for="newEmail">Email</label>
{{input id="newEmail" type="email" value=newUser.email placeholder="Email" class=(if hasEmailEmptyError 'form-control mb-2 mr-sm-4 mb-sm-0 is-invalid' 'form-control mb-2 mr-sm-4 mb-sm-0')}}
<button type="submit" class="btn btn-success" {{action 'add'}}>Add</button>
</form>
</div>
</div>
{{/if}}