Integrate ajax select2 menus in all asset checkouts

This commit is contained in:
snipe 2017-10-26 02:28:17 -07:00
parent 75b527ab59
commit 82690e1fd7
17 changed files with 89958 additions and 198 deletions

View file

@ -263,6 +263,61 @@ class AssetsController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
}
/**
* Display a formatted JSON response for the select2 menus
*
* @todo: create a transformer for handling these responses
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
*
* @return \Illuminate\Http\Response
*/
public function selectlist(Request $request)
{
$this->authorize('view', Asset::class);
$assets = Company::scopeCompanyables(Asset::select([
'assets.id',
'assets.name',
'assets.asset_tag',
'assets.model_id',
]))->with('model')->RTD();
if ($request->has('search')) {
$assets = $assets->where('assets.name', 'LIKE', '%'.$request->get('search').'%')
->orWhere('assets.asset_tag', 'LIKE', '%'.$request->get('search').'%')
->join('models AS assets_models',function ($join) use ($request) {
$join->on('assets_models.id', "=", "assets.model_id");
})->orWhere('assets_models.name','LIKE','%'.$request->get('search').'%');
}
$assets = $assets->paginate(50);
$assets_array = [];
foreach ($assets as $asset) {
$assets_array[] =
[
'id' => (int) $asset->id,
'text' => e($asset->present()->fullName),
'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null,
];
}
$results = [
'items' => $assets_array,
'pagination' =>
[
'more' => ($assets->currentPage() >= $assets->lastPage()) ? false : true,
'per_page' => $assets->perPage()
],
'total_count' => $assets->total(),
'page' => $assets->currentPage(),
'page_count' => $assets->lastPage()
];
return $results;
}
/**
* Accepts a POST request to create a new asset

View file

@ -139,4 +139,55 @@ class LocationsController extends Controller
$location->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/locations/message.delete.success')));
}
/**
* Display a formatted JSON response for the select2 menus
*
* @todo: create a transformer for handling these responses
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
*
* @return \Illuminate\Http\Response
*/
public function selectlist(Request $request)
{
$this->authorize('view', Location::class);
$locations = Location::select([
'locations.id',
'locations.name',
'locations.image',
]);
if ($request->has('search')) {
$locations = $locations->where('locations.name', 'LIKE', '%'.$request->get('search').'%');
}
$locations = $locations->paginate(50);
$locations_array = [];
foreach ($locations as $location) {
$locations_array[] =
[
'id' => (int) $location->id,
'text' => e($location->name),
'image' => ($location->image) ? url('/').'/uploads/locations/'.$location->image : null,
];
}
$results = [
'items' => $locations_array,
'pagination' =>
[
'more' => ($locations->currentPage() >= $locations->lastPage()) ? false : true,
'per_page' => $locations->perPage()
],
'total_count' => $locations->total(),
'page' => $locations->currentPage(),
'page_count' => $locations->lastPage()
];
return $results;
}
}

View file

