Add support for setting IP aliases though panel
This commit is contained in:
parent
723e34a784
commit
a9d0b4a4fe
6 changed files with 188 additions and 94 deletions
|
@ -7,6 +7,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
* Support for creating server without having to assign a node and allocation manually. Simply select the checkbox or pass `auto_deploy=true` to the API to auto-select a node and allocation given a location.
|
* Support for creating server without having to assign a node and allocation manually. Simply select the checkbox or pass `auto_deploy=true` to the API to auto-select a node and allocation given a location.
|
||||||
|
* Support for setting IP Aliases through the panel on the node overview page. Also cleaned up allocation removal.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Prevent clicking server start button until server is completely off, not just stopping.
|
* Prevent clicking server start button until server is completely off, not just stopping.
|
||||||
|
|
|
@ -96,32 +96,21 @@ class NodesController extends Controller
|
||||||
public function getView(Request $request, $id)
|
public function getView(Request $request, $id)
|
||||||
{
|
{
|
||||||
$node = Models\Node::findOrFail($id);
|
$node = Models\Node::findOrFail($id);
|
||||||
$allocations = [];
|
|
||||||
$alloc = Models\Allocation::select('ip', 'port', 'assigned_to')->where('node', $node->id)->orderBy('ip', 'asc')->orderBy('port', 'asc')->get();
|
|
||||||
if ($alloc) {
|
|
||||||
foreach($alloc as &$alloc) {
|
|
||||||
if (!array_key_exists($alloc->ip, $allocations)) {
|
|
||||||
$allocations[$alloc->ip] = [[
|
|
||||||
'port' => $alloc->port,
|
|
||||||
'assigned_to' => $alloc->assigned_to
|
|
||||||
]];
|
|
||||||
} else {
|
|
||||||
array_push($allocations[$alloc->ip], [
|
|
||||||
'port' => $alloc->port,
|
|
||||||
'assigned_to' => $alloc->assigned_to
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return view('admin.nodes.view', [
|
return view('admin.nodes.view', [
|
||||||
'node' => $node,
|
'node' => $node,
|
||||||
'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail', 'services.name as a_serviceName')
|
'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail', 'services.name as a_serviceName')
|
||||||
->join('users', 'users.id', '=', 'servers.owner')
|
->join('users', 'users.id', '=', 'servers.owner')
|
||||||
->join('services', 'services.id', '=', 'servers.service')
|
->join('services', 'services.id', '=', 'servers.service')
|
||||||
->where('node', $id)->paginate(10),
|
->where('node', $id)->paginate(10, ['*'], 'servers'),
|
||||||
'stats' => Models\Server::select(DB::raw('SUM(memory) as memory, SUM(disk) as disk'))->where('node', $node->id)->first(),
|
'stats' => Models\Server::select(DB::raw('SUM(memory) as memory, SUM(disk) as disk'))->where('node', $node->id)->first(),
|
||||||
'locations' => Models\Location::all(),
|
'locations' => Models\Location::all(),
|
||||||
'allocations' => json_decode(json_encode($allocations), false),
|
'allocations' => Models\Allocation::select('allocations.*', 'servers.name as assigned_to_name')
|
||||||
|
->where('allocations.node', $node->id)
|
||||||
|
->leftJoin('servers', 'servers.id', '=', 'allocations.assigned_to')
|
||||||
|
->orderBy('allocations.ip', 'asc')
|
||||||
|
->orderBy('allocations.port', 'asc')
|
||||||
|
->paginate(20, ['*'], 'allocations'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,24 +140,51 @@ class NodesController extends Controller
|
||||||
])->withInput();
|
])->withInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteAllocation(Request $request, $id, $ip, $port = null)
|
public function deallocateSingle(Request $request, $node, $allocation)
|
||||||
{
|
{
|
||||||
$query = Models\Allocation::where('node', $id)->whereNull('assigned_to')->where('ip', $ip);
|
$query = Models\Allocation::where('node', $node)->whereNull('assigned_to')->where('id', $allocation)->delete();
|
||||||
if (is_null($port) || $port === 'undefined') {
|
if ((int) $query === 0) {
|
||||||
$allocation = $query;
|
|
||||||
} else {
|
|
||||||
$allocation = $query->where('port', $port)->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$allocation) {
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'error' => 'Unable to find an allocation matching those details to delete.'
|
'error' => 'Unable to find an allocation matching those details to delete.'
|
||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
$allocation->delete();
|
|
||||||
return response('', 204);
|
return response('', 204);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deallocateBlock(Request $request, $node)
|
||||||
|
{
|
||||||
|
$query = Models\Allocation::where('node', $node)->whereNull('assigned_to')->where('ip', $request->input('ip'))->delete();
|
||||||
|
if ((int) $query === 0) {
|
||||||
|
Alert::danger('There was an error while attempting to delete allocations on that IP.')->flash();
|
||||||
|
return redirect()->route('admin.nodes.view', [
|
||||||
|
'id' => $node,
|
||||||
|
'tab' => 'tab_allocations'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
Alert::success('Deleted all unallocated ports for <code>' . $request->input('ip') . '</code>.')->flash();
|
||||||
|
return redirect()->route('admin.nodes.view', [
|
||||||
|
'id' => $node,
|
||||||
|
'tab' => 'tab_allocations'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAlias(Request $request, $node)
|
||||||
|
{
|
||||||
|
if (!$request->input('allocation')) {
|
||||||
|
return response('Missing required parameters.', 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$update = Models\Allocation::findOrFail($request->input('allocation'));
|
||||||
|
$update->ip_alias = $request->input('alias');
|
||||||
|
$update->save();
|
||||||
|
|
||||||
|
return response('', 204);
|
||||||
|
} catch (\Exception $ex) {
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getAllocationsJson(Request $request, $id)
|
public function getAllocationsJson(Request $request, $id)
|
||||||
{
|
{
|
||||||
$allocations = Models\Allocation::select('ip')->where('node', $id)->groupBy('ip')->get();
|
$allocations = Models\Allocation::select('ip')->where('node', $id)->groupBy('ip')->get();
|
||||||
|
|
|
@ -243,8 +243,17 @@ class AdminRoutes {
|
||||||
'uses' => 'Admin\NodesController@postView'
|
'uses' => 'Admin\NodesController@postView'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$router->delete('/view/{id}/allocation/{ip}/{port?}', [
|
$router->delete('/view/{id}/deallocate/single/{allocation}', [
|
||||||
'uses' => 'Admin\NodesController@deleteAllocation'
|
'uses' => 'Admin\NodesController@deallocateSingle'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$router->post('/view/{id}/deallocate/block', [
|
||||||
|
'uses' => 'Admin\NodesController@deallocateBlock'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$router->post('/view/{id}/alias', [
|
||||||
|
'as' => 'admin.nodes.alias',
|
||||||
|
'uses' => 'Admin\NodesController@setAlias'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$router->get('/view/{id}/allocations.json', [
|
$router->get('/view/{id}/allocations.json', [
|
||||||
|
|
|
@ -90,6 +90,21 @@ body{font-size:13px}
|
||||||
.btn-xxs{padding:2px 6px;font-size:10px;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:2px}
|
.btn-xxs{padding:2px 6px;font-size:10px;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:2px}
|
||||||
.form-control{height:36px}
|
.form-control{height:36px}
|
||||||
.input-group-addon{font-size:12px;}
|
.input-group-addon{font-size:12px;}
|
||||||
|
.input-sm {
|
||||||
|
height: 30px;
|
||||||
|
padding: 4px 8px !important;
|
||||||
|
font-size: 12px !important;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
.input-loader {
|
||||||
|
display: none;
|
||||||
|
position:relative;
|
||||||
|
top: -23px;
|
||||||
|
float: right;
|
||||||
|
right: 5px;
|
||||||
|
color: #cccccc;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
pre{display:block;padding:12px 12px;margin:0;font-size:12px;color:#c7254e;background-color:#f9f2f4;border:1px solid #c7254e;border-radius:0;white-space:pre}
|
pre{display:block;padding:12px 12px;margin:0;font-size:12px;color:#c7254e;background-color:#f9f2f4;border:1px solid #c7254e;border-radius:0;white-space:pre}
|
||||||
.badge.label-danger {background: #d9534f !important;}
|
.badge.label-danger {background: #d9534f !important;}
|
||||||
.close {color:#000;opacity:0.2;font-size:1.6em;}
|
.close {color:#000;opacity:0.2;font-size:1.6em;}
|
||||||
|
@ -102,6 +117,9 @@ form .text-muted {margin: 0 0 -5.5px}
|
||||||
.label{border-radius: .25em;padding: .2em .6em .3em;}
|
.label{border-radius: .25em;padding: .2em .6em .3em;}
|
||||||
kbd{border-radius: .25em}
|
kbd{border-radius: .25em}
|
||||||
.modal-open .modal {padding-left: 0px !important;padding-right: 0px !important;overflow-y: scroll;}
|
.modal-open .modal {padding-left: 0px !important;padding-right: 0px !important;overflow-y: scroll;}
|
||||||
|
.align-middle {
|
||||||
|
vertical-align: middle !important;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pillboxes
|
* Pillboxes
|
||||||
|
|
|
@ -307,45 +307,6 @@
|
||||||
<div class="tab-pane" id="tab_allocation">
|
<div class="tab-pane" id="tab_allocation">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"></div>
|
<div class="panel-heading"></div>
|
||||||
<div class="panel-body">
|
|
||||||
<table class="table table-striped table-bordered table-hover" style="margin-bottom:0;">
|
|
||||||
<thead>
|
|
||||||
<td>IP Address</td>
|
|
||||||
<td>Ports</td>
|
|
||||||
<td></td>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach($allocations as $ip => $ports)
|
|
||||||
<tr>
|
|
||||||
<td><span style="cursor:pointer" data-action="delete" data-ip="{{ $ip }}" data-total="{{ count($ports) }}" class="is-ipblock"><i class="fa fa-fw fa-square-o"></i></span> {{ $ip }}</td>
|
|
||||||
<td>
|
|
||||||
@foreach($ports as $id => $allocation)
|
|
||||||
@if (($id % 2) === 0)
|
|
||||||
@if($allocation->assigned_to === null)
|
|
||||||
<span style="cursor:pointer" data-action="delete" data-ip="{{ $ip }}" data-port="{{ $allocation->port }}"><i class="fa fa-fw fa-square-o"></i> {{ $allocation->port }} <br /></span>
|
|
||||||
@else
|
|
||||||
<i class="fa fa-fw fa-check-square-o"></i> {{ $allocation->port }} <br />
|
|
||||||
@endif
|
|
||||||
@endif
|
|
||||||
@endforeach
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
@foreach($ports as $id => $allocation)
|
|
||||||
@if (($id % 2) === 1)
|
|
||||||
@if($allocation->assigned_to === null)
|
|
||||||
<span style="cursor:pointer" data-action="delete" data-ip="{{ $ip }}" data-port="{{ $allocation->port }}"><i class="fa fa-fw fa-square-o"></i> {{ $allocation->port }} <br /></span>
|
|
||||||
@else
|
|
||||||
<i class="fa fa-fw fa-check-square-o"></i> {{ $allocation->port }} <br />
|
|
||||||
@endif
|
|
||||||
@endif
|
|
||||||
@endforeach
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="panel-heading" style="border-top: 1px solid #ddd;"></div>
|
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<h4 style="margin-top:0;">Allocate Additional Ports</h4>
|
<h4 style="margin-top:0;">Allocate Additional Ports</h4>
|
||||||
<form action="{{ route('admin.nodes.post.allocations', $node->id) }}" method="POST">
|
<form action="{{ route('admin.nodes.post.allocations', $node->id) }}" method="POST">
|
||||||
|
@ -391,6 +352,43 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="panel-heading" style="border-top: 1px solid #ddd;"></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="row">
|
||||||
|
<table class="table table-hover" style="margin-bottom:0;">
|
||||||
|
<thead style="font-weight:bold;">
|
||||||
|
<td>IP Address <i class="fa fa-fw fa-minus-square" style="font-weight:normal;color:#d9534f;cursor:pointer;" data-toggle="modal" data-target="#allocationModal"></i></td>
|
||||||
|
<td>IP Alias</td>
|
||||||
|
<td>Port</td>
|
||||||
|
<td>Assigned To</td>
|
||||||
|
<td></td>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($allocations as $allocation)
|
||||||
|
<tr>
|
||||||
|
<td class="col-sm-3 align-middle">{{ $allocation->ip }}</td>
|
||||||
|
<td class="col-sm-3 align-middle">
|
||||||
|
<input class="form-control input-sm" type="text" value="{{ $allocation->ip_alias }}" data-action="set-alias" data-id="{{ $allocation->id }}" placeholder="none" />
|
||||||
|
<span class="input-loader"><i class="fa fa-refresh fa-spin fa-fw"></i></span>
|
||||||
|
</td>
|
||||||
|
<td class="col-sm-2 align-middle">{{ $allocation->port }}</td>
|
||||||
|
<td class="col-sm-3 align-middle">@if(!is_null($allocation->assigned_to))<a href="{{ route('admin.servers.view', $allocation->assigned_to) }}">{{ $allocation->assigned_to_name }}</a>@endif</td>
|
||||||
|
<td class="col-sm-1 align-middle">
|
||||||
|
@if(is_null($allocation->assigned_to))
|
||||||
|
<a href="#" data-action="deallocate" data-id="{{ $allocation->id }}"><span class="badge label-danger"><i class="fa fa-trash-o"></i></span></a>
|
||||||
|
@else
|
||||||
|
<span class="badge label-default"><i class="fa fa-trash-o"></i></span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="col-md-12 text-center">
|
||||||
|
{{ $allocations->appends(['tab' => 'tab_allocation'])->links() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" id="tab_servers">
|
<div class="tab-pane" id="tab_servers">
|
||||||
|
@ -458,6 +456,38 @@
|
||||||
<div class="col-xs-11" id="col11_setter"></div>
|
<div class="col-xs-11" id="col11_setter"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="modal fade" id="allocationModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 class="modal-title">Delete Allocations for IP Block</h4>
|
||||||
|
</div>
|
||||||
|
<form action="{{ route('admin.nodes.view', $node->id) }}/deallocate/block" method="POST">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<select class="form-control" name="ip">
|
||||||
|
<?php $displayed = []; ?>
|
||||||
|
@foreach($allocations as $allocation)
|
||||||
|
@if(!array_key_exists($allocation->ip, $displayed))
|
||||||
|
<option value="{{ $allocation->ip }}">{{ $allocation->ip }}</option>
|
||||||
|
<?php $displayed[$allocation->ip] = true; ?>
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
{{{ csrf_field() }}}
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||||
|
<button type="submit" class="btn btn-danger">Delete Allocations</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('#sidebar_links').find("a[href='/admin/nodes']").addClass('active');
|
$('#sidebar_links').find("a[href='/admin/nodes']").addClass('active');
|
||||||
|
@ -655,14 +685,13 @@ $(document).ready(function () {
|
||||||
$(this).find('i').css('color', 'inherit').addClass('fa-square-o').removeClass('fa-minus-square');
|
$(this).find('i').css('color', 'inherit').addClass('fa-square-o').removeClass('fa-minus-square');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('span[data-action="delete"]').click(function (event) {
|
$('a[data-action="deallocate"]').click(function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var element = $(this);
|
var element = $(this);
|
||||||
var deleteIp = $(this).data('ip');
|
var allocation = $(this).data('id');
|
||||||
var deletePort = $(this).data('port');
|
|
||||||
swal({
|
swal({
|
||||||
title: '',
|
title: '',
|
||||||
text: 'Are you sure you want to delete this port?',
|
text: 'Are you sure you want to delete this allocation?',
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
allowOutsideClick: true,
|
allowOutsideClick: true,
|
||||||
|
@ -673,27 +702,12 @@ $(document).ready(function () {
|
||||||
}, function () {
|
}, function () {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
url: '{{ route('admin.nodes.view', $node->id) }}/allocation/' + deleteIp + '/' + deletePort,
|
url: '{{ route('admin.nodes.view', $node->id) }}/deallocate/single/' + allocation,
|
||||||
headers: {
|
headers: {
|
||||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||||
}
|
}
|
||||||
}).done(function (data) {
|
}).done(function (data) {
|
||||||
if (element.hasClass('is-ipblock')) {
|
element.parent().parent().addClass('warning').delay(100).fadeOut();
|
||||||
var tMatched = 0;
|
|
||||||
element.parent().parent().find('*').each(function () {
|
|
||||||
if ($(this).attr('data-port') && $(this).attr('data-ip')) {
|
|
||||||
$(this).fadeOut();
|
|
||||||
tMatched++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (tMatched === element.data('total')) {
|
|
||||||
element.fadeOut();
|
|
||||||
$('li[data-action="alloc_dropdown_val"][data-value="' + deleteIp + '"]').remove();
|
|
||||||
element.parent().parent().slideUp().remove();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
element.fadeOut();
|
|
||||||
}
|
|
||||||
swal({
|
swal({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: 'Port Deleted!',
|
title: 'Port Deleted!',
|
||||||
|
@ -709,6 +723,42 @@ $(document).ready(function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var typingTimer;
|
||||||
|
$('input[data-action="set-alias"]').keyup(function () {
|
||||||
|
clearTimeout(typingTimer);
|
||||||
|
$(this).parent().removeClass('has-error has-success');
|
||||||
|
typingTimer = setTimeout(sendAlias, 700, $(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
var fadeTimers = [];
|
||||||
|
function sendAlias(element) {
|
||||||
|
element.parent().find('.input-loader').show();
|
||||||
|
clearTimeout(fadeTimers[element.data('id')]);
|
||||||
|
$.ajax({
|
||||||
|
method: 'POST',
|
||||||
|
url: '{{ route('admin.nodes.alias', $node->id) }}',
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
alias: element.val(),
|
||||||
|
allocation: element.data('id')
|
||||||
|
}
|
||||||
|
}).done(function (data) {
|
||||||
|
element.parent().addClass('has-success');
|
||||||
|
}).fail(function (jqXHR) {
|
||||||
|
console.error(jqXHR);
|
||||||
|
element.parent().addClass('has-error');
|
||||||
|
}).always(function () {
|
||||||
|
element.parent().find('.input-loader').hide();
|
||||||
|
fadeTimers[element.data('id')] = setTimeout(clearHighlight, 2500, element);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearHighlight(element) {
|
||||||
|
element.parent().removeClass('has-error has-success');
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
@if ($paginator->count() > 1)
|
@if ($paginator->lastPage() > 1)
|
||||||
<ul class="pagination">
|
<ul class="pagination">
|
||||||
<!-- Previous Page Link -->
|
<!-- Previous Page Link -->
|
||||||
@if ($paginator->onFirstPage())
|
@if ($paginator->onFirstPage())
|
||||||
<li class="disabled"><span>«</span></li>
|
{{-- <li class="disabled"><span>«</span></li> --}}
|
||||||
@else
|
@else
|
||||||
<li><a href="{{ $paginator->previousPageUrl() }}" rel="prev">«</a></li>
|
<li><a href="{{ $paginator->previousPageUrl() }}" rel="prev">«</a></li>
|
||||||
@endif
|
@endif
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
@if ($paginator->hasMorePages())
|
@if ($paginator->hasMorePages())
|
||||||
<li><a href="{{ $paginator->nextPageUrl() }}" rel="next">»</a></li>
|
<li><a href="{{ $paginator->nextPageUrl() }}" rel="next">»</a></li>
|
||||||
@else
|
@else
|
||||||
<li class="disabled"><span>»</span></li>
|
{{-- <li class="disabled"><span>»</span></li> --}}
|
||||||
@endif
|
@endif
|
||||||
</ul>
|
</ul>
|
||||||
@endif
|
@endif
|
||||||
|
|
Loading…
Reference in a new issue