Integrate ajax select2 menus in all asset checkouts
This commit is contained in:
parent
75b527ab59
commit
82690e1fd7
17 changed files with 89958 additions and 198 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
6892
public/css/app.css
6892
public/css/app.css
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
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
52945
public/js/build/vue.js
52945
public/js/build/vue.js
File diff suppressed because one or more lines are too long
8692
public/js/dist/all.js
vendored
8692
public/js/dist/all.js
vendored
File diff suppressed because one or more lines are too long
|
@ -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"
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Add table
Reference in a new issue