More additions to server creation page.

Adds memory/disk/etc. fields as well as selecting the service type and
option. Still need to add in the ability to set the variables once an
option is selected.
This commit is contained in:
Dane Everitt 2015-12-08 18:34:18 -05:00
parent e77cea6f99
commit f47f0cd549
6 changed files with 189 additions and 21 deletions

View file

@ -5,6 +5,7 @@ namespace Pterodactyl\Http\Controllers\Admin;
use Debugbar; use Debugbar;
use Pterodactyl\Models\Allocation; use Pterodactyl\Models\Allocation;
use Pterodactyl\Models\Node; use Pterodactyl\Models\Node;
use Pterodactyl\Models\ServiceOptions;
use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@ -24,6 +25,12 @@ class AjaxController extends Controller
} }
/**
* Returns a JSON tree of all avaliable nodes in a given location.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function postNewServerGetNodes(Request $request) public function postNewServerGetNodes(Request $request)
{ {
@ -33,10 +40,16 @@ class AjaxController extends Controller
], 500); ], 500);
} }
return response(Node::select('id', 'name', 'public')->where('location', $request->input('location'))->get()->toJson()); return response()->json(Node::select('id', 'name', 'public')->where('location', $request->input('location'))->get());
} }
/**
* Returns a JSON tree of all avaliable IPs and Ports on a given node.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function postNewServerGetIps(Request $request) public function postNewServerGetIps(Request $request)
{ {
@ -60,4 +73,23 @@ class AjaxController extends Controller
} }
/**
* Returns a JSON tree of all avaliable options for a given service.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function postNewServerServiceOptions(Request $request)
{
if(!$request->input('service')) {
return response()->json([
'error' => 'Missing service in request.'
], 500);
}
return response()->json(ServiceOptions::select('id', 'name')->where('parent_service', $request->input('service'))->orderBy('name', 'asc')->get());
}
} }

View file

@ -4,8 +4,8 @@ namespace Pterodactyl\Http\Controllers\Admin;
use Debugbar; use Debugbar;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\Location; use Pterodactyl\Models\Location;
use Pterodactyl\Models\Service;
use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@ -38,7 +38,8 @@ class ServersController extends Controller
public function getNew(Request $request) public function getNew(Request $request)
{ {
return view('admin.servers.new', [ return view('admin.servers.new', [
'locations' => Location::all() 'locations' => Location::all(),
'services' => Service::all()
]); ]);
} }

View file

@ -28,6 +28,7 @@ class AdminRoutes {
$router->group(['prefix' => 'ajax'], function ($server) use ($router) { $router->group(['prefix' => 'ajax'], function ($server) use ($router) {
$router->post('/new/server/get-nodes', [ 'uses' => 'Admin\AjaxController@postNewServerGetNodes' ]); $router->post('/new/server/get-nodes', [ 'uses' => 'Admin\AjaxController@postNewServerGetNodes' ]);
$router->post('/new/server/get-ips', [ 'uses' => 'Admin\AjaxController@postNewServerGetIps' ]); $router->post('/new/server/get-ips', [ 'uses' => 'Admin\AjaxController@postNewServerGetIps' ]);
$router->post('/new/server/service-options', [ 'uses' => 'Admin\AjaxController@postNewServerServiceOptions' ]);
}); });
}); });

View file

@ -73,3 +73,4 @@ pre{display:block;padding:12px 12px;margin:0;font-size:12px;color:#c7254e;backgr
.close {color:#000;opacity:0.2;font-size:1.6em;} .close {color:#000;opacity:0.2;font-size:1.6em;}
.close:hover {color:#000;opacity:0.5;} .close:hover {color:#000;opacity:0.5;}
.filename {outline: none;width:450px;background: transparent;margin-left:-5px;padding:0;border: 0px;font-family: "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight: 250;line-height: 1.1;font-size: 19px;color: #aaa} .filename {outline: none;width:450px;background: transparent;margin-left:-5px;padding:0;border: 0px;font-family: "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight: 250;line-height: 1.1;font-size: 19px;color: #aaa}
form .text-muted {margin: 0 0 -5.5px}

View file

@ -19,7 +19,7 @@
<label for="server_name" class="control-label">Server Name</label> <label for="server_name" class="control-label">Server Name</label>
<div> <div>
<input type="text" autocomplete="off" name="server_name" class="form-control" /> <input type="text" autocomplete="off" name="server_name" class="form-control" />
<p class="text-muted" style="margin: 0 0 -10.5px;"><small><em>Character limits: <code>a-zA-Z0-9_-</code> and <code>[Space]</code> (max 35 characters)</em></small></p> <p class="text-muted"><small><em>Character limits: <code>a-zA-Z0-9_-</code> and <code>[Space]</code> (max 35 characters)</em></small></p>
</div> </div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
@ -33,7 +33,7 @@
<div id="load_settings"> <div id="load_settings">
<div class="well"> <div class="well">
<div class="row"> <div class="row">
<div class="ajax_loading_box" style="display:none;"><i class="fa fa-refresh fa-spin" id="position_me"></i></div> <div class="ajax_loading_box" style="display:none;"><i class="fa fa-refresh fa-spin ajax_loading_position"></i></div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="location" class="control-label">Server Location</label> <label for="location" class="control-label">Server Location</label>
<div> <div>
@ -43,6 +43,7 @@
<option value="{{ $location->id }}">{{ $location->long }} ({{ $location->short }})</option> <option value="{{ $location->id }}">{{ $location->long }} ({{ $location->short }})</option>
@endforeach @endforeach
</select> </select>
<p class="text-muted"><small>The location in which this server will be deployed.</small></p>
</div> </div>
</div> </div>
<div class="form-group col-md-6 hidden"> <div class="form-group col-md-6 hidden">
@ -51,6 +52,7 @@
<select name="node" id="getNode" class="form-control"> <select name="node" id="getNode" class="form-control">
<option></option> <option></option>
</select> </select>
<p class="text-muted"><small>The node which this server will be deployed to.</small></p>
</div> </div>
</div> </div>
</div> </div>
@ -61,12 +63,97 @@
<select name="node" id="getIP" class="form-control"> <select name="node" id="getIP" class="form-control">
<option></option> <option></option>
</select> </select>
<p class="text-muted"><small>Select the main IP that this server will be listening on. You can assign additional open IPs and ports below.</small></p>
</div> </div>
</div> </div>
<div class="form-group col-md-6 hidden"> <div class="form-group col-md-6 hidden">
<label for="location" class="control-label">Server Port</label> <label for="location" class="control-label">Server Port</label>
<div> <div>
<select name="node" id="getPort" class="form-control"></select> <select name="node" id="getPort" class="form-control"></select>
<p class="text-muted"><small>Select the main port that this server will be listening on.</small></p>
</div>
</div>
</div>
</div>
</div>
<div class="well">
<div class="row">
<div class="form-group col-md-3 col-xs-6">
<label for="memory" class="control-label">Memory</label>
<div class="input-group">
<input type="text" name="memory" class="form-control" />
<span class="input-group-addon">MB</span>
</div>
</div>
<div class="form-group col-md-3 col-xs-6">
<label for="disk" class="control-label">Disk Space</label>
<div class="input-group">
<input type="text" name="disk" class="form-control" />
<span class="input-group-addon">MB</span>
</div>
</div>
<div class="form-group col-md-3 col-xs-6">
<label for="cpu" class="control-label">CPU Limit</label>
<div class="input-group">
<input type="text" name="cpu" value="0" class="form-control" />
<span class="input-group-addon">%</span>
</div>
</div>
<div class="form-group col-md-3 col-xs-6">
<label for="io" class="control-label">Block I/O</label>
<div class="input-group">
<input type="text" name="io" value="500" class="form-control" />
<span class="input-group-addon">I/O</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p class="text-muted"><small>If you do not want to limit CPU usage set the value to <code>0</code>. To determine a value, take the number <em>physical</em> cores and multiply it by 100. For example, on a quad core system <code>(4 * 100 = 400)</code> there is <code>400%</code> available. To limit a server to using half of a single core, you would set the value to <code>50</code>. To allow a server to use up to two physical cores, set the value to <code>200</code>. BlockIO should be a value between <code>10</code> and <code>1000</code>. Please see <a href="https://docs.docker.com/reference/run/#block-io-bandwidth-blkio-constraint" target="_blank">this documentation</a> for more information about it.</small><p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6" id="load_services">
<div class="well">
<div class="row">
<div class="ajax_loading_box" style="display:none;"><i class="fa fa-refresh fa-spin ajax_loading_position"></i></div>
<div class="form-group col-md-12">
<label for="service" class="control-label">Service Type</label>
<div>
<select name="node" id="getService" class="form-control">
<option></option>
@foreach($services as $service)
<option value="{{ $service->id }}">{{ $service->name }}</option>
@endforeach
</select>
<p class="text-muted"><small>Select the type of service that this server will be running.</small></p>
</div>
</div>
<div class="form-group col-md-12 hidden">
<label for="service_option" class="control-label">Service Option</label>
<div>
<select name="node" id="getOption" class="form-control">
<option></option>
</select>
<p class="text-muted"><small>Select the type of service that this server will be running.</small></p>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="well">
<div class="row">
<div class="form-group col-md-12">
<label for="use_custom_image" class="control-label">Use Custom Docker Image</label>
<div class="input-group">
<span class="input-group-addon">
<input type="checkbox" name="use_custom_image" />
</span>
<input type="text" class="form-control" name="custom_image_name" disabled />
</div>
<p class="text-muted"><small>If you would like to use a custom docker image for this server please enter it here. Most users can ignore this option.</small></p>
</div> </div>
</div> </div>
</div> </div>
@ -76,9 +163,15 @@
</div> </div>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$('input[name="use_custom_image"]').change(function () {
$('input[name="custom_image_name"]').val('').prop('disabled', !($(this).is(':checked')));
});
var nodeData = null; var nodeData = null;
var currentLocation = null; var currentLocation = null;
var currentNode = null; var currentNode = null;
var currentService = null;
$('#getLocation').on('change', function (event) { $('#getLocation').on('change', function (event) {
if ($('#getLocation').val() === '' || $('#getLocation').val() === currentLocation) { if ($('#getLocation').val() === '' || $('#getLocation').val() === currentLocation) {
@ -93,7 +186,7 @@ $(document).ready(function () {
$('#getIP').html('<option></option>').parent().parent().addClass('hidden'); $('#getIP').html('<option></option>').parent().parent().addClass('hidden');
$('#getPort').html('').parent().parent().addClass('hidden'); $('#getPort').html('').parent().parent().addClass('hidden');
handleLoader(true); handleLoader('#load_settings', true);
$.ajax({ $.ajax({
method: 'POST', method: 'POST',
@ -105,7 +198,7 @@ $(document).ready(function () {
location: $('#getLocation').val() location: $('#getLocation').val()
} }
}).done(function (data) { }).done(function (data) {
var data = $.parseJSON(data); //var data = $.parseJSON(data);
$.each(data, function (i, item) { $.each(data, function (i, item) {
var isPublic = (item.public !== 1) ? '(Private Node)' : ''; var isPublic = (item.public !== 1) ? '(Private Node)' : '';
$('#getNode').append('<option value="' + item.id + '">' + item.name + ' ' + isPublic + '</option>'); $('#getNode').append('<option value="' + item.id + '">' + item.name + ' ' + isPublic + '</option>');
@ -113,9 +206,10 @@ $(document).ready(function () {
$('#getNode').parent().parent().removeClass('hidden') $('#getNode').parent().parent().removeClass('hidden')
}).fail(function (jqXHR) { }).fail(function (jqXHR) {
alert('An error occured while attempting to load a list of nodes in this location.'); alert('An error occured while attempting to load a list of nodes in this location.');
currentLocation = null;
console.log(jqXHR); console.log(jqXHR);
}).always(function () { }).always(function () {
handleLoader(); handleLoader('#load_settings');
}) })
}); });
$('#getNode').on('change', function (event) { $('#getNode').on('change', function (event) {
@ -130,7 +224,7 @@ $(document).ready(function () {
$('#getIP').html('<option></option>').parent().parent().addClass('hidden'); $('#getIP').html('<option></option>').parent().parent().addClass('hidden');
$('#getPort').html('').parent().parent().addClass('hidden'); $('#getPort').html('').parent().parent().addClass('hidden');
handleLoader(true); handleLoader('#load_settings', true);
$.ajax({ $.ajax({
method: 'POST', method: 'POST',
@ -148,12 +242,15 @@ $(document).ready(function () {
}); });
$('#getIP').parent().parent().removeClass('hidden'); $('#getIP').parent().parent().removeClass('hidden');
}).fail(function (jqXHR) { }).fail(function (jqXHR) {
alert('An error occured while attempting to get IPs and Ports avaliable on this node.');
currentNode = null;
console.log(jqXHR); console.log(jqXHR);
}).always(function () { }).always(function () {
handleLoader(); handleLoader('#load_settings');
}); });
}); });
$('#getIP').on('change', function (event) { $('#getIP').on('change', function (event) {
if ($('#getIP').val() === '') { if ($('#getIP').val() === '') {
@ -170,27 +267,63 @@ $(document).ready(function () {
}); });
$('#getService').on('change', function (event) {
if ($('#getService').val() === '' || $('#getService').val() === currentService) {
return;
}
currentService = $('#getService').val();
handleLoader('#load_services', true);
$.ajax({
method: 'POST',
url: '/admin/ajax/new/server/service-options',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
data: {
service: $('#getService').val()
}
}).done(function (data) {
$.each(data, function (i, option) {
$('#getOption').append('<option value="' + option.id + '">' + option.name + '</option>');
});
$('#getOption').parent().parent().removeClass('hidden');
}).fail(function (jqXHR) {
alert('An error occured while attempting to list options for this service.');
currentService = null;
console.log(jqXHR);
}).always(function () {
handleLoader('#load_services');
});
});
// Show Loading Animation // Show Loading Animation
function handleLoader (show) { function handleLoader (element, show) {
var spinner = $(element).find('.ajax_loading_position');
var popover = $(element).find('.ajax_loading_box');
// Show Animation // Show Animation
if (show === true){ if (typeof show !== 'undefined') {
var height = $('#load_settings').height(); var height = $(element).height();
var width = $('#load_settings').width(); var width = $(element).width();
var center_height = (height / 2) - 16; var center_height = (height / 2) - 16;
var center_width = (width / 2) - 16; var center_width = (width / 2) - 16;
$('#position_me').css({ spinner.css({
'top': center_height, 'top': center_height,
'left': center_width, 'left': center_width,
'font-size': '32px' 'font-size': '32px'
}); });
$(".ajax_loading_box").css({ popover.css({
'height': height, 'height': height,
'margin': '-20px 0 0 -5px', 'margin': '-20px 0 0 -5px',
'width': width 'width': width
}).fadeIn(); }).fadeIn();
} else { } else {
$('.ajax_loading_box').fadeOut(100); popover.hide();
} }
} }