This breaks literally the entire panel.

This commit is contained in:
Dane Everitt 2017-10-06 23:57:53 -05:00
parent 344c1a9885
commit df87ea0867
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
88 changed files with 1205 additions and 992 deletions

View file

@ -0,0 +1,31 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
return [
'notices' => [
'created' => 'A new nest, :name, has been successfully created.',
'deleted' => 'Successfully deleted the requested nest from the Panel.',
'updated' => 'Successfully updated the nest configuration options.',
],
'eggs' => [
'notices' => [
'deleted' => 'Successfully deleted the requested egg from the Panel.',
'updated' => 'Egg configuration has been updated successfully.',
'script_updated' => 'Egg install script has been updated and will run whenever servers are installed.',
'egg_created' => 'A new egg was laid successfully. You will need to restart any running daemons to apply this new egg.',
],
],
'variables' => [
'notices' => [
'variable_deleted' => 'The variable ":variable" has been deleted and will no longer be available to servers once rebuilt.',
'variable_updated' => 'The variable ":variable" has been updated. You will need to rebuild any servers using this variable in order to apply changes.',
'variable_created' => 'New variable has successfully been created and assigned to this egg.',
],
],
];

View file

@ -1,32 +0,0 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
return [
'notices' => [
'service_created' => 'A new service, :name, has been successfully created.',
'service_deleted' => 'Successfully deleted the requested service from the Panel.',
'service_updated' => 'Successfully updated the service configuration options.',
'functions_updated' => 'The service functions file has been updated. You will need to reboot your Nodes in order for these changes to be applied.',
],
'options' => [
'notices' => [
'option_deleted' => 'Successfully deleted the requested service option from the Panel.',
'option_updated' => 'Service option configuration has been updated successfully.',
'script_updated' => 'Service option install script has been updated and will run whenever servers are installed.',
'option_created' => 'New service option was created successfully. You will need to restart any running daemons to apply this new service.',
],
],
'variables' => [
'notices' => [
'variable_deleted' => 'The variable ":variable" has been deleted and will no longer be available to servers once rebuilt.',
'variable_updated' => 'The variable ":variable" has been updated. You will need to rebuild any servers using this variable in order to apply changes.',
'variable_created' => 'New variable has successfully been created and assigned to this service option.',
],
],
];

View file

@ -18,21 +18,20 @@ return [
'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.',
'cidr_out_of_range' => 'CIDR notation only allows masks between /25 and /32.',
],
'service' => [
'delete_has_servers' => 'A service with active servers attached to it cannot be deleted from the Panel.',
'options' => [
'duplicate_tag' => 'A service option with that tag already exists for this service.',
'delete_has_servers' => 'A service option with active servers attached to it cannot be deleted from the Panel.',
'invalid_copy_id' => 'The service option selected for copying a script from either does not exist, or is copying a script itself.',
'must_be_child' => 'The "Copy Settings From" directive for this option must be a child option for the selected service.',
'has_children' => 'This service option is a parent to one or more other options. Please delete those options before deleting this option.',
'nest' => [
'delete_has_servers' => 'A Nest with active servers attached to it cannot be deleted from the Panel.',
'egg' => [
'delete_has_servers' => 'An Egg with active servers attached to it cannot be deleted from the Panel.',
'invalid_copy_id' => 'The Egg selected for copying a script from either does not exist, or is copying a script itself.',
'must_be_child' => 'The "Copy Settings From" directive for this Egg must be a child option for the selected Nest.',
'has_children' => 'This Egg is a parent to one or more other Eggs. Please delete those Eggs before deleting this Egg.',
],
'variables' => [
'env_not_unique' => 'The environment variable :name must be unique to this service option.',
'env_not_unique' => 'The environment variable :name must be unique to this Egg.',
'reserved_name' => 'The environment variable :name is protected and cannot be assigned to a variable.',
],
'exporter' => [
'import_file_error' => 'The XML file provided was not valid.',
'importer' => [
'file_error' => 'The JSON file provided was not valid.',
'invalid_json_provided' => 'The JSON file provided is not in a format that can be recognized.',
],
],

View file

@ -6,16 +6,16 @@
@extends('layouts.admin')
@section('title')
Service &rarr; Option: {{ $option->name }}
Nests &rarr; Egg: {{ $egg->name }}
@endsection
@section('content-header')
<h1>{{ $option->name }}<small>{{ str_limit($option->description, 50) }}</small></h1>
<h1>{{ $egg->name }}<small>{{ str_limit($egg->description, 50) }}</small></h1>
<ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li>
<li><a href="{{ route('admin.services') }}">Service</a></li>
<li><a href="{{ route('admin.services.view', $option->service->id) }}">{{ $option->service->name }}</a></li>
<li class="active">{{ $option->name }}</li>
<li><a href="{{ route('admin.nests') }}">Nests</a></li>
<li><a href="{{ route('admin.nests.view', $egg->nest->id) }}">{{ $egg->nest->name }}</a></li>
<li class="active">{{ $egg->name }}</li>
</ol>
@endsection
@ -24,18 +24,18 @@
<div class="col-xs-12">
<div class="nav-tabs-custom nav-tabs-floating">
<ul class="nav nav-tabs">
<li class="active"><a href="{{ route('admin.services.option.view', $option->id) }}">Configuration</a></li>
<li><a href="{{ route('admin.services.option.variables', $option->id) }}">Variables</a></li>
<li><a href="{{ route('admin.services.option.scripts', $option->id) }}">Scripts</a></li>
<li class="active"><a href="{{ route('admin.nests.egg.view', $egg->id) }}">Configuration</a></li>
<li><a href="{{ route('admin.nests.egg.variables', $egg->id) }}">Variables</a></li>
<li><a href="{{ route('admin.nests.egg.scripts', $egg->id) }}">Scripts</a></li>
</ul>
</div>
</div>
</div>
<form action="{{ route('admin.services.option.view', $option->id) }}" method="POST">
<form action="{{ route('admin.nests.egg.view', $egg->id) }}" method="POST">
<div class="row">
<div class="col-xs-12">
<div class="callout callout-info">
<strong>Notice:</strong> Editing the Option Tag or any of the Process Management fields <em>requires</em> that each daemon be rebooted to apply the changes.
<strong>Notice:</strong> Editing an Egg or any of the Process Management fields <em>requires</em> that each Daemon be rebooted in order to apply the changes.
</div>
</div>
<div class="col-xs-12">
@ -47,30 +47,26 @@
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="pName" class="form-label">Option Name</label>
<input type="text" id="pName" name="name" value="{{ $option->name }}" class="form-control" />
<p class="text-muted small">A simple, human-readable name to use as an identifier for this service.</p>
<label for="pName" class="control-label">Name <span class="field-required"></span></label>
<input type="text" id="pName" name="name" value="{{ $egg->name }}" class="form-control" />
<p class="text-muted small">A simple, human-readable name to use as an identifier for this Egg.</p>
</div>
<div class="form-group">
<label for="pDescription" class="form-label">Description</label>
<textarea id="pDescription" name="description" class="form-control" rows="10">{{ $option->description }}</textarea>
<p class="text-muted small">A description of this service that will be displayed throughout the panel as needed.</p>
<label for="pDescription" class="control-label">Description <span class="field-required"></span></label>
<textarea id="pDescription" name="description" class="form-control" rows="10">{{ $egg->description }}</textarea>
<p class="text-muted small">A description of this Egg that will be displayed throughout the Panel as needed.</p>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label class="form-label">Option Tag</label>
<input type="text" disabled value="{{ $option->tag }}" class="form-control" />
<label for="pDockerImage" class="control-label">Docker Image <span class="field-required"></span></label>
<input type="text" id="pDockerImage" name="docker_image" value="{{ $egg->docker_image }}" class="form-control" />
<p class="text-muted small">The default docker image that should be used for new servers using this Egg. This can be changed per-server as needed.</p>
</div>
<div class="form-group">
<label for="pDockerImage" class="control-label">Docker Image <span class="field-optional"></label>
<input type="text" id="pDockerImage" name="docker_image" value="{{ $option->docker_image }}" class="form-control" />
<p class="text-muted small">The default docker image that should be used for new servers under this service option. This can be left blank to use the parent service's defined image, and can also be changed per-server.</p>
</div>
<div class="form-group">
<label for="pStartup" class="control-label">Startup Command <span class="field-optional"></label>
<textarea id="pStartup" name="startup" class="form-control" rows="4" placeholder="{{ $option->service->startup }}">{{ $option->startup }}</textarea>
<p class="text-muted small">The default statup command that should be used for new servers under this service option. This can be left blank to use the parent service's startup, and can also be changed per-server.</p>
<label for="pStartup" class="control-label">Startup Command <span class="field-required"></span></label>
<textarea id="pStartup" name="startup" class="form-control" rows="9">{{ $egg->startup }}</textarea>
<p class="text-muted small">The default statup command that should be used for new servers using this Egg.</p>
</div>
</div>
</div>
@ -87,7 +83,7 @@
<div class="col-xs-12">
<div class="alert alert-warning">
<p>The following configuration options should not be edited unless you understand how this system works. If wrongly modified it is possible for the daemon to break.</p>
<p>All fields are required unless you select a seperate option from the 'Copy Settings From' dropdown, in which case fields may be left blank to use the values from that option.</p>
<p>All fields are required unless you select a seperate option from the 'Copy Settings From' dropdown, in which case fields may be left blank to use the values from that Egg.</p>
</div>
</div>
<div class="col-sm-6">
@ -95,32 +91,32 @@
<label for="pConfigFrom" class="form-label">Copy Settings From</label>
<select name="config_from" id="pConfigFrom" class="form-control">
<option value="0">None</option>
@foreach($option->service->options as $o)
<option value="{{ $o->id }}" {{ ($option->config_from !== $o->id) ?: 'selected' }}>{{ $o->name }} &lt;{{ $option->tag }}&gt;</option>
@foreach($egg->nest->eggs as $o)
<option value="{{ $o->id }}" {{ ($egg->config_from !== $o->id) ?: 'selected' }}>{{ $o->name }} &lt;{{ $o->author }}&gt;</option>
@endforeach
</select>
<p class="text-muted small">If you would like to default to settings from another option select the option from the menu above.</p>
<p class="text-muted small">If you would like to default to settings from another Egg select it from the menu above.</p>
</div>
<div class="form-group">
<label for="pConfigStop" class="form-label">Stop Command</label>
<input type="text" id="pConfigStop" name="config_stop" class="form-control" value="{{ $option->config_stop }}" />
<input type="text" id="pConfigStop" name="config_stop" class="form-control" value="{{ $egg->config_stop }}" />
<p class="text-muted small">The command that should be sent to server processes to stop them gracefully. If you need to send a <code>SIGINT</code> you should enter <code>^C</code> here.</p>
</div>
<div class="form-group">
<label for="pConfigLogs" class="form-label">Log Configuration</label>
<textarea data-action="handle-tabs" id="pConfigLogs" name="config_logs" class="form-control" rows="6">{{ ! is_null($option->config_logs) ? json_encode(json_decode($option->config_logs), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) : '' }}</textarea>
<textarea data-action="handle-tabs" id="pConfigLogs" name="config_logs" class="form-control" rows="6">{{ ! is_null($egg->config_logs) ? json_encode(json_decode($egg->config_logs), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) : '' }}</textarea>
<p class="text-muted small">This should be a JSON representation of where log files are stored, and wether or not the daemon should be creating custom logs.</p>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="pConfigFiles" class="form-label">Configuration Files</label>
<textarea data-action="handle-tabs" id="pConfigFiles" name="config_files" class="form-control" rows="6">{{ ! is_null($option->config_files) ? json_encode(json_decode($option->config_files), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) : '' }}</textarea>
<textarea data-action="handle-tabs" id="pConfigFiles" name="config_files" class="form-control" rows="6">{{ ! is_null($egg->config_files) ? json_encode(json_decode($egg->config_files), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) : '' }}</textarea>
<p class="text-muted small">This should be a JSON representation of configuration files to modify and what parts should be changed.</p>
</div>
<div class="form-group">
<label for="pConfigStartup" class="form-label">Start Configuration</label>
<textarea data-action="handle-tabs" id="pConfigStartup" name="config_startup" class="form-control" rows="6">{{ ! is_null($option->config_startup) ? json_encode(json_decode($option->config_startup), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) : '' }}</textarea>
<textarea data-action="handle-tabs" id="pConfigStartup" name="config_startup" class="form-control" rows="6">{{ ! is_null($egg->config_startup) ? json_encode(json_decode($egg->config_startup), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) : '' }}</textarea>
<p class="text-muted small">This should be a JSON representation of what values the daemon should be looking for when booting a server to determine completion.</p>
</div>
</div>
@ -131,8 +127,8 @@
<button id="deleteButton" type="submit" name="_method" value="DELETE" class="btn btn-danger btn-sm muted muted-hover">
<i class="fa fa-trash-o"></i>
</button>
<button type="submit" name="_method" value="PATCH" class="btn btn-primary btn-sm pull-right">Edit Option</button>
<a href="{{ route('admin.services.option.export', ['option' => $option->id]) }}" class="btn btn-sm btn-info pull-right" style="margin-right:10px;">Export Option Configuration</a>
<button type="submit" name="_method" value="PATCH" class="btn btn-primary btn-sm pull-right">Save</button>
<a href="{{ route('admin.nests.egg.export', ['option' => $egg->id]) }}" class="btn btn-sm btn-info pull-right" style="margin-right:10px;">Export</a>
</div>
</div>
</div>

View file

@ -6,14 +6,14 @@
@extends('layouts.admin')
@section('title')
Service
Nests
@endsection
@section('content-header')
<h1>Service<small>All services currently available on this system.</small></h1>
<h1>Nests<small>All nests currently available on this system.</small></h1>
<ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li>
<li class="active">Service</li>
<li class="active">Nests</li>
</ol>
@endsection
@ -21,7 +21,7 @@
<div class="row">
<div class="col-xs-12">
<div class="alert alert-danger">
Services are a powerful feature of Pterodactyl Panel that allow for extreme flexibility and configuration. Please note that while powerful, modifing a service wrongly can very easily brick your servers and cause more problems. Please avoid editing our default services those provided by <code>support@pterodactyl.io</code> unless you are absolutely sure of what you are doing.
Eggs are a powerful feature of Pterodactyl Panel that allow for extreme flexibility and configuration. Please note that while powerful, modifing an egg wrongly can very easily brick your servers and cause more problems. Please avoid editing our default eggs those provided by <code>support@pterodactyl.io</code> unless you are absolutely sure of what you are doing.
</div>
</div>
</div>
@ -29,10 +29,10 @@
<div class="col-xs-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">Configured Service</h3>
<h3 class="box-title">Configured Nests</h3>
<div class="box-tools">
<a href="#" class="btn btn-sm btn-success" data-toggle="modal" data-target="#importServiceOptionModal" role="button"><i class="fa fa-upload"></i> Import Service Option</a>
<a href="{{ route('admin.services.new') }}" class="btn btn-primary btn-sm">Create New</a>
<a href="#" class="btn btn-sm btn-success" data-toggle="modal" data-target="#importServiceOptionModal" role="button"><i class="fa fa-upload"></i> Import Egg</a>
<a href="{{ route('admin.nests.new') }}" class="btn btn-primary btn-sm">Create New</a>
</div>
</div>
<div class="box-body table-responsive no-padding">
@ -40,17 +40,17 @@
<tr>
<th>Name</th>
<th>Description</th>
<th class="text-center">Options</th>
<th class="text-center">Eggs</th>
<th class="text-center">Packs</th>
<th class="text-center">Servers</th>
</tr>
@foreach($services as $service)
@foreach($nests as $nest)
<tr>
<td class="middle"><a href="{{ route('admin.services.view', $service->id) }}" data-toggle="tooltip" data-placement="right" title="{{ $service->author }}">{{ $service->name }}</a></td>
<td class="col-xs-6 middle">{{ $service->description }}</td>
<td class="text-center middle"><code>{{ $service->options_count }}</code></td>
<td class="text-center middle"><code>{{ $service->packs_count }}</code></td>
<td class="text-center middle"><code>{{ $service->servers_count }}</code></td>
<td class="middle"><a href="{{ route('admin.nests.view', $nest->id) }}" data-toggle="tooltip" data-placement="right" title="{{ $nest->author }}">{{ $nest->name }}</a></td>
<td class="col-xs-6 middle">{{ $nest->description }}</td>
<td class="text-center middle"><code>{{ $nest->eggs_count }}</code></td>
<td class="text-center middle"><code>{{ $nest->packs_count }}</code></td>
<td class="text-center middle"><code>{{ $nest->servers_count }}</code></td>
</tr>
@endforeach
</table>
@ -63,26 +63,26 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Import a Service Option</h4>
<h4 class="modal-title">Import an Egg</h4>
</div>
<form action="{{ route('admin.services.option.import') }}" enctype="multipart/form-data" method="POST">
<form action="{{ route('admin.nests.egg.import') }}" enctype="multipart/form-data" method="POST">
<div class="modal-body">
<div class="form-group">
<label class="control-label" for="pImportFile">Service File <span class="field-required"></span></label>
<label class="control-label" for="pImportFile">Egg File <span class="field-required"></span></label>
<div>
<input id="pImportFile" type="file" name="import_file" class="form-control" accept="application/json" />
<p class="small text-muted">Select the <code>.json</code> file for the new service option that you wish to import.</p>
<p class="small text-muted">Select the <code>.json</code> file for the new egg that you wish to import.</p>
</div>
</div>
<div class="form-group">
<label class="control-label" for="pImportToService">Associated Service <span class="field-required"></span></label>
<label class="control-label" for="pImportToService">Associated Nest <span class="field-required"></span></label>
<div>
<select id="pImportToService" name="import_to_service">
@foreach($services as $service)
<option value="{{ $service->id }}">{{ $service->name }} &lt;{{ $service->author }}&gt;</option>
@foreach($nests as $nest)
<option value="{{ $nest->id }}">{{ $nest->name }} &lt;{{ $nest->author }}&gt;</option>
@endforeach
</select>
<p class="small text-muted">Select the service that this option will be associated with from the dropdown. If you wish to associate it with a new service you will need to create that service before continuing.</p>
<p class="small text-muted">Select the nest that this egg will be associated with from the dropdown. If you wish to associate it with a new nest you will need to create that nest before continuing.</p>
</div>
</div>
</div>

View file

@ -6,32 +6,32 @@
@extends('layouts.admin')
@section('title')
New Service
New Nest
@endsection
@section('content-header')
<h1>New Service<small>Configure a new service to deploy to all nodes.</small></h1>
<h1>New Nest<small>Configure a new nest to deploy to all nodes.</small></h1>
<ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li>
<li><a href="{{ route('admin.services') }}">Service</a></li>
<li><a href="{{ route('admin.nests') }}">Nests</a></li>
<li class="active">New</li>
</ol>
@endsection
@section('content')
<form action="{{ route('admin.services.new') }}" method="POST">
<form action="{{ route('admin.nests.new') }}" method="POST">
<div class="row">
<div class="col-md-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">New Service</h3>
<h3 class="box-title">New Nest</h3>
</div>
<div class="box-body">
<div class="form-group">
<label class="control-label">Name</label>
<div>
<input type="text" name="name" class="form-control" value="{{ old('name') }}" />
<p class="text-muted"><small>This should be a descriptive category name that emcompasses all of the options within the service.</small></p>
<p class="text-muted"><small>This should be a descriptive category name that emcompasses all of the eggs within the nest.</small></p>
</div>
</div>
<div class="form-group">
@ -43,7 +43,7 @@
</div>
<div class="box-footer">
{!! csrf_field() !!}
<button type="input" class="btn btn-primary pull-right">Save Service</button>
<button type="submit" class="btn btn-primary pull-right">Save</button>
</div>
</div>
</div>

View file

@ -6,41 +6,41 @@
@extends('layouts.admin')
@section('title')
Service &rarr; {{ $service->name }}
Nests &rarr; {{ $nest->name }}
@endsection
@section('content-header')
<h1>{{ $service->name }}<small>{{ str_limit($service->description, 50) }}</small></h1>
<h1>{{ $nest->name }}<small>{{ str_limit($nest->description, 50) }}</small></h1>
<ol class="breadcrumb">
<li><a href="{{ route('admin.index') }}">Admin</a></li>
<li><a href="{{ route('admin.services') }}">Service</a></li>
<li class="active">{{ $service->name }}</li>
<li><a href="{{ route('admin.nests') }}">Nests</a></li>
<li class="active">{{ $nest->name }}</li>
</ol>
@endsection
@section('content')
<div class="row">
<form action="{{ route('admin.services.view', $service->id) }}" method="POST">
<form action="{{ route('admin.nests.view', $nest->id) }}" method="POST">
<div class="col-md-6">
<div class="box">
<div class="box-body">
<div class="form-group">
<label class="control-label">Name <span class="field-required"></span></label>
<div>
<input type="text" name="name" class="form-control" value="{{ $service->name }}" />
<input type="text" name="name" class="form-control" value="{{ $nest->name }}" />
<p class="text-muted"><small>This should be a descriptive category name that emcompasses all of the options within the service.</small></p>
</div>
</div>
<div class="form-group">
<label class="control-label">Description <span class="field-required"></span></label>
<div>
<textarea name="description" class="form-control" rows="7">{{ $service->description }}</textarea>
<textarea name="description" class="form-control" rows="7">{{ $nest->description }}</textarea>
</div>
</div>
</div>
<div class="box-footer">
{!! csrf_field() !!}
<button type="submit" name="_method" value="PATCH" class="btn btn-primary btn-sm pull-right">Edit Option</button>
<button type="submit" name="_method" value="PATCH" class="btn btn-primary btn-sm pull-right">Save</button>
<button id="deleteButton" type="submit" name="_method" value="DELETE" class="btn btn-sm btn-danger muted muted-hover"><i class="fa fa-trash-o"></i></button>
</div>
</div>
@ -52,14 +52,14 @@
<div class="form-group">
<label class="control-label">Author</label>
<div>
<input type="text" readonly class="form-control" value="{{ $service->author }}" />
<input type="text" readonly class="form-control" value="{{ $nest->author }}" />
<p class="text-muted small">The author of this service option. Please direct questions and issues to them unless this is an official option authored by <code>support@pterodactyl.io</code>.</p>
</div>
</div>
<div class="form-group">
<label class="control-label">UUID</label>
<div>
<input type="text" readonly class="form-control" value="{{ $service->uuid }}" />
<input type="text" readonly class="form-control" value="{{ $nest->uuid }}" />
<p class="text-muted small">A unique identifier that all servers using this option are assigned for identification purposes.</p>
</div>
</div>
@ -71,28 +71,30 @@
<div class="col-xs-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">Configured Options</h3>
<h3 class="box-title">Nest Eggs</h3>
</div>
<div class="box-body table-responsive no-padding">
<table class="table table-hover">
<tr>
<th>Name</th>
<th>Description</th>
<th>Tag</th>
<th class="text-center">Servers</th>
<th class="text-center"></th>
</tr>
@foreach($service->options as $option)
@foreach($nest->eggs as $egg)
<tr>
<td><a href="{{ route('admin.services.option.view', $option->id) }}">{{ $option->name }}</a></td>
<td class="col-xs-6">{!! $option->description !!}</td>
<td><code>{{ $option->tag }}</code></td>
<td class="text-center">{{ $option->servers->count() }}</td>
<td class="align-middle"><a href="{{ route('admin.nests.egg.view', $egg->id) }}">{{ $egg->name }}</a></td>
<td class="col-xs-8 align-middle">{!! $egg->description !!}</td>
<td class="text-center align-middle"><code>{{ $egg->servers->count() }}</code></td>
<td class="align-middle">
<a href="{{ route('admin.nests.egg.export', ['egg' => $egg->id]) }}"><i class="fa fa-download"></i></a>
</td>
</tr>
@endforeach
</table>
</div>
<div class="box-footer">
<a href="{{ route('admin.services.option.new') }}"><button class="btn btn-success btn-sm pull-right">New Service Option</button></a>
<a href="{{ route('admin.nests.egg.new') }}"><button class="btn btn-success btn-sm pull-right">New Egg</button></a>
</div>
</div>
</div>

View file

@ -112,9 +112,9 @@
</a>
</li>
<li class="header">SERVICE MANAGEMENT</li>
<li class="{{ ! starts_with(Route::currentRouteName(), 'admin.services') ?: 'active' }}">
<a href="{{ route('admin.services') }}">
<i class="fa fa-th-large"></i> <span>Service</span>
<li class="{{ ! starts_with(Route::currentRouteName(), 'admin.nests') ?: 'active' }}">
<a href="{{ route('admin.nests') }}">
<i class="fa fa-th-large"></i> <span>Nests</span>
</a>
</li>
<li class="{{ ! starts_with(Route::currentRouteName(), 'admin.packs') ?: 'active' }}">