Merge remote-tracking branch 'origin/product_links' into development
This commit is contained in:
commit
75622d3958
13 changed files with 437 additions and 102 deletions
|
@ -3,6 +3,10 @@
|
|||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Egg;
|
||||
use App\Models\Location;
|
||||
use App\Models\Nest;
|
||||
use App\Models\Node;
|
||||
use App\Models\Configuration;
|
||||
use App\Models\Product;
|
||||
use Exception;
|
||||
|
@ -33,7 +37,18 @@ class ProductController extends Controller
|
|||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('admin.products.create');
|
||||
return view('admin.products.create' , [
|
||||
'locations' => Location::with('nodes')->get(),
|
||||
'nests' => Nest::with('eggs')->get(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function clone(Request $request , Product $product){
|
||||
return view('admin.products.create' , [
|
||||
'product' => $product,
|
||||
'locations' => Location::with('nodes')->get(),
|
||||
'nests' => Nest::with('eggs')->get(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,11 +72,17 @@ class ProductController extends Controller
|
|||
"databases" => "required|numeric|max:1000000|min:0",
|
||||
"backups" => "required|numeric|max:1000000|min:0",
|
||||
"allocations" => "required|numeric|max:1000000|min:0",
|
||||
"nodes.*" => "required|exists:nodes,id",
|
||||
"eggs.*" => "required|exists:eggs,id",
|
||||
"disabled" => "nullable",
|
||||
]);
|
||||
|
||||
$disabled = !is_null($request->input('disabled'));
|
||||
Product::create(array_merge($request->all(), ['disabled' => $disabled]));
|
||||
$product = Product::create(array_merge($request->all(), ['disabled' => $disabled]));
|
||||
|
||||
#link nodes and eggs
|
||||
$product->eggs()->attach($request->input('eggs'));
|
||||
$product->nodes()->attach($request->input('nodes'));
|
||||
|
||||
return redirect()->route('admin.products.index')->with('success', 'product has been created!');
|
||||
}
|
||||
|
@ -89,7 +110,9 @@ class ProductController extends Controller
|
|||
public function edit(Product $product)
|
||||
{
|
||||
return view('admin.products.edit', [
|
||||
'product' => $product
|
||||
'product' => $product,
|
||||
'locations' => Location::with('nodes')->get(),
|
||||
'nests' => Nest::with('eggs')->get(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -115,12 +138,20 @@ class ProductController extends Controller
|
|||
"databases" => "required|numeric|max:1000000|min:0",
|
||||
"backups" => "required|numeric|max:1000000|min:0",
|
||||
"allocations" => "required|numeric|max:1000000|min:0",
|
||||
"nodes.*" => "required|exists:nodes,id",
|
||||
"eggs.*" => "required|exists:eggs,id",
|
||||
"disabled" => "nullable",
|
||||
]);
|
||||
|
||||
$disabled = !is_null($request->input('disabled'));
|
||||
$product->update(array_merge($request->all(), ['disabled' => $disabled]));
|
||||
|
||||
#link nodes and eggs
|
||||
$product->eggs()->detach();
|
||||
$product->nodes()->detach();
|
||||
$product->eggs()->attach($request->input('eggs'));
|
||||
$product->nodes()->attach($request->input('nodes'));
|
||||
|
||||
return redirect()->route('admin.products.index')->with('success', 'product has been updated!');
|
||||
}
|
||||
|
||||
|
@ -166,6 +197,7 @@ class ProductController extends Controller
|
|||
->addColumn('actions', function (Product $product) {
|
||||
return '
|
||||
<a data-content="Show" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.products.show', $product->id) . '" class="btn btn-sm text-white btn-warning mr-1"><i class="fas fa-eye"></i></a>
|
||||
<a data-content="Clone" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.products.clone', $product->id) . '" class="btn btn-sm text-white btn-primary mr-1"><i class="fas fa-clone"></i></a>
|
||||
<a data-content="Edit" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.products.edit', $product->id) . '" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
|
||||
|
||||
<form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.products.destroy', $product->id) . '">
|
||||
|
@ -179,6 +211,12 @@ class ProductController extends Controller
|
|||
->addColumn('servers', function (Product $product) {
|
||||
return $product->servers()->count();
|
||||
})
|
||||
->addColumn('nodes', function (Product $product) {
|
||||
return $product->nodes()->count();
|
||||
})
|
||||
->addColumn('eggs', function (Product $product) {
|
||||
return $product->eggs()->count();
|
||||
})
|
||||
->addColumn('disabled', function (Product $product) {
|
||||
$checked = $product->disabled == false ? "checked" : "";
|
||||
return '
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Egg;
|
||||
use App\Models\Product;
|
||||
use App\Models\UsefulLink;
|
||||
use App\Models\Configuration;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
|
@ -6,6 +6,7 @@ use App\Classes\Pterodactyl;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class Egg extends Model
|
||||
{
|
||||
|
@ -23,14 +24,6 @@ class Egg extends Model
|
|||
'environment',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function nest()
|
||||
{
|
||||
return $this->belongsTo(Nest::class, 'id', 'nest_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
|
@ -39,7 +32,7 @@ class Egg extends Model
|
|||
$array = [];
|
||||
|
||||
foreach (json_decode($this->environment) as $variable) {
|
||||
foreach ($variable as $key => $value){
|
||||
foreach ($variable as $key => $value) {
|
||||
$array[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
@ -47,12 +40,13 @@ class Egg extends Model
|
|||
return $array;
|
||||
}
|
||||
|
||||
public static function syncEggs(){
|
||||
public static function syncEggs()
|
||||
{
|
||||
|
||||
Nest::all()->each(function (Nest $nest) {
|
||||
Nest::all()->each(function (Nest $nest) {
|
||||
$eggs = Pterodactyl::getEggs($nest);
|
||||
|
||||
foreach ($eggs as $egg){
|
||||
foreach ($eggs as $egg) {
|
||||
$array = [];
|
||||
$environment = [];
|
||||
|
||||
|
@ -64,17 +58,32 @@ class Egg extends Model
|
|||
$array['startup'] = $egg['attributes']['startup'];
|
||||
|
||||
//get environment variables
|
||||
foreach ($egg['attributes']['relationships']['variables']['data'] as $variable){
|
||||
foreach ($egg['attributes']['relationships']['variables']['data'] as $variable) {
|
||||
$environment[$variable['attributes']['env_variable']] = $variable['attributes']['default_value'];
|
||||
}
|
||||
|
||||
$array['environment'] = json_encode([$environment]);
|
||||
|
||||
self::firstOrCreate(['id' => $array['id']] , $array);
|
||||
self::firstOrCreate(['id' => $array['id']], $array);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function nest()
|
||||
{
|
||||
return $this->belongsTo(Nest::class, 'id', 'nest_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsToMany
|
||||
*/
|
||||
public function products()
|
||||
{
|
||||
return $this->belongsToMany(Product::class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use Exception;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class Node extends Model
|
||||
{
|
||||
|
@ -48,4 +49,12 @@ class Node extends Model
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsToMany
|
||||
*/
|
||||
public function products()
|
||||
{
|
||||
return $this->belongsToMany(Product::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ use Hidehalo\Nanoid\Client;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Spatie\Activitylog\Traits\LogsActivity;
|
||||
|
||||
class Product extends Model
|
||||
|
@ -25,6 +27,11 @@ class Product extends Model
|
|||
|
||||
$product->{$product->getKeyName()} = $client->generateId($size = 21);
|
||||
});
|
||||
|
||||
static::deleting(function(Product $product) {
|
||||
$product->nodes()->detach();
|
||||
$product->eggs()->detach();
|
||||
});
|
||||
}
|
||||
|
||||
public function getHourlyPrice()
|
||||
|
@ -45,8 +52,22 @@ class Product extends Model
|
|||
/**
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function servers(): BelongsTo
|
||||
public function servers()
|
||||
{
|
||||
return $this->belongsTo(Server::class, 'id', 'product_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsToMany
|
||||
*/
|
||||
public function eggs() {
|
||||
return $this->belongsToMany(Egg::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsToMany
|
||||
*/
|
||||
public function nodes() {
|
||||
return $this->belongsToMany(Node::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateEggProductTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('egg_product', function (Blueprint $table) {
|
||||
$table->foreignId('egg_id')->constrained();
|
||||
$table->foreignUuid('product_id')->constrained();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('egg_product');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateNodeProductTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('node_product', function (Blueprint $table) {
|
||||
$table->foreignId('node_id')->constrained();
|
||||
$table->foreignUuid('product_id')->constrained();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('node_product');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddDisabledToEggsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('eggs', function (Blueprint $table) {
|
||||
$table->boolean('disabled')->default(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('eggs', function (Blueprint $table) {
|
||||
$table->dropColumn('disabled');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -25,19 +25,22 @@
|
|||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
<form action="{{route('admin.products.store')}}" method="POST">
|
||||
@csrf
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">Product Details</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form action="{{ route('admin.products.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="d-flex flex-row-reverse">
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" name="disabled"
|
||||
class="custom-control-input custom-control-input-danger" id="switch1">
|
||||
<label class="custom-control-label" for="switch1">Disabled <i data-toggle="popover"
|
||||
data-trigger="hover"
|
||||
class="custom-control-input custom-control-input-danger" id="switch1">
|
||||
<label class="custom-control-label" for="switch1">Disabled <i
|
||||
data-toggle="popover" data-trigger="hover"
|
||||
data-content="Will hide this option from being selected"
|
||||
class="fas fa-info-circle"></i></label>
|
||||
</div>
|
||||
|
@ -47,9 +50,9 @@
|
|||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input value="{{ old('name') }}" id="name" name="name" type="text"
|
||||
class="form-control @error('name') is-invalid @enderror"
|
||||
required="required">
|
||||
<input value="{{$product->name ?? old('name')}}" id="name" name="name" type="text"
|
||||
class="form-control @error('name') is-invalid @enderror"
|
||||
required="required">
|
||||
@error('name')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -58,10 +61,11 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="price">Price in {{ CREDITS_DISPLAY_NAME }}</label>
|
||||
<input value="{{ old('price') }}" id="price" name="price" type="number"
|
||||
class="form-control @error('price') is-invalid @enderror"
|
||||
required="required">
|
||||
<label for="price">Price in credits</label>
|
||||
<input value="{{$product->price ?? old('price')}}" id="price" name="price"
|
||||
type="number"
|
||||
class="form-control @error('price') is-invalid @enderror"
|
||||
required="required">
|
||||
@error('price')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -72,9 +76,10 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label for="memory">Memory</label>
|
||||
<input value="{{ old('memory') }}" id="memory" name="memory" type="number"
|
||||
class="form-control @error('memory') is-invalid @enderror"
|
||||
required="required">
|
||||
<input value="{{$product->memory ?? old('memory')}}" id="memory" name="memory"
|
||||
type="number"
|
||||
class="form-control @error('memory') is-invalid @enderror"
|
||||
required="required">
|
||||
@error('memory')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -84,8 +89,10 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label for="cpu">Cpu</label>
|
||||
<input value="{{ old('cpu') }}" id="cpu" name="cpu" type="number"
|
||||
class="form-control @error('cpu') is-invalid @enderror" required="required">
|
||||
<input value="{{$product->cpu ?? old('cpu')}}" id="cpu" name="cpu"
|
||||
type="number"
|
||||
class="form-control @error('cpu') is-invalid @enderror"
|
||||
required="required">
|
||||
@error('cpu')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -95,9 +102,10 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label for="swap">Swap</label>
|
||||
<input value="{{ old('swap') }}" id="swap" name="swap" type="number"
|
||||
class="form-control @error('swap') is-invalid @enderror"
|
||||
required="required">
|
||||
<input value="{{$product->swap ?? old('swap')}}" id="swap" name="swap"
|
||||
type="number"
|
||||
class="form-control @error('swap') is-invalid @enderror"
|
||||
required="required">
|
||||
@error('swap')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -107,11 +115,13 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label for="description">Description <i data-toggle="popover"
|
||||
data-trigger="hover" data-content="This is what the users sees"
|
||||
class="fas fa-info-circle"></i></label>
|
||||
<textarea id="description" name="description" type="text"
|
||||
class="form-control @error('description') is-invalid @enderror"
|
||||
required="required">{{ old('description') }}</textarea>
|
||||
data-trigger="hover"
|
||||
data-content="This is what the users sees"
|
||||
class="fas fa-info-circle"></i></label>
|
||||
<textarea id="description" name="description"
|
||||
type="text"
|
||||
class="form-control @error('description') is-invalid @enderror"
|
||||
required="required">{{$product->description ?? old('description')}}</textarea>
|
||||
@error('description')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -123,9 +133,10 @@
|
|||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="disk">Disk</label>
|
||||
<input value="{{ old('disk') ?? 1000 }}" id="disk" name="disk" type="number"
|
||||
class="form-control @error('disk') is-invalid @enderror"
|
||||
required="required">
|
||||
<input value="{{$product->disk ?? old('disk') ?? 1000}}" id="disk" name="disk"
|
||||
type="number"
|
||||
class="form-control @error('disk') is-invalid @enderror"
|
||||
required="required">
|
||||
@error('disk')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -151,8 +162,10 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label for="io">IO</label>
|
||||
<input value="{{ old('io') ?? 500 }}" id="io" name="io" type="number"
|
||||
class="form-control @error('io') is-invalid @enderror" required="required">
|
||||
<input value="{{$product->io ?? old('io') ?? 500}}" id="io" name="io"
|
||||
type="number"
|
||||
class="form-control @error('io') is-invalid @enderror"
|
||||
required="required">
|
||||
@error('io')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -161,9 +174,11 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label for="databases">Databases</label>
|
||||
<input value="{{ old('databases') ?? 1 }}" id="databases" name="databases"
|
||||
type="number" class="form-control @error('databases') is-invalid @enderror"
|
||||
required="required">
|
||||
<input value="{{$product->databases ?? old('databases') ?? 1}}" id="databases"
|
||||
name="databases"
|
||||
type="number"
|
||||
class="form-control @error('databases') is-invalid @enderror"
|
||||
required="required">
|
||||
@error('databases')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -172,9 +187,11 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label for="backups">Backups</label>
|
||||
<input value="{{ old('backups') ?? 1 }}" id="backups" name="backups"
|
||||
type="number" class="form-control @error('backups') is-invalid @enderror"
|
||||
required="required">
|
||||
<input value="{{$product->backups ?? old('backups') ?? 1}}" id="backups"
|
||||
name="backups"
|
||||
type="number"
|
||||
class="form-control @error('backups') is-invalid @enderror"
|
||||
required="required">
|
||||
@error('backups')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -183,10 +200,11 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label for="allocations">Allocations</label>
|
||||
<input value="{{ old('allocations') ?? 0 }}" id="allocations"
|
||||
name="allocations" type="number"
|
||||
class="form-control @error('allocations') is-invalid @enderror"
|
||||
required="required">
|
||||
<input value="{{$product->allocations ?? old('allocations') ?? 0}}"
|
||||
id="allocations" name="allocations"
|
||||
type="number"
|
||||
class="form-control @error('allocations') is-invalid @enderror"
|
||||
required="required">
|
||||
@error('allocations')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -201,11 +219,73 @@
|
|||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">Product Linking <i data-toggle="popover" data-trigger="hover"
|
||||
data-content="Linked products will only be available when the user has selected the linked node and/or egg"
|
||||
class="fas fa-info-circle"></i></h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="nodes">Nodes</label>
|
||||
<select id="nodes" style="width:100%" class="custom-select @error('nodes') is-invalid @enderror"
|
||||
name="nodes[]" multiple="multiple" autocomplete="off">
|
||||
@foreach($locations as $location)
|
||||
<optgroup label="{{$location->name}}">
|
||||
@foreach($location->nodes as $node)
|
||||
<option @if(isset($product)) @if($product->nodes->contains('id' , $node->id)) selected
|
||||
@endif @endif value="{{$node->id}}">{{$node->name}}</option>
|
||||
@endforeach
|
||||
</optgroup>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('nodes')
|
||||
<div class="text-danger">
|
||||
{{$message}}
|
||||
</div>
|
||||
@enderror
|
||||
<div class="text-muted">
|
||||
This product will only be available for these nodes
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="eggs">Eggs</label>
|
||||
<select id="eggs" style="width:100%" class="custom-select @error('eggs') is-invalid @enderror"
|
||||
name="eggs[]" multiple="multiple" autocomplete="off">
|
||||
@foreach($nests as $nest)
|
||||
<optgroup label="{{$nest->name}}">
|
||||
@foreach($nest->eggs as $egg)
|
||||
<option @if(isset($product)) @if($product->eggs->contains('id' , $egg->id)) selected
|
||||
@endif @endif value="{{$egg->id}}">{{$egg->name}}</option>
|
||||
@endforeach
|
||||
</optgroup>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('eggs')
|
||||
<div class="text-danger">
|
||||
{{$message}}
|
||||
</div>
|
||||
@enderror
|
||||
<div class="text-muted">
|
||||
This product will only be available for these eggs
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
@ -216,6 +296,10 @@
|
|||
$('[data-toggle="popover"]').popover();
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
})
|
||||
</script>
|
||||
$('.custom-select').select2();
|
||||
|
||||
@endsection
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
</div>
|
||||
<div class="col-sm-6">
|
||||
<ol class="breadcrumb float-sm-right">
|
||||
<li class="breadcrumb-item"><a href="{{ route('home') }}">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('admin.products.index') }}">Products</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{route('home')}}">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{route('admin.products.index')}}">Products</a></li>
|
||||
<li class="breadcrumb-item"><a class="text-muted"
|
||||
href="{{ route('admin.products.edit', $product->id) }}">Edit</a>
|
||||
href="{{route('admin.products.edit' , $product->id)}}">Edit</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
@ -25,31 +25,34 @@
|
|||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
<form action="{{route('admin.products.update' , $product->id)}}" method="POST">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
@if($product->servers()->count() > 0)
|
||||
<div class="callout callout-danger">
|
||||
<h4>Editing the resource options will not automatically update the servers on
|
||||
pterodactyl's side!</h4>
|
||||
<p class="text-muted">Automatically updating resource options on pterodactyl side is on
|
||||
my todo list :)</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($product->servers()->count() > 0)
|
||||
<div class="callout callout-danger">
|
||||
<h4>Editing the resource options will not automatically update the servers on pterodactyl's
|
||||
side!</h4>
|
||||
<p class="text-muted">Automatically updating resource options on pterodactyl side is on my
|
||||
todo list :)</p>
|
||||
</div>
|
||||
@endif
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">Product Details</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form action="{{ route('admin.products.update', $product->id) }}" method="POST">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<div class="d-flex flex-row-reverse">
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" @if ($product->disabled) checked @endif name="disabled"
|
||||
class="custom-control-input custom-control-input-danger" id="switch1">
|
||||
<label class="custom-control-label" for="switch1">Disabled <i data-toggle="popover"
|
||||
data-trigger="hover"
|
||||
<input type="checkbox" @if($product->disabled) checked @endif name="disabled"
|
||||
class="custom-control-input custom-control-input-danger" id="switch1">
|
||||
<label class="custom-control-label" for="switch1">Disabled <i
|
||||
data-toggle="popover" data-trigger="hover"
|
||||
data-content="Will hide this option from being selected"
|
||||
class="fas fa-info-circle"></i></label>
|
||||
</div>
|
||||
|
@ -57,6 +60,7 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input value="{{ $product->name }}" id="name" name="name" type="text"
|
||||
|
@ -118,11 +122,13 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label for="description">Description <i data-toggle="popover"
|
||||
data-trigger="hover" data-content="This is what the users sees"
|
||||
class="fas fa-info-circle"></i></label>
|
||||
<textarea id="description" name="description" type="text"
|
||||
class="form-control @error('description') is-invalid @enderror"
|
||||
required="required">{{ $product->description }}</textarea>
|
||||
data-trigger="hover"
|
||||
data-content="This is what the users sees"
|
||||
class="fas fa-info-circle"></i></label>
|
||||
<textarea id="description" name="description"
|
||||
type="text"
|
||||
class="form-control @error('description') is-invalid @enderror"
|
||||
required="required">{{$product->description}}</textarea>
|
||||
@error('description')
|
||||
<div class="invalid-feedback">
|
||||
{{ $message }}
|
||||
|
@ -210,21 +216,87 @@
|
|||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">Product Linking <i data-toggle="popover" data-trigger="hover"
|
||||
data-content="Linked products will only be available when the user has selected the linked node and/or egg"
|
||||
class="fas fa-info-circle"></i></h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="nodes">Nodes</label>
|
||||
<select id="nodes" style="width:100%"
|
||||
class="custom-select @error('nodes') is-invalid @enderror" name="nodes[]"
|
||||
multiple="multiple" autocomplete="off">
|
||||
@foreach($locations as $location)
|
||||
<optgroup label="{{$location->name}}">
|
||||
@foreach($location->nodes as $node)
|
||||
<option @if($product->nodes->contains('id' , $node->id)) selected
|
||||
@endif value="{{$node->id}}">{{$node->name}}</option>
|
||||
@endforeach
|
||||
</optgroup>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('nodes')
|
||||
<div class="text-danger">
|
||||
{{$message}}
|
||||
</div>
|
||||
@enderror
|
||||
<div class="text-muted">
|
||||
This product will only be available for these nodes
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="eggs">Eggs</label>
|
||||
<select id="eggs" style="width:100%"
|
||||
class="custom-select @error('eggs') is-invalid @enderror" name="eggs[]"
|
||||
multiple="multiple" autocomplete="off">
|
||||
@foreach($nests as $nest)
|
||||
<optgroup label="{{$nest->name}}">
|
||||
@foreach($nest->eggs as $egg)
|
||||
<option @if($product->eggs->contains('id' , $egg->id)) selected
|
||||
@endif value="{{$egg->id}}">{{$egg->name}}</option>
|
||||
@endforeach
|
||||
</optgroup>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('eggs')
|
||||
<div class="text-danger">
|
||||
{{$message}}
|
||||
</div>
|
||||
@enderror
|
||||
<div class="text-muted">
|
||||
This product will only be available for these eggs
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT -->
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
$('.custom-select').select2();
|
||||
})
|
||||
</script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$('[data-toggle="popover"]').popover();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@endsection
|
||||
|
|
|
@ -46,10 +46,10 @@
|
|||
<th>Cpu</th>
|
||||
<th>Swap</th>
|
||||
<th>Disk</th>
|
||||
<th>IO</th>
|
||||
<th>Databases</th>
|
||||
<th>Backups</th>
|
||||
<th>Allocations</th>
|
||||
<th>Eggs</th>
|
||||
<th>Nodes</th>
|
||||
<th>Servers</th>
|
||||
<th>Created at</th>
|
||||
<th></th>
|
||||
|
@ -79,6 +79,7 @@
|
|||
processing: true,
|
||||
serverSide: true,
|
||||
stateSave: true,
|
||||
order: [[ 2, "asc" ]],
|
||||
ajax: "{{route('admin.products.datatable')}}",
|
||||
columns: [
|
||||
{data: 'disabled'},
|
||||
|
@ -88,10 +89,10 @@
|
|||
{data: 'cpu'},
|
||||
{data: 'swap'},
|
||||
{data: 'disk'},
|
||||
{data: 'io'},
|
||||
{data: 'databases'},
|
||||
{data: 'backups'},
|
||||
{data: 'allocations'},
|
||||
{data: 'nodes', sortable: false},
|
||||
{data: 'eggs', sortable: false},
|
||||
{data: 'servers', sortable: false},
|
||||
{data: 'created_at'},
|
||||
{data: 'actions', sortable: false},
|
||||
|
|
|
@ -340,6 +340,8 @@
|
|||
<script type="text/javascript" src="https://cdn.datatables.net/v/bs4/dt-1.10.24/datatables.min.js"></script>
|
||||
<!-- Summernote -->
|
||||
<script src="{{asset('plugins/summernote/summernote-bs4.min.js')}}"></script>
|
||||
<!-- select2 -->
|
||||
<script src="{{asset('plugins/select2/js/select2.min.js')}}"></script>
|
||||
|
||||
<!-- Moment.js -->
|
||||
<script src="{{asset('plugins/moment/moment.min.js')}}"></script>
|
||||
|
|
|
@ -87,6 +87,7 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
|
|||
Route::resource('servers', AdminServerController::class);
|
||||
|
||||
Route::get('products/datatable', [ProductController::class, 'datatable'])->name('products.datatable');
|
||||
Route::get('products/clone/{product}', [ProductController::class, 'clone'])->name('products.clone');
|
||||
Route::patch('products/disable/{product}', [ProductController::class, 'disable'])->name('products.disable');
|
||||
Route::resource('products', ProductController::class);
|
||||
|
||||
|
|
Loading…
Reference in a new issue