Skip to content

Commit 262ef78

Browse files
ayan4m1DaneEveritt
authored andcommitted
Allow deletion of multiple allocations at once (pterodactyl#1322)
1 parent 053d791 commit 262ef78

File tree

6 files changed

+164
-7
lines changed

6 files changed

+164
-7
lines changed

app/Http/Controllers/Admin/NodesController.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,27 @@ public function allocationRemoveSingle(int $node, Allocation $allocation): Respo
285285
return response('', 204);
286286
}
287287

288+
/**
289+
* Removes multiple individual allocations from a node.
290+
*
291+
* @param \Illuminate\Http\Request $request
292+
* @param int $node
293+
* @return \Illuminate\Http\Response
294+
*
295+
* @throws \Pterodactyl\Exceptions\Service\Allocation\ServerUsingAllocationException
296+
*/
297+
public function allocationRemoveMultiple(Request $request, int $node): Response
298+
{
299+
$allocations = $request->input('allocations');
300+
foreach ($allocations as $rawAllocation) {
301+
$allocation = new Allocation();
302+
$allocation->id = $rawAllocation['id'];
303+
$this->allocationRemoveSingle($node, $allocation);
304+
}
305+
306+
return response('', 204);
307+
}
308+
288309
/**
289310
* Remove all allocations for a specific IP at once on a node.
290311
*

public/js/laroute.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/themes/pterodactyl/js/frontend/files/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ class FileManager {
113113
addFolderButton() {
114114
$('[data-action="add-folder"]').unbind().on('click', () => {
115115
new ActionsClass().folder($('#file_listing').data('current-dir') || '/');
116-
})
116+
});
117117
}
118118

119119
selectRow() {

resources/lang/en/server.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@
258258
],
259259
],
260260
],
261+
'allocations' => [
262+
'mass_actions' => 'Mass Actions',
263+
'delete' => 'Delete Allocations',
264+
],
261265
'files' => [
262266
'exceptions' => [
263267
'invalid_mime' => 'This type of file cannot be edited via the Panel\'s built-in editor.',

resources/themes/pterodactyl/admin/nodes/view/allocation.blade.php

Lines changed: 136 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,42 @@
3939
<div class="box-header with-border">
4040
<h3 class="box-title">Existing Allocations</h3>
4141
</div>
42-
<div class="box-body table-responsive no-padding">
42+
<div class="box-body table-responsive no-padding" style="overflow-x: visible">
4343
<table class="table table-hover" style="margin-bottom:0;">
4444
<tr>
45+
<th>
46+
<input type="checkbox" class="select-all-files hidden-xs" data-action="selectAll">
47+
</th>
4548
<th>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></th>
4649
<th>IP Alias</th>
4750
<th>Port</th>
4851
<th>Assigned To</th>
49-
<th></th>
52+
<th>
53+
<div class="btn-group hidden-xs">
54+
<button type="button" id="mass_actions" class="btn btn-sm btn-default dropdown-toggle disabled"
55+
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">@lang('server.allocations.mass_actions') <span class="caret"></span>
56+
</button>
57+
<ul class="dropdown-menu dropdown-massactions">
58+
<li><a href="#" id="selective-deletion" data-action="selective-deletion">@lang('server.allocations.delete') <i class="fa fa-fw fa-trash-o"></i></a></li>
59+
</ul>
60+
</div>
61+
</th>
5062
</tr>
5163
@foreach($node->allocations as $allocation)
5264
<tr>
53-
<td class="col-sm-3 middle">{{ $allocation->ip }}</td>
65+
<td class="middle min-size" data-identifier="type">
66+
@if(is_null($allocation->server_id))
67+
<input type="checkbox" class="select-file hidden-xs" data-action="addSelection">
68+
@else
69+
<input disabled="disabled" type="checkbox" class="select-file hidden-xs" data-action="addSelection">
70+
@endif
71+
</td>
72+
<td class="col-sm-3 middle" data-identifier="ip">{{ $allocation->ip }}</td>
5473
<td class="col-sm-3 middle">
5574
<input class="form-control input-sm" type="text" value="{{ $allocation->ip_alias }}" data-action="set-alias" data-id="{{ $allocation->id }}" placeholder="none" />
5675
<span class="input-loader"><i class="fa fa-refresh fa-spin fa-fw"></i></span>
5776
</td>
58-
<td class="col-sm-2 middle">{{ $allocation->port }}</td>
77+
<td class="col-sm-2 middle" data-identifier="port">{{ $allocation->port }}</td>
5978
<td class="col-sm-3 middle">
6079
@if(! is_null($allocation->server))
6180
<a href="{{ route('admin.servers.view', $allocation->server_id) }}">{{ $allocation->server->name }}</a>
@@ -153,17 +172,35 @@
153172
@section('footer-scripts')
154173
@parent
155174
<script>
175+
$('[data-action="addSelection"]').on('click', function () {
176+
updateMassActions();
177+
});
178+
179+
$('[data-action="selectAll"]').on('click', function () {
180+
$('input.select-file').not(':disabled').prop('checked', function (i, val) {
181+
return !val;
182+
});
183+
184+
updateMassActions();
185+
});
186+
187+
$('[data-action="selective-deletion"]').on('mousedown', function () {
188+
deleteSelected();
189+
});
190+
156191
$('#pAllocationIP').select2({
157192
tags: true,
158193
maximumSelectionLength: 1,
159194
selectOnClose: true,
160195
tokenSeparators: [',', ' '],
161196
});
197+
162198
$('#pAllocationPorts').select2({
163199
tags: true,
164200
selectOnClose: true,
165201
tokenSeparators: [',', ' '],
166202
});
203+
167204
$('button[data-action="deallocate"]').click(function (event) {
168205
event.preventDefault();
169206
var element = $(this);
@@ -216,7 +253,7 @@ function sendAlias(element) {
216253
alias: element.val(),
217254
allocation_id: element.data('id'),
218255
}
219-
}).done(function (data) {
256+
}).done(function () {
220257
element.parent().addClass('has-success');
221258
}).fail(function (jqXHR) {
222259
console.error(jqXHR);
@@ -230,5 +267,99 @@ function sendAlias(element) {
230267
function clearHighlight(element) {
231268
element.parent().removeClass('has-error has-success');
232269
}
270+
271+
function updateMassActions() {
272+
if ($('input.select-file:checked').length > 0) {
273+
$('#mass_actions').removeClass('disabled');
274+
} else {
275+
$('#mass_actions').addClass('disabled');
276+
}
277+
}
278+
279+
function deleteSelected() {
280+
var selectedIds = [];
281+
var selectedItems = [];
282+
var selectedItemsElements = [];
283+
284+
$('input.select-file:checked').each(function () {
285+
var $parent = $($(this).closest('tr'));
286+
var id = $parent.find('[data-action="deallocate"]').data('id');
287+
var $ip = $parent.find('td[data-identifier="ip"]');
288+
var $port = $parent.find('td[data-identifier="port"]');
289+
var block = `${$ip.text()}:${$port.text()}`;
290+
291+
selectedIds.push({
292+
id: id
293+
});
294+
selectedItems.push(block);
295+
selectedItemsElements.push($parent);
296+
});
297+
298+
if (selectedItems.length !== 0) {
299+
var formattedItems = "";
300+
var i = 0;
301+
$.each(selectedItems, function (key, value) {
302+
formattedItems += ("<code>" + value + "</code>, ");
303+
i++;
304+
return i < 5;
305+
});
306+
307+
formattedItems = formattedItems.slice(0, -2);
308+
if (selectedItems.length > 5) {
309+
formattedItems += ', and ' + (selectedItems.length - 5) + ' other(s)';
310+
}
311+
312+
swal({
313+
type: 'warning',
314+
title: '',
315+
text: 'Are you sure you want to delete the following allocations: ' + formattedItems + '?',
316+
html: true,
317+
showCancelButton: true,
318+
showConfirmButton: true,
319+
closeOnConfirm: false,
320+
showLoaderOnConfirm: true
321+
}, function () {
322+
$.ajax({
323+
method: 'DELETE',
324+
url: Router.route('admin.nodes.view.allocation.removeMultiple', {
325+
node: Pterodactyl.node.id
326+
}),
327+
headers: {'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content')},
328+
data: JSON.stringify({
329+
allocations: selectedIds
330+
}),
331+
contentType: 'application/json',
332+
processData: false
333+
}).done(function () {
334+
$('#file_listing input:checked').each(function () {
335+
$(this).prop('checked', false);
336+
});
337+
338+
$.each(selectedItemsElements, function () {
339+
$(this).addClass('warning').delay(200).fadeOut();
340+
});
341+
342+
swal({
343+
type: 'success',
344+
title: 'Allocations Deleted'
345+
});
346+
}).fail(function (jqXHR) {
347+
console.error(jqXHR);
348+
swal({
349+
type: 'error',
350+
title: 'Whoops!',
351+
html: true,
352+
text: 'An error occurred while attempting to delete these allocations. Please try again.',
353+
});
354+
});
355+
});
356+
} else {
357+
swal({
358+
type: 'warning',
359+
title: '',
360+
text: 'Please select allocation(s) to delete.',
361+
});
362+
}
363+
}
233364
</script>
234365
@endsection

routes/admin.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@
153153

154154
Route::delete('/view/{node}/delete', 'NodesController@delete')->name('admin.nodes.view.delete');
155155
Route::delete('/view/{node}/allocation/remove/{allocation}', 'NodesController@allocationRemoveSingle')->name('admin.nodes.view.allocation.removeSingle');
156+
Route::delete('/view/{node}/allocations', 'NodesController@allocationRemoveMultiple')->name('admin.nodes.view.allocation.removeMultiple');
156157
});
157158

158159
/*

0 commit comments

Comments
 (0)