mirror of
https://github.com/pterodactyl/panel.git
synced 2024-11-22 09:02:28 +01:00
Merge pull request #1909 from pterodactyl/enhancement/new-server-admin
Enhancements to new server admin
This commit is contained in:
commit
72c144e309
@ -65,14 +65,14 @@ class EmailSettingsCommand extends Command
|
||||
public function handle()
|
||||
{
|
||||
$this->variables['MAIL_DRIVER'] = $this->option('driver') ?? $this->choice(
|
||||
trans('command/messages.environment.mail.ask_driver'), [
|
||||
trans('command/messages.environment.mail.ask_driver'), [
|
||||
'smtp' => 'SMTP Server',
|
||||
'mail' => 'PHP\'s Internal Mail Function',
|
||||
'mailgun' => 'Mailgun Transactional Email',
|
||||
'mandrill' => 'Mandrill Transactional Email',
|
||||
'postmark' => 'Postmarkapp Transactional Email',
|
||||
], $this->config->get('mail.driver', 'smtp')
|
||||
);
|
||||
);
|
||||
|
||||
$method = 'setup' . studly_case($this->variables['MAIL_DRIVER']) . 'DriverVariables';
|
||||
if (method_exists($this, $method)) {
|
||||
|
@ -22,4 +22,12 @@ interface UserRepositoryInterface extends RepositoryInterface, SearchableInterfa
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function filterUsersByQuery(?string $query): Collection;
|
||||
|
||||
/**
|
||||
* Returns a user with the given id in a format that can be used for dropdowns.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Pterodactyl\Models\Model
|
||||
*/
|
||||
public function filterById(int $id): \Pterodactyl\Models\Model;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use Exception;
|
||||
use Carbon\Carbon;
|
||||
use Cron\CronExpression;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\ViewErrorBag;
|
||||
|
||||
class Utilities
|
||||
{
|
||||
@ -50,4 +51,15 @@ class Utilities
|
||||
sprintf('%s %s %s * %s', $minute, $hour, $dayOfMonth, $dayOfWeek)
|
||||
)->getNextRunDate());
|
||||
}
|
||||
|
||||
public static function checked($name, $default)
|
||||
{
|
||||
$errors = session('errors');
|
||||
|
||||
if (isset($errors) && $errors instanceof ViewErrorBag && $errors->any()) {
|
||||
return old($name) ? 'checked' : '';
|
||||
}
|
||||
|
||||
return ($default) ? 'checked' : '';
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +165,7 @@ class DatabaseController extends Controller
|
||||
$this->alert->danger(
|
||||
sprintf('There was an error while trying to connect to the host or while executing a query: "%s"', $exception->getMessage())
|
||||
)->flash();
|
||||
|
||||
return $redirect->withInput($request->normalize());
|
||||
} else {
|
||||
throw $exception;
|
||||
|
@ -177,10 +177,15 @@ class UserController extends Controller
|
||||
* Get a JSON response of users on the system.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Support\Collection
|
||||
* @return \Illuminate\Support\Collection|\Pterodactyl\Models\Model
|
||||
*/
|
||||
public function json(Request $request)
|
||||
{
|
||||
// Handle single user requests.
|
||||
if ($request->query('user_id')) {
|
||||
return $this->repository->filterById($request->input('user_id'));
|
||||
}
|
||||
|
||||
return $this->repository->filterUsersByQuery($request->input('q'));
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ class ScheduleTaskController extends ClientApiController
|
||||
}
|
||||
|
||||
$this->repository->update($task->id, [
|
||||
'action' => $request->input('action'),
|
||||
'action' => $request->input('action'),
|
||||
'payload' => $request->input('payload'),
|
||||
'time_offset' => $request->input('time_offset'),
|
||||
]);
|
||||
|
@ -3,8 +3,6 @@
|
||||
namespace Pterodactyl\Http\Controllers\Api\Remote\Servers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Repositories\Eloquent\BackupRepository;
|
||||
|
@ -54,4 +54,22 @@ class UserRepository extends EloquentRepository implements UserRepositoryInterfa
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a user with the given id in a format that can be used for dropdowns.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Pterodactyl\Models\Model
|
||||
*/
|
||||
public function filterById(int $id): \Pterodactyl\Models\Model
|
||||
{
|
||||
$this->setColumns([
|
||||
'id', 'email', 'username', 'name_first', 'name_last',
|
||||
]);
|
||||
|
||||
$model = $this->getBuilder()->findOrFail($id, $this->getColumns())->getModel();
|
||||
$model->md5 = md5(strtolower($model->email));
|
||||
|
||||
return $model;
|
||||
}
|
||||
}
|
||||
|
@ -168,8 +168,8 @@ return [
|
||||
| Cast the given "real type" to the given "type".
|
||||
|
|
||||
*/
|
||||
'type_overrides' => [
|
||||
'type_overrides' => [
|
||||
'integer' => 'int',
|
||||
'boolean' => 'bool',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
@ -3,8 +3,8 @@
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Cake\Chronos\Chronos;
|
||||
use Illuminate\Support\Str;
|
||||
use Faker\Generator as Faker;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Faker\Generator as Faker;
|
||||
use Pterodactyl\Models\ApiKey;
|
||||
|
||||
/*
|
||||
|
@ -26,8 +26,8 @@ class ChangeServicesToUseAMoreUniqueIdentifier extends Migration
|
||||
|
||||
DB::table('services')->get(['id', 'author', 'uuid'])->each(function ($service) {
|
||||
DB::table('services')->where('id', $service->id)->update([
|
||||
'author' => ($service->author === 'ptrdctyl-v040-11e6-8b77-86f30ca893d3') ? 'support@pterodactyl.io' : 'unknown@unknown-author.com',
|
||||
'uuid' => Uuid::uuid4()->toString(),
|
||||
'author' => ($service->author === 'ptrdctyl-v040-11e6-8b77-86f30ca893d3') ? 'support@pterodactyl.io' : 'unknown@unknown-author.com',
|
||||
'uuid' => Uuid::uuid4()->toString(),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -44,12 +44,12 @@ class MergePermissionsTableIntoSubusers extends Migration
|
||||
{
|
||||
foreach (DB::select('SELECT id, permissions FROM subusers') as $datum) {
|
||||
$values = [];
|
||||
foreach(json_decode($datum->permissions, true) as $permission) {
|
||||
foreach (json_decode($datum->permissions, true) as $permission) {
|
||||
$values[] = $datum->id;
|
||||
$values[] = $permission;
|
||||
}
|
||||
|
||||
if (!empty($values)) {
|
||||
if (! empty($values)) {
|
||||
$string = 'VALUES ' . implode(', ', array_fill(0, count($values) / 2, '(?, ?)'));
|
||||
|
||||
DB::insert('INSERT INTO permissions(`subuser_id`, `permission`) ' . $string, $values);
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateBackupsTable extends Migration
|
||||
{
|
||||
|
@ -3,9 +3,9 @@
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Contracts\Encryption\Encrypter;
|
||||
|
||||
class StoreNodeTokensAsEncryptedValue extends Migration
|
||||
|
@ -21,65 +21,29 @@ $(document).ready(function() {
|
||||
$('#pNestId').select2({
|
||||
placeholder: 'Select a Nest',
|
||||
}).change();
|
||||
|
||||
$('#pEggId').select2({
|
||||
placeholder: 'Select a Nest Egg',
|
||||
});
|
||||
|
||||
$('#pPackId').select2({
|
||||
placeholder: 'Select a Service Pack',
|
||||
});
|
||||
|
||||
$('#pNodeId').select2({
|
||||
placeholder: 'Select a Node',
|
||||
}).change();
|
||||
|
||||
$('#pAllocation').select2({
|
||||
placeholder: 'Select a Default Allocation',
|
||||
});
|
||||
|
||||
$('#pAllocationAdditional').select2({
|
||||
placeholder: 'Select Additional Allocations',
|
||||
});
|
||||
|
||||
$('#pUserId').select2({
|
||||
ajax: {
|
||||
url: '/admin/users/accounts.json',
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
return {
|
||||
q: params.term, // search term
|
||||
page: params.page,
|
||||
};
|
||||
},
|
||||
processResults: function (data, params) {
|
||||
return { results: data };
|
||||
},
|
||||
cache: true,
|
||||
},
|
||||
escapeMarkup: function (markup) { return markup; },
|
||||
minimumInputLength: 2,
|
||||
templateResult: function (data) {
|
||||
if (data.loading) return data.text;
|
||||
|
||||
return '<div class="user-block"> \
|
||||
<img class="img-circle img-bordered-xs" src="https://www.gravatar.com/avatar/' + data.md5 + '?s=120" alt="User Image"> \
|
||||
<span class="username"> \
|
||||
<a href="#">' + data.name_first + ' ' + data.name_last +'</a> \
|
||||
</span> \
|
||||
<span class="description"><strong>' + data.email + '</strong> - ' + data.username + '</span> \
|
||||
</div>';
|
||||
},
|
||||
templateSelection: function (data) {
|
||||
return '<div> \
|
||||
<span> \
|
||||
<img class="img-rounded img-bordered-xs" src="https://www.gravatar.com/avatar/' + data.md5 + '?s=120" style="height:28px;margin-top:-4px;" alt="User Image"> \
|
||||
</span> \
|
||||
<span style="padding-left:5px;"> \
|
||||
' + data.name_first + ' ' + data.name_last + ' (<strong>' + data.email + '</strong>) \
|
||||
</span> \
|
||||
</div>';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var lastActiveBox = null;
|
||||
let lastActiveBox = null;
|
||||
$(document).on('click', function (event) {
|
||||
if (lastActiveBox !== null) {
|
||||
lastActiveBox.removeClass('box-primary');
|
||||
@ -97,10 +61,8 @@ $('#pNodeId').on('change', function () {
|
||||
data: v.allocations,
|
||||
placeholder: 'Select a Default Allocation',
|
||||
});
|
||||
$('#pAllocationAdditional').html('').select2({
|
||||
data: v.allocations,
|
||||
placeholder: 'Select Additional Allocations',
|
||||
})
|
||||
|
||||
updateAdditionalAllocations();
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -117,8 +79,8 @@ $('#pNestId').on('change', function (event) {
|
||||
});
|
||||
|
||||
$('#pEggId').on('change', function (event) {
|
||||
var parentChain = _.get(Pterodactyl.nests, $('#pNestId').val(), null);
|
||||
var objectChain = _.get(parentChain, 'eggs.' + $(this).val(), null);
|
||||
let parentChain = _.get(Pterodactyl.nests, $('#pNestId').val(), null);
|
||||
let objectChain = _.get(parentChain, 'eggs.' + $(this).val(), null);
|
||||
|
||||
$('#pDefaultContainer').val(_.get(objectChain, 'docker_image', 'not defined!'));
|
||||
|
||||
@ -139,10 +101,13 @@ $('#pEggId').on('change', function (event) {
|
||||
),
|
||||
});
|
||||
|
||||
const variableIds = {};
|
||||
$('#appendVariablesTo').html('');
|
||||
$.each(_.get(objectChain, 'variables', []), function (i, item) {
|
||||
var isRequired = (item.required === 1) ? '<span class="label label-danger">Required</span> ' : '';
|
||||
var dataAppend = ' \
|
||||
variableIds[item.env_variable] = 'var_ref_' + item.id;
|
||||
|
||||
let isRequired = (item.required === 1) ? '<span class="label label-danger">Required</span> ' : '';
|
||||
let dataAppend = ' \
|
||||
<div class="form-group col-sm-6"> \
|
||||
<label for="var_ref_' + item.id + '" class="control-label">' + isRequired + item.name + '</label> \
|
||||
<input type="text" id="var_ref_' + item.id + '" autocomplete="off" name="environment[' + item.env_variable + ']" class="form-control" value="' + item.default_value + '" /> \
|
||||
@ -153,4 +118,86 @@ $('#pEggId').on('change', function (event) {
|
||||
';
|
||||
$('#appendVariablesTo').append(dataAppend);
|
||||
});
|
||||
|
||||
// If you receive a warning on this line, it should be fine to ignore. this function is
|
||||
// defined in "resources/views/admin/servers/new.blade.php" near the bottom of the file.
|
||||
serviceVariablesUpdated($('#pEggId').val(), variableIds);
|
||||
});
|
||||
|
||||
$('#pAllocation').on('change', function () {
|
||||
updateAdditionalAllocations();
|
||||
});
|
||||
|
||||
function updateAdditionalAllocations() {
|
||||
let currentAllocation = $('#pAllocation').val();
|
||||
let currentNode = $('#pNodeId').val();
|
||||
|
||||
$.each(Pterodactyl.nodeData, function (i, v) {
|
||||
if (v.id == currentNode) {
|
||||
let allocations = [];
|
||||
|
||||
for (let i = 0; i < v.allocations.length; i++) {
|
||||
const allocation = v.allocations[i];
|
||||
|
||||
if (allocation.id != currentAllocation) {
|
||||
allocations.push(allocation);
|
||||
}
|
||||
}
|
||||
|
||||
$('#pAllocationAdditional').html('').select2({
|
||||
data: allocations,
|
||||
placeholder: 'Select Additional Allocations',
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initUserIdSelect(data) {
|
||||
$('#pUserId').select2({
|
||||
ajax: {
|
||||
url: '/admin/users/accounts.json',
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
|
||||
data: function (params) {
|
||||
return {
|
||||
q: params.term, // search term
|
||||
page: params.page,
|
||||
};
|
||||
},
|
||||
|
||||
processResults: function (data, params) {
|
||||
return { results: data };
|
||||
},
|
||||
|
||||
cache: true,
|
||||
},
|
||||
|
||||
data: data,
|
||||
escapeMarkup: function (markup) { return markup; },
|
||||
minimumInputLength: 2,
|
||||
|
||||
templateResult: function (data) {
|
||||
if (data.loading) return data.text;
|
||||
|
||||
return '<div class="user-block"> \
|
||||
<img class="img-circle img-bordered-xs" src="https://www.gravatar.com/avatar/' + data.md5 + '?s=120" alt="User Image"> \
|
||||
<span class="username"> \
|
||||
<a href="#">' + data.name_first + ' ' + data.name_last +'</a> \
|
||||
</span> \
|
||||
<span class="description"><strong>' + data.email + '</strong> - ' + data.username + '</span> \
|
||||
</div>';
|
||||
},
|
||||
|
||||
templateSelection: function (data) {
|
||||
return '<div> \
|
||||
<span> \
|
||||
<img class="img-rounded img-bordered-xs" src="https://www.gravatar.com/avatar/' + data.md5 + '?s=120" style="height:28px;margin-top:-4px;" alt="User Image"> \
|
||||
</span> \
|
||||
<span style="padding-left:5px;"> \
|
||||
' + data.name_first + ' ' + data.name_last + ' (<strong>' + data.email + '</strong>) \
|
||||
</span> \
|
||||
</div>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Core Details</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
@ -33,20 +34,23 @@
|
||||
<input type="text" class="form-control" id="pName" name="name" value="{{ old('name') }}" placeholder="Server Name">
|
||||
<p class="small text-muted no-margin">Character limits: <code>a-z A-Z 0-9 _ - .</code> and <code>[Space]</code> (max 200 characters).</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pUserId">Server Owner</label>
|
||||
<select class="form-control" style="padding-left:0;" name="owner_id" id="pUserId"></select>
|
||||
<select id="pUserId" name="owner_id" class="form-control" style="padding-left:0;"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="description" class="control-label">Server Description</label>
|
||||
<textarea name="description" rows="3" class="form-control">{{ old('description') }}</textarea>
|
||||
<label for="pDescription" class="control-label">Server Description</label>
|
||||
<textarea id="pDescription" name="description" rows="3" class="form-control">{{ old('description') }}</textarea>
|
||||
<p class="text-muted small">A brief description of this server.</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="checkbox checkbox-primary no-margin-bottom">
|
||||
<input id="pStartOnCreation" name="start_on_completion" type="checkbox" value="1" checked />
|
||||
<input id="pStartOnCreation" name="start_on_completion" type="checkbox" {{ \Pterodactyl\Helpers\Utilities::checked('start_on_completion', 1) }} />
|
||||
<label for="pStartOnCreation" class="strong">Start Server when Installed</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -55,6 +59,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="box">
|
||||
@ -62,6 +67,7 @@
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Allocation Management</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body row">
|
||||
<div class="form-group col-sm-4">
|
||||
<label for="pNodeId">Node</label>
|
||||
@ -78,22 +84,26 @@
|
||||
</optgroup>
|
||||
@endforeach
|
||||
</select>
|
||||
|
||||
<p class="small text-muted no-margin">The node which this server will be deployed to.</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-sm-4">
|
||||
<label for="pAllocation">Default Allocation</label>
|
||||
<select name="allocation_id" id="pAllocation" class="form-control"></select>
|
||||
<select id="pAllocation" name="allocation_id" class="form-control"></select>
|
||||
<p class="small text-muted no-margin">The main allocation that will be assigned to this server.</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-sm-4">
|
||||
<label for="pAllocationAdditional">Additional Allocation(s)</label>
|
||||
<select name="allocation_additional[]" id="pAllocationAdditional" class="form-control" multiple></select>
|
||||
<select id="pAllocationAdditional" name="allocation_additional[]" class="form-control" multiple></select>
|
||||
<p class="small text-muted no-margin">Additional allocations to assign to this server on creation.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="box">
|
||||
@ -101,18 +111,20 @@
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Application Feature Limits</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body row">
|
||||
<div class="form-group col-xs-6">
|
||||
<label for="cpu" class="control-label">Database Limit</label>
|
||||
<label for="pDatabaseLimit" class="control-label">Database Limit</label>
|
||||
<div>
|
||||
<input type="text" name="database_limit" class="form-control" value="{{ old('database_limit', 0) }}"/>
|
||||
<input type="text" id="pDatabaseLimit" name="database_limit" class="form-control" value="{{ old('database_limit', 0) }}"/>
|
||||
</div>
|
||||
<p class="text-muted small">The total number of databases a user is allowed to create for this server. Leave blank to allow unlimited.</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-xs-6">
|
||||
<label for="cpu" class="control-label">Allocation Limit</label>
|
||||
<label for="pAllocationLimit" class="control-label">Allocation Limit</label>
|
||||
<div>
|
||||
<input type="text" name="allocation_limit" class="form-control" value="{{ old('allocation_limit', 0) }}"/>
|
||||
<input type="text" id="pAllocationLimit" name="allocation_limit" class="form-control" value="{{ old('allocation_limit', 0) }}"/>
|
||||
</div>
|
||||
<p class="text-muted small">The total number of allocations a user is allowed to create for this server. Leave blank to allow unlimited.</p>
|
||||
</div>
|
||||
@ -126,71 +138,90 @@
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Resource Management</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body row">
|
||||
<div class="form-group col-xs-6">
|
||||
<label for="pCPU">CPU Limit</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" value="{{ old('cpu', 0) }}" name="cpu" id="pCPU" />
|
||||
<input type="text" id="pCPU" name="cpu" class="form-control" value="{{ old('cpu', 0) }}" />
|
||||
<span class="input-group-addon">%</span>
|
||||
</div>
|
||||
<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 of <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/engine/reference/run/#/block-io-bandwidth-blkio-constraint" target="_blank">this documentation</a> for more information about it.<p>
|
||||
|
||||
<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 of <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/engine/reference/run/#/block-io-bandwidth-blkio-constraint" target="_blank">this documentation</a> for more information about it.<p>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-xs-6">
|
||||
<label for="pThreads">CPU Threads</label>
|
||||
|
||||
<div>
|
||||
<input type="text" class="form-control" value="{{ old('threads') }}" name="threads" id="pThreads" />
|
||||
<input type="text" id="pThreads" name="threads" class="form-control" value="{{ old('threads') }}" />
|
||||
</div>
|
||||
|
||||
<p class="text-muted small"><strong>Advanced:</strong> Enter the specific CPU cores that this process can run on, or leave blank to allow all cores. This can be a single number, or a comma seperated list. Example: <code>0</code>, <code>0-1,3</code>, or <code>0,1,3,4</code>.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body row">
|
||||
<div class="form-group col-xs-6">
|
||||
<label for="pMemory">Memory</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="text" value="{{ old('memory') }}" class="form-control" name="memory" id="pMemory" />
|
||||
<input type="text" id="pMemory" name="memory" class="form-control" value="{{ old('memory') }}" />
|
||||
<span class="input-group-addon">MB</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-xs-6">
|
||||
<label for="pSwap">Swap</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="text" value="{{ old('swap', 0) }}" class="form-control" name="swap" id="pSwap" />
|
||||
<input type="text" id="pSwap" name="swap" class="form-control" value="{{ old('swap', 0) }}" />
|
||||
<span class="input-group-addon">MB</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-footer no-border no-pad-top no-pad-bottom">
|
||||
<p class="text-muted small">If you do not want to assign swap space to a server, simply put <code>0</code> for the value, or <code>-1</code> to allow unlimited swap space. If you want to disable memory limiting on a server, simply enter <code>0</code> into the memory field.<p>
|
||||
</div>
|
||||
|
||||
<div class="box-body row">
|
||||
<div class="form-group col-xs-6">
|
||||
<label for="pDisk">Disk Space</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" value="{{ old('disk') }}" name="disk" id="pDisk" />
|
||||
<span class="input-group-addon">MB</span>
|
||||
<input type="text" id="pDisk" name="disk" class="form-control" value="{{ old('disk') }}" />
|
||||
<span class="input-group-addon">MB</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-xs-6">
|
||||
<label for="pIO">Block IO Weight</label>
|
||||
|
||||
<div>
|
||||
<input type="text" class="form-control" value="{{ old('io', 500) }}" name="io" id="pIO" />
|
||||
<input type="text" id="pIO" name="io" class="form-control" value="{{ old('io', 500) }}" />
|
||||
</div>
|
||||
<p class="text-muted small"><strong>Advanced</strong>: The IO performance of this server relative to other <em>running</em> containers on the system. Value should be between <code>10</code> and <code>1000</code>.</code></p>
|
||||
|
||||
<p class="text-muted small"><strong>Advanced</strong>: The IO performance of this server relative to other <em>running</em> containers on the system. Value should be between <code>10</code> and <code>1000</code>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Nest Configuration</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body row">
|
||||
<div class="form-group col-xs-12">
|
||||
<label for="pNestId">Nest</label>
|
||||
<select name="nest_id" id="pNestId" class="form-control">
|
||||
|
||||
<select id="pNestId" name="nest_id" class="form-control">
|
||||
@foreach($nests as $nest)
|
||||
<option value="{{ $nest->id }}"
|
||||
@if($nest->id === old('nest_id'))
|
||||
@ -199,33 +230,40 @@
|
||||
>{{ $nest->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
|
||||
<p class="small text-muted no-margin">Select the Nest that this server will be grouped under.</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-xs-12">
|
||||
<label for="pEggId">Egg</label>
|
||||
<select name="egg_id" id="pEggId" class="form-control"></select>
|
||||
<select id="pEggId" name="egg_id" class="form-control"></select>
|
||||
<p class="small text-muted no-margin">Select the Egg that will define how this server should operate.</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-xs-12">
|
||||
<label for="pPackId">Data Pack</label>
|
||||
<select name="pack_id" id="pPackId" class="form-control"></select>
|
||||
<select id="pPackId" name="pack_id" class="form-control"></select>
|
||||
<p class="small text-muted no-margin">Select a data pack to be automatically installed on this server when first created.</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-xs-12">
|
||||
<div class="checkbox checkbox-primary no-margin-bottom">
|
||||
<input id="pSkipScripting" name="skip_scripts" type="checkbox" value="1" />
|
||||
<input type="checkbox" id="pSkipScripting" name="skip_scripts" {{ \Pterodactyl\Helpers\Utilities::checked('skip_scripts', 0) }} />
|
||||
<label for="pSkipScripting" class="strong">Skip Egg Install Script</label>
|
||||
</div>
|
||||
|
||||
<p class="small text-muted no-margin">If the selected Egg has an install script attached to it, the script will run during install after the pack is installed. If you would like to skip this step, check this box.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Docker Configuration</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body row">
|
||||
<div class="form-group col-xs-12">
|
||||
<label for="pDefaultContainer">Docker Image</label>
|
||||
@ -236,23 +274,28 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Startup Configuration</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body row">
|
||||
<div class="form-group col-xs-12">
|
||||
<label for="pStartup">Startup Command</label>
|
||||
<input type="text" id="pStartup" value="{{ old('startup') }}" class="form-control" name="startup" />
|
||||
<input type="text" id="pStartup" name="startup" value="{{ old('startup') }}" class="form-control" />
|
||||
<p class="small text-muted no-margin">The following data substitutes are available for the startup command: <code>@{{SERVER_MEMORY}}</code>, <code>@{{SERVER_IP}}</code>, and <code>@{{SERVER_PORT}}</code>. They will be replaced with the allocated memory, server IP, and server port respectively.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-header with-border" style="margin-top:-10px;">
|
||||
<h3 class="box-title">Service Variables</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body row" id="appendVariablesTo"></div>
|
||||
|
||||
<div class="box-footer">
|
||||
{!! csrf_field() !!}
|
||||
<input type="submit" class="btn btn-success pull-right" value="Create Server" />
|
||||
@ -266,5 +309,84 @@
|
||||
@section('footer-scripts')
|
||||
@parent
|
||||
{!! Theme::js('vendor/lodash/lodash.js') !!}
|
||||
|
||||
<script type="application/javascript">
|
||||
// Persist 'Service Variables'
|
||||
function serviceVariablesUpdated(eggId, ids) {
|
||||
@if (old('egg_id'))
|
||||
// Check if the egg id matches.
|
||||
if (eggId != '{{ old('egg_id') }}') {
|
||||
return;
|
||||
}
|
||||
|
||||
@if (old('environment'))
|
||||
@foreach (old('environment') as $key => $value)
|
||||
$('#' + ids['{{ $key }}']).val('{{ $value }}');
|
||||
@endforeach
|
||||
@endif
|
||||
@endif
|
||||
}
|
||||
// END Persist 'Service Variables'
|
||||
</script>
|
||||
|
||||
{!! Theme::js('js/admin/new-server.js') !!}
|
||||
|
||||
<script type="application/javascript">
|
||||
$(document).ready(function() {
|
||||
// Persist 'Server Owner' select2
|
||||
@if (old('owner_id'))
|
||||
$.ajax({
|
||||
url: '/admin/users/accounts.json?user_id={{ old('owner_id') }}',
|
||||
dataType: 'json',
|
||||
}).then(function (data) {
|
||||
initUserIdSelect([ data ]);
|
||||
});
|
||||
@else
|
||||
initUserIdSelect();
|
||||
@endif
|
||||
// END Persist 'Server Owner' select2
|
||||
|
||||
// Persist 'Node' select2
|
||||
@if (old('node_id'))
|
||||
$('#pNodeId').val('{{ old('node_id') }}').change();
|
||||
|
||||
// Persist 'Default Allocation' select2
|
||||
@if (old('allocation_id'))
|
||||
$('#pAllocation').val('{{ old('allocation_id') }}').change();
|
||||
@endif
|
||||
// END Persist 'Default Allocation' select2
|
||||
|
||||
// Persist 'Additional Allocations' select2
|
||||
@if (old('allocation_additional'))
|
||||
const additional_allocations = [];
|
||||
|
||||
@for ($i = 0; $i < count(old('allocation_additional')); $i++)
|
||||
additional_allocations.push('{{ old('allocation_additional.'.$i)}}');
|
||||
@endfor
|
||||
|
||||
$('#pAllocationAdditional').val(additional_allocations).change();
|
||||
@endif
|
||||
// END Persist 'Additional Allocations' select2
|
||||
@endif
|
||||
// END Persist 'Node' select2
|
||||
|
||||
// Persist 'Nest' select2
|
||||
@if (old('nest_id'))
|
||||
$('#pNestId').val('{{ old('nest_id') }}').change();
|
||||
|
||||
// Persist 'Egg' select2
|
||||
@if (old('egg_id'))
|
||||
$('#pEggId').val('{{ old('egg_id') }}').change();
|
||||
@endif
|
||||
// END Persist 'Egg' select2
|
||||
|
||||
// Persist 'Data Pack' select2
|
||||
@if (old('pack_id'))
|
||||
$('#pPackId').val('{{ old('pack_id') }}').change();
|
||||
@endif
|
||||
// END Persist 'Data Pack' select2
|
||||
@endif
|
||||
// END Persist 'Nest' select2
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
@ -173,7 +173,7 @@
|
||||
</footer>
|
||||
</div>
|
||||
@section('footer-scripts')
|
||||
{!! Theme::js('js/keyboard.polyfill.js') !!}
|
||||
<script src="/js/keyboard.polyfill.js" type="application/javascript"></script>
|
||||
<script>keyboardeventKeyPolyfill.polyfill();</script>
|
||||
|
||||
{!! Theme::js('vendor/jquery/jquery.min.js?t={cache-version}') !!}
|
||||
@ -185,7 +185,7 @@
|
||||
{!! Theme::js('vendor/bootstrap-notify/bootstrap-notify.min.js?t={cache-version}') !!}
|
||||
{!! Theme::js('vendor/select2/select2.full.min.js?t={cache-version}') !!}
|
||||
{!! Theme::js('js/admin/functions.js?t={cache-version}') !!}
|
||||
{!! Theme::js('js/autocomplete.js?t={cache-version}') !!}
|
||||
<script src="/js/autocomplete.js" type="application/javascript"></script>
|
||||
|
||||
@if(Auth::user()->root_admin)
|
||||
<script>
|
||||
|
@ -52,7 +52,7 @@
|
||||
|
||||
{!! Theme::js('vendor/jquery/jquery.min.js?t={cache-version}') !!}
|
||||
{!! Theme::js('vendor/bootstrap/bootstrap.min.js?t={cache-version}') !!}
|
||||
{!! Theme::js('js/autocomplete.js?t={cache-version}') !!}
|
||||
<script src="/js/autocomplete.js" type="application/javascript"></script>
|
||||
{!! Theme::js('vendor/particlesjs/particles.min.js?t={cache-version}') !!}
|
||||
<script type="text/javascript">
|
||||
/* particlesJS.load(@dom-id, @path-json, @callback (optional)); */
|
||||
|
@ -274,7 +274,7 @@
|
||||
<div class="control-sidebar-bg"></div>
|
||||
</div>
|
||||
@section('footer-scripts')
|
||||
{!! Theme::js('js/keyboard.polyfill.js?t={cache-version}') !!}
|
||||
<script src="/js/keyboard.polyfill.js" type="application/javascript"></script>
|
||||
<script>keyboardeventKeyPolyfill.polyfill();</script>
|
||||
|
||||
{!! Theme::js('vendor/jquery/jquery.min.js?t={cache-version}') !!}
|
||||
@ -284,7 +284,7 @@
|
||||
{!! Theme::js('vendor/adminlte/app.min.js?t={cache-version}') !!}
|
||||
{!! Theme::js('vendor/socketio/socket.io.v203.min.js?t={cache-version}') !!}
|
||||
{!! Theme::js('vendor/bootstrap-notify/bootstrap-notify.min.js?t={cache-version}') !!}
|
||||
{!! Theme::js('js/autocomplete.js?t={cache-version}') !!}
|
||||
<script src="/js/autocomplete.js" type="application/javascript"></script>
|
||||
|
||||
@if(Auth::user()->root_admin)
|
||||
<script>
|
||||
|
@ -54,11 +54,11 @@ class PackUpdateServiceTest extends TestCase
|
||||
{
|
||||
$model = factory(Pack::class)->make();
|
||||
$this->repository->shouldReceive('withoutFreshModel->update')->with($model->id, [
|
||||
'locked' => false,
|
||||
'visible' => false,
|
||||
'selectable' => false,
|
||||
'test-data' => 'value',
|
||||
])->once()->andReturn(1);
|
||||
'locked' => false,
|
||||
'visible' => false,
|
||||
'selectable' => false,
|
||||
'test-data' => 'value',
|
||||
])->once()->andReturn(1);
|
||||
|
||||
$this->assertEquals(1, $this->service->handle($model, ['test-data' => 'value']));
|
||||
}
|
||||
@ -88,11 +88,11 @@ class PackUpdateServiceTest extends TestCase
|
||||
$this->repository->shouldReceive('setColumns')->with(['id', 'egg_id'])->once()->andReturnSelf()
|
||||
->shouldReceive('find')->with($model->id)->once()->andReturn($model);
|
||||
$this->repository->shouldReceive('withoutFreshModel->update')->with($model->id, [
|
||||
'locked' => false,
|
||||
'visible' => false,
|
||||
'selectable' => false,
|
||||
'test-data' => 'value',
|
||||
])->once()->andReturn(1);
|
||||
'locked' => false,
|
||||
'visible' => false,
|
||||
'selectable' => false,
|
||||
'test-data' => 'value',
|
||||
])->once()->andReturn(1);
|
||||
|
||||
$this->assertEquals(1, $this->service->handle($model->id, ['test-data' => 'value']));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user