@ -273,14 +273,16 @@ class AssetPresenter extends Presenter
**/
public function name()
{
if (empty($this->name)) {
if (isset($this->model)) {
return $this->model->name.' ('.$this->asset_tag.')';
if (empty($this->model->name)) {
if (isset($this->model->model)) {
return $this->model->model->name.' ('.$this->model->asset_tag.')';
}
return $this->asset_tag;
return $this->model->asset_tag;
} else {
return $this->name.' ('.$this->asset_tag.')';
return $this->model->name . ' (' . $this->model->asset_tag . ')';
}
}
/**
@ -289,7 +291,18 @@ class AssetPresenter extends Presenter
*/
public function fullName()
{
return $this->name();
$str = '';
if ($this->model->name) {
$str .= $this->name;
}
if ($this->asset_tag) {
$str .= ' ('.$this->model->asset_tag.')';
}
if ($this->model->model) {
$str .= ' - '.$this->model->model->name;
}
return $str;
}
/**
* Returns the date this item hits EOL.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4377
public/css/dist/all.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

8692
public/js/dist/all.js vendored

File diff suppressed because one or more lines are too long

View file

@ -1,14 +1,10 @@
{
"/js/build/vue.js": "/js/build/vue.js?id=e6804371942215bd1d7d",
"/css/AdminLTE.css": "/css/AdminLTE.css?id=b8be19a285eaf44eec37",
"/css/app.css": "/css/app.css?id=407edb63cc6b6dc62405",
"/css/overrides.css": "/css/overrides.css?id=9ae1a3c861441320c5a1",
"/js/build/vue.js.map": "/js/build/vue.js.map?id=3b3d417664a61dcce3e9",
"/css/AdminLTE.css.map": "/css/AdminLTE.css.map?id=99f5a5a03c4155cf69f6",
"/css/app.css.map": "/css/app.css.map?id=bdbe05e6ecd70ccfac72",
"/css/overrides.css.map": "/css/overrides.css.map?id=898c91d4a425b01b589b",
"/css/dist/all.css": "/css/dist/all.css?id=7c3842d2639193ac7e88",
"/js/dist/all.js": "/js/dist/all.js?id=f14abfc2506d42ffb0f5",
"/css/build/all.css": "/css/build/all.css?id=7c3842d2639193ac7e88",
"/js/build/all.js": "/js/build/all.js?id=f14abfc2506d42ffb0f5"
"/js/build/vue.js": "/js/build/vue.js?id=e9504cad01a748f9b0fa",
"/css/AdminLTE.css": "/css/AdminLTE.css?id=889dc040f2ddfca6efde",
"/css/app.css": "/css/app.css?id=3a1e8c168fa8714043a6",
"/css/overrides.css": "/css/overrides.css?id=3911514a8a64a4247483",
"/css/dist/all.css": "/css/dist/all.css?id=f2d4896e67e878a47434",
"/js/dist/all.js": "/js/dist/all.js?id=b967aad5fdaca0a91359",
"/css/build/all.css": "/css/build/all.css?id=f2d4896e67e878a47434",
"/js/build/all.js": "/js/build/all.js?id=b967aad5fdaca0a91359"
}

View file

@ -180,14 +180,78 @@ $(document).ready(function () {
}
$('.datepicker').datepicker();
$(document).ready(function() {
$("#toggle_nav").toggle(function() {
var datepicker = $.fn.datepicker.noConflict(); // return $.fn.datepicker to previously assigned value
$.fn.bootstrapDP = datepicker;
$('.datepicker').datepicker();
// Crazy select2 rich dropdowns with images!
$('.js-data-ajax').each( function (i,item) {
var link = $(item);
var endpoint = link.data("endpoint");
var select = link.data("select");
link.select2({
ajax: {
url: baseUrl + '/api/v1/' + endpoint + '/selectlist',
dataType: 'json',
delay: 250,
headers: {
"X-Requested-With": 'XMLHttpRequest',
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
},
data: function (params) {
var data = {
search: params.term,
page: params.page || 1
};
return data;
},
processResults: function (data, params) {
params.page = params.page || 1;
var answer = {
results: data.items,
pagination: {
more: "true" //(params.page < data.page_count)
}
};
return answer;
},
cache: true
},
escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
templateResult: formatDatalist,
templateSelection: formatDataSelection
});
});
function formatDatalist (datalist) {
var loading_markup = '<i class="fa fa-spinner fa-spin" aria-hidden="true"></i> Loading...';
if (datalist.loading) {
return loading_markup;
}
var markup = "<div class='clearfix'>" ;
markup +="<div class='pull-left' style='padding-right: 10px;'>";
if (datalist.image) {
markup += "<img src='" + datalist.image + "' style='max-height: 20px'>";
} else {
markup += "<div style='height: 20px; width: 20px;'></div>";
}
markup += "</div><div>" + datalist.text + "</div>";
markup += "</div>";
return markup;
}
function formatDataSelection (datalist) {
return datalist.text;
}

View file

@ -95,10 +95,14 @@
// clicked 'add' on to add a new 'thing'
// this code adds the newly created object to that select
var selector = document.getElementById(select);
console.warn("The selector we should've selecte dis: "+select);
console.dir(selector);
if(!selector) {
return false;
}
console.warn("onChange Selector Thing should've activated? Here's the selector");
console.dir(selector);
selector.options[selector.length] = new Option(name, id);
selector.selectedIndex = selector.length - 1;
$(selector).trigger("change");

View file

@ -47,45 +47,58 @@
<div id="assigned_user" class="form-group{{ $errors->has('assigned_to') ? ' has-error' : '' }}">
<div id="assigned_user" class="form-group{{ $errors->has('assigned_user') ? ' has-error' : '' }}">
{{ Form::label('assigned_user', trans('admin/hardware/form.checkout_to'), array('class' => 'col-md-3 control-label')) }}
<div class="col-md-7 required">
<select class="js-data-user-ajax" name="assigned_user" style="width: 350px;">
<select class="js-data-ajax" data-endpoint="users" name="assigned_user" style="width: 100%" id="assigned_user_select">
<option value="">{{ trans('general.select_user') }}</option>
</select>
</div>
{!! $errors->first('assigned_user', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
<div class="col-md-1 col-sm-1 text-left">
@can('create', \App\Models\User::class)
<a href='{{ route('modal.user') }}' data-toggle="modal" data-target="#createModal" data-dependency="user" data-select='assigned_user_select' class="btn btn-sm btn-default">New</a>
@endcan
</div>
</div>
@if (!$asset->requireAcceptance())
<!-- Assets -->
<div id="assigned_asset" class="form-group{{ $errors->has('assigned_to') ? ' has-error' : '' }}">
{{ Form::label('assigned_asset', trans('admin/hardware/form.checkout_to'), array('class' => 'col-md-3 control-label')) }}
<div class="col-md-7 required">
{{ Form::select('assigned_asset', $assets_list , Input::old('assigned_asset', $asset->assigned_type == 'App\Models\Asset' ? $asset->assigned_to : 0), array('class'=>'select2', 'id'=>'assigned_asset', 'style'=>'width:100%')) }}
{!! $errors->first('assigned_asset', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
</div>
</div>
<!-- Locations -->
<div id="assigned_location" class="form-group{{ $errors->has('assigned_to') ? ' has-error' : '' }}">
{{ Form::label('assigned_location', trans('admin/hardware/form.checkout_to'), array('class' => 'col-md-3 control-label')) }}
<div class="col-md-7 required">
{{ Form::select('assigned_location', $locations_list , Input::old('assigned_location', $asset->assigned_type == 'App\Models\Asset' ? $asset->assigned_to : 0), array('class'=>'select2', 'id'=>'assigned_location', 'style'=>'width:100%')) }}
{!! $errors->first('assigned_location', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
</div>
</div>
{!! $errors->first('assigned_user', '<div class="col-md-8 col-md-offset-3"><span class="alert-msg"><i class="fa fa-times"></i> :message</span></div>') !!}
</div>
@if (!$asset->requireAcceptance())
<!-- Asset -->
<div id="assigned_asset" class="form-group{{ $errors->has('assigned_asset') ? ' has-error' : '' }}">
{{ Form::label('assigned_asset', trans('admin/hardware/form.checkout_to'), array('class' => 'col-md-3 control-label')) }}
<div class="col-md-7 required">
<select class="js-data-ajax" data-endpoint="hardware" name="assigned_asset" style="width: 100%" id="assigned_asset_select">
<option value="">{{ trans('general.select_asset') }}</option>
</select>
</div>
{!! $errors->first('assigned_asset', '<div class="col-md-8 col-md-offset-3"><span class="alert-msg"><i class="fa fa-times"></i> :message</span></div>') !!}
</div>
<!-- Location -->
<div id="assigned_location" class="form-group{{ $errors->has('assigned_location') ? ' has-error' : '' }}">
{{ Form::label('assigned_location', trans('admin/hardware/form.checkout_to'), array('class' => 'col-md-3 control-label')) }}
<div class="col-md-7 required">
<select class="js-data-ajax" data-endpoint="locations" name="assigned_location" style="width: 100%" id="assigned_location_select">
<option value="">{{ trans('general.select_location') }}</option>
</select>
</div>
<div class="col-md-1 col-sm-1 text-left">
@can('create', \App\Models\Location::class)
<a href='{{ route('modal.location') }}' data-toggle="modal" data-target="#createModal" data-dependency="location" data-select='assigned_location_select' class="btn btn-sm btn-default">New</a>
@endcan
</div>
{!! $errors->first('assigned_location', '<div class="col-md-8 col-md-offset-3"><span class="alert-msg"><i class="fa fa-times"></i> :message</span></div>') !!}
</div>
@endif
<!-- Checkout/Checkin Date -->
<div class="form-group {{ $errors->has('checkout_at') ? 'error' : '' }}">
@ -164,9 +177,12 @@
@section('moar_scripts')
<script nonce="{{ csrf_token() }}">
// create the assigned assets listing box for the right side of the screen
$(function() {
$('#assigned_user').on("change",function () {
var userid = $('#assigned_user option:selected').val();
if(userid=='') {
console.warn('no user selected');
$('#current_assets_box').fadeOut();

View file

@ -658,73 +658,6 @@
<script src="{{ url(mix('js/dist/all.js')) }}" nonce="{{ csrf_token() }}"></script>
<script nonce="{{ csrf_token() }}">
$(function () {
var datepicker = $.fn.datepicker.noConflict(); // return $.fn.datepicker to previously assigned value
$.fn.bootstrapDP = datepicker;
$('.datepicker').datepicker();
});
// Crazy select2 rich dropdowns with images!
$(".js-data-user-ajax").select2({
ajax: {
url: '{{ route('api.users.selectlist') }}',
dataType: 'json',
delay: 250,
headers: {
"X-Requested-With": 'XMLHttpRequest',
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
},
data: function (params) {
var data = {
search: params.term,
page: params.page || 1
};
return data;
},
processResults: function (data, params) {
params.page = params.page || 1;
var answer = {
results: data.items,
pagination: {
more: "true" //(params.page < data.page_count)
}
};
return answer;
},
cache: true
},
escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
templateResult: formatUserlist,
templateSelection: formatUserSelection
});
function formatUserlist (userlist) {
var loading_markup = '<i class="fa fa-spinner fa-spin" aria-hidden="true"></i> Loading...';
if (userlist.loading) {
return loading_markup;
}
var markup = "<div class='clearfix'>" ;
markup +="<div class='pull-left' style='padding-right: 10px;'>";
markup += "<img src='" + userlist.image + "' style='max-height: 20px'></div>";
markup += "<div>" + userlist.text + "</div>";
markup += "</div>";
return markup;
}
function formatUserSelection (userlist) {
return userlist.text;
}
</script>
@section('moar_scripts')
@show

View file

@ -226,6 +226,12 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
Route::group(['prefix' => 'hardware'], function () {
Route::get( 'selectlist', [
'as' => 'assets.selectlist',
'uses' => 'AssetsController@selectlist'
]);
Route::post('audit', [
'as' => 'api.asset.audit',
'uses' => 'AssetsController@audit'
@ -331,21 +337,6 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
/*--- Locations API ---*/
Route::resource('locations', 'LocationsController',
[
'names' =>
[
'index' => 'api.locations.index',
'show' => 'api.locations.show',
'store' => 'api.locations.store',
'update' => 'api.locations.update',
'destroy' => 'api.locations.destroy'
],
'except' => ['create', 'edit'],
'parameters' => ['location' => 'location_id']
]
); // Locations resource
Route::group(['prefix' => 'locations'], function () {
Route::get('{location}/users',
@ -369,9 +360,33 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
'uses' => 'LocationsController@show'
]
);
Route::get( 'selectlist', [
'as' => 'locations.selectlist',
'uses' => 'LocationsController@selectlist'
]);
}); // Locations group
Route::resource('locations', 'LocationsController',
[
'names' =>
[
'index' => 'api.locations.index',
'show' => 'api.locations.show',
'store' => 'api.locations.store',
'update' => 'api.locations.update',
'destroy' => 'api.locations.destroy'
],
'except' => ['create', 'edit'],
'parameters' => ['location' => 'location_id']
]
); // Locations resource
/*--- Manufacturers API ---*/
Route::resource('manufacturers', 'ManufacturersController',