Rework permissions view (#2756)

* Early layout work on a cleaner permissions interface

* Cleanup layout.  Make new permissions view work.  Still needs some css and javascript improvements.  Also need to do the same thing to the group view.

* Improve styling, add javascript to toggle an entire group of permissions if choosing the permission on the header row.  Would be nice to add collapsing of sections in the future.

* Toggle viewing sections.

* Special case places where we only have one item in a group to only display the item once.

* Filter getCreate the same way.
This commit is contained in:
Daniel Meltzer 2016-10-12 14:06:28 -05:00 committed by snipe
parent 4b6ba6cb30
commit 2e0a7abbe9
3 changed files with 473 additions and 343 deletions

View file

@ -81,6 +81,7 @@ class UsersController extends Controller
$permissions = config('permissions');
$userPermissions = Helper::selectedPermissionsArray($permissions, Input::old('permissions', array()));
$permissions = $this->filterDisplayable($permissions);
$location_list = Helper::locationsList();
$manager_list = Helper::managerList();
@ -233,6 +234,17 @@ class UsersController extends Controller
* @param int $id
* @return View
*/
private function filterDisplayable($permissions) {
$output = null;
foreach($permissions as $key=>$permission) {
$output[$key] = array_filter($permission, function($p) {
return $p['display'] === true;
});
}
return $output;
}
public function getEdit($id = null)
{
try {
@ -249,7 +261,7 @@ class UsersController extends Controller
$userGroups = $user->groups()->pluck('name', 'id');
$user->permissions = $user->decodePermissions();
$userPermissions = Helper::selectedPermissionsArray($permissions, $user->permissions);
$permissions = $this->filterDisplayable($permissions);
$location_list = Helper::locationsList();
$company_list = Helper::companyList();
$manager_list = Helper::managerList();
@ -282,7 +294,6 @@ class UsersController extends Controller
// permissions here before we update the user.
$permissions = $request->input('permissions', array());
app('request')->request->set('permissions', $permissions);
// Only update the email address if locking is set to false
if (config('app.lock_passwords')) {
return redirect()->route('users')->with('error', 'Denied! You cannot update user information on the demo.');
@ -333,7 +344,6 @@ class UsersController extends Controller
$user->notes = e($request->input('notes'));
$user->permissions = json_encode($request->input('permission'));
if ($user->manager_id == "") {
$user->manager_id = null;
}

View file

@ -288,7 +288,6 @@
</a>
<ul class="dropdown-menu">
<!-- User image -->
<li>
<li {!! (Request::is('account/profile') ? ' class="active"' : '') !!}>
<a href="{{ route('view-assets') }}">
<i class="fa fa-check fa-fw"></i> @lang('general.viewassets')
@ -304,7 +303,6 @@
@lang('general.logout')
</a>
</li>
</li>
</ul>
</li>
@ -434,7 +432,7 @@
<li{!! (Request::query('status') == 'Pending' ? ' class="active"' : '') !!}><a href="{{ URL::to('hardware?status=Pending') }}">@lang('general.pending')</a></li>
<li{!! (Request::query('status') == 'Undeployable' ? ' class="active"' : '') !!} ><a href="{{ URL::to('hardware?status=Undeployable') }}">@lang('general.undeployable')</a></li>
<li{!! (Request::query('status') == 'Archived' ? ' class="active"' : '') !!}><a href="{{ URL::to('hardware?status=Archived') }}">@lang('admin/hardware/general.archived')</a></li>
<li{!! (Request::query('status') == 'Requestable' ? ' class="active"' : '') !!}><a href="{{ URL::to('hardware?status=Requestable') }}"><a href="{{ URL::to('hardware?status=Requestable') }}" >@lang('admin/hardware/general.requestable')</a></li>
<li{!! (Request::query('status') == 'Requestable' ? ' class="active"' : '') !!}><a href="{{ URL::to('hardware?status=Requestable') }}">@lang('admin/hardware/general.requestable')</a></li>
<li class="divider">&nbsp;</li>
<li{!! (Request::is('hardware/bulkcheckout') ? ' class="active>"' : '') !!}>

View file

@ -21,25 +21,58 @@
@section('content')
<style>
.form-horizontal .control-label {
.form-horizontal .control-label {
padding-top: 0px;
}
}
input[type='text'][disabled], input[disabled], textarea[disabled], input[readonly], textarea[readonly], .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
input[type='text'][disabled], input[disabled], textarea[disabled], input[readonly], textarea[readonly], .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
background-color: white;
color: #555555;
cursor:text;
}
.radio-padding {
padding-left: 50px;
}
}
table.permissions {
display:flex;
flex-direction: column;
}
.permissions.table > thead, .permissions.table > tbody {
margin: 15px;
margin-top: 0px;
}
.permissions.table > tbody+tbody {
margin: 15px;
}
.header-row {
border-bottom: 1px solid #ccc;
}
.header-row h3 {
margin:0px;
}
.permissions-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.table > tbody > tr > td.permissions-item {
padding: 1px;
padding-left: 8px;
}
table, tbody {
border: 1px solid #ccc;
}
.header-name {
cursor: pointer;
}
</style>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form class="form-horizontal" method="post" action="" autocomplete="off" id="userForm">
<form class="form-horizontal" method="post" autocomplete="off" id="userForm">
<!-- CSRF Token -->
<input type="hidden" name="_token" value="{{ csrf_token() }}">
@ -49,6 +82,7 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
<li class="active"><a href="#tab_1" data-toggle="tab">Information</a></li>
<li><a href="#tab_2" data-toggle="tab">Permissions</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab_1">
<div class="row">
@ -72,13 +106,22 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
</div>
</div>
<!-- Username -->
<!-- Username -->
<div class="form-group {{ $errors->has('username') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="username">{{ trans('admin/users/table.username') }}</label>
<div class="col-md-8{{ (\App\Helpers\Helper::checkIfRequired($user, 'username')) ? ' required' : '' }}">
@if ($user->ldap_import!='1')
<input class="form-control" type="text" name="username" id="username" value="{{ Input::old('username', $user->username) }}" {{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }} autocomplete="false" readonly onfocus="this.removeAttribute('readonly');">
<input
class="form-control"
type="text"
name="username"
id="username"
value="{{ Input::old('username', $user->username) }}"
autocomplete="false"
readonly
onfocus="this.removeAttribute('readonly');"
{{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }}
>
@if (config('app.lock_passwords') && ($user->id))
<p class="help-block">{{ trans('admin/users/table.lock_passwords') }}</p>
@endif
@ -90,14 +133,24 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
</div>
</div>
<!-- Password -->
<div class="form-group {{ $errors->has('password') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="password">{{ trans('admin/users/table.password') }}
<label class="col-md-3 control-label" for="password">
{{ trans('admin/users/table.password') }}
</label>
<div class="col-md-5{{ (\App\Helpers\Helper::checkIfRequired($user, 'password')) ? ' required' : '' }}">
@if ($user->ldap_import!='1')
<input type="password" name="password" class="form-control" id="password" value="" {{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }} autocomplete="false" readonly onfocus="this.removeAttribute('readonly');">
<input
type="password"
name="password"
class="form-control"
id="password"
value=""
autocomplete="false"
readonly
onfocus="this.removeAttribute('readonly');"
{{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }}
>
@else
(Managed via LDAP)
@endif
@ -114,10 +167,19 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
@if ($user->ldap_import!='1')
<!-- Password Confirm -->
<div class="form-group {{ $errors->has('password_confirm') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="password_confirm">{{ trans('admin/users/table.password_confirm') }}
<label class="col-md-3 control-label" for="password_confirm">
{{ trans('admin/users/table.password_confirm') }}
</label>
<div class="col-md-5{{ ((\App\Helpers\Helper::checkIfRequired($user, 'first_name')) && (!$user->id)) ? ' required' : '' }}">
<input type="password" name="password_confirm" id="password_confirm" class="form-control" value="" {{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }} autocomplete="off">
<div class="col-md-5 {{ ((\App\Helpers\Helper::checkIfRequired($user, 'first_name')) && (!$user->id)) ? ' required' : '' }}">
<input
type="password"
name="password_confirm"
id="password_confirm"
class="form-control"
value=""
autocomplete="off"
{{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }}
>
@if (config('app.lock_passwords') && ($user->id))
<p class="help-block">{{ trans('admin/users/table.lock_passwords') }}</p>
@endif
@ -126,16 +188,24 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
</div>
@endif
<!-- Email -->
<div class="form-group {{ $errors->has('email') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="email">{{ trans('admin/users/table.email') }} </label>
<div class="col-md-8{{ (\App\Helpers\Helper::checkIfRequired($user, 'email')) ? ' required' : '' }}">
<input class="form-control" type="text" name="email" id="email" value="{{ Input::old('email', $user->email) }}" {{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }} autocomplete="off" readonly onfocus="this.removeAttribute('readonly');">
<input
class="form-control"
type="text"
name="email"
id="email"
value="{{ Input::old('email', $user->email) }}"
{{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }}
autocomplete="off"
readonly
onfocus="this.removeAttribute('readonly');"
>
@if (config('app.lock_passwords') && ($user->id))
<p class="help-block">{{ trans('admin/users/table.lock_passwords') }}</p>
@endif
{!! $errors->first('email', '<span class="alert-msg">:message</span>') !!}
</div>
</div>
@ -154,9 +224,6 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
</div>
@endif
<!-- language -->
<div class="form-group {{ $errors->has('locale') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="locale">{{ trans('general.language') }}</label>
@ -166,12 +233,17 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
</div>
</div>
<!-- Employee Number -->
<div class="form-group {{ $errors->has('employee_num') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="employee_num">{{ trans('admin/users/table.employee_num') }}</label>
<div class="col-md-8">
<input class="form-control" type="text" name="employee_num" id="employee_num" value="{{ Input::old('employee_num', $user->employee_num) }}" />
<input
class="form-control"
type="text"
name="employee_num"
id="employee_num"
value="{{ Input::old('employee_num', $user->employee_num) }}"
/>
{!! $errors->first('employee_num', '<span class="alert-msg">:message</span>') !!}
</div>
</div>
@ -181,13 +253,19 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
<div class="form-group {{ $errors->has('jobtitle') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="jobtitle">{{ trans('admin/users/table.title') }}</label>
<div class="col-md-8">
<input class="form-control" type="text" name="jobtitle" id="jobtitle" value="{{ Input::old('jobtitle', $user->jobtitle) }}" />
<input
class="form-control"
type="text"
name="jobtitle"
id="jobtitle"
value="{{ Input::old('jobtitle', $user->jobtitle) }}"
/>
{!! $errors->first('jobtitle', '<span class="alert-msg">:message</span>') !!}
</div>
</div>
<!-- Manager -->
<!-- Manager -->
<div class="form-group {{ $errors->has('manager_id') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="manager_id">{{ trans('admin/users/table.manager') }}</label>
<div class="col-md-8">
@ -196,7 +274,7 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
</div>
</div>
<!-- Location -->
<!-- Location -->
<div class="form-group {{ $errors->has('location_id') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="location_id">{{ trans('admin/users/table.location') }}
</label>
@ -206,7 +284,7 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
</div>
</div>
<!-- Phone -->
<!-- Phone -->
<div class="form-group {{ $errors->has('phone') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="phone">{{ trans('admin/users/table.phone') }}</label>
<div class="col-md-4">
@ -215,12 +293,17 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
</div>
</div>
<!-- Activation Status -->
<!-- Activation Status -->
<div class="form-group {{ $errors->has('activated') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="activated">{{ trans('admin/users/table.activated') }}</label>
<div class="col-md-8">
<div class="controls">
<select{{ ($user->id === Auth::user()->id ? ' disabled="disabled"' : '') }} name="activated" id="activated" {{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }}>
<select
{{ ($user->id === Auth::user()->id ? ' disabled="disabled"' : '') }}
name="activated"
id="activated"
{{ ((config('app.lock_passwords') && ($user->id)) ? ' disabled' : '') }}
>
@if ($user->id)
<option value="1"{{ ($user->isActivated() ? ' selected="selected"' : '') }}>{{ trans('general.yes') }}</option>
<option value="0"{{ ( ! $user->isActivated() ? ' selected="selected"' : '') }}>{{ trans('general.no') }}</option>
@ -230,7 +313,6 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
@endif
</select>
{!! $errors->first('activated', '<span class="alert-msg">:message</span>') !!}
</div>
</div>
@ -250,8 +332,13 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
<label class="col-md-3 control-label" for="groups"> {{ trans('general.groups') }}</label>
<div class="col-md-5">
<div class="controls">
<select name="groups[]" id="groups[]" multiple="multiple" class="form-control" {{ ((Config::get('app.lock_passwords') || ($user->id==Auth::user()->id) || (!Auth::user()->isSuperUser())) ? ' disabled' : '') }}>
<select
name="groups[]"
id="groups[]"
multiple="multiple"
class="form-control"
{{ ((Config::get('app.lock_passwords') || ($user->id==Auth::user()->id) || (!Auth::user()->isSuperUser())) ? ' disabled' : '') }}
>
@foreach ($groups as $id => $group)
<option value="{{ $id }}"
@ -263,7 +350,6 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
<span class="help-block">
{{ trans('admin/users/table.groupnotes') }}
</span>
</div>
</div>
@ -288,90 +374,114 @@ input[type='text'][disabled], input[disabled], textarea[disabled], input[readonl
</div>
</div>
</div><!-- /.tab-pane -->
<div class="tab-pane" id="tab_2">
<div class="col-md-10 col-md-offset-2">
@if (!Auth::user()->isSuperUser())
<p class="alert alert-warning">Only superadmins may grant a user superadmin access.</p>
@endif
<?php $counter = 1; ?>
@foreach ($permissions as $area => $permission)
@for ($i = 0; $i < count($permission); $i++)
<?php
$permission_name = $permission[$i]['permission'];
?>
@if ($counter == 2)
<div id="nonadmin">
@endif
@if ($permission[$i]['display'])
<h3>{{ $area }}: {{ $permission[$i]['label'] }}</h3>
<p>{{ $permission[$i]['note'] }}</p>
<!-- radio -->
<div class="form-group" style="padding-left: 15px;">
<label class="radio-padding">
@if (($permission_name == 'superuser') && (!Auth::user()->isSuperUser()))
{{ Form::radio('permission['.$permission_name.']', '1', $userPermissions[$permission_name] == '1', ['disabled'=>'disabled']) }}
@else
{{ Form::radio('permission['.$permission_name.']', '1', $userPermissions[$permission_name] == '1', ['class' => "$permission_name"]) }}
@endif
Grant</label>
<label class="radio-padding">
@if (($permission_name == 'superuser') && (!Auth::user()->isSuperUser()))
{{ Form::radio('permission['.$permission_name.']', '-1', $userPermissions[$permission_name] == '-1', ['disabled'=>'disabled']) }}
@else
{{ Form::radio('permission['.$permission_name.']', '-1', $userPermissions[$permission_name] == '-1', ['class' => "$permission_name"]) }}
@endif
Deny</label>
<label class="radio-padding">
@if (($permission_name == 'superuser') && (!Auth::user()->isSuperUser()))
{{ Form::radio('permission['.$permission_name.']', '0', $userPermissions[$permission_name] =='0', ['disabled'=>'disabled']) }}
@else
{{ Form::radio('permission['.$permission_name.']', '0', $userPermissions[$permission_name] =='0', ['class' => "$permission_name"]) }}
@endif
Inherit</label>
</div>
<hr>
@endif
<table class="table table-striped permissions">
<thead>
<tr class="permissions-row">
<th class="col-md-2"><span class="line"></span>Permission</th>
<th class="col-md-1"><span class="line"></span>Grant</th>
<th class="col-md-1"><span class="line"></span>Deny</th>
<th class="col-md-1"><span class="line"></span>Inherit</th>
</tr>
</thead>
@foreach ($permissions as $area => $permissionsArray)
@if (count($permissionsArray) == 1)
<tbody class="permissions-group">
<?php $localPermission = $permissionsArray[0] ?>
<tr class="header-row permissions-row">
<td class="col-md-2 tooltip-base permissions-item"
data-toggle="tooltip"
data-placement="right"
title="{{ $localPermission['note'] }}"
>
<h4>{{ $area . ': ' . $localPermission['label'] }}</h4>
</td>
<td class="col-md-1 permissions-item">
@endfor
@if ($counter == count($permissions))
{{ Form::radio('permission['.$localPermission['permission'].']', '1',$userPermissions[$localPermission['permission'] ] == '1',['value'=>"grant"]) }}
</div>
</td>
<td class="col-md-1 permissions-item">
{{ Form::radio('permission['.$localPermission['permission'].']', '-1',$userPermissions[$localPermission['permission'] ] == '-1',['value'=>"deny"]) }}
</td>
<td class="col-md-1 permissions-item">
{{ Form::radio('permission['.$localPermission['permission'].']','0',$userPermissions[$localPermission['permission'] ] == '0',['value'=>"inherit"] ) }}
</td>
</tr>
</tbody>
@else
<tbody class="permissions-group">
<tr class="header-row permissions-row">
<td class="col-md-2 header-name">
<h3>{{ $area }}</h3>
</td>
<td class="col-md-1 permissions-item">
{{ Form::radio("$area", '1',false,['value'=>"grant"]) }}
</td>
<td class="col-md-1 permissions-item">
{{ Form::radio("$area", '-1',false,['value'=>"deny"]) }}
</td>
<td class="col-md-1 permissions-item">
{{ Form::radio("$area", '0',false,['value'=>"inherit"] ) }}
</td>
</tr>
@foreach ($permissionsArray as $index => $permission)
<tr class="permissions-row">
@if ($permission['display'])
<td
class="col-md-2 tooltip-base permissions-item"
data-toggle="tooltip"
data-placement="right"
title="{{ $permission['note'] }}"
>
{{ $permission['label'] }}
</td>
<td class="col-md-1 permissions-item">
@if (($permission['permission'] == 'superuser') && (!Auth::user()->isSuperUser()))
{{ Form::radio('permission['.$permission['permission'].']', '1', $userPermissions[$permission['permission'] ] == '1', ["value"=>"grant", 'disabled'=>'disabled']) }}
@else
{{ Form::radio('permission['.$permission['permission'].']', '1', $userPermissions[ $permission['permission'] ] == '1', ["value"=>"grant"]) }}
@endif
<?php $counter++; ?>
</td>
<td class="col-md-1 permissions-item">
@if (($permission['permission'] == 'superuser') && (!Auth::user()->isSuperUser()))
{{ Form::radio('permission['.$permission['permission'].']', '-1', $userPermissions[$permission['permission'] ] == '-1', ["value"=>"deny", 'disabled'=>'disabled']) }}
@else
{{ Form::radio('permission['.$permission['permission'].']', '-1', $userPermissions[$permission['permission'] ] == '-1', ["value"=>"deny"]) }}
@endif
</td>
<td class="col-md-1 permissions-item">
@if (($permission['permission'] == 'superuser') && (!Auth::user()->isSuperUser()))
{{ Form::radio('permission['.$permission['permission'].']', '0', $userPermissions[$permission['permission']] =='0', ["value"=>"inherit", 'disabled'=>'disabled']) }}
@else
{{ Form::radio('permission['.$permission['permission'].']', '0', $userPermissions[$permission['permission']] =='0', ["value"=>"inherit"]) }}
@endif
</td>
@endif
</tr>
@endforeach
</div>
</tbody>
@endif
@endforeach
</table>
</div><!-- /.tab-pane -->
</div><!-- /.tab-content -->
<div class="box-footer text-right">
<button type="submit" class="btn btn-success"><i class="fa fa-check icon-white"></i> {{ trans('general.save') }}</button>
</div>
</div><!-- nav-tabs-custom -->
</form>
</div>
</div>
@stop
@section('moar_scripts')
<script>
$(document).ready(function() {
@ -390,6 +500,19 @@ $(document).ready(function() {
});
</script>
<script>
$('tr.header-row input:radio').click(function() {
value = $(this).attr('value');
$(this).parent().parent().siblings().each(function() {
$(this).find('td input:radio[value='+value+']').prop("checked", true);
})
});
$('.header-name').click(function() {
$(this).parent().nextUntil('tr.header-row').slideToggle(500);
})
</script>
<script src="{{ asset('assets/js/pGenerator.jquery.js') }}"></script>
<script>
@ -397,6 +520,7 @@ $(document).ready(function() {
$(document).ready(function(){
$('.tooltip-base').tooltip({container: 'body'})
$(".superuser").change(function() {
var perms = $(this).val();
if (perms =='1') {
@ -422,5 +546,3 @@ $(document).ready(function(){
});
</script>
@stop
@stop