update includes
This commit is contained in:
272
app/Http/Controllers/WorkshopController.php
Normal file
272
app/Http/Controllers/WorkshopController.php
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Workshop;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class WorkshopController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$homeView = true;
|
||||||
|
$search = $request->get('search', '');
|
||||||
|
|
||||||
|
$query = Workshop::query();
|
||||||
|
|
||||||
|
if(!auth()->user()?->admin) {
|
||||||
|
$query = $query->where('status', '!=', 'draft');
|
||||||
|
}
|
||||||
|
|
||||||
|
if($request->has('search') && $request->search !== '') {
|
||||||
|
$homeView = false;
|
||||||
|
$query = $query->where(function ($query) use ($request) {
|
||||||
|
$query->where('title', 'like', '%' . $request->search . '%')
|
||||||
|
->orWhere('content', 'like', '%' . $request->search . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if($request->has('location') && $request->location !== '') {
|
||||||
|
$homeView = false;
|
||||||
|
$query = $query->whereHas('location', function ($query) use ($request) {
|
||||||
|
$query->where('name', 'like', '%' . $request->location . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if($request->has('date') && $request->date !== '') {
|
||||||
|
$homeView = false;
|
||||||
|
$dates = explode('-', $request->date);
|
||||||
|
$dates = array_map('trim', $dates);
|
||||||
|
$dates = array_map(function($date) {
|
||||||
|
$date = trim($date);
|
||||||
|
|
||||||
|
if(preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
if(preg_match('/^(\d{2})-(\d{2})-(\d{2})$/', $date, $matches)) {
|
||||||
|
return '20' . $matches[1] . '-' . $matches[2] . '-' . $matches[3];
|
||||||
|
}
|
||||||
|
if(preg_match('/^\d{4}-\d{2}$/', $date)) {
|
||||||
|
return $date . '-01';
|
||||||
|
}
|
||||||
|
if(preg_match('/^\d{4}$/', $date)) {
|
||||||
|
return $date . '-01-01';
|
||||||
|
}
|
||||||
|
if(preg_match('/^(\d{2})\/(\d{2})\/(\d{2})$/', $date, $matches)) {
|
||||||
|
return '20' . $matches[3] . '-' . $matches[2] . '-' . $matches[1];
|
||||||
|
}
|
||||||
|
if(preg_match('/^(\d{2})\/(\d{2})\/(\d{4})$/', $date, $matches)) {
|
||||||
|
return $matches[3] . '-' . $matches[2] . '-' . $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}, $dates);
|
||||||
|
|
||||||
|
if(count($dates) == 2) {
|
||||||
|
// If there are two dates, filter between starts_at and ends_at
|
||||||
|
$query = $query->whereDate('starts_at', '>=', $dates[0])
|
||||||
|
->whereDate('ends_at', '<=', $dates[1]);
|
||||||
|
} else {
|
||||||
|
// If there is one date, filter starts_at that date or newer
|
||||||
|
$query = $query->whereDate('starts_at', '>=', $dates[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($homeView) {
|
||||||
|
$query = $query->where('starts_at', '>=', Carbon::now()->subDays(8))
|
||||||
|
->orderBy('starts_at', 'asc');
|
||||||
|
} else {
|
||||||
|
$query = $query->orderBy('starts_at', 'asc');
|
||||||
|
}
|
||||||
|
|
||||||
|
$workshops = $query->paginate(12);
|
||||||
|
return view('workshop.index', [
|
||||||
|
'workshops' => $workshops,
|
||||||
|
'search' => $search,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function past_index(Request $request)
|
||||||
|
{
|
||||||
|
return view('workshop.index', [
|
||||||
|
'workshops' => [],
|
||||||
|
// 'search' => $search,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function admin_index(Request $request)
|
||||||
|
{
|
||||||
|
$query = Workshop::query();
|
||||||
|
|
||||||
|
if($request->has('search')) {
|
||||||
|
$query->where('title', 'like', '%' . $request->search . '%');
|
||||||
|
$query->orWhere('content', 'like', '%' . $request->search . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
$workshops = $query->orderBy('starts_at', 'desc')->paginate(12)->onEachSide(1);
|
||||||
|
|
||||||
|
return view('admin.workshop.index', [
|
||||||
|
'workshops' => $workshops
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function admin_create()
|
||||||
|
{
|
||||||
|
return view('admin.workshop.edit');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function admin_store(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'title' => 'required',
|
||||||
|
'content' => 'required',
|
||||||
|
'starts_at' => 'required',
|
||||||
|
'ends_at' => 'required|after:starts_at',
|
||||||
|
'publish_at' => 'required',
|
||||||
|
'closes_at' => 'required',
|
||||||
|
'status' => 'required',
|
||||||
|
'hero_media_name' => 'required|exists:media,name',
|
||||||
|
'registration_data' => 'required_unless:registration,none',
|
||||||
|
], [
|
||||||
|
'title.required' => __('validation.custom_messages.title_required'),
|
||||||
|
'content.required' => __('validation.custom_messages.content_required'),
|
||||||
|
'starts_at.required' => __('validation.custom_messages.starts_at_required'),
|
||||||
|
'ends_at.required' => __('validation.custom_messages.ends_at_required'),
|
||||||
|
'ends_at.after' => __('validation.custom_messages.ends_at_after'),
|
||||||
|
'publish_at.required' => __('validation.custom_messages.publish_at_required'),
|
||||||
|
'closes_at.required' => __('validation.custom_messages.closes_at_required'),
|
||||||
|
'status.required' => __('validation.custom_messages.status_required'),
|
||||||
|
'hero_media_name.required' => __('validation.custom_messages.hero_media_name_required'),
|
||||||
|
'hero_media_name.exists' => __('validation.custom_messages.hero_media_name_exists'),
|
||||||
|
'registration_data.required_unless' => __('validation.custom_messages.registration_data_required_unless'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$workshopData = $request->all();
|
||||||
|
$workshopData['user_id'] = auth()->user()->id;
|
||||||
|
|
||||||
|
if($workshopData['status'] === 'open' && Carbon::parse($workshopData['starts_at'])->lt(Carbon::now())) {
|
||||||
|
$workshopData['status'] = 'closed';
|
||||||
|
}
|
||||||
|
|
||||||
|
$workshop = Workshop::create($workshopData);
|
||||||
|
$workshop->updateFiles($request->input('files'));
|
||||||
|
|
||||||
|
session()->flash('message', 'Workshop has been created');
|
||||||
|
session()->flash('message-title', 'Workshop created');
|
||||||
|
session()->flash('message-type', 'success');
|
||||||
|
return redirect()->route('admin.workshop.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(Workshop $workshop)
|
||||||
|
{
|
||||||
|
if(!auth()->user()?->admin && $workshop->status == 'draft') {
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('workshop.show', ['workshop' => $workshop]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function admin_edit(Workshop $workshop)
|
||||||
|
{
|
||||||
|
return view('admin.workshop.edit', ['workshop' => $workshop]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function admin_update(Request $request, Workshop $workshop)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'title' => 'required',
|
||||||
|
'content' => 'required',
|
||||||
|
'starts_at' => 'required',
|
||||||
|
'ends_at' => 'required|after:starts_at',
|
||||||
|
'publish_at' => 'required',
|
||||||
|
'closes_at' => 'required',
|
||||||
|
'status' => 'required',
|
||||||
|
'hero_media_name' => 'required|exists:media,name',
|
||||||
|
'registration_data' => 'required_unless:registration,none',
|
||||||
|
], [
|
||||||
|
'title.required' => __('validation.custom_messages.title_required'),
|
||||||
|
'content.required' => __('validation.custom_messages.content_required'),
|
||||||
|
'starts_at.required' => __('validation.custom_messages.starts_at_required'),
|
||||||
|
'ends_at.required' => __('validation.custom_messages.ends_at_required'),
|
||||||
|
'ends_at.after' => __('validation.custom_messages.ends_at_after'),
|
||||||
|
'publish_at.required' => __('validation.custom_messages.publish_at_required'),
|
||||||
|
'closes_at.required' => __('validation.custom_messages.closes_at_required'),
|
||||||
|
'status.required' => __('validation.custom_messages.status_required'),
|
||||||
|
'hero_media_name.required' => __('validation.custom_messages.hero_media_name_required'),
|
||||||
|
'hero_media_name.exists' => __('validation.custom_messages.hero_media_name_exists'),
|
||||||
|
'registration_data.required_unless' => __('validation.custom_messages.registration_data_required_unless'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$workshopData = $request->all();
|
||||||
|
if($workshopData['status'] === 'open' && Carbon::parse($workshopData['starts_at'])->lt(Carbon::now())) {
|
||||||
|
$workshopData['status'] = 'closed';
|
||||||
|
}
|
||||||
|
|
||||||
|
$workshop->update($workshopData);
|
||||||
|
$workshop->updateFiles($request->input('files'));
|
||||||
|
|
||||||
|
session()->flash('message', 'Workshop has been updated');
|
||||||
|
session()->flash('message-title', 'Workshop updated');
|
||||||
|
session()->flash('message-type', 'success');
|
||||||
|
return redirect()->route('admin.workshop.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function admin_destroy(Workshop $workshop)
|
||||||
|
{
|
||||||
|
$workshop->delete();
|
||||||
|
session()->flash('message', 'Workshop has been deleted');
|
||||||
|
session()->flash('message-title', 'Workshop deleted');
|
||||||
|
session()->flash('message-type', 'danger');
|
||||||
|
|
||||||
|
return redirect()->route('admin.workshop.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duplicate the specified resource.
|
||||||
|
*/
|
||||||
|
public function admin_duplicate(Workshop $workshop)
|
||||||
|
{
|
||||||
|
$newWorkshop = $workshop->replicate();
|
||||||
|
$newWorkshop->title = $newWorkshop->title . ' (copy)';
|
||||||
|
$newWorkshop->status = 'draft';
|
||||||
|
$newWorkshop->save();
|
||||||
|
|
||||||
|
foreach($workshop->files as $file) {
|
||||||
|
$newWorkshop->files()->attach($file->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
session()->flash('message', 'Workshop has been duplicated');
|
||||||
|
session()->flash('message-title', 'Workshop duplicated');
|
||||||
|
session()->flash('message-type', 'success');
|
||||||
|
|
||||||
|
return redirect()->route('admin.workshop.edit', $newWorkshop);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
app/Models/Workshop.php
Normal file
52
app/Models/Workshop.php
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Traits\HasFiles;
|
||||||
|
use App\Traits\Slug;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Workshop extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, Slug, HasFiles;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'title',
|
||||||
|
'content',
|
||||||
|
'starts_at',
|
||||||
|
'ends_at',
|
||||||
|
'publish_at',
|
||||||
|
'closes_at',
|
||||||
|
'status',
|
||||||
|
'price',
|
||||||
|
'ages',
|
||||||
|
'registration',
|
||||||
|
'registration_data',
|
||||||
|
'location_id',
|
||||||
|
'user_id',
|
||||||
|
'hero_media_name'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'starts_at' => 'datetime',
|
||||||
|
'ends_at' => 'datetime',
|
||||||
|
'publish_at' => 'datetime',
|
||||||
|
'closes_at' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function author()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hero()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Media::class, 'hero_media_name');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function location()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Location::class, 'location_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
80
config/flare.php
Normal file
80
config/flare.php
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Spatie\FlareClient\FlareMiddleware\AddGitInformation;
|
||||||
|
use Spatie\FlareClient\FlareMiddleware\RemoveRequestIp;
|
||||||
|
use Spatie\FlareClient\FlareMiddleware\CensorRequestBodyFields;
|
||||||
|
use Spatie\FlareClient\FlareMiddleware\CensorRequestHeaders;
|
||||||
|
use Spatie\LaravelIgnition\FlareMiddleware\AddDumps;
|
||||||
|
use Spatie\LaravelIgnition\FlareMiddleware\AddEnvironmentInformation;
|
||||||
|
use Spatie\LaravelIgnition\FlareMiddleware\AddExceptionInformation;
|
||||||
|
use Spatie\LaravelIgnition\FlareMiddleware\AddJobs;
|
||||||
|
use Spatie\LaravelIgnition\FlareMiddleware\AddLogs;
|
||||||
|
use Spatie\LaravelIgnition\FlareMiddleware\AddQueries;
|
||||||
|
use Spatie\LaravelIgnition\FlareMiddleware\AddNotifierName;
|
||||||
|
|
||||||
|
return [
|
||||||
|
/*
|
||||||
|
|
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Flare API key
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Specify Flare's API key below to enable error reporting to the service.
|
||||||
|
|
|
||||||
|
| More info: https://flareapp.io/docs/general/projects
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'key' => env('FLARE_KEY'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These middleware will modify the contents of the report sent to Flare.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'flare_middleware' => [
|
||||||
|
RemoveRequestIp::class,
|
||||||
|
AddGitInformation::class,
|
||||||
|
AddNotifierName::class,
|
||||||
|
AddEnvironmentInformation::class,
|
||||||
|
AddExceptionInformation::class,
|
||||||
|
AddDumps::class,
|
||||||
|
AddLogs::class => [
|
||||||
|
'maximum_number_of_collected_logs' => 200,
|
||||||
|
],
|
||||||
|
AddQueries::class => [
|
||||||
|
'maximum_number_of_collected_queries' => 200,
|
||||||
|
'report_query_bindings' => true,
|
||||||
|
],
|
||||||
|
AddJobs::class => [
|
||||||
|
'max_chained_job_reporting_depth' => 5,
|
||||||
|
],
|
||||||
|
CensorRequestBodyFields::class => [
|
||||||
|
'censor_fields' => [
|
||||||
|
'password',
|
||||||
|
'password_confirmation',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
CensorRequestHeaders::class => [
|
||||||
|
'headers' => [
|
||||||
|
'API-KEY',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Reporting log statements
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| If this setting is `false` log statements won't be sent as events to Flare,
|
||||||
|
| no matter which error level you specified in the Flare log channel.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'send_logs_as_events' => true,
|
||||||
|
];
|
||||||
277
config/ignition.php
Normal file
277
config/ignition.php
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Spatie\Ignition\Solutions\SolutionProviders\BadMethodCallSolutionProvider;
|
||||||
|
use Spatie\Ignition\Solutions\SolutionProviders\MergeConflictSolutionProvider;
|
||||||
|
use Spatie\Ignition\Solutions\SolutionProviders\UndefinedPropertySolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Recorders\DumpRecorder\DumpRecorder;
|
||||||
|
use Spatie\LaravelIgnition\Recorders\JobRecorder\JobRecorder;
|
||||||
|
use Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder;
|
||||||
|
use Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\DefaultDbNameSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\GenericLaravelExceptionSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\IncorrectValetDbCredentialsSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\InvalidRouteActionSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\MissingAppKeySolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\MissingColumnSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\MissingImportSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\MissingLivewireComponentSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\MissingMixManifestSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\MissingViteManifestSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\RunningLaravelDuskInProductionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\TableNotFoundSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\UndefinedViewVariableSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\UnknownValidationSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\ViewNotFoundSolutionProvider;
|
||||||
|
use Spatie\LaravelIgnition\Solutions\SolutionProviders\OpenAiSolutionProvider;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Editor
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Choose your preferred editor to use when clicking any edit button.
|
||||||
|
|
|
||||||
|
| Supported: "phpstorm", "vscode", "vscode-insiders", "textmate", "emacs",
|
||||||
|
| "sublime", "atom", "nova", "macvim", "idea", "netbeans",
|
||||||
|
| "xdebug", "phpstorm-remote"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'editor' => env('IGNITION_EDITOR', 'phpstorm'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Theme
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify which theme Ignition should use.
|
||||||
|
|
|
||||||
|
| Supported: "light", "dark", "auto"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'theme' => env('IGNITION_THEME', 'auto'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Sharing
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| You can share local errors with colleagues or others around the world.
|
||||||
|
| Sharing is completely free and doesn't require an account on Flare.
|
||||||
|
|
|
||||||
|
| If necessary, you can completely disable sharing below.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'enable_share_button' => env('IGNITION_SHARING_ENABLED', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Register Ignition commands
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Ignition comes with an additional make command that lets you create
|
||||||
|
| new solution classes more easily. To keep your default Laravel
|
||||||
|
| installation clean, this command is not registered by default.
|
||||||
|
|
|
||||||
|
| You can enable the command registration below.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'register_commands' => env('REGISTER_IGNITION_COMMANDS', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Solution Providers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| You may specify a list of solution providers (as fully qualified class
|
||||||
|
| names) that shouldn't be loaded. Ignition will ignore these classes
|
||||||
|
| and possible solutions provided by them will never be displayed.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'solution_providers' => [
|
||||||
|
// from spatie/ignition
|
||||||
|
BadMethodCallSolutionProvider::class,
|
||||||
|
MergeConflictSolutionProvider::class,
|
||||||
|
UndefinedPropertySolutionProvider::class,
|
||||||
|
|
||||||
|
// from spatie/laravel-ignition
|
||||||
|
IncorrectValetDbCredentialsSolutionProvider::class,
|
||||||
|
MissingAppKeySolutionProvider::class,
|
||||||
|
DefaultDbNameSolutionProvider::class,
|
||||||
|
TableNotFoundSolutionProvider::class,
|
||||||
|
MissingImportSolutionProvider::class,
|
||||||
|
InvalidRouteActionSolutionProvider::class,
|
||||||
|
ViewNotFoundSolutionProvider::class,
|
||||||
|
RunningLaravelDuskInProductionProvider::class,
|
||||||
|
MissingColumnSolutionProvider::class,
|
||||||
|
UnknownValidationSolutionProvider::class,
|
||||||
|
MissingMixManifestSolutionProvider::class,
|
||||||
|
MissingViteManifestSolutionProvider::class,
|
||||||
|
MissingLivewireComponentSolutionProvider::class,
|
||||||
|
UndefinedViewVariableSolutionProvider::class,
|
||||||
|
GenericLaravelExceptionSolutionProvider::class,
|
||||||
|
OpenAiSolutionProvider::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Ignored Solution Providers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| You may specify a list of solution providers (as fully qualified class
|
||||||
|
| names) that shouldn't be loaded. Ignition will ignore these classes
|
||||||
|
| and possible solutions provided by them will never be displayed.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'ignored_solution_providers' => [
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Runnable Solutions
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Some solutions that Ignition displays are runnable and can perform
|
||||||
|
| various tasks. By default, runnable solutions are only enabled when your
|
||||||
|
| app has debug mode enabled and the environment is `local` or
|
||||||
|
| `development`.
|
||||||
|
|
|
||||||
|
| Using the `IGNITION_ENABLE_RUNNABLE_SOLUTIONS` environment variable, you
|
||||||
|
| can override this behaviour and enable or disable runnable solutions
|
||||||
|
| regardless of the application's environment.
|
||||||
|
|
|
||||||
|
| Default: env('IGNITION_ENABLE_RUNNABLE_SOLUTIONS')
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'enable_runnable_solutions' => env('IGNITION_ENABLE_RUNNABLE_SOLUTIONS'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Remote Path Mapping
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| If you are using a remote dev server, like Laravel Homestead, Docker, or
|
||||||
|
| even a remote VPS, it will be necessary to specify your path mapping.
|
||||||
|
|
|
||||||
|
| Leaving one, or both of these, empty or null will not trigger the remote
|
||||||
|
| URL changes and Ignition will treat your editor links as local files.
|
||||||
|
|
|
||||||
|
| "remote_sites_path" is an absolute base path for your sites or projects
|
||||||
|
| in Homestead, Vagrant, Docker, or another remote development server.
|
||||||
|
|
|
||||||
|
| Example value: "/home/vagrant/Code"
|
||||||
|
|
|
||||||
|
| "local_sites_path" is an absolute base path for your sites or projects
|
||||||
|
| on your local computer where your IDE or code editor is running on.
|
||||||
|
|
|
||||||
|
| Example values: "/Users/<name>/Code", "C:\Users\<name>\Documents\Code"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'remote_sites_path' => env('IGNITION_REMOTE_SITES_PATH', base_path()),
|
||||||
|
'local_sites_path' => env('IGNITION_LOCAL_SITES_PATH', ''),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Housekeeping Endpoint Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Ignition registers a couple of routes when it is enabled. Below you may
|
||||||
|
| specify a route prefix that will be used to host all internal links.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'housekeeping_endpoint_prefix' => '_ignition',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Settings File
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Ignition allows you to save your settings to a specific global file.
|
||||||
|
|
|
||||||
|
| If no path is specified, a file with settings will be saved to the user's
|
||||||
|
| home directory. The directory depends on the OS and its settings but it's
|
||||||
|
| typically `~/.ignition.json`. In this case, the settings will be applied
|
||||||
|
| to all of your projects where Ignition is used and the path is not
|
||||||
|
| specified.
|
||||||
|
|
|
||||||
|
| However, if you want to store your settings on a project basis, or you
|
||||||
|
| want to keep them in another directory, you can specify a path where
|
||||||
|
| the settings file will be saved. The path should be an existing directory
|
||||||
|
| with correct write access.
|
||||||
|
| For example, create a new `ignition` folder in the storage directory and
|
||||||
|
| use `storage_path('ignition')` as the `settings_file_path`.
|
||||||
|
|
|
||||||
|
| Default value: '' (empty string)
|
||||||
|
*/
|
||||||
|
|
||||||
|
'settings_file_path' => '',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Recorders
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Ignition registers a couple of recorders when it is enabled. Below you may
|
||||||
|
| specify a recorders will be used to record specific events.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'recorders' => [
|
||||||
|
DumpRecorder::class,
|
||||||
|
JobRecorder::class,
|
||||||
|
LogRecorder::class,
|
||||||
|
QueryRecorder::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When a key is set, we'll send your exceptions to Open AI to generate a solution
|
||||||
|
*/
|
||||||
|
'open_ai_key' => env('IGNITION_OPEN_AI_KEY'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Include arguments
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Ignition show you stack traces of exceptions with the arguments that were
|
||||||
|
| passed to each method. This feature can be disabled here.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'with_stack_frame_arguments' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Argument reducers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Ignition show you stack traces of exceptions with the arguments that were
|
||||||
|
| passed to each method. To make these variables more readable, you can
|
||||||
|
| specify a list of classes here which summarize the variables.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'argument_reducers' => [
|
||||||
|
\Spatie\Backtrace\Arguments\Reducers\BaseTypeArgumentReducer::class,
|
||||||
|
\Spatie\Backtrace\Arguments\Reducers\ArrayArgumentReducer::class,
|
||||||
|
\Spatie\Backtrace\Arguments\Reducers\StdClassArgumentReducer::class,
|
||||||
|
\Spatie\Backtrace\Arguments\Reducers\EnumArgumentReducer::class,
|
||||||
|
\Spatie\Backtrace\Arguments\Reducers\ClosureArgumentReducer::class,
|
||||||
|
\Spatie\Backtrace\Arguments\Reducers\DateTimeArgumentReducer::class,
|
||||||
|
\Spatie\Backtrace\Arguments\Reducers\DateTimeZoneArgumentReducer::class,
|
||||||
|
\Spatie\Backtrace\Arguments\Reducers\SymphonyRequestArgumentReducer::class,
|
||||||
|
\Spatie\LaravelIgnition\ArgumentReducers\ModelArgumentReducer::class,
|
||||||
|
\Spatie\LaravelIgnition\ArgumentReducers\CollectionArgumentReducer::class,
|
||||||
|
\Spatie\Backtrace\Arguments\Reducers\StringableArgumentReducer::class,
|
||||||
|
],
|
||||||
|
];
|
||||||
50
config/tinker.php
Normal file
50
config/tinker.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Console Commands
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows you to add additional Artisan commands that should
|
||||||
|
| be available within the Tinker environment. Once the command is in
|
||||||
|
| this array you may execute the command in Tinker using its name.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'commands' => [
|
||||||
|
// App\Console\Commands\ExampleCommand::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Auto Aliased Classes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Tinker will not automatically alias classes in your vendor namespaces
|
||||||
|
| but you may explicitly allow a subset of classes to get aliased by
|
||||||
|
| adding the names of each of those classes to the following list.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'alias' => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Classes That Should Not Be Aliased
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Typically, Tinker automatically aliases classes as you require them in
|
||||||
|
| Tinker. However, you may wish to never alias certain classes, which
|
||||||
|
| you may accomplish by listing the classes in the following array.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'dont_alias' => [
|
||||||
|
'App\Nova',
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
5
lang/vendor/clamav-validator/en/validation.php
vendored
Normal file
5
lang/vendor/clamav-validator/en/validation.php
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'clamav' => ':attribute contains virus.',
|
||||||
|
];
|
||||||
172
resources/views/admin/workshop/edit.blade.php
Normal file
172
resources/views/admin/workshop/edit.blade.php
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
@php
|
||||||
|
$workshopContent = isset($workshop) ? $workshop->content : '';
|
||||||
|
@endphp
|
||||||
|
<x-layout>
|
||||||
|
<x-mast backRoute="admin.workshop.index" backTitle="Workshops">{{ isset($workshop) ? 'Edit' : 'Create' }} Workshop</x-mast>
|
||||||
|
|
||||||
|
<x-container class="mt-4">
|
||||||
|
<form x-data="{type:'physical',registration:'{{old('registration', $workshop->registration ?? 'none')}}'}" method="POST" action="{{ route('admin.workshop.' . (isset($workshop) ? 'update' : 'store'), $workshop ?? []) }}">
|
||||||
|
@isset($workshop)
|
||||||
|
@method('PUT')
|
||||||
|
@endisset
|
||||||
|
@csrf
|
||||||
|
<div class="mb-4">
|
||||||
|
<x-ui.input label="Title" name="title" value="{!! isset($workshop) ? $workshop->title : '' !!}" />
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<x-ui.media label="Image" name="hero_media_name" value="{{ $workshop->hero_media_name ?? '' }}" allow_uploads="true" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col sm:flex-row sm:gap-8">
|
||||||
|
<div class="flex-1">
|
||||||
|
<x-ui.select label="Type" name="type" x-model="type">
|
||||||
|
<option value="physical" {{ ($workshop->location_id ?? '') !== '' || !isset($workshop) ? 'selected' : '' }}>Physical</option>
|
||||||
|
<option value="online" {{ ($workshop->location_id ?? '') === null ? 'selected' : '' }}>Online</option>
|
||||||
|
</x-ui.select>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<span x-show="type==='physical'">
|
||||||
|
<x-ui.select label="Location" name="location_id">
|
||||||
|
@foreach(\App\Models\Location::orderByRaw("name = 'Online' DESC, name ASC")->get() as $location)
|
||||||
|
<option value="{{ $location->id }}" {{ ($workshop->location_id ?? '') === $location->id ? 'selected' : '' }}>{{ $location->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</x-ui.select>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col sm:flex-row sm:gap-8">
|
||||||
|
<div class="flex-1">
|
||||||
|
<x-ui.input type="datetime-local" label="Start Date" name="starts_at" value="{{ \App\Helpers::timestampNoSeconds($workshop->starts_at ?? '') }}" onchange="updatedStartsAt()"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<x-ui.input type="datetime-local" label="End Date" name="ends_at" value="{{ \App\Helpers::timestampNoSeconds($workshop->ends_at ?? '') }}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col sm:flex-row sm:gap-8">
|
||||||
|
<div class="flex-1">
|
||||||
|
<x-ui.select label="Status" name="status">
|
||||||
|
<option value="draft" {{ ($workshop->status ?? '') === 'draft' ? 'selected' : '' }}>Draft</option>
|
||||||
|
<option value="open" {{ ($workshop->status ?? '') === 'open' ? 'selected' : '' }}>Open</option>
|
||||||
|
<option value="private" {{ ($workshop->status ?? '') === 'private' ? 'selected' : '' }}>Private</option>
|
||||||
|
<option value="full" {{ ($workshop->status ?? '') === 'full' ? 'selected' : '' }}>Full</option>
|
||||||
|
<option value="scheduled" {{ ($workshop->status ?? '') === 'scheduled' ? 'selected' : '' }}>Scheduled</option>
|
||||||
|
<option value="closed" {{ ($workshop->status ?? '') === 'closed' ? 'selected' : '' }}>Closed</option>
|
||||||
|
<option value="cancelled" {{ ($workshop->status ?? '') === 'cancelled' ? 'selected' : '' }}>Cancelled</option>
|
||||||
|
</x-ui.select>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<x-ui.input type="datetime-local" label="Publish Date" name="publish_at" value="{{ \App\Helpers::timestampNoSeconds($workshop->publish_at ?? '') }}" onchange="updatedPublishAt()" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col sm:flex-row sm:gap-8">
|
||||||
|
<div class="hidden sm:block flex-1">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<x-ui.input type="datetime-local" label="Closes Date" name="closes_at" value="{{ \App\Helpers::timestampNoSeconds($workshop->closes_at ?? '') }}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col sm:flex-row sm:gap-8">
|
||||||
|
<div class="flex-1">
|
||||||
|
<x-ui.input label="Price" name="price" info="Leave blank to hide from public. Also supports Free, TBD or TBC" value="{{ $workshop->price ?? '' }}" />
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<x-ui.input label="Ages" name="ages" info="Leave blank to hide from public" value="{{ $workshop->ages ?? '8+' }}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col sm:flex-row sm:gap-8">
|
||||||
|
<div class="flex-1">
|
||||||
|
<x-ui.select label="Registration" name="registration" x-model="registration" onchange="document.getElementsByName('registration_data').forEach((e)=>e.value='')">
|
||||||
|
<option value="none" {{ (old('registration', $workshop->registration ?? '')) === 'none' ? 'selected' : '' }}>None</option>
|
||||||
|
<option value="link" {{ (old('registration', $workshop->registration ?? '')) === 'link' ? 'selected' : '' }}>External Link</option>
|
||||||
|
<option value="email" {{ (old('registration', $workshop->registration ?? '')) === 'email' ? 'selected' : '' }}>External Email</option>
|
||||||
|
<option value="message" {{ (old('registration', $workshop->registration ?? '')) === 'message' ? 'selected' : '' }}>Custom Message</option>
|
||||||
|
</x-ui.select>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<span x-show="registration==='link'">
|
||||||
|
<x-ui.input label="Registration URL" name="registration_url" id="registration_url" value="{!! isset($workshop) ? $workshop->registration_data : '' !!}" error="{{ $errors->first('registration_data') }}" />
|
||||||
|
</span>
|
||||||
|
<span x-show="registration==='email'">
|
||||||
|
<x-ui.input label="Registration Email" name="registration_email" id="registration_email" value="{{ $workshop->registration_data ?? '' }}" error="{{ $errors->first('registration_data') }}" />
|
||||||
|
</span>
|
||||||
|
<span x-show="registration==='message'">
|
||||||
|
<x-ui.input label="Registration Message" name="registration_message" id="registration_message" value="{{ $workshop->registration_data ?? '' }}" error="{{ $errors->first('registration_data') }}" />
|
||||||
|
</span>
|
||||||
|
<input type="hidden" name="registration_data" id="registration_data" value="{{ $workshop->registration_data ?? '' }}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<x-ui.editor
|
||||||
|
label="Content"
|
||||||
|
name="content"
|
||||||
|
value="{!! $workshopContent !!}"
|
||||||
|
></x-ui.editor>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<x-ui.filelist
|
||||||
|
label="Files"
|
||||||
|
name="files"
|
||||||
|
editor="true"
|
||||||
|
value="{!! isset($workshop) ? $workshop->files()->orderBy('name')->get() : '' !!}"
|
||||||
|
></x-ui.filelist>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end gap-4 mt-8">
|
||||||
|
@isset($workshop)
|
||||||
|
<x-ui.button type="button" color="danger" x-data x-on:click.prevent="SM.confirmDelete('{{ csrf_token() }}', 'Delete workshop?', 'Are you sure you want to delete this workshop? This action cannot be undone', '{{ route('admin.workshop.destroy', $workshop) }}')">Delete</x-ui.button>
|
||||||
|
@endisset
|
||||||
|
<x-ui.button type="submit">{{ isset($workshop) ? 'Save' : 'Create' }}</x-ui.button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</x-container>
|
||||||
|
</x-layout>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function updatedStartsAt() {
|
||||||
|
const startsAt = document.getElementsByName('starts_at')[0].value;
|
||||||
|
console.log(startsAt);
|
||||||
|
|
||||||
|
const elemEndsAt = document.getElementsByName('ends_at')[0];
|
||||||
|
if(elemEndsAt.value === '') {
|
||||||
|
let endsAt = new Date(startsAt);
|
||||||
|
endsAt.setHours(endsAt.getHours() + 1);
|
||||||
|
document.getElementsByName('ends_at')[0].value = SM.toLocalISOString(endsAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
let closesAt = new Date(startsAt);
|
||||||
|
closesAt.setHours(closesAt.getHours() - 2);
|
||||||
|
document.getElementsByName('closes_at')[0].value = SM.toLocalISOString(closesAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatedPublishAt() {
|
||||||
|
const publishAt = document.getElementsByName('publish_at')[0].value;
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
if (publishAt > now) {
|
||||||
|
document.getElementsByName('status')[0].value = 'scheduled';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const elementIds = ['registration_url', 'registration_email', 'registration_message'];
|
||||||
|
const registrationElem = document.getElementById('registration_data');
|
||||||
|
|
||||||
|
if(registrationElem) {
|
||||||
|
elementIds.forEach(id => {
|
||||||
|
const elem = document.getElementById(id);
|
||||||
|
if (elem) {
|
||||||
|
elem.addEventListener('change', function(event) {
|
||||||
|
registrationElem.value = event.target.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Initalize */
|
||||||
|
const elemPublishAt = document.getElementsByName('publish_at')[0];
|
||||||
|
if(elemPublishAt && elemPublishAt.value === '') {
|
||||||
|
let publishAt = new Date();
|
||||||
|
document.getElementsByName('publish_at')[0].value = SM.toLocalISOString(publishAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
55
resources/views/admin/workshop/index.blade.php
Normal file
55
resources/views/admin/workshop/index.blade.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<x-layout>
|
||||||
|
<x-mast>Workshops</x-mast>
|
||||||
|
|
||||||
|
<x-container>
|
||||||
|
<div class="flex my-4 items-center">
|
||||||
|
<div class="flex-1">
|
||||||
|
<x-ui.button type="link" href="{{ route('admin.workshop.create') }}">Create</x-ui.button>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<x-ui.search name="search" label="Search" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if($workshops->isEmpty())
|
||||||
|
<x-none-found item="workshops" search="{{ request()->get('search') }}" />
|
||||||
|
@else
|
||||||
|
<x-ui.table>
|
||||||
|
<x-slot:header>
|
||||||
|
<th>Title</th>
|
||||||
|
<th class="hidden lg:table-cell">Status</th>
|
||||||
|
<th class="hidden lg:table-cell">Location</th>
|
||||||
|
<th class="hidden md:table-cell">Starts</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</x-slot:header>
|
||||||
|
<x-slot:body>
|
||||||
|
@foreach ($workshops as $workshop)
|
||||||
|
<tr>
|
||||||
|
<td class="flex items-center">
|
||||||
|
<img src="{{ $workshop->hero->thumbnail }}" class="max-h-12 max-w-12 -ml-2 -my-3 mr-3 inline rounded" alt="{{ $workshop->hero->title }}" />
|
||||||
|
<div>
|
||||||
|
<div class="whitespace-normal">{{ $workshop->title }}</div>
|
||||||
|
<div class="lg:hidden text-xs text-gray-500">{{ $workshop->location->name }} ({{ ucwords($workshop->status) }})</div>
|
||||||
|
<div class="md:hidden text-xs text-gray-500">{{ \Carbon\Carbon::parse($workshop->starts_at)->format('j/m/Y g:i a') }}</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="hidden lg:table-cell">{{ ucwords($workshop->status) }}</td>
|
||||||
|
<td class="hidden lg:table-cell">{{ $workshop->location->name }}</td>
|
||||||
|
<td class="hidden md:table-cell">{{ \Carbon\Carbon::parse($workshop->starts_at)->format('M j Y, g:i a') }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="flex justify-center gap-3">
|
||||||
|
<a href="{{ route('admin.workshop.edit', $workshop) }}" class="hover:text-primary-color" title="Edit"><i class="fa-solid fa-pen-to-square"></i></a>
|
||||||
|
<a href="{{ route('admin.workshop.duplicate', $workshop) }}" class="hover:text-primary-color" title="Duplicate"><i class="fa-regular fa-copy"></i></a>
|
||||||
|
<a href="#" class="hover:text-red-600" x-data x-on:click.prevent="SM.confirmDelete('{{ csrf_token() }}', 'Delete workshop?', 'Are you sure you want to delete this workshop? This action cannot be undone', '{{ route('admin.workshop.destroy', $workshop) }}')" title="Delete"><i class="fa-solid fa-trash"></i></a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</x-slot:body>
|
||||||
|
</x-ui.table>
|
||||||
|
|
||||||
|
{{ $workshops->appends(request()->query())->links() }}
|
||||||
|
@endif
|
||||||
|
|
||||||
|
</x-container>
|
||||||
|
</x-layout>
|
||||||
45
resources/views/components/panel-workshop.blade.php
Normal file
45
resources/views/components/panel-workshop.blade.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
@props(['workshop'])
|
||||||
|
|
||||||
|
@php
|
||||||
|
$statusClass = $workshop->status;
|
||||||
|
$statusTitle = $workshop->status;
|
||||||
|
|
||||||
|
if($workshop->status === 'scheduled') {
|
||||||
|
$statusClass = 'soon';
|
||||||
|
$statusTitle = 'Open soon';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<a href="{{ route('workshop.show', $workshop) }}" class="flex flex-col bg-white border rounded-lg overflow-hidden hover:shadow-lg hover:scale-[101%] transition-all relative {{ $attributes->get('class') }}">
|
||||||
|
<div class="shadow border rounded px-3 py-2 absolute top-2 left-2 flex flex-col justify-center items-center bg-white">
|
||||||
|
<div class="text-gray-600 font-bold leading-none">{{ $workshop->starts_at->format('j') }}</div>
|
||||||
|
<div class="text-gray-600 text-xs uppercase">{{ $workshop->starts_at->format('M') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="border border-white border-opacity-50 absolute flex items-center justify-center top-5 -right-9 bg-gray-500 w-36 text-sm text-white font-bold uppercase py-1 rotate-45 h-8 sm-banner-{{ strtolower($statusClass) }}">{{ $statusTitle }}</div>
|
||||||
|
<img src="{{ $workshop->hero?->url }}?md" alt="{{ $workshop->title }}" class="w-full h-64 object-cover object-center">
|
||||||
|
<div class="flex-grow p-4 flex flex-col">
|
||||||
|
<h2 class="flex-grow {{ strlen($workshop->title) > 25 ? 'text-lg' : 'text-xl' }} font-bold mb-2">{{ $workshop->title }}</h2>
|
||||||
|
<div class="text-gray-600 text-sm mb-1 flex gap-2">
|
||||||
|
<div class="w-6 flex items-center justify-center">
|
||||||
|
<i class="fa-regular fa-calendar"></i>
|
||||||
|
</div>{{ $workshop->starts_at->format('j/m/Y @ g:i a') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-600 text-sm mb-1 flex gap-2">
|
||||||
|
<div class="w-6 flex items-center justify-center">
|
||||||
|
<i class="fa-solid fa-location-dot"></i>
|
||||||
|
</div>{{ $workshop->location->name }}
|
||||||
|
</div>
|
||||||
|
@if($workshop->ages)
|
||||||
|
<div class="text-gray-600 text-sm mb-1 flex gap-2">
|
||||||
|
<div class="w-6 flex items-center justify-center">
|
||||||
|
<i class="fa-regular fa-face-smile"></i>
|
||||||
|
</div>{{ isset($workshop->ages) && $workshop->ages !== '' ? 'Ages ' . $workshop->ages : 'All ages' }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<div class="text-gray-600 text-sm mb-1 flex gap-2">
|
||||||
|
<div class="w-6 flex items-center justify-center">
|
||||||
|
<i class="fa-solid fa-dollar-sign"></i>
|
||||||
|
</div>{{ isset($workshop->price) && $workshop->price !== '' && $workshop->price !== '0' ? $workshop->price : 'Free' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
5
resources/views/errors/401.blade.php
Normal file
5
resources/views/errors/401.blade.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@extends('errors::minimal')
|
||||||
|
|
||||||
|
@section('title', __('Unauthorized'))
|
||||||
|
@section('code', '401')
|
||||||
|
@section('message', __('Unauthorized'))
|
||||||
5
resources/views/errors/402.blade.php
Normal file
5
resources/views/errors/402.blade.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@extends('errors::minimal')
|
||||||
|
|
||||||
|
@section('title', __('Payment Required'))
|
||||||
|
@section('code', '402')
|
||||||
|
@section('message', __('Payment Required'))
|
||||||
5
resources/views/errors/419.blade.php
Normal file
5
resources/views/errors/419.blade.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@extends('errors::minimal')
|
||||||
|
|
||||||
|
@section('title', __('Page Expired'))
|
||||||
|
@section('code', '419')
|
||||||
|
@section('message', __('Page Expired'))
|
||||||
5
resources/views/errors/429.blade.php
Normal file
5
resources/views/errors/429.blade.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@extends('errors::minimal')
|
||||||
|
|
||||||
|
@section('title', __('Too Many Requests'))
|
||||||
|
@section('code', '429')
|
||||||
|
@section('message', __('Too Many Requests'))
|
||||||
5
resources/views/errors/500.blade.php
Normal file
5
resources/views/errors/500.blade.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@extends('errors::minimal')
|
||||||
|
|
||||||
|
@section('title', __('Server Error'))
|
||||||
|
@section('code', '500')
|
||||||
|
@section('message', __('Server Error'))
|
||||||
53
resources/views/errors/layout.blade.php
Normal file
53
resources/views/errors/layout.blade.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<title>@yield('title')</title>
|
||||||
|
|
||||||
|
<!-- Styles -->
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #636b6f;
|
||||||
|
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
font-weight: 100;
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-height {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-center {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.position-ref {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 36px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="flex-center position-ref full-height">
|
||||||
|
<div class="content">
|
||||||
|
<div class="title">
|
||||||
|
@yield('message')
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
34
resources/views/errors/minimal.blade.php
Normal file
34
resources/views/errors/minimal.blade.php
Normal file
File diff suppressed because one or more lines are too long
58
resources/views/vendor/notifications/email.blade.php
vendored
Normal file
58
resources/views/vendor/notifications/email.blade.php
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<x-mail::message>
|
||||||
|
{{-- Greeting --}}
|
||||||
|
@if (! empty($greeting))
|
||||||
|
# {{ $greeting }}
|
||||||
|
@else
|
||||||
|
@if ($level === 'error')
|
||||||
|
# @lang('Whoops!')
|
||||||
|
@else
|
||||||
|
# @lang('Hello!')
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
|
||||||
|
{{-- Intro Lines --}}
|
||||||
|
@foreach ($introLines as $line)
|
||||||
|
{{ $line }}
|
||||||
|
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
{{-- Action Button --}}
|
||||||
|
@isset($actionText)
|
||||||
|
<?php
|
||||||
|
$color = match ($level) {
|
||||||
|
'success', 'error' => $level,
|
||||||
|
default => 'primary',
|
||||||
|
};
|
||||||
|
?>
|
||||||
|
<x-mail::button :url="$actionUrl" :color="$color">
|
||||||
|
{{ $actionText }}
|
||||||
|
</x-mail::button>
|
||||||
|
@endisset
|
||||||
|
|
||||||
|
{{-- Outro Lines --}}
|
||||||
|
@foreach ($outroLines as $line)
|
||||||
|
{{ $line }}
|
||||||
|
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
{{-- Salutation --}}
|
||||||
|
@if (! empty($salutation))
|
||||||
|
{{ $salutation }}
|
||||||
|
@else
|
||||||
|
@lang('Regards'),<br>
|
||||||
|
{{ config('app.name') }}
|
||||||
|
@endif
|
||||||
|
|
||||||
|
{{-- Subcopy --}}
|
||||||
|
@isset($actionText)
|
||||||
|
<x-slot:subcopy>
|
||||||
|
@lang(
|
||||||
|
"If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\n".
|
||||||
|
'into your web browser:',
|
||||||
|
[
|
||||||
|
'actionText' => $actionText,
|
||||||
|
]
|
||||||
|
) <span class="break-all">[{{ $displayableActionUrl }}]({{ $actionUrl }})</span>
|
||||||
|
</x-slot:subcopy>
|
||||||
|
@endisset
|
||||||
|
</x-mail::message>
|
||||||
33
resources/views/workshop/index.blade.php
Normal file
33
resources/views/workshop/index.blade.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<x-layout>
|
||||||
|
<x-slot name="title">Workshops</x-slot>
|
||||||
|
<x-mast title="Workshops" :tabs="[
|
||||||
|
['title' => 'Upcoming', 'route' => route('workshop.index')],
|
||||||
|
['title' => 'Past', 'route' => route('workshop.past.index')],
|
||||||
|
]"/>
|
||||||
|
<section class="bg-gray-100">
|
||||||
|
<x-container class="my-4">
|
||||||
|
<x-ui.search class="md:hidden" name="search" label="Search" value="{{ request()->get('search') }}" />
|
||||||
|
<form class="hidden md:flex gap-4" method="GET" action="{{ request()->url() }}">
|
||||||
|
<x-ui.input no-label class="my-0 flex-1" type="text" name="search" label="Keywords" value="{{ request()->get('search') }}"/>
|
||||||
|
<x-ui.input no-label class="my-0 flex-1" type="text" name="location" label="Location" value="{{ request()->get('location') }}"/>
|
||||||
|
<x-ui.input no-label class="my-0 flex-1" type="text" name="date" label="Date Range" value="{{ request()->get('date') }}"/>
|
||||||
|
<x-ui.button type="submit"><i class="fa-solid fa-magnifying-glass"></i></x-ui.button>
|
||||||
|
</form>
|
||||||
|
</x-container>
|
||||||
|
|
||||||
|
@if($workshops->isEmpty())
|
||||||
|
<x-container class="mt-8">
|
||||||
|
<x-none-found item="workshops" search="{{ request()->get('search') }}" />
|
||||||
|
</x-container>
|
||||||
|
@else
|
||||||
|
<x-container class="mt-4" inner-class="grid md:grid-cols-2 lg:grid-cols-3 gap-8 w-full">
|
||||||
|
@foreach ($workshops as $workshop)
|
||||||
|
<x-panel-workshop :workshop="$workshop" />
|
||||||
|
@endforeach
|
||||||
|
</x-container>
|
||||||
|
<x-container>
|
||||||
|
{{ $workshops->appends(request()->query())->links() }}
|
||||||
|
</x-container>
|
||||||
|
@endif
|
||||||
|
</section>
|
||||||
|
</x-layout>
|
||||||
69
resources/views/workshop/show.blade.php
Normal file
69
resources/views/workshop/show.blade.php
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<x-layout>
|
||||||
|
<x-container>
|
||||||
|
<x-ui.image-hero :image="$workshop->hero?->url" class="my-8" />
|
||||||
|
<div class="flex sm:gap-16 gap-4 flex-col sm:flex-row">
|
||||||
|
<div class="flex flex-col flex-1">
|
||||||
|
<h1 class="text-3xl font-bold mb-6">{!! $workshop->title !!}</h1>
|
||||||
|
<article class="content mb-4">{!! $workshop->content !!}</article>
|
||||||
|
<x-ui.filelist class="mt-16" value="{!! $workshop->files()->orderBy('name')->get() !!}" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col sm:pt-8 basis-64 flex-grow-0 flex-shrink-0">
|
||||||
|
@if($workshop->status === 'closed')
|
||||||
|
<div class="sm-registration-closed">Registration for this event has closed.</div>
|
||||||
|
@elseif($workshop->status === 'full')
|
||||||
|
<div class="sm-registration-full">This workshop is currently full.</div>
|
||||||
|
@elseif($workshop->status === 'private')
|
||||||
|
<div class="sm-registration-private">This is a private event. Please contact the organiser for details.</div>
|
||||||
|
@if($workshop->registration === 'link')
|
||||||
|
<x-ui.button href="{!! $workshop->registration_data !!}" class="my-4">Register for Event</x-ui.button>
|
||||||
|
@elseif($workshop->registration === 'message')
|
||||||
|
<div class="sm-registration-message">{{ $workshop->registration_data }}</div>
|
||||||
|
@endif
|
||||||
|
@elseif($workshop->status === 'scheduled')
|
||||||
|
<div class="sm-registration-scheduled">Registration for this workshop will open soon.</div>
|
||||||
|
@elseif($workshop->status === 'cancelled')
|
||||||
|
<div class="sm-registration-cancelled">This workshop has been cancelled.</div>
|
||||||
|
@elseif($workshop->registration === 'none')
|
||||||
|
<div class="sm-registration-none">Registration not required for this event. Arrive early to avoid disappointment as seating maybe limited.</div>
|
||||||
|
@elseif($workshop->registration === 'link')
|
||||||
|
<x-ui.button href="{!! $workshop->registration_data !!}" class="my-4">Register for Event</x-ui.button>
|
||||||
|
@elseif($workshop->registration === 'email')
|
||||||
|
<div class="sm-registration-email">Registration for this event by emailing <a href="mailto:{{ $workshop->registration_data }}" class="link">{{ $workshop->registration_data }}</a>.</div>
|
||||||
|
@elseif($workshop->registration === 'message')
|
||||||
|
<div class="sm-registration-message">{{ $workshop->registration_data }}</div>
|
||||||
|
@endif
|
||||||
|
@if(auth()->user()?->admin)
|
||||||
|
<x-ui.button class="mb-4" color="primary-outline" href="{{ route('admin.workshop.edit', $workshop) }}">Edit Workshop</x-ui.button>
|
||||||
|
@endif
|
||||||
|
<h2 class="text-gray-600 text-lg font-bold mt-4 mb-2"><i class="mr-1 fa-regular fa-calendar"></i> Date/Time</h2>
|
||||||
|
<p class="text-gray-600 text-sm pl-6 mb-6">{!! implode('<br />', \App\Helpers::createTimeDurationStr($workshop->starts_at, $workshop->ends_at)) !!}</p>
|
||||||
|
<h2 class="text-gray-600 text-lg font-bold mb-2"><i class="mr-1 fa-solid fa-location-dot"></i> Location</h2>
|
||||||
|
<div class="text-gray-600 text-sm pl-6 mb-6">
|
||||||
|
@if($workshop->location->url)
|
||||||
|
<a href="{{ $workshop->location->url }}" class="link">
|
||||||
|
@endif
|
||||||
|
<p>{{ $workshop->location->name }}</p>
|
||||||
|
@if($workshop->location->url)
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($workshop->location->address_url)
|
||||||
|
<a href="{{ $workshop->location->address_url }}" class="link" target="_blank">
|
||||||
|
@endif
|
||||||
|
<p class="text-xs">{{ $workshop->location->address }}</p>
|
||||||
|
@if($workshop->location->address_url)
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<h2 class="text-gray-600 text-lg font-bold mb-2"><i class="mr-1 fa-regular fa-face-smile"></i> {{ isset($workshop->ages) && $workshop->ages !== '' ? 'Ages ' . $workshop->ages : 'All ages' }}</h2>
|
||||||
|
@if(\App\Helpers::isUnderAge($workshop->ages))
|
||||||
|
<p class="text-gray-600 text-xs pl-3 ml-2 mb-6 border-l-4 border-l-yellow-400">Parental supervision may be required for children 8 years of age and under.</p>
|
||||||
|
@endif
|
||||||
|
<h2 class="text-gray-600 text-lg font-bold mb-2"><i class="mr-1 fa-solid fa-dollar-sign"></i> {{ isset($workshop->price) && $workshop->price !== '' && $workshop->price !== '0' ? $workshop->price : 'Free' }}</h2>
|
||||||
|
{{-- @if(isset($workshop->price) && $workshop->price !== '' && $workshop->price !== '0' && strtolower($workshop->price) !== 'free')--}}
|
||||||
|
{{-- <p class="text-gray-600 text-xs pl-3 ml-2 mb-6 border-l-4 border-l-green-500">Payment by cash or EFTPOS accepted. Please ensure correct change.</p>--}}
|
||||||
|
{{-- @endif--}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-container>
|
||||||
|
</x-layout>
|
||||||
518
sail
Normal file
518
sail
Normal file
@@ -0,0 +1,518 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
UNAMEOUT="$(uname -s)"
|
||||||
|
|
||||||
|
# Verify operating system is supported...
|
||||||
|
case "${UNAMEOUT}" in
|
||||||
|
Linux*) MACHINE=linux;;
|
||||||
|
Darwin*) MACHINE=mac;;
|
||||||
|
*) MACHINE="UNKNOWN"
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$MACHINE" == "UNKNOWN" ]; then
|
||||||
|
echo "Unsupported operating system [$(uname -s)]. Laravel Sail supports macOS, Linux, and Windows (WSL2)." >&2
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine if stdout is a terminal...
|
||||||
|
if test -t 1; then
|
||||||
|
# Determine if colors are supported...
|
||||||
|
ncolors=$(tput colors)
|
||||||
|
|
||||||
|
if test -n "$ncolors" && test "$ncolors" -ge 8; then
|
||||||
|
BOLD="$(tput bold)"
|
||||||
|
YELLOW="$(tput setaf 3)"
|
||||||
|
GREEN="$(tput setaf 2)"
|
||||||
|
NC="$(tput sgr0)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Function that prints the available commands...
|
||||||
|
function display_help {
|
||||||
|
echo "Laravel Sail"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Usage:${NC}" >&2
|
||||||
|
echo " sail COMMAND [options] [arguments]"
|
||||||
|
echo
|
||||||
|
echo "Unknown commands are passed to the docker-compose binary."
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}docker-compose Commands:${NC}"
|
||||||
|
echo " ${GREEN}sail up${NC} Start the application"
|
||||||
|
echo " ${GREEN}sail up -d${NC} Start the application in the background"
|
||||||
|
echo " ${GREEN}sail stop${NC} Stop the application"
|
||||||
|
echo " ${GREEN}sail restart${NC} Restart the application"
|
||||||
|
echo " ${GREEN}sail ps${NC} Display the status of all containers"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Artisan Commands:${NC}"
|
||||||
|
echo " ${GREEN}sail artisan ...${NC} Run an Artisan command"
|
||||||
|
echo " ${GREEN}sail artisan queue:work${NC}"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}PHP Commands:${NC}"
|
||||||
|
echo " ${GREEN}sail php ...${NC} Run a snippet of PHP code"
|
||||||
|
echo " ${GREEN}sail php -v${NC}"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Composer Commands:${NC}"
|
||||||
|
echo " ${GREEN}sail composer ...${NC} Run a Composer command"
|
||||||
|
echo " ${GREEN}sail composer require laravel/sanctum${NC}"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Node Commands:${NC}"
|
||||||
|
echo " ${GREEN}sail node ...${NC} Run a Node command"
|
||||||
|
echo " ${GREEN}sail node --version${NC}"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}NPM Commands:${NC}"
|
||||||
|
echo " ${GREEN}sail npm ...${NC} Run a npm command"
|
||||||
|
echo " ${GREEN}sail npx${NC} Run a npx command"
|
||||||
|
echo " ${GREEN}sail npm run prod${NC}"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Yarn Commands:${NC}"
|
||||||
|
echo " ${GREEN}sail yarn ...${NC} Run a Yarn command"
|
||||||
|
echo " ${GREEN}sail yarn run prod${NC}"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Database Commands:${NC}"
|
||||||
|
echo " ${GREEN}sail mysql${NC} Start a MySQL CLI session within the 'mysql' container"
|
||||||
|
echo " ${GREEN}sail mariadb${NC} Start a MySQL CLI session within the 'mariadb' container"
|
||||||
|
echo " ${GREEN}sail psql${NC} Start a PostgreSQL CLI session within the 'pgsql' container"
|
||||||
|
echo " ${GREEN}sail redis${NC} Start a Redis CLI session within the 'redis' container"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Debugging:${NC}"
|
||||||
|
echo " ${GREEN}sail debug ...${NC} Run an Artisan command in debug mode"
|
||||||
|
echo " ${GREEN}sail debug queue:work${NC}"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Running Tests:${NC}"
|
||||||
|
echo " ${GREEN}sail test${NC} Run the PHPUnit tests via the Artisan test command"
|
||||||
|
echo " ${GREEN}sail phpunit ...${NC} Run PHPUnit"
|
||||||
|
echo " ${GREEN}sail pest ...${NC} Run Pest"
|
||||||
|
echo " ${GREEN}sail pint ...${NC} Run Pint"
|
||||||
|
echo " ${GREEN}sail dusk${NC} Run the Dusk tests (Requires the laravel/dusk package)"
|
||||||
|
echo " ${GREEN}sail dusk:fails${NC} Re-run previously failed Dusk tests (Requires the laravel/dusk package)"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Container CLI:${NC}"
|
||||||
|
echo " ${GREEN}sail shell${NC} Start a shell session within the application container"
|
||||||
|
echo " ${GREEN}sail bash${NC} Alias for 'sail shell'"
|
||||||
|
echo " ${GREEN}sail root-shell${NC} Start a root shell session within the application container"
|
||||||
|
echo " ${GREEN}sail root-bash${NC} Alias for 'sail root-shell'"
|
||||||
|
echo " ${GREEN}sail tinker${NC} Start a new Laravel Tinker session"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Sharing:${NC}"
|
||||||
|
echo " ${GREEN}sail share${NC} Share the application publicly via a temporary URL"
|
||||||
|
echo " ${GREEN}sail open${NC} Open the site in your browser"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Binaries:${NC}"
|
||||||
|
echo " ${GREEN}sail bin ...${NC} Run Composer binary scripts from the vendor/bin directory"
|
||||||
|
echo
|
||||||
|
echo "${YELLOW}Customization:${NC}"
|
||||||
|
echo " ${GREEN}sail artisan sail:publish${NC} Publish the Sail configuration files"
|
||||||
|
echo " ${GREEN}sail build --no-cache${NC} Rebuild all of the Sail containers"
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Proxy the "help" command...
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
if [ "$1" == "help" ] || [ "$1" == "-h" ] || [ "$1" == "-help" ] || [ "$1" == "--help" ]; then
|
||||||
|
display_help
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
display_help
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Source the ".env" file so Laravel's environment variables are available...
|
||||||
|
if [ ! -z "$APP_ENV" ] && [ -f ./.env.$APP_ENV ]; then
|
||||||
|
source ./.env.$APP_ENV;
|
||||||
|
elif [ -f ./.env ]; then
|
||||||
|
source ./.env;
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Define environment variables...
|
||||||
|
export APP_PORT=${APP_PORT:-80}
|
||||||
|
export APP_SERVICE=${APP_SERVICE:-"laravel.test"}
|
||||||
|
export DB_PORT=${DB_PORT:-3306}
|
||||||
|
export WWWUSER=${WWWUSER:-$UID}
|
||||||
|
export WWWGROUP=${WWWGROUP:-$(id -g)}
|
||||||
|
|
||||||
|
export SAIL_FILES=${SAIL_FILES:-""}
|
||||||
|
export SAIL_SHARE_DASHBOARD=${SAIL_SHARE_DASHBOARD:-4040}
|
||||||
|
export SAIL_SHARE_SERVER_HOST=${SAIL_SHARE_SERVER_HOST:-"laravel-sail.site"}
|
||||||
|
export SAIL_SHARE_SERVER_PORT=${SAIL_SHARE_SERVER_PORT:-8080}
|
||||||
|
export SAIL_SHARE_SUBDOMAIN=${SAIL_SHARE_SUBDOMAIN:-""}
|
||||||
|
export SAIL_SHARE_DOMAIN=${SAIL_SHARE_DOMAIN:-"$SAIL_SHARE_SERVER_HOST"}
|
||||||
|
export SAIL_SHARE_SERVER=${SAIL_SHARE_SERVER:-""}
|
||||||
|
|
||||||
|
# Function that outputs Sail is not running...
|
||||||
|
function sail_is_not_running {
|
||||||
|
echo "${BOLD}Sail is not running.${NC}" >&2
|
||||||
|
echo "" >&2
|
||||||
|
echo "${BOLD}You may Sail using the following commands:${NC} './vendor/bin/sail up' or './vendor/bin/sail up -d'" >&2
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Define Docker Compose command prefix...
|
||||||
|
docker compose &> /dev/null
|
||||||
|
if [ $? == 0 ]; then
|
||||||
|
DOCKER_COMPOSE=(docker compose)
|
||||||
|
else
|
||||||
|
DOCKER_COMPOSE=(docker-compose)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$SAIL_FILES" ]; then
|
||||||
|
# Convert SAIL_FILES to an array...
|
||||||
|
IFS=':' read -ra SAIL_FILES <<< "$SAIL_FILES"
|
||||||
|
|
||||||
|
for FILE in "${SAIL_FILES[@]}"; do
|
||||||
|
if [ -f "$FILE" ]; then
|
||||||
|
DOCKER_COMPOSE+=(-f "$FILE")
|
||||||
|
else
|
||||||
|
echo "${BOLD}Unable to find Docker Compose file: '${FILE}'${NC}" >&2
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
EXEC="yes"
|
||||||
|
|
||||||
|
if [ -z "$SAIL_SKIP_CHECKS" ]; then
|
||||||
|
# Ensure that Docker is running...
|
||||||
|
if ! docker info > /dev/null 2>&1; then
|
||||||
|
echo "${BOLD}Docker is not running.${NC}" >&2
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine if Sail is currently up...
|
||||||
|
if "${DOCKER_COMPOSE[@]}" ps "$APP_SERVICE" 2>&1 | grep 'Exit\|exited'; then
|
||||||
|
echo "${BOLD}Shutting down old Sail processes...${NC}" >&2
|
||||||
|
|
||||||
|
"${DOCKER_COMPOSE[@]}" down > /dev/null 2>&1
|
||||||
|
|
||||||
|
EXEC="no"
|
||||||
|
elif [ -z "$("${DOCKER_COMPOSE[@]}" ps -q)" ]; then
|
||||||
|
EXEC="no"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARGS=()
|
||||||
|
|
||||||
|
# Proxy PHP commands to the "php" binary on the application container...
|
||||||
|
if [ "$1" == "php" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" "php" "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy vendor binary commands on the application container...
|
||||||
|
elif [ "$1" == "bin" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" ./vendor/bin/"$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy docker-compose commands to the docker-compose binary on the application container...
|
||||||
|
elif [ "$1" == "docker-compose" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" "${DOCKER_COMPOSE[@]}")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy Composer commands to the "composer" binary on the application container...
|
||||||
|
elif [ "$1" == "composer" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" "composer" "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy Artisan commands to the "artisan" binary on the application container...
|
||||||
|
elif [ "$1" == "artisan" ] || [ "$1" == "art" ] || [ "$1" == "a" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" php artisan "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy the "debug" command to the "php artisan" binary on the application container with xdebug enabled...
|
||||||
|
elif [ "$1" == "debug" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail -e XDEBUG_SESSION=1)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" php artisan "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy the "test" command to the "php artisan test" Artisan command...
|
||||||
|
elif [ "$1" == "test" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" php artisan test "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy the "phpunit" command to "php vendor/bin/phpunit"...
|
||||||
|
elif [ "$1" == "phpunit" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" php vendor/bin/phpunit "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy the "pest" command to "php vendor/bin/pest"...
|
||||||
|
elif [ "$1" == "pest" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" php vendor/bin/pest "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy the "pint" command to "php vendor/bin/pint"...
|
||||||
|
elif [ "$1" == "pint" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" php vendor/bin/pint "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy the "dusk" command to the "php artisan dusk" Artisan command...
|
||||||
|
elif [ "$1" == "dusk" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=(-e "APP_URL=http://${APP_SERVICE}")
|
||||||
|
ARGS+=(-e "DUSK_DRIVER_URL=http://selenium:4444/wd/hub")
|
||||||
|
ARGS+=("$APP_SERVICE" php artisan dusk "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy the "dusk:fails" command to the "php artisan dusk:fails" Artisan command...
|
||||||
|
elif [ "$1" == "dusk:fails" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=(-e "APP_URL=http://${APP_SERVICE}")
|
||||||
|
ARGS+=(-e "DUSK_DRIVER_URL=http://selenium:4444/wd/hub")
|
||||||
|
ARGS+=("$APP_SERVICE" php artisan dusk:fails "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Initiate a Laravel Tinker session within the application container...
|
||||||
|
elif [ "$1" == "tinker" ] ; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" php artisan tinker)
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy Node commands to the "node" binary on the application container...
|
||||||
|
elif [ "$1" == "node" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" node "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy NPM commands to the "npm" binary on the application container...
|
||||||
|
elif [ "$1" == "npm" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" npm "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy NPX commands to the "npx" binary on the application container...
|
||||||
|
elif [ "$1" == "npx" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" npx "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Proxy YARN commands to the "yarn" binary on the application container...
|
||||||
|
elif [ "$1" == "yarn" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" yarn "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Initiate a MySQL CLI terminal session within the "mysql" container...
|
||||||
|
elif [ "$1" == "mysql" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=(mysql bash -c)
|
||||||
|
ARGS+=("MYSQL_PWD=\${MYSQL_PASSWORD} mysql -u \${MYSQL_USER} \${MYSQL_DATABASE}")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Initiate a MySQL CLI terminal session within the "mariadb" container...
|
||||||
|
elif [ "$1" == "mariadb" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=(mariadb bash -c)
|
||||||
|
ARGS+=("MYSQL_PWD=\${MYSQL_PASSWORD} mysql -u \${MYSQL_USER} \${MYSQL_DATABASE}")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Initiate a PostgreSQL CLI terminal session within the "pgsql" container...
|
||||||
|
elif [ "$1" == "psql" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=(pgsql bash -c)
|
||||||
|
ARGS+=("PGPASSWORD=\${PGPASSWORD} psql -U \${POSTGRES_USER} \${POSTGRES_DB}")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Initiate a Bash shell within the application container...
|
||||||
|
elif [ "$1" == "shell" ] || [ "$1" == "bash" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec -u sail)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" bash "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Initiate a root user Bash shell within the application container...
|
||||||
|
elif [ "$1" == "root-shell" ] || [ "$1" == "root-bash" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=("$APP_SERVICE" bash "$@")
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Initiate a Redis CLI terminal session within the "redis" container...
|
||||||
|
elif [ "$1" == "redis" ] ; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
ARGS+=(exec)
|
||||||
|
[ ! -t 0 ] && ARGS+=(-T)
|
||||||
|
ARGS+=(redis redis-cli)
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Share the site...
|
||||||
|
elif [ "$1" == "share" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
docker run --init --rm -p "$SAIL_SHARE_DASHBOARD":4040 -t beyondcodegmbh/expose-server:latest share http://host.docker.internal:"$APP_PORT" \
|
||||||
|
--server-host="$SAIL_SHARE_SERVER_HOST" \
|
||||||
|
--server-port="$SAIL_SHARE_SERVER_PORT" \
|
||||||
|
--auth="$SAIL_SHARE_TOKEN" \
|
||||||
|
--server="$SAIL_SHARE_SERVER" \
|
||||||
|
--subdomain="$SAIL_SHARE_SUBDOMAIN" \
|
||||||
|
--domain="$SAIL_SHARE_DOMAIN" \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
exit
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Open the site...
|
||||||
|
elif [ "$1" == "open" ]; then
|
||||||
|
shift 1
|
||||||
|
|
||||||
|
if [ "$EXEC" == "yes" ]; then
|
||||||
|
open $APP_URL
|
||||||
|
|
||||||
|
exit
|
||||||
|
else
|
||||||
|
sail_is_not_running
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Pass unknown commands to the "docker-compose" binary...
|
||||||
|
else
|
||||||
|
ARGS+=("$@")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run Docker Compose with the defined arguments...
|
||||||
|
"${DOCKER_COMPOSE[@]}" "${ARGS[@]}"
|
||||||
Reference in New Issue
Block a user