commit
7ffebd71f3
@ -4,3 +4,7 @@ APP_KEY=
|
|||||||
|
|
||||||
DB_PASSWORD=
|
DB_PASSWORD=
|
||||||
REDIS_PASSWORD=
|
REDIS_PASSWORD=
|
||||||
|
|
||||||
|
PUSHER_APP_ID=
|
||||||
|
PUSHER_APP_KEY=
|
||||||
|
PUSHER_APP_SECRET=
|
||||||
|
28
app/Events/TestEvent.php
Normal file
28
app/Events/TestEvent.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use Illuminate\Broadcasting\Channel;
|
||||||
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||||
|
use Illuminate\Broadcasting\PresenceChannel;
|
||||||
|
use Illuminate\Broadcasting\PrivateChannel;
|
||||||
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class TestEvent implements ShouldBroadcast
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
public $teamId;
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->teamId = auth()->user()->currentTeam()->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function broadcastOn(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new PrivateChannel("custom.{$this->teamId}"),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,6 @@ class Dashboard extends Component
|
|||||||
{
|
{
|
||||||
public $projects = [];
|
public $projects = [];
|
||||||
public $servers = [];
|
public $servers = [];
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->servers = Server::ownedByCurrentTeam()->get();
|
$this->servers = Server::ownedByCurrentTeam()->get();
|
||||||
|
29
app/Http/Livewire/Modal/EditCompose.php
Normal file
29
app/Http/Livewire/Modal/EditCompose.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Modal;
|
||||||
|
|
||||||
|
use App\Models\Service;
|
||||||
|
use Livewire\Component;
|
||||||
|
use LivewireUI\Modal\ModalComponent;
|
||||||
|
|
||||||
|
class EditCompose extends ModalComponent
|
||||||
|
{
|
||||||
|
public Service $service;
|
||||||
|
public $serviceId;
|
||||||
|
protected $rules = [
|
||||||
|
'service.docker_compose_raw' => 'required',
|
||||||
|
'service.docker_compose' => 'required',
|
||||||
|
];
|
||||||
|
public function mount() {
|
||||||
|
$this->service = Service::find($this->serviceId);
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.modal.edit-compose');
|
||||||
|
}
|
||||||
|
public function submit() {
|
||||||
|
$this->emit('warning', "Saving new docker compose...");
|
||||||
|
$this->emit('saveCompose', $this->service->docker_compose_raw);
|
||||||
|
$this->closeModal();
|
||||||
|
}
|
||||||
|
}
|
110
app/Http/Livewire/Project/Application/Command.php
Normal file
110
app/Http/Livewire/Project/Application/Command.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Project\Application;
|
||||||
|
|
||||||
|
use App\Models\Application;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\Service;
|
||||||
|
use App\Models\StandaloneMariadb;
|
||||||
|
use App\Models\StandaloneMongodb;
|
||||||
|
use App\Models\StandaloneMysql;
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
|
use App\Models\StandaloneRedis;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Command extends Component
|
||||||
|
{
|
||||||
|
public string $command;
|
||||||
|
public string $container;
|
||||||
|
public $containers;
|
||||||
|
public $parameters;
|
||||||
|
public $resource;
|
||||||
|
public string $type;
|
||||||
|
public string $workDir = '';
|
||||||
|
public Server $server;
|
||||||
|
public $servers = [];
|
||||||
|
|
||||||
|
protected $rules = [
|
||||||
|
'server' => 'required',
|
||||||
|
'container' => 'required',
|
||||||
|
'command' => 'required',
|
||||||
|
'workDir' => 'nullable',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->containers = collect();
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
if (data_get($this->parameters, 'application_uuid')) {
|
||||||
|
$this->type = 'application';
|
||||||
|
$this->resource = Application::where('uuid', $this->parameters['application_uuid'])->firstOrFail();
|
||||||
|
$this->server = $this->resource->destination->server;
|
||||||
|
$containers = getCurrentApplicationContainerStatus($this->server, $this->resource->id, 0);
|
||||||
|
if ($containers->count() > 0) {
|
||||||
|
$containers->each(function ($container) {
|
||||||
|
$this->containers->push(str_replace('/', '', $container['Names']));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (data_get($this->parameters, 'database_uuid')) {
|
||||||
|
$this->type = 'database';
|
||||||
|
$resource = StandalonePostgresql::where('uuid', $this->parameters['database_uuid'])->first();
|
||||||
|
if (is_null($resource)) {
|
||||||
|
$resource = StandaloneRedis::where('uuid', $this->parameters['database_uuid'])->first();
|
||||||
|
if (is_null($resource)) {
|
||||||
|
$resource = StandaloneMongodb::where('uuid', $this->parameters['database_uuid'])->first();
|
||||||
|
if (is_null($resource)) {
|
||||||
|
$resource = StandaloneMysql::where('uuid', $this->parameters['database_uuid'])->first();
|
||||||
|
if (is_null($resource)) {
|
||||||
|
$resource = StandaloneMariadb::where('uuid', $this->parameters['database_uuid'])->first();
|
||||||
|
if (is_null($resource)) {
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->resource = $resource;
|
||||||
|
$this->server = $this->resource->destination->server;
|
||||||
|
$this->container = $this->resource->uuid;
|
||||||
|
$this->containers->push($this->container);
|
||||||
|
} else if (data_get($this->parameters, 'service_uuid')) {
|
||||||
|
$this->type = 'service';
|
||||||
|
$this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
|
||||||
|
$this->resource->applications()->get()->each(function ($application) {
|
||||||
|
if (str(data_get($application, 'status'))->contains('running')) {
|
||||||
|
$this->containers->push(data_get($application, 'name') . '-' . data_get($this->resource, 'uuid'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$this->resource->databases()->get()->each(function ($database) {
|
||||||
|
if (str(data_get($database, 'status'))->contains('running')) {
|
||||||
|
$this->containers->push(data_get($database, 'name') . '-' . data_get($this->resource, 'uuid'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->server = $this->resource->server;
|
||||||
|
}
|
||||||
|
if ($this->containers->count() > 1) {
|
||||||
|
$this->container = $this->containers->first();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function runCommand()
|
||||||
|
{
|
||||||
|
$this->validate();
|
||||||
|
try {
|
||||||
|
if (!empty($this->workDir)) {
|
||||||
|
$exec = "docker exec -w {$this->workDir} {$this->container} {$this->command}";
|
||||||
|
} else {
|
||||||
|
$exec = "docker exec {$this->container} {$this->command}";
|
||||||
|
}
|
||||||
|
$activity = remote_process([$exec], $this->server, ignore_errors: true);
|
||||||
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.project.shared.execute-container-command');
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,7 @@ public function mount()
|
|||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
$this->application = $application;
|
$this->application = $application;
|
||||||
$mainServer = $application->destination->server;
|
$mainServer = $this->application->destination->server;
|
||||||
$servers = Server::ownedByCurrentTeam()->get();
|
$servers = Server::ownedByCurrentTeam()->get();
|
||||||
$this->servers = $servers->filter(function ($server) use ($mainServer) {
|
$this->servers = $servers->filter(function ($server) use ($mainServer) {
|
||||||
return $server->id != $mainServer->id;
|
return $server->id != $mainServer->id;
|
||||||
|
@ -18,7 +18,6 @@ class DeploymentNavbar extends Component
|
|||||||
public Server $server;
|
public Server $server;
|
||||||
public bool $is_debug_enabled = false;
|
public bool $is_debug_enabled = false;
|
||||||
protected $listeners = ['deploymentFinished'];
|
protected $listeners = ['deploymentFinished'];
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->application = Application::find($this->application_deployment_queue->application_id);
|
$this->application = Application::find($this->application_deployment_queue->application_id);
|
||||||
|
@ -29,8 +29,6 @@ class General extends Component
|
|||||||
public ?string $initialDockerComposeLocation = null;
|
public ?string $initialDockerComposeLocation = null;
|
||||||
public ?string $initialDockerComposePrLocation = null;
|
public ?string $initialDockerComposePrLocation = null;
|
||||||
|
|
||||||
public bool $is_static;
|
|
||||||
|
|
||||||
public $parsedServices = [];
|
public $parsedServices = [];
|
||||||
public $parsedServiceDomains = [];
|
public $parsedServiceDomains = [];
|
||||||
|
|
||||||
@ -124,6 +122,10 @@ public function instantSave()
|
|||||||
{
|
{
|
||||||
$this->application->settings->save();
|
$this->application->settings->save();
|
||||||
$this->emit('success', 'Settings saved.');
|
$this->emit('success', 'Settings saved.');
|
||||||
|
$this->application->refresh();
|
||||||
|
if ($this->ports_exposes !== $this->application->ports_exposes) {
|
||||||
|
$this->resetDefaultLabels(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public function loadComposeFile($isInit = false)
|
public function loadComposeFile($isInit = false)
|
||||||
{
|
{
|
||||||
@ -156,7 +158,7 @@ public function generateDomain(string $serviceName)
|
|||||||
public function updatedApplicationBuildPack()
|
public function updatedApplicationBuildPack()
|
||||||
{
|
{
|
||||||
if ($this->application->build_pack !== 'nixpacks') {
|
if ($this->application->build_pack !== 'nixpacks') {
|
||||||
$this->application->settings->is_static = $this->is_static = false;
|
$this->application->settings->is_static = false;
|
||||||
$this->application->settings->save();
|
$this->application->settings->save();
|
||||||
}
|
}
|
||||||
if ($this->application->build_pack === 'dockercompose') {
|
if ($this->application->build_pack === 'dockercompose') {
|
||||||
|
@ -39,6 +39,26 @@ public function force_deploy_without_cache()
|
|||||||
$this->deploy(force_rebuild: true);
|
$this->deploy(force_rebuild: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deployNew()
|
||||||
|
{
|
||||||
|
if ($this->application->build_pack === 'dockercompose' && is_null($this->application->docker_compose_raw)) {
|
||||||
|
$this->emit('error', 'Please load a Compose file first.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->setDeploymentUuid();
|
||||||
|
queue_application_deployment(
|
||||||
|
application_id: $this->application->id,
|
||||||
|
deployment_uuid: $this->deploymentUuid,
|
||||||
|
force_rebuild: false,
|
||||||
|
is_new_deployment: true,
|
||||||
|
);
|
||||||
|
return redirect()->route('project.application.deployment', [
|
||||||
|
'project_uuid' => $this->parameters['project_uuid'],
|
||||||
|
'application_uuid' => $this->parameters['application_uuid'],
|
||||||
|
'deployment_uuid' => $this->deploymentUuid,
|
||||||
|
'environment_name' => $this->parameters['environment_name'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
public function deploy(bool $force_rebuild = false)
|
public function deploy(bool $force_rebuild = false)
|
||||||
{
|
{
|
||||||
if ($this->application->build_pack === 'dockercompose' && is_null($this->application->docker_compose_raw)) {
|
if ($this->application->build_pack === 'dockercompose' && is_null($this->application->docker_compose_raw)) {
|
||||||
@ -72,6 +92,22 @@ public function stop()
|
|||||||
$this->application->save();
|
$this->application->save();
|
||||||
$this->application->refresh();
|
$this->application->refresh();
|
||||||
}
|
}
|
||||||
|
public function restartNew()
|
||||||
|
{
|
||||||
|
$this->setDeploymentUuid();
|
||||||
|
queue_application_deployment(
|
||||||
|
application_id: $this->application->id,
|
||||||
|
deployment_uuid: $this->deploymentUuid,
|
||||||
|
restart_only: true,
|
||||||
|
is_new_deployment: true,
|
||||||
|
);
|
||||||
|
return redirect()->route('project.application.deployment', [
|
||||||
|
'project_uuid' => $this->parameters['project_uuid'],
|
||||||
|
'application_uuid' => $this->parameters['application_uuid'],
|
||||||
|
'deployment_uuid' => $this->deploymentUuid,
|
||||||
|
'environment_name' => $this->parameters['environment_name'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
public function restart()
|
public function restart()
|
||||||
{
|
{
|
||||||
$this->setDeploymentUuid();
|
$this->setDeploymentUuid();
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Service;
|
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class ComposeModal extends Component
|
|
||||||
{
|
|
||||||
public ?string $raw = null;
|
|
||||||
public ?string $actual = null;
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
return view('livewire.project.service.compose-modal');
|
|
||||||
}
|
|
||||||
public function submit() {
|
|
||||||
$this->emit('warning', "Saving new docker compose...");
|
|
||||||
$this->emit('saveCompose', $this->raw);
|
|
||||||
}
|
|
||||||
}
|
|
110
app/Http/Livewire/Project/Shared/ExecuteContainerCommand.php
Normal file
110
app/Http/Livewire/Project/Shared/ExecuteContainerCommand.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Project\Shared;
|
||||||
|
|
||||||
|
use App\Models\Application;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\Service;
|
||||||
|
use App\Models\StandaloneMariadb;
|
||||||
|
use App\Models\StandaloneMongodb;
|
||||||
|
use App\Models\StandaloneMysql;
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
|
use App\Models\StandaloneRedis;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class ExecuteContainerCommand extends Component
|
||||||
|
{
|
||||||
|
public string $command;
|
||||||
|
public string $container;
|
||||||
|
public $containers;
|
||||||
|
public $parameters;
|
||||||
|
public $resource;
|
||||||
|
public string $type;
|
||||||
|
public string $workDir = '';
|
||||||
|
public Server $server;
|
||||||
|
public $servers = [];
|
||||||
|
|
||||||
|
protected $rules = [
|
||||||
|
'server' => 'required',
|
||||||
|
'container' => 'required',
|
||||||
|
'command' => 'required',
|
||||||
|
'workDir' => 'nullable',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->containers = collect();
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
if (data_get($this->parameters, 'application_uuid')) {
|
||||||
|
$this->type = 'application';
|
||||||
|
$this->resource = Application::where('uuid', $this->parameters['application_uuid'])->firstOrFail();
|
||||||
|
$this->server = $this->resource->destination->server;
|
||||||
|
$containers = getCurrentApplicationContainerStatus($this->server, $this->resource->id, 0);
|
||||||
|
if ($containers->count() > 0) {
|
||||||
|
$containers->each(function ($container) {
|
||||||
|
$this->containers->push(str_replace('/', '', $container['Names']));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (data_get($this->parameters, 'database_uuid')) {
|
||||||
|
$this->type = 'database';
|
||||||
|
$resource = StandalonePostgresql::where('uuid', $this->parameters['database_uuid'])->first();
|
||||||
|
if (is_null($resource)) {
|
||||||
|
$resource = StandaloneRedis::where('uuid', $this->parameters['database_uuid'])->first();
|
||||||
|
if (is_null($resource)) {
|
||||||
|
$resource = StandaloneMongodb::where('uuid', $this->parameters['database_uuid'])->first();
|
||||||
|
if (is_null($resource)) {
|
||||||
|
$resource = StandaloneMysql::where('uuid', $this->parameters['database_uuid'])->first();
|
||||||
|
if (is_null($resource)) {
|
||||||
|
$resource = StandaloneMariadb::where('uuid', $this->parameters['database_uuid'])->first();
|
||||||
|
if (is_null($resource)) {
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->resource = $resource;
|
||||||
|
$this->server = $this->resource->destination->server;
|
||||||
|
$this->container = $this->resource->uuid;
|
||||||
|
$this->containers->push($this->container);
|
||||||
|
} else if (data_get($this->parameters, 'service_uuid')) {
|
||||||
|
$this->type = 'service';
|
||||||
|
$this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
|
||||||
|
$this->resource->applications()->get()->each(function ($application) {
|
||||||
|
if (str(data_get($application, 'status'))->contains('running')) {
|
||||||
|
$this->containers->push(data_get($application, 'name') . '-' . data_get($this->resource, 'uuid'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$this->resource->databases()->get()->each(function ($database) {
|
||||||
|
if (str(data_get($database, 'status'))->contains('running')) {
|
||||||
|
$this->containers->push(data_get($database, 'name') . '-' . data_get($this->resource, 'uuid'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->server = $this->resource->server;
|
||||||
|
}
|
||||||
|
if ($this->containers->count() > 0) {
|
||||||
|
$this->container = $this->containers->first();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function runCommand()
|
||||||
|
{
|
||||||
|
$this->validate();
|
||||||
|
try {
|
||||||
|
if (!empty($this->workDir)) {
|
||||||
|
$exec = "docker exec -w {$this->workDir} {$this->container} {$this->command}";
|
||||||
|
} else {
|
||||||
|
$exec = "docker exec {$this->container} {$this->command}";
|
||||||
|
}
|
||||||
|
$activity = remote_process([$exec], $this->server, ignore_errors: true);
|
||||||
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.project.shared.execute-container-command');
|
||||||
|
}
|
||||||
|
}
|
@ -44,6 +44,7 @@ public function mount()
|
|||||||
{
|
{
|
||||||
$this->wildcard_domain = $this->server->settings->wildcard_domain;
|
$this->wildcard_domain = $this->server->settings->wildcard_domain;
|
||||||
$this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage;
|
$this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage;
|
||||||
|
$this->validateServer();
|
||||||
}
|
}
|
||||||
public function serverRefresh($install = true)
|
public function serverRefresh($install = true)
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,17 @@
|
|||||||
|
|
||||||
class Sponsorship extends Component
|
class Sponsorship extends Component
|
||||||
{
|
{
|
||||||
|
public function getListeners()
|
||||||
|
{
|
||||||
|
$teamId = auth()->user()->currentTeam()->id;
|
||||||
|
return [
|
||||||
|
"echo-private:custom.{$teamId},TestEvent" => 'testEvent',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
public function testEvent()
|
||||||
|
{
|
||||||
|
$this->emit('success', 'Realtime events configured!');
|
||||||
|
}
|
||||||
public function disable()
|
public function disable()
|
||||||
{
|
{
|
||||||
auth()->user()->update(['is_notification_sponsorship_enabled' => false]);
|
auth()->user()->update(['is_notification_sponsorship_enabled' => false]);
|
||||||
|
@ -1094,6 +1094,9 @@ private function generate_healthcheck_commands()
|
|||||||
} else {
|
} else {
|
||||||
$health_check_port = $this->application->health_check_port;
|
$health_check_port = $this->application->health_check_port;
|
||||||
}
|
}
|
||||||
|
if ($this->application->settings->is_static || $this->application->build_pack === 'static') {
|
||||||
|
$health_check_port = 80;
|
||||||
|
}
|
||||||
if ($this->application->health_check_path) {
|
if ($this->application->health_check_path) {
|
||||||
$this->full_healthcheck_url = "{$this->application->health_check_method}: {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path}";
|
$this->full_healthcheck_url = "{$this->application->health_check_method}: {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path}";
|
||||||
$generated_healthchecks_commands = [
|
$generated_healthchecks_commands = [
|
||||||
@ -1248,11 +1251,17 @@ private function start_by_compose_file()
|
|||||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} pull"), "hidden" => true],
|
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} pull"), "hidden" => true],
|
||||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
|
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
if ($this->docker_compose_location) {
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up --build -d"), "hidden" => true],
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
|
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$this->application_deployment_queue->addLogEntry("New container started.");
|
$this->application_deployment_queue->addLogEntry("New container started.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
180
app/Jobs/ApplicationDeploymentNewJob.php
Normal file
180
app/Jobs/ApplicationDeploymentNewJob.php
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Enums\ApplicationDeploymentStatus;
|
||||||
|
use App\Models\Application;
|
||||||
|
use App\Models\ApplicationDeploymentQueue;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Traits\ExecuteRemoteCommand;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use RuntimeException;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class ApplicationDeploymentNewJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, ExecuteRemoteCommand;
|
||||||
|
|
||||||
|
public $timeout = 3600;
|
||||||
|
public $tries = 1;
|
||||||
|
|
||||||
|
public static int $batch_counter = 0;
|
||||||
|
public Server $mainServer;
|
||||||
|
public $servers;
|
||||||
|
public string $basedir;
|
||||||
|
public string $workdir;
|
||||||
|
|
||||||
|
public string $deploymentUuid;
|
||||||
|
public int $pullRequestId = 0;
|
||||||
|
|
||||||
|
// Git related
|
||||||
|
public string $gitImportCommands;
|
||||||
|
public ?string $gitType = null;
|
||||||
|
public string $gitRepository;
|
||||||
|
public string $gitBranch;
|
||||||
|
public int $gitPort;
|
||||||
|
public string $gitFullRepoUrl;
|
||||||
|
|
||||||
|
public function __construct(public ApplicationDeploymentQueue $deployment, public Application $application)
|
||||||
|
{
|
||||||
|
$this->mainServer = data_get($this->application, 'destination.server');
|
||||||
|
$this->deploymentUuid = data_get($this->deployment, 'deployment_uuid');
|
||||||
|
$this->pullRequestId = data_get($this->deployment, 'pull_request_id', 0);
|
||||||
|
$this->gitType = data_get($this->deployment, 'git_type');
|
||||||
|
|
||||||
|
$this->basedir = $this->application->generateBaseDir($this->deploymentUuid);
|
||||||
|
$this->workdir = $this->basedir . rtrim($this->application->base_directory, '/');
|
||||||
|
}
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ray()->clearAll();
|
||||||
|
$this->deployment->setStatus(ApplicationDeploymentStatus::IN_PROGRESS->value);
|
||||||
|
|
||||||
|
$hostIpMappings = $this->mainServer->getHostIPMappings($this->application->destination->network);
|
||||||
|
if ($this->application->dockerfile_target_build) {
|
||||||
|
$buildTarget = " --target {$this->application->dockerfile_target_build} ";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the git repository and port (custom port or default port)
|
||||||
|
[
|
||||||
|
'repository' => $this->gitRepository,
|
||||||
|
'port' => $this->gitPort
|
||||||
|
] = $this->application->customRepository();
|
||||||
|
|
||||||
|
// Get the git branch and git import commands
|
||||||
|
[
|
||||||
|
'commands' => $this->gitImportCommands,
|
||||||
|
'branch' => $this->gitBranch,
|
||||||
|
'fullRepoUrl' => $this->gitFullRepoUrl
|
||||||
|
] = $this->application->generateGitImportCommands($this->deploymentUuid, $this->pullRequestId, $this->gitType);
|
||||||
|
|
||||||
|
$this->servers = $this->application->servers();
|
||||||
|
|
||||||
|
if ($this->deployment->restart_only) {
|
||||||
|
if ($this->application->build_pack === 'dockerimage') {
|
||||||
|
throw new \Exception('Restart only is not supported for docker image based deployments');
|
||||||
|
}
|
||||||
|
$this->deployment->addLogEntry("Starting deployment of {$this->application->name}.");
|
||||||
|
$this->servers->each(function ($server) {
|
||||||
|
$this->deployment->addLogEntry("Restarting {$this->application->name} on {$server->name}.");
|
||||||
|
$this->restartOnly($server);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$this->next(ApplicationDeploymentStatus::FINISHED->value);
|
||||||
|
} catch (Throwable $exception) {
|
||||||
|
$this->fail($exception);
|
||||||
|
} finally {
|
||||||
|
$this->servers->each(function ($server) {
|
||||||
|
$this->deployment->addLogEntry("Cleaning up temporary containers on {$server->name}.");
|
||||||
|
$server->executeRemoteCommand(
|
||||||
|
commands: collect([])->push([
|
||||||
|
"command" => "docker rm -f {$this->deploymentUuid}",
|
||||||
|
"hidden" => true,
|
||||||
|
"ignoreErrors" => true,
|
||||||
|
]),
|
||||||
|
loggingModel: $this->deployment
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function restartOnly(Server $server)
|
||||||
|
{
|
||||||
|
$server->executeRemoteCommand(
|
||||||
|
commands: $this->application->prepareHelperImage($this->deploymentUuid),
|
||||||
|
loggingModel: $this->deployment
|
||||||
|
);
|
||||||
|
|
||||||
|
$privateKey = data_get($this->application, 'private_key.private_key', null);
|
||||||
|
$gitLsRemoteCommand = collect([]);
|
||||||
|
if ($privateKey) {
|
||||||
|
$privateKey = base64_decode($privateKey);
|
||||||
|
$gitLsRemoteCommand
|
||||||
|
->push([
|
||||||
|
"command" => executeInDocker($this->deploymentUuid, "mkdir -p /root/.ssh")
|
||||||
|
])
|
||||||
|
->push([
|
||||||
|
"command" => executeInDocker($this->deploymentUuid, "echo '{$privateKey}' | base64 -d > /root/.ssh/id_rsa")
|
||||||
|
])
|
||||||
|
->push([
|
||||||
|
"command" => executeInDocker($this->deploymentUuid, "chmod 600 /root/.ssh/id_rsa")
|
||||||
|
])
|
||||||
|
->push([
|
||||||
|
"name" => "git_commit_sha",
|
||||||
|
"command" => executeInDocker($this->deploymentUuid, "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->gitPort} -o Port={$this->gitPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git ls-remote {$this->gitFullRepoUrl} {$this->gitBranch}"),
|
||||||
|
"hidden" => true,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$gitLsRemoteCommand->push([
|
||||||
|
"name" => "git_commit_sha",
|
||||||
|
"command" => executeInDocker($this->deploymentUuid, "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->gitPort} -o Port={$this->gitPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git ls-remote {$this->gitFullRepoUrl} {$this->gitBranch}"),
|
||||||
|
"hidden" => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$this->deployment->addLogEntry("Checking if there is any new commit on {$this->gitBranch} branch.");
|
||||||
|
|
||||||
|
$server->executeRemoteCommand(
|
||||||
|
commands: $gitLsRemoteCommand,
|
||||||
|
loggingModel: $this->deployment
|
||||||
|
);
|
||||||
|
$commit = str($this->deployment->getOutput('git_commit_sha'))->before("\t");
|
||||||
|
|
||||||
|
[
|
||||||
|
'productionImageName' => $productionImageName
|
||||||
|
] = $this->application->generateImageNames($commit, $this->pullRequestId);
|
||||||
|
|
||||||
|
$this->deployment->addLogEntry("Checking if the image {$productionImageName} already exists.");
|
||||||
|
$server->checkIfDockerImageExists($productionImageName, $this->deployment);
|
||||||
|
|
||||||
|
if (str($this->deployment->getOutput('local_image_found'))->isNotEmpty()) {
|
||||||
|
$this->deployment->addLogEntry("Image {$productionImageName} already exists. Skipping the build.");
|
||||||
|
|
||||||
|
$server->createWorkDirForDeployment($this->workdir, $this->deployment);
|
||||||
|
|
||||||
|
$this->application->generateDockerComposeFile($server, $this->deployment, $this->workdir);
|
||||||
|
$this->application->rollingUpdateApplication($server, $this->deployment, $this->workdir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new RuntimeException('Cannot find image anywhere. Please redeploy the application.');
|
||||||
|
}
|
||||||
|
public function failed(Throwable $exception): void
|
||||||
|
{
|
||||||
|
ray($exception);
|
||||||
|
$this->next(ApplicationDeploymentStatus::FAILED->value);
|
||||||
|
}
|
||||||
|
private function next(string $status)
|
||||||
|
{
|
||||||
|
// If the deployment is cancelled by the user, don't update the status
|
||||||
|
if ($this->deployment->status !== ApplicationDeploymentStatus::CANCELLED_BY_USER->value) {
|
||||||
|
$this->deployment->update([
|
||||||
|
'status' => $status,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
queue_next_deployment($this->application, isNew: true);
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Spatie\Activitylog\Models\Activity;
|
use Spatie\Activitylog\Models\Activity;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
@ -48,6 +49,65 @@ protected static function booted()
|
|||||||
$application->environment_variables_preview()->delete();
|
$application->environment_variables_preview()->delete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Build packs / deployment types
|
||||||
|
|
||||||
|
|
||||||
|
public function servers(): Collection
|
||||||
|
{
|
||||||
|
$mainServer = data_get($this, 'destination.server');
|
||||||
|
$additionalDestinations = data_get($this, 'additional_destinations', null);
|
||||||
|
$additionalServers = collect([]);
|
||||||
|
if ($this->isMultipleServerDeployment()) {
|
||||||
|
ray('asd');
|
||||||
|
if (str($additionalDestinations)->isNotEmpty()) {
|
||||||
|
$additionalDestinations = str($additionalDestinations)->explode(',');
|
||||||
|
foreach ($additionalDestinations as $destinationId) {
|
||||||
|
$destination = StandaloneDocker::find($destinationId)->whereNot('id', $mainServer->id)->first();
|
||||||
|
$server = data_get($destination, 'server');
|
||||||
|
$additionalServers->push($server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collect([$mainServer])->merge($additionalServers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateImageNames(string $commit, int $pullRequestId)
|
||||||
|
{
|
||||||
|
if ($this->dockerfile) {
|
||||||
|
if ($this->docker_registry_image_name) {
|
||||||
|
$buildImageName = Str::lower("{$this->docker_registry_image_name}:build");
|
||||||
|
$productionImageName = Str::lower("{$this->docker_registry_image_name}:latest");
|
||||||
|
} else {
|
||||||
|
$buildImageName = Str::lower("{$this->uuid}:build");
|
||||||
|
$productionImageName = Str::lower("{$this->uuid}:latest");
|
||||||
|
}
|
||||||
|
} else if ($this->build_pack === 'dockerimage') {
|
||||||
|
$productionImageName = Str::lower("{$this->docker_registry_image_name}:{$this->docker_registry_image_tag}");
|
||||||
|
} else if ($pullRequestId === 0) {
|
||||||
|
$dockerImageTag = str($commit)->substr(0, 128);
|
||||||
|
if ($this->docker_registry_image_name) {
|
||||||
|
$buildImageName = Str::lower("{$this->docker_registry_image_name}:{$dockerImageTag}-build");
|
||||||
|
$productionImageName = Str::lower("{$this->docker_registry_image_name}:{$dockerImageTag}");
|
||||||
|
} else {
|
||||||
|
$buildImageName = Str::lower("{$this->uuid}:{$dockerImageTag}-build");
|
||||||
|
$productionImageName = Str::lower("{$this->uuid}:{$dockerImageTag}");
|
||||||
|
}
|
||||||
|
} else if ($pullRequestId !== 0) {
|
||||||
|
if ($this->docker_registry_image_name) {
|
||||||
|
$buildImageName = Str::lower("{$this->docker_registry_image_name}:pr-{$pullRequestId}-build");
|
||||||
|
$productionImageName = Str::lower("{$this->docker_registry_image_name}:pr-{$pullRequestId}");
|
||||||
|
} else {
|
||||||
|
$buildImageName = Str::lower("{$this->uuid}:pr-{$pullRequestId}-build");
|
||||||
|
$productionImageName = Str::lower("{$this->uuid}:pr-{$pullRequestId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'buildImageName' => $buildImageName,
|
||||||
|
'productionImageName' => $productionImageName,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// End of build packs / deployment types
|
||||||
|
|
||||||
public function link()
|
public function link()
|
||||||
{
|
{
|
||||||
if (data_get($this, 'environment.project.uuid')) {
|
if (data_get($this, 'environment.project.uuid')) {
|
||||||
@ -385,9 +445,7 @@ public function isConfigurationChanged($save = false)
|
|||||||
}
|
}
|
||||||
public function isMultipleServerDeployment()
|
public function isMultipleServerDeployment()
|
||||||
{
|
{
|
||||||
if (isDev()) {
|
return false;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (data_get($this, 'additional_destinations') && data_get($this, 'docker_registry_image_name')) {
|
if (data_get($this, 'additional_destinations') && data_get($this, 'docker_registry_image_name')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -431,6 +489,294 @@ function generateBaseDir(string $uuid)
|
|||||||
{
|
{
|
||||||
return "/artifacts/{$uuid}";
|
return "/artifacts/{$uuid}";
|
||||||
}
|
}
|
||||||
|
function generateHealthCheckCommands()
|
||||||
|
{
|
||||||
|
if ($this->dockerfile || $this->build_pack === 'dockerfile' || $this->build_pack === 'dockerimage') {
|
||||||
|
// TODO: disabled HC because there are several ways to hc a simple docker image, hard to figure out a good way. Like some docker images (pocketbase) does not have curl.
|
||||||
|
return 'exit 0';
|
||||||
|
}
|
||||||
|
if (!$this->health_check_port) {
|
||||||
|
$health_check_port = $this->ports_exposes_array[0];
|
||||||
|
} else {
|
||||||
|
$health_check_port = $this->health_check_port;
|
||||||
|
}
|
||||||
|
if ($this->health_check_path) {
|
||||||
|
$this->full_healthcheck_url = "{$this->health_check_method}: {$this->health_check_scheme}://{$this->health_check_host}:{$health_check_port}{$this->health_check_path}";
|
||||||
|
$generated_healthchecks_commands = [
|
||||||
|
"curl -s -X {$this->health_check_method} -f {$this->health_check_scheme}://{$this->health_check_host}:{$health_check_port}{$this->health_check_path} > /dev/null"
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$this->full_healthcheck_url = "{$this->health_check_method}: {$this->health_check_scheme}://{$this->health_check_host}:{$health_check_port}/";
|
||||||
|
$generated_healthchecks_commands = [
|
||||||
|
"curl -s -X {$this->health_check_method} -f {$this->health_check_scheme}://{$this->health_check_host}:{$health_check_port}/"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return implode(' ', $generated_healthchecks_commands);
|
||||||
|
}
|
||||||
|
function generateLocalPersistentVolumes(int $pullRequestId)
|
||||||
|
{
|
||||||
|
$persistentStorages = [];
|
||||||
|
$volumeNames = [];
|
||||||
|
foreach ($this->persistentStorages as $persistentStorage) {
|
||||||
|
$volume_name = $persistentStorage->host_path ?? $persistentStorage->name;
|
||||||
|
if ($pullRequestId !== 0) {
|
||||||
|
$volume_name = $volume_name . '-pr-' . $pullRequestId;
|
||||||
|
}
|
||||||
|
$persistentStorages[] = $volume_name . ':' . $persistentStorage->mount_path;
|
||||||
|
|
||||||
|
if ($persistentStorage->host_path) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $persistentStorage->name;
|
||||||
|
|
||||||
|
if ($pullRequestId !== 0) {
|
||||||
|
$name = $name . '-pr-' . $pullRequestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
$volumeNames[$name] = [
|
||||||
|
'name' => $name,
|
||||||
|
'external' => false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'persistentStorages' => $persistentStorages,
|
||||||
|
'volumeNames' => $volumeNames,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
public function generateEnvironmentVariables($ports)
|
||||||
|
{
|
||||||
|
$environmentVariables = collect();
|
||||||
|
// ray('Generate Environment Variables')->green();
|
||||||
|
if ($this->pull_request_id === 0) {
|
||||||
|
// ray($this->runtime_environment_variables)->green();
|
||||||
|
foreach ($this->runtime_environment_variables as $env) {
|
||||||
|
$environmentVariables->push("$env->key=$env->value");
|
||||||
|
}
|
||||||
|
foreach ($this->nixpacks_environment_variables as $env) {
|
||||||
|
$environmentVariables->push("$env->key=$env->value");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// ray($this->runtime_environment_variables_preview)->green();
|
||||||
|
foreach ($this->runtime_environment_variables_preview as $env) {
|
||||||
|
$environmentVariables->push("$env->key=$env->value");
|
||||||
|
}
|
||||||
|
foreach ($this->nixpacks_environment_variables_preview as $env) {
|
||||||
|
$environmentVariables->push("$env->key=$env->value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add PORT if not exists, use the first port as default
|
||||||
|
if ($environmentVariables->filter(fn ($env) => Str::of($env)->contains('PORT'))->isEmpty()) {
|
||||||
|
$environmentVariables->push("PORT={$ports[0]}");
|
||||||
|
}
|
||||||
|
return $environmentVariables->all();
|
||||||
|
}
|
||||||
|
function generateDockerComposeFile(Server $server, ApplicationDeploymentQueue $deployment, string $workdir)
|
||||||
|
{
|
||||||
|
$pullRequestId = $deployment->pull_request_id;
|
||||||
|
$ports = $this->settings->is_static ? [80] : $this->ports_exposes_array;
|
||||||
|
$container_name = generateApplicationContainerName($this, $this->pull_request_id);
|
||||||
|
$commit = str($deployment->getOutput('git_commit_sha'))->before("\t");
|
||||||
|
|
||||||
|
[
|
||||||
|
'productionImageName' => $productionImageName
|
||||||
|
] = $this->generateImageNames($commit, $pullRequestId);
|
||||||
|
|
||||||
|
[
|
||||||
|
'persistentStorages' => $persistentStorages,
|
||||||
|
'volumeNames' => $volumeNames
|
||||||
|
] = $this->generateLocalPersistentVolumes($pullRequestId);
|
||||||
|
|
||||||
|
$environmentVariables = $this->generateEnvironmentVariables($ports);
|
||||||
|
|
||||||
|
if (data_get($this, 'custom_labels')) {
|
||||||
|
$labels = collect(str($this->custom_labels)->explode(','));
|
||||||
|
$labels = $labels->filter(function ($value, $key) {
|
||||||
|
return !Str::startsWith($value, 'coolify.');
|
||||||
|
});
|
||||||
|
$this->custom_labels = $labels->implode(',');
|
||||||
|
$this->save();
|
||||||
|
} else {
|
||||||
|
$labels = collect(generateLabelsApplication($this, $this->preview));
|
||||||
|
}
|
||||||
|
if ($this->pull_request_id !== 0) {
|
||||||
|
$labels = collect(generateLabelsApplication($this, $this->preview));
|
||||||
|
}
|
||||||
|
$labels = $labels->merge(defaultLabels($this->id, $this->uuid, $this->pull_request_id))->toArray();
|
||||||
|
$docker_compose = [
|
||||||
|
'version' => '3.8',
|
||||||
|
'services' => [
|
||||||
|
$container_name => [
|
||||||
|
'image' => $productionImageName,
|
||||||
|
'container_name' => $container_name,
|
||||||
|
'restart' => RESTART_MODE,
|
||||||
|
'environment' => $environmentVariables,
|
||||||
|
'expose' => $ports,
|
||||||
|
'networks' => [
|
||||||
|
$this->destination->network,
|
||||||
|
],
|
||||||
|
'healthcheck' => [
|
||||||
|
'test' => [
|
||||||
|
'CMD-SHELL',
|
||||||
|
$this->generateHealthCheckCommands()
|
||||||
|
],
|
||||||
|
'interval' => $this->health_check_interval . 's',
|
||||||
|
'timeout' => $this->health_check_timeout . 's',
|
||||||
|
'retries' => $this->health_check_retries,
|
||||||
|
'start_period' => $this->health_check_start_period . 's'
|
||||||
|
],
|
||||||
|
'mem_limit' => $this->limits_memory,
|
||||||
|
'memswap_limit' => $this->limits_memory_swap,
|
||||||
|
'mem_swappiness' => $this->limits_memory_swappiness,
|
||||||
|
'mem_reservation' => $this->limits_memory_reservation,
|
||||||
|
'cpus' => (int) $this->limits_cpus,
|
||||||
|
'cpuset' => $this->limits_cpuset,
|
||||||
|
'cpu_shares' => $this->limits_cpu_shares,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'networks' => [
|
||||||
|
$this->destination->network => [
|
||||||
|
'external' => true,
|
||||||
|
'name' => $this->destination->network,
|
||||||
|
'attachable' => true
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
if ($server->isSwarm()) {
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name . '.container_name');
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name . '.expose');
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name . '.restart');
|
||||||
|
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name . '.mem_limit');
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name . '.memswap_limit');
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name . '.mem_swappiness');
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name . '.mem_reservation');
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name . '.cpus');
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name . '.cpuset');
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name . '.cpu_shares');
|
||||||
|
|
||||||
|
$docker_compose['services'][$container_name]['deploy'] = [
|
||||||
|
'placement' => [
|
||||||
|
'constraints' => [
|
||||||
|
'node.role == worker'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'mode' => 'replicated',
|
||||||
|
'replicas' => 1,
|
||||||
|
'update_config' => [
|
||||||
|
'order' => 'start-first'
|
||||||
|
],
|
||||||
|
'rollback_config' => [
|
||||||
|
'order' => 'start-first'
|
||||||
|
],
|
||||||
|
'labels' => $labels,
|
||||||
|
'resources' => [
|
||||||
|
'limits' => [
|
||||||
|
'cpus' => $this->limits_cpus,
|
||||||
|
'memory' => $this->limits_memory,
|
||||||
|
],
|
||||||
|
'reservations' => [
|
||||||
|
'cpus' => $this->limits_cpus,
|
||||||
|
'memory' => $this->limits_memory,
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$docker_compose['services'][$container_name]['labels'] = $labels;
|
||||||
|
}
|
||||||
|
if ($server->isLogDrainEnabled() && $this->isLogDrainEnabled()) {
|
||||||
|
$docker_compose['services'][$container_name]['logging'] = [
|
||||||
|
'driver' => 'fluentd',
|
||||||
|
'options' => [
|
||||||
|
'fluentd-address' => "tcp://127.0.0.1:24224",
|
||||||
|
'fluentd-async' => "true",
|
||||||
|
'fluentd-sub-second-precision' => "true",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if ($this->settings->is_gpu_enabled) {
|
||||||
|
$docker_compose['services'][$container_name]['deploy']['resources']['reservations']['devices'] = [
|
||||||
|
[
|
||||||
|
'driver' => data_get($this, 'settings.gpu_driver', 'nvidia'),
|
||||||
|
'capabilities' => ['gpu'],
|
||||||
|
'options' => data_get($this, 'settings.gpu_options', [])
|
||||||
|
]
|
||||||
|
];
|
||||||
|
if (data_get($this, 'settings.gpu_count')) {
|
||||||
|
$count = data_get($this, 'settings.gpu_count');
|
||||||
|
if ($count === 'all') {
|
||||||
|
$docker_compose['services'][$container_name]['deploy']['resources']['reservations']['devices'][0]['count'] = $count;
|
||||||
|
} else {
|
||||||
|
$docker_compose['services'][$container_name]['deploy']['resources']['reservations']['devices'][0]['count'] = (int) $count;
|
||||||
|
}
|
||||||
|
} else if (data_get($this, 'settings.gpu_device_ids')) {
|
||||||
|
$docker_compose['services'][$container_name]['deploy']['resources']['reservations']['devices'][0]['ids'] = data_get($this, 'settings.gpu_device_ids');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($this->isHealthcheckDisabled()) {
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name . '.healthcheck');
|
||||||
|
}
|
||||||
|
if (count($this->ports_mappings_array) > 0 && $this->pull_request_id === 0) {
|
||||||
|
$docker_compose['services'][$container_name]['ports'] = $this->ports_mappings_array;
|
||||||
|
}
|
||||||
|
if (count($persistentStorages) > 0) {
|
||||||
|
$docker_compose['services'][$container_name]['volumes'] = $persistentStorages;
|
||||||
|
}
|
||||||
|
if (count($volumeNames) > 0) {
|
||||||
|
$docker_compose['volumes'] = $volumeNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
$docker_compose['services'][$this->uuid] = $docker_compose['services'][$container_name];
|
||||||
|
|
||||||
|
data_forget($docker_compose, 'services.' . $container_name);
|
||||||
|
|
||||||
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
$server->executeRemoteCommand(
|
||||||
|
commands: collect([])->push([
|
||||||
|
'command' => executeInDocker($deployment->deployment_uuid, "echo '{$docker_compose_base64}' | base64 -d > {$workdir}/docker-compose.yml"),
|
||||||
|
'hidden' => true,
|
||||||
|
'ignoreErrors' => true
|
||||||
|
]),
|
||||||
|
loggingModel: $deployment
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function rollingUpdateApplication(Server $server, ApplicationDeploymentQueue $deployment, string $workdir)
|
||||||
|
{
|
||||||
|
$pullRequestId = $deployment->pull_request_id;
|
||||||
|
$containerName = generateApplicationContainerName($this, $pullRequestId);
|
||||||
|
// if (count($this->ports_mappings_array) > 0) {
|
||||||
|
// $deployment->addLogEntry('Application has ports mapped to the host system, rolling update is not supported.');
|
||||||
|
$containers = getCurrentApplicationContainerStatus($server, $this->id, $pullRequestId);
|
||||||
|
ray($containers);
|
||||||
|
// if ($pullRequestId === 0) {
|
||||||
|
// $containers = $containers->filter(function ($container) use ($containerName) {
|
||||||
|
// return data_get($container, 'Names') !== $containerName;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
$containers->each(function ($container) use ($server, $deployment) {
|
||||||
|
$removingContainerName = data_get($container, 'Names');
|
||||||
|
$server->executeRemoteCommand(
|
||||||
|
commands: collect([])->push([
|
||||||
|
'command' => "docker rm -f $removingContainerName",
|
||||||
|
'hidden' => true,
|
||||||
|
'ignoreErrors' => true
|
||||||
|
]),
|
||||||
|
loggingModel: $deployment
|
||||||
|
);
|
||||||
|
});
|
||||||
|
// }
|
||||||
|
$server->executeRemoteCommand(
|
||||||
|
commands: collect([])->push([
|
||||||
|
'command' => executeInDocker($deployment->deployment_uuid, "docker compose --project-directory {$workdir} up --build -d"),
|
||||||
|
'hidden' => true,
|
||||||
|
'ignoreErrors' => true
|
||||||
|
]),
|
||||||
|
loggingModel: $deployment
|
||||||
|
);
|
||||||
|
$deployment->addLogEntry("New container started.");
|
||||||
|
}
|
||||||
function setGitImportSettings(string $deployment_uuid, string $git_clone_command)
|
function setGitImportSettings(string $deployment_uuid, string $git_clone_command)
|
||||||
{
|
{
|
||||||
$baseDir = $this->generateBaseDir($deployment_uuid);
|
$baseDir = $this->generateBaseDir($deployment_uuid);
|
||||||
|
@ -9,6 +9,11 @@ class ApplicationDeploymentQueue extends Model
|
|||||||
{
|
{
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
public function setStatus(string $status) {
|
||||||
|
$this->update([
|
||||||
|
'status' => $status,
|
||||||
|
]);
|
||||||
|
}
|
||||||
public function getOutput($name)
|
public function getOutput($name)
|
||||||
{
|
{
|
||||||
if (!$this->logs) {
|
if (!$this->logs) {
|
||||||
|
@ -16,29 +16,16 @@ class ApplicationSetting extends Model
|
|||||||
'is_git_submodules_enabled' => 'boolean',
|
'is_git_submodules_enabled' => 'boolean',
|
||||||
'is_git_lfs_enabled' => 'boolean',
|
'is_git_lfs_enabled' => 'boolean',
|
||||||
];
|
];
|
||||||
protected $fillable = [
|
protected $guarded = [];
|
||||||
'application_id',
|
|
||||||
'is_static',
|
|
||||||
'is_auto_deploy_enabled',
|
|
||||||
'is_force_https_enabled',
|
|
||||||
'is_debug_enabled',
|
|
||||||
'is_preview_deployments_enabled',
|
|
||||||
'is_git_submodules_enabled',
|
|
||||||
'is_git_lfs_enabled',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function isStatic(): Attribute
|
public function isStatic(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
set: function ($value) {
|
set: function ($value) {
|
||||||
if (is_null($this->application->ports_exposes)) {
|
|
||||||
if ($value) {
|
if ($value) {
|
||||||
$this->application->ports_exposes = '80';
|
$this->application->ports_exposes = 80;
|
||||||
} else {
|
|
||||||
$this->application->ports_exposes = '3000';
|
|
||||||
}
|
}
|
||||||
$this->application->save();
|
$this->application->save();
|
||||||
}
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -86,7 +86,8 @@ public function settings()
|
|||||||
{
|
{
|
||||||
return $this->hasOne(ServerSetting::class);
|
return $this->hasOne(ServerSetting::class);
|
||||||
}
|
}
|
||||||
public function addInitialNetwork() {
|
public function addInitialNetwork()
|
||||||
|
{
|
||||||
if ($this->id === 0) {
|
if ($this->id === 0) {
|
||||||
if ($this->isSwarm()) {
|
if ($this->isSwarm()) {
|
||||||
SwarmDocker::create([
|
SwarmDocker::create([
|
||||||
@ -381,17 +382,17 @@ public function isSwarm()
|
|||||||
public function validateConnection()
|
public function validateConnection()
|
||||||
{
|
{
|
||||||
$server = Server::find($this->id);
|
$server = Server::find($this->id);
|
||||||
if ($this->skipServer()) {
|
if ($server->skipServer()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$uptime = instant_remote_process(['uptime'], $this, false);
|
$uptime = instant_remote_process(['uptime'], $server, false);
|
||||||
if (!$uptime) {
|
if (!$uptime) {
|
||||||
$this->settings()->update([
|
$server->settings()->update([
|
||||||
'is_reachable' => false,
|
'is_reachable' => false,
|
||||||
]);
|
]);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
$this->settings()->update([
|
$server->settings()->update([
|
||||||
'is_reachable' => true,
|
'is_reachable' => true,
|
||||||
]);
|
]);
|
||||||
$server->update([
|
$server->update([
|
||||||
@ -399,8 +400,8 @@ public function validateConnection()
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_get($this, 'unreachable_notification_sent') === true) {
|
if (data_get($server, 'unreachable_notification_sent') === true) {
|
||||||
$this->team->notify(new Revived($this));
|
$server->team->notify(new Revived($server));
|
||||||
$server->update(['unreachable_notification_sent' => false]);
|
$server->update(['unreachable_notification_sent' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,4 +537,74 @@ public function stopApplicationRelatedRunningContainers(string $applicationId, s
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
public function getHostIPMappings($network)
|
||||||
|
{
|
||||||
|
$addHosts = null;
|
||||||
|
$allContainers = instant_remote_process(["docker network inspect {$network} -f '{{json .Containers}}' "], $this);
|
||||||
|
if (!is_null($allContainers)) {
|
||||||
|
$allContainers = format_docker_command_output_to_json($allContainers);
|
||||||
|
$ips = collect([]);
|
||||||
|
if (count($allContainers) > 0) {
|
||||||
|
$allContainers = $allContainers[0];
|
||||||
|
foreach ($allContainers as $container) {
|
||||||
|
$containerName = data_get($container, 'Name');
|
||||||
|
if ($containerName === 'coolify-proxy') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$containerIp = data_get($container, 'IPv4Address');
|
||||||
|
if ($containerName && $containerIp) {
|
||||||
|
$containerIp = str($containerIp)->before('/');
|
||||||
|
$ips->put($containerName, $containerIp->value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$addHosts = $ips->map(function ($ip, $name) {
|
||||||
|
return "--add-host $name:$ip";
|
||||||
|
})->implode(' ');
|
||||||
|
}
|
||||||
|
return $addHosts;
|
||||||
|
}
|
||||||
|
public function checkIfDockerImageExists(string $imageName, ApplicationDeploymentQueue $deployment)
|
||||||
|
{
|
||||||
|
$this->executeRemoteCommand(
|
||||||
|
commands: collect([
|
||||||
|
[
|
||||||
|
"name" => "local_image_found",
|
||||||
|
"command" => "docker images -q {$imageName} 2>/dev/null",
|
||||||
|
"hidden" => true,
|
||||||
|
]
|
||||||
|
]),
|
||||||
|
loggingModel: $deployment
|
||||||
|
);
|
||||||
|
if (str($deployment->getOutput('local_image_found'))->isEmpty()) {
|
||||||
|
$this->executeRemoteCommand(
|
||||||
|
commands: collect([
|
||||||
|
[
|
||||||
|
"command" => "docker pull {$imageName} 2>/dev/null",
|
||||||
|
"ignoreErrors" => true,
|
||||||
|
"hidden" => true
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"name" => "local_image_found",
|
||||||
|
"command" => "docker images -q {$imageName} 2>/dev/null",
|
||||||
|
"hidden" => true,
|
||||||
|
]
|
||||||
|
]),
|
||||||
|
loggingModel: $deployment
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function createWorkDirForDeployment(string $workdir, ApplicationDeploymentQueue $deployment)
|
||||||
|
{
|
||||||
|
$this->executeRemoteCommand(
|
||||||
|
commands: collect([
|
||||||
|
[
|
||||||
|
"command" => executeInDocker($deployment->deployment_uuid, "mkdir -p {$workdir}"),
|
||||||
|
"ignoreErrors" => true,
|
||||||
|
"hidden" => true
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
loggingModel: $deployment
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,28 +8,15 @@
|
|||||||
|
|
||||||
class EventServiceProvider extends ServiceProvider
|
class EventServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* The event to listener mappings for the application.
|
|
||||||
*
|
|
||||||
* @var array<class-string, array<int, class-string>>
|
|
||||||
*/
|
|
||||||
protected $listen = [
|
protected $listen = [
|
||||||
Registered::class => [
|
// Registered::class => [
|
||||||
SendEmailVerificationNotification::class,
|
// SendEmailVerificationNotification::class,
|
||||||
],
|
// ],
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* Register any events for your application.
|
|
||||||
*/
|
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if events and listeners should be automatically discovered.
|
|
||||||
*/
|
|
||||||
public function shouldDiscoverEvents(): bool
|
public function shouldDiscoverEvents(): bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use App\Jobs\ApplicationDeployDockerImageJob;
|
use App\Jobs\ApplicationDeployDockerImageJob;
|
||||||
use App\Jobs\ApplicationDeploymentJob;
|
use App\Jobs\ApplicationDeploymentJob;
|
||||||
|
use App\Jobs\ApplicationDeploymentNewJob;
|
||||||
use App\Jobs\ApplicationDeploySimpleDockerfileJob;
|
use App\Jobs\ApplicationDeploySimpleDockerfileJob;
|
||||||
use App\Jobs\ApplicationRestartJob;
|
use App\Jobs\ApplicationRestartJob;
|
||||||
use App\Jobs\MultipleApplicationDeploymentJob;
|
use App\Jobs\MultipleApplicationDeploymentJob;
|
||||||
@ -11,7 +12,7 @@
|
|||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
function queue_application_deployment(int $application_id, string $deployment_uuid, int | null $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $restart_only = false, ?string $git_type = null)
|
function queue_application_deployment(int $application_id, string $deployment_uuid, int | null $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $restart_only = false, ?string $git_type = null, bool $is_new_deployment = false)
|
||||||
{
|
{
|
||||||
$deployment = ApplicationDeploymentQueue::create([
|
$deployment = ApplicationDeploymentQueue::create([
|
||||||
'application_id' => $application_id,
|
'application_id' => $application_id,
|
||||||
@ -36,21 +37,34 @@ function queue_application_deployment(int $application_id, string $deployment_uu
|
|||||||
if ($running_deployments->count() > 0) {
|
if ($running_deployments->count() > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ($is_new_deployment) {
|
||||||
|
dispatch(new ApplicationDeploymentNewJob(
|
||||||
|
deployment: $deployment,
|
||||||
|
application: Application::find($application_id)
|
||||||
|
))->onConnection('long-running')->onQueue('long-running');
|
||||||
|
} else {
|
||||||
dispatch(new ApplicationDeploymentJob(
|
dispatch(new ApplicationDeploymentJob(
|
||||||
application_deployment_queue_id: $deployment->id,
|
application_deployment_queue_id: $deployment->id,
|
||||||
))->onConnection('long-running')->onQueue('long-running');
|
))->onConnection('long-running')->onQueue('long-running');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function queue_next_deployment(Application $application)
|
function queue_next_deployment(Application $application, bool $isNew = false)
|
||||||
{
|
{
|
||||||
$next_found = ApplicationDeploymentQueue::where('application_id', $application->id)->where('status', 'queued')->first();
|
$next_found = ApplicationDeploymentQueue::where('application_id', $application->id)->where('status', 'queued')->first();
|
||||||
if ($next_found) {
|
if ($next_found) {
|
||||||
|
if ($isNew) {
|
||||||
|
dispatch(new ApplicationDeploymentNewJob(
|
||||||
|
deployment: $next_found,
|
||||||
|
application: $application
|
||||||
|
))->onConnection('long-running')->onQueue('long-running');
|
||||||
|
} else {
|
||||||
dispatch(new ApplicationDeploymentJob(
|
dispatch(new ApplicationDeploymentJob(
|
||||||
application_deployment_queue_id: $next_found->id,
|
application_deployment_queue_id: $next_found->id,
|
||||||
))->onConnection('long-running')->onQueue('long-running');
|
))->onConnection('long-running')->onQueue('long-running');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Deployment things
|
// Deployment things
|
||||||
function generateHostIpMapping(Server $server, string $network)
|
function generateHostIpMapping(Server $server, string $network)
|
||||||
{
|
{
|
||||||
|
@ -1124,7 +1124,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $pull_request_id, $topLevelVolumes) {
|
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $pull_request_id, $topLevelVolumes) {
|
||||||
if (is_string($volume)) {
|
if (is_string($volume)) {
|
||||||
$volume = str($volume);
|
$volume = str($volume);
|
||||||
if ($volume->contains(':')) {
|
if ($volume->contains(':') && !$volume->startsWith('/')) {
|
||||||
$name = $volume->before(':');
|
$name = $volume->before(':');
|
||||||
$mount = $volume->after(':');
|
$mount = $volume->after(':');
|
||||||
$newName = $resource->uuid . "-{$name}-pr-$pull_request_id";
|
$newName = $resource->uuid . "-{$name}-pr-$pull_request_id";
|
||||||
@ -1138,13 +1138,13 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
if ($source) {
|
if ($source) {
|
||||||
$newSource = $resource->uuid . "-{$source}-pr-$pull_request_id";
|
$newSource = $resource->uuid . "-{$source}-pr-$pull_request_id";
|
||||||
data_set($volume, 'source', $newSource);
|
data_set($volume, 'source', $newSource);
|
||||||
|
if (!str($source)->startsWith('/')) {
|
||||||
$topLevelVolumes->put($newSource, [
|
$topLevelVolumes->put($newSource, [
|
||||||
'name' => $newSource,
|
'name' => $newSource,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $volume->value();
|
return $volume->value();
|
||||||
});
|
});
|
||||||
data_set($service, 'volumes', $serviceVolumes->toArray());
|
data_set($service, 'volumes', $serviceVolumes->toArray());
|
||||||
@ -1154,7 +1154,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes) {
|
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes) {
|
||||||
if (is_string($volume)) {
|
if (is_string($volume)) {
|
||||||
$volume = str($volume);
|
$volume = str($volume);
|
||||||
if ($volume->contains(':')) {
|
if ($volume->contains(':') && !$volume->startsWith('/')) {
|
||||||
$name = $volume->before(':');
|
$name = $volume->before(':');
|
||||||
$mount = $volume->after(':');
|
$mount = $volume->after(':');
|
||||||
if ($name->startsWith('.') || $name->startsWith('~')) {
|
if ($name->startsWith('.') || $name->startsWith('~')) {
|
||||||
@ -1175,7 +1175,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
} else if (is_array($volume)) {
|
} else if (is_array($volume)) {
|
||||||
$source = data_get($volume, 'source');
|
$source = data_get($volume, 'source');
|
||||||
if ($source) {
|
if ($source) {
|
||||||
if (str($source, '.') || str($source, '~')) {
|
if ((str($source)->startsWith('.') || str($source)->startsWith('~')) && !str($source)->startsWith('/')) {
|
||||||
$dir = base_configuration_dir() . '/applications/' . $resource->uuid;
|
$dir = base_configuration_dir() . '/applications/' . $resource->uuid;
|
||||||
if (str($source, '.')) {
|
if (str($source, '.')) {
|
||||||
$source = str('.', $dir, $source);
|
$source = str('.', $dir, $source);
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"nubs/random-name-generator": "^2.2",
|
"nubs/random-name-generator": "^2.2",
|
||||||
"phpseclib/phpseclib": "~3.0",
|
"phpseclib/phpseclib": "~3.0",
|
||||||
"poliander/cron": "^3.0",
|
"poliander/cron": "^3.0",
|
||||||
|
"pusher/pusher-php-server": "^7.2",
|
||||||
"resend/resend-laravel": "^0.5.0",
|
"resend/resend-laravel": "^0.5.0",
|
||||||
"sentry/sentry-laravel": "^3.4",
|
"sentry/sentry-laravel": "^3.4",
|
||||||
"spatie/laravel-activitylog": "^4.7.3",
|
"spatie/laravel-activitylog": "^4.7.3",
|
||||||
@ -38,6 +39,7 @@
|
|||||||
"stripe/stripe-php": "^12.0",
|
"stripe/stripe-php": "^12.0",
|
||||||
"symfony/yaml": "^6.2",
|
"symfony/yaml": "^6.2",
|
||||||
"visus/cuid2": "^2.0.0",
|
"visus/cuid2": "^2.0.0",
|
||||||
|
"wire-elements/modal": "^1.0",
|
||||||
"yosymfony/toml": "^1.0"
|
"yosymfony/toml": "^1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
1279
composer.lock
generated
1279
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -194,7 +194,7 @@
|
|||||||
App\Providers\AppServiceProvider::class,
|
App\Providers\AppServiceProvider::class,
|
||||||
App\Providers\FortifyServiceProvider::class,
|
App\Providers\FortifyServiceProvider::class,
|
||||||
App\Providers\AuthServiceProvider::class,
|
App\Providers\AuthServiceProvider::class,
|
||||||
// App\Providers\BroadcastServiceProvider::class,
|
App\Providers\BroadcastServiceProvider::class,
|
||||||
App\Providers\EventServiceProvider::class,
|
App\Providers\EventServiceProvider::class,
|
||||||
App\Providers\HorizonServiceProvider::class,
|
App\Providers\HorizonServiceProvider::class,
|
||||||
App\Providers\RouteServiceProvider::class,
|
App\Providers\RouteServiceProvider::class,
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'default' => env('BROADCAST_DRIVER', 'null'),
|
'default' => env('BROADCAST_DRIVER', 'pusher'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@ -32,13 +32,13 @@
|
|||||||
|
|
||||||
'pusher' => [
|
'pusher' => [
|
||||||
'driver' => 'pusher',
|
'driver' => 'pusher',
|
||||||
'key' => env('PUSHER_APP_KEY'),
|
'key' => env('PUSHER_APP_KEY', 'coolify'),
|
||||||
'secret' => env('PUSHER_APP_SECRET'),
|
'secret' => env('PUSHER_APP_SECRET', 'coolify'),
|
||||||
'app_id' => env('PUSHER_APP_ID'),
|
'app_id' => env('PUSHER_APP_ID', 'coolify'),
|
||||||
'options' => [
|
'options' => [
|
||||||
'host' => env('PUSHER_HOST') ?: 'api-' . env('PUSHER_APP_CLUSTER', 'mt1') . '.pusher.com',
|
'host' => env('PUSHER_BACKEND_HOST', 'coolify-soketi'),
|
||||||
'port' => env('PUSHER_PORT', 443),
|
'port' => env('PUSHER_BACKEND_PORT', 6001),
|
||||||
'scheme' => env('PUSHER_SCHEME', 'https'),
|
'scheme' => env('PUSHER_SCHEME', 'http'),
|
||||||
'encrypted' => true,
|
'encrypted' => true,
|
||||||
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
||||||
],
|
],
|
||||||
|
52
config/livewire-ui-modal.php
Normal file
52
config/livewire-ui-modal.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Include CSS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The modal uses TailwindCSS, if you don't use TailwindCSS you will need
|
||||||
|
| to set this parameter to true. This includes the modern-normalize css.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'include_css' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Include JS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Livewire UI will inject the required Javascript in your blade template.
|
||||||
|
| If you want to bundle the required Javascript you can set this to false
|
||||||
|
| and add `require('vendor/wire-elements/modal/resources/js/modal');`
|
||||||
|
| to your script bundler like webpack.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'include_js' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Modal Component Defaults
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure the default properties for a modal component.
|
||||||
|
|
|
||||||
|
| Supported modal_max_width
|
||||||
|
| 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl', '6xl', '7xl'
|
||||||
|
*/
|
||||||
|
'component_defaults' => [
|
||||||
|
'modal_max_width' => '7xl',
|
||||||
|
|
||||||
|
'close_modal_on_click_away' => true,
|
||||||
|
|
||||||
|
'close_modal_on_escape' => true,
|
||||||
|
|
||||||
|
'close_modal_on_escape_is_forceful' => true,
|
||||||
|
|
||||||
|
'dispatch_close_event' => false,
|
||||||
|
|
||||||
|
'destroy_on_close' => false,
|
||||||
|
],
|
||||||
|
];
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.153',
|
'release' => '4.0.0-beta.154',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.153';
|
return '4.0.0-beta.154';
|
||||||
|
@ -13,11 +13,11 @@ class StandaloneDockerSeeder extends Seeder
|
|||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
// StandaloneDocker::create([
|
StandaloneDocker::create([
|
||||||
// 'id' => 0,
|
'id' => 0,
|
||||||
// 'name' => 'Standalone Docker 1',
|
'name' => 'Standalone Docker 1',
|
||||||
// 'network' => 'coolify',
|
'network' => 'coolify',
|
||||||
// 'server_id' => 0,
|
'server_id' => 0,
|
||||||
// ]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,12 @@ services:
|
|||||||
SSL_MODE: "off"
|
SSL_MODE: "off"
|
||||||
AUTORUN_LARAVEL_STORAGE_LINK: "false"
|
AUTORUN_LARAVEL_STORAGE_LINK: "false"
|
||||||
AUTORUN_LARAVEL_MIGRATION: "false"
|
AUTORUN_LARAVEL_MIGRATION: "false"
|
||||||
|
PUSHER_HOST: "${PUSHER_HOST}"
|
||||||
|
PUSHER_PORT: "${PUSHER_PORT:-6001}"
|
||||||
|
PUSHER_SCHEME: "${PUSHER_SCHEME:-http}"
|
||||||
|
PUSHER_APP_ID: "${PUSHER_APP_ID:-coolify}"
|
||||||
|
PUSHER_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
|
||||||
|
PUSHER_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}"
|
||||||
volumes:
|
volumes:
|
||||||
- .:/var/www/html/:cached
|
- .:/var/www/html/:cached
|
||||||
postgres:
|
postgres:
|
||||||
@ -44,9 +50,21 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- /data/coolify/_volumes/redis/:/data
|
- /data/coolify/_volumes/redis/:/data
|
||||||
# - coolify-redis-data-dev:/data
|
# - coolify-redis-data-dev:/data
|
||||||
|
soketi:
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
ports:
|
||||||
|
- "${FORWARD_SOKETI_PORT:-6001}:6001"
|
||||||
|
environment:
|
||||||
|
SOKETI_DEBUG: "false"
|
||||||
|
SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID:-coolify}"
|
||||||
|
SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
|
||||||
|
SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}"
|
||||||
vite:
|
vite:
|
||||||
image: node:20
|
image: node:20
|
||||||
working_dir: /var/www/html
|
working_dir: /var/www/html
|
||||||
|
# environment:
|
||||||
|
# VITE_PUSHER_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
|
||||||
ports:
|
ports:
|
||||||
- "${VITE_PORT:-5173}:${VITE_PORT:-5173}"
|
- "${VITE_PORT:-5173}:${VITE_PORT:-5173}"
|
||||||
volumes:
|
volumes:
|
||||||
@ -60,14 +78,14 @@ services:
|
|||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- /data/coolify/:/data/coolify
|
- /data/coolify/:/data/coolify
|
||||||
# - coolify-data-dev:/data/coolify
|
# - coolify-data-dev:/data/coolify
|
||||||
remote-host:
|
# remote-host:
|
||||||
<<: *testing-host-base
|
# <<: *testing-host-base
|
||||||
container_name: coolify-remote-host
|
# container_name: coolify-remote-host
|
||||||
volumes:
|
# volumes:
|
||||||
- /:/host
|
# - /:/host
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
# - /var/run/docker.sock:/var/run/docker.sock
|
||||||
- /data/coolify/:/data/coolify
|
# - /data/coolify/:/data/coolify
|
||||||
# - coolify-data-dev:/data/coolify
|
# # - coolify-data-dev:/data/coolify
|
||||||
mailpit:
|
mailpit:
|
||||||
image: "axllent/mailpit:latest"
|
image: "axllent/mailpit:latest"
|
||||||
container_name: coolify-mail
|
container_name: coolify-mail
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
coolify:
|
coolify:
|
||||||
image: "ghcr.io/coollabsio/coolify:${LATEST_IMAGE:-4.0.0-beta.20}"
|
image: "ghcr.io/coollabsio/coolify:${LATEST_IMAGE:-4.0.0-beta.153}"
|
||||||
volumes:
|
volumes:
|
||||||
- type: bind
|
- type: bind
|
||||||
source: /data/coolify/source/.env
|
source: /data/coolify/source/.env
|
||||||
@ -35,6 +35,14 @@ services:
|
|||||||
- PHP_PM_START_SERVERS=1
|
- PHP_PM_START_SERVERS=1
|
||||||
- PHP_PM_MIN_SPARE_SERVERS=1
|
- PHP_PM_MIN_SPARE_SERVERS=1
|
||||||
- PHP_PM_MAX_SPARE_SERVERS=10
|
- PHP_PM_MAX_SPARE_SERVERS=10
|
||||||
|
- PUSHER_HOST
|
||||||
|
- PUSHER_BACKEND_HOST
|
||||||
|
- PUSHER_PORT
|
||||||
|
- PUSHER_BACKEND_PORT
|
||||||
|
- PUSHER_SCHEME
|
||||||
|
- PUSHER_APP_ID
|
||||||
|
- PUSHER_APP_KEY
|
||||||
|
- PUSHER_APP_SECRET
|
||||||
- SELF_HOSTED
|
- SELF_HOSTED
|
||||||
- WAITLIST
|
- WAITLIST
|
||||||
- SUBSCRIPTION_PROVIDER
|
- SUBSCRIPTION_PROVIDER
|
||||||
@ -74,8 +82,8 @@ services:
|
|||||||
- "${APP_PORT:-8000}"
|
- "${APP_PORT:-8000}"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: curl --fail http://localhost:80/api/health || exit 1
|
test: curl --fail http://localhost:80/api/health || exit 1
|
||||||
interval: 4s
|
interval: 5s
|
||||||
retries: 5
|
retries: 10
|
||||||
timeout: 2s
|
timeout: 2s
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
@ -97,8 +105,8 @@ services:
|
|||||||
"-d",
|
"-d",
|
||||||
"${DB_DATABASE:-coolify}"
|
"${DB_DATABASE:-coolify}"
|
||||||
]
|
]
|
||||||
interval: 2s
|
interval: 5s
|
||||||
retries: 5
|
retries: 10
|
||||||
timeout: 2s
|
timeout: 2s
|
||||||
redis:
|
redis:
|
||||||
command: redis-server --save 20 1 --loglevel warning --requirepass ${REDIS_PASSWORD}
|
command: redis-server --save 20 1 --loglevel warning --requirepass ${REDIS_PASSWORD}
|
||||||
@ -108,8 +116,21 @@ services:
|
|||||||
- coolify-redis:/data
|
- coolify-redis:/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: redis-cli ping
|
test: redis-cli ping
|
||||||
interval: 2s
|
interval: 5s
|
||||||
retries: 5
|
retries: 10
|
||||||
|
timeout: 2s
|
||||||
|
soketi:
|
||||||
|
ports:
|
||||||
|
- "${SOKETI_PORT:-6001}:6001"
|
||||||
|
environment:
|
||||||
|
SOKETI_DEBUG: "${SOKETI_DEBUG:-false}"
|
||||||
|
SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID}"
|
||||||
|
SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY}"
|
||||||
|
SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET}"
|
||||||
|
healthcheck:
|
||||||
|
test: wget -qO- http://localhost:6001/ready || exit 1
|
||||||
|
interval: 5s
|
||||||
|
retries: 10
|
||||||
timeout: 2s
|
timeout: 2s
|
||||||
volumes:
|
volumes:
|
||||||
coolify-db:
|
coolify-db:
|
||||||
|
@ -24,6 +24,12 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- coolify
|
- coolify
|
||||||
|
soketi:
|
||||||
|
image: 'quay.io/soketi/soketi:1.6-16-alpine'
|
||||||
|
container_name: coolify-soketi
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- coolify
|
||||||
networks:
|
networks:
|
||||||
coolify:
|
coolify:
|
||||||
name: coolify
|
name: coolify
|
||||||
|
385
package-lock.json
generated
385
package-lock.json
generated
@ -5,20 +5,24 @@
|
|||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@alpinejs/focus": "^3.13.3",
|
||||||
"@tailwindcss/typography": "0.5.10",
|
"@tailwindcss/typography": "0.5.10",
|
||||||
"alpinejs": "3.13.2",
|
"alpinejs": "3.13.3",
|
||||||
"daisyui": "4.3.1",
|
"daisyui": "4.4.19",
|
||||||
|
"ioredis": "5.3.2",
|
||||||
"tailwindcss-scrollbar": "0.1.0"
|
"tailwindcss-scrollbar": "0.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "4.5.0",
|
"@vitejs/plugin-vue": "4.5.1",
|
||||||
"autoprefixer": "10.4.16",
|
"autoprefixer": "10.4.16",
|
||||||
"axios": "1.6.2",
|
"axios": "1.6.2",
|
||||||
|
"laravel-echo": "1.15.3",
|
||||||
"laravel-vite-plugin": "0.8.1",
|
"laravel-vite-plugin": "0.8.1",
|
||||||
"postcss": "8.4.31",
|
"postcss": "8.4.32",
|
||||||
"tailwindcss": "3.3.5",
|
"pusher-js": "8.4.0-rc2",
|
||||||
"vite": "4.5.0",
|
"tailwindcss": "3.3.6",
|
||||||
"vue": "3.3.8"
|
"vite": "4.5.1",
|
||||||
|
"vue": "3.3.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@alloc/quick-lru": {
|
"node_modules/@alloc/quick-lru": {
|
||||||
@ -32,10 +36,19 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@alpinejs/focus": {
|
||||||
|
"version": "3.13.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@alpinejs/focus/-/focus-3.13.3.tgz",
|
||||||
|
"integrity": "sha512-fTRX/9wOfysyZ1PJ4gHeUnmiNTIgqBDIqKxeP5iMvj1UHD3TFLDXllvoIKH3ezqcsyQZqxd/q1MFM7dlIhkmeg==",
|
||||||
|
"dependencies": {
|
||||||
|
"focus-trap": "^6.9.4",
|
||||||
|
"tabbable": "^5.3.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.23.3",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz",
|
||||||
"integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==",
|
"integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
@ -396,6 +409,11 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ioredis/commands": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.3",
|
"version": "0.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||||
@ -503,9 +521,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitejs/plugin-vue": {
|
"node_modules/@vitejs/plugin-vue": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.5.1.tgz",
|
||||||
"integrity": "sha512-a2WSpP8X8HTEww/U00bU4mX1QpLINNuz/2KMNpLsdu3BzOpak3AGI1CJYBTXcc4SPhaD0eNRUp7IyQK405L5dQ==",
|
"integrity": "sha512-DaUzYFr+2UGDG7VSSdShKa9sIWYBa1LL8KC0MNOf2H5LjcTPjob0x8LbkqXWmAtbANJCkpiQTj66UVcQkN2s3g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^14.18.0 || >=16.0.0"
|
"node": "^14.18.0 || >=16.0.0"
|
||||||
@ -516,77 +534,77 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-core": {
|
"node_modules/@vue/compiler-core": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.10.tgz",
|
||||||
"integrity": "sha512-hN/NNBUECw8SusQvDSqqcVv6gWq8L6iAktUR0UF3vGu2OhzRqcOiAno0FmBJWwxhYEXRlQJT5XnoKsVq1WZx4g==",
|
"integrity": "sha512-doe0hODR1+i1menPkRzJ5MNR6G+9uiZHIknK3Zn5OcIztu6GGw7u0XUzf3AgB8h/dfsZC9eouzoLo3c3+N/cVA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.23.0",
|
"@babel/parser": "^7.23.5",
|
||||||
"@vue/shared": "3.3.8",
|
"@vue/shared": "3.3.10",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-core/node_modules/@vue/shared": {
|
"node_modules/@vue/compiler-core/node_modules/@vue/shared": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||||
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==",
|
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-dom": {
|
"node_modules/@vue/compiler-dom": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.10.tgz",
|
||||||
"integrity": "sha512-+PPtv+p/nWDd0AvJu3w8HS0RIm/C6VGBIRe24b9hSyNWOAPEUosFZ5diwawwP8ip5sJ8n0Pe87TNNNHnvjs0FQ==",
|
"integrity": "sha512-NCrqF5fm10GXZIK0GrEAauBqdy+F2LZRt3yNHzrYjpYBuRssQbuPLtSnSNjyR9luHKkWSH8we5LMB3g+4z2HvA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-core": "3.3.8",
|
"@vue/compiler-core": "3.3.10",
|
||||||
"@vue/shared": "3.3.8"
|
"@vue/shared": "3.3.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-dom/node_modules/@vue/shared": {
|
"node_modules/@vue/compiler-dom/node_modules/@vue/shared": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||||
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==",
|
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-sfc": {
|
"node_modules/@vue/compiler-sfc": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.10.tgz",
|
||||||
"integrity": "sha512-WMzbUrlTjfYF8joyT84HfwwXo+8WPALuPxhy+BZ6R4Aafls+jDBnSz8PDz60uFhuqFbl3HxRfxvDzrUf3THwpA==",
|
"integrity": "sha512-xpcTe7Rw7QefOTRFFTlcfzozccvjM40dT45JtrE3onGm/jBLZ0JhpKu3jkV7rbDFLeeagR/5RlJ2Y9SvyS0lAg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.23.0",
|
"@babel/parser": "^7.23.5",
|
||||||
"@vue/compiler-core": "3.3.8",
|
"@vue/compiler-core": "3.3.10",
|
||||||
"@vue/compiler-dom": "3.3.8",
|
"@vue/compiler-dom": "3.3.10",
|
||||||
"@vue/compiler-ssr": "3.3.8",
|
"@vue/compiler-ssr": "3.3.10",
|
||||||
"@vue/reactivity-transform": "3.3.8",
|
"@vue/reactivity-transform": "3.3.10",
|
||||||
"@vue/shared": "3.3.8",
|
"@vue/shared": "3.3.10",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"magic-string": "^0.30.5",
|
"magic-string": "^0.30.5",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.32",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-sfc/node_modules/@vue/shared": {
|
"node_modules/@vue/compiler-sfc/node_modules/@vue/shared": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||||
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==",
|
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-ssr": {
|
"node_modules/@vue/compiler-ssr": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.10.tgz",
|
||||||
"integrity": "sha512-hXCqQL/15kMVDBuoBYpUnSYT8doDNwsjvm3jTefnXr+ytn294ySnT8NlsFHmTgKNjwpuFy7XVV8yTeLtNl/P6w==",
|
"integrity": "sha512-12iM4jA4GEbskwXMmPcskK5wImc2ohKm408+o9iox3tfN9qua8xL0THIZtoe9OJHnXP4eOWZpgCAAThEveNlqQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.3.8",
|
"@vue/compiler-dom": "3.3.10",
|
||||||
"@vue/shared": "3.3.8"
|
"@vue/shared": "3.3.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-ssr/node_modules/@vue/shared": {
|
"node_modules/@vue/compiler-ssr/node_modules/@vue/shared": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||||
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==",
|
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/reactivity": {
|
"node_modules/@vue/reactivity": {
|
||||||
@ -598,83 +616,83 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/reactivity-transform": {
|
"node_modules/@vue/reactivity-transform": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.10.tgz",
|
||||||
"integrity": "sha512-49CvBzmZNtcHua0XJ7GdGifM8GOXoUMOX4dD40Y5DxI3R8OUhMlvf2nvgUAcPxaXiV5MQQ1Nwy09ADpnLQUqRw==",
|
"integrity": "sha512-0xBdk+CKHWT+Gev8oZ63Tc0qFfj935YZx+UAynlutnrDZ4diFCVFMWixn65HzjE3S1iJppWOo6Tt1OzASH7VEg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.23.0",
|
"@babel/parser": "^7.23.5",
|
||||||
"@vue/compiler-core": "3.3.8",
|
"@vue/compiler-core": "3.3.10",
|
||||||
"@vue/shared": "3.3.8",
|
"@vue/shared": "3.3.10",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"magic-string": "^0.30.5"
|
"magic-string": "^0.30.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/reactivity-transform/node_modules/@vue/shared": {
|
"node_modules/@vue/reactivity-transform/node_modules/@vue/shared": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||||
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==",
|
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-core": {
|
"node_modules/@vue/runtime-core": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.10.tgz",
|
||||||
"integrity": "sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==",
|
"integrity": "sha512-DZ0v31oTN4YHX9JEU5VW1LoIVgFovWgIVb30bWn9DG9a7oA415idcwsRNNajqTx8HQJyOaWfRKoyuP2P2TYIag==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/reactivity": "3.3.8",
|
"@vue/reactivity": "3.3.10",
|
||||||
"@vue/shared": "3.3.8"
|
"@vue/shared": "3.3.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-core/node_modules/@vue/reactivity": {
|
"node_modules/@vue/runtime-core/node_modules/@vue/reactivity": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.10.tgz",
|
||||||
"integrity": "sha512-ctLWitmFBu6mtddPyOKpHg8+5ahouoTCRtmAHZAXmolDtuZXfjL2T3OJ6DL6ezBPQB1SmMnpzjiWjCiMYmpIuw==",
|
"integrity": "sha512-H5Z7rOY/JLO+e5a6/FEXaQ1TMuOvY4LDVgT+/+HKubEAgs9qeeZ+NhADSeEtrNQeiKLDuzeKc8v0CUFpB6Pqgw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/shared": "3.3.8"
|
"@vue/shared": "3.3.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-core/node_modules/@vue/shared": {
|
"node_modules/@vue/runtime-core/node_modules/@vue/shared": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||||
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==",
|
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-dom": {
|
"node_modules/@vue/runtime-dom": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.10.tgz",
|
||||||
"integrity": "sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==",
|
"integrity": "sha512-c/jKb3ny05KJcYk0j1m7Wbhrxq7mZYr06GhKykDMNRRR9S+/dGT8KpHuNQjv3/8U4JshfkAk6TpecPD3B21Ijw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/runtime-core": "3.3.8",
|
"@vue/runtime-core": "3.3.10",
|
||||||
"@vue/shared": "3.3.8",
|
"@vue/shared": "3.3.10",
|
||||||
"csstype": "^3.1.2"
|
"csstype": "^3.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-dom/node_modules/@vue/shared": {
|
"node_modules/@vue/runtime-dom/node_modules/@vue/shared": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||||
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==",
|
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/server-renderer": {
|
"node_modules/@vue/server-renderer": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.10.tgz",
|
||||||
"integrity": "sha512-zVCUw7RFskvPuNlPn/8xISbrf0zTWsTSdYTsUTN1ERGGZGVnRxM2QZ3x1OR32+vwkkCm0IW6HmJ49IsPm7ilLg==",
|
"integrity": "sha512-0i6ww3sBV3SKlF3YTjSVqKQ74xialMbjVYGy7cOTi7Imd8ediE7t72SK3qnvhrTAhOvlQhq6Bk6nFPdXxe0sAg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-ssr": "3.3.8",
|
"@vue/compiler-ssr": "3.3.10",
|
||||||
"@vue/shared": "3.3.8"
|
"@vue/shared": "3.3.10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vue": "3.3.8"
|
"vue": "3.3.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/server-renderer/node_modules/@vue/shared": {
|
"node_modules/@vue/server-renderer/node_modules/@vue/shared": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||||
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==",
|
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/shared": {
|
"node_modules/@vue/shared": {
|
||||||
@ -683,9 +701,9 @@
|
|||||||
"integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA=="
|
"integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA=="
|
||||||
},
|
},
|
||||||
"node_modules/alpinejs": {
|
"node_modules/alpinejs": {
|
||||||
"version": "3.13.2",
|
"version": "3.13.3",
|
||||||
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.2.tgz",
|
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.3.tgz",
|
||||||
"integrity": "sha512-WzojeeN082kLZznGI1HAuP8yFJSWqJ1fGdz2mUjj45H4y0XwToE7fFqtI3mCPRR+BpcSbxT/NL+FyPnYAWSltw==",
|
"integrity": "sha512-WZ6WQjkAOl+WdW/jukzNHq9zHFDNKmkk/x6WF7WdyNDD6woinrfXCVsZXm0galjbco+pEpYmJLtwlZwcOfIVdg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/reactivity": "~3.1.1"
|
"@vue/reactivity": "~3.1.1"
|
||||||
}
|
}
|
||||||
@ -896,6 +914,14 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cluster-key-slot": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/combined-stream": {
|
"node_modules/combined-stream": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
@ -956,9 +982,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/daisyui": {
|
"node_modules/daisyui": {
|
||||||
"version": "4.3.1",
|
"version": "4.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.4.19.tgz",
|
||||||
"integrity": "sha512-dCi91VD+57lkoBd10CjdW4wPOeOPYvvzQbxti6xmyQbDMbCeCXwNq2KdoU798I4OsCcD5B+n7yVG7HAgYW+cvw==",
|
"integrity": "sha512-IjOLWwnndD4N7Ut5CDxbUsaVtbqXPeVHM92IcgxGFxpuOd3CCKW/PAXZH6JoBTHFRaN57vB9XqEhdWm5yC+bPA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"css-selector-tokenizer": "^0.8",
|
"css-selector-tokenizer": "^0.8",
|
||||||
"culori": "^3",
|
"culori": "^3",
|
||||||
@ -973,6 +999,22 @@
|
|||||||
"url": "https://opencollective.com/daisyui"
|
"url": "https://opencollective.com/daisyui"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/debug": {
|
||||||
|
"version": "4.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/delayed-stream": {
|
"node_modules/delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
@ -982,6 +1024,14 @@
|
|||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/denque": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/didyoumean": {
|
"node_modules/didyoumean": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||||
@ -1100,6 +1150,14 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/focus-trap": {
|
||||||
|
"version": "6.9.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.4.tgz",
|
||||||
|
"integrity": "sha512-v2NTsZe2FF59Y+sDykKY+XjqZ0cPfhq/hikWVL88BqLivnNiEffAsac6rP6H45ff9wG9LL5ToiDqrLEP9GX9mw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tabbable": "^5.3.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||||
@ -1233,6 +1291,29 @@
|
|||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/ioredis": {
|
||||||
|
"version": "5.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
|
||||||
|
"integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@ioredis/commands": "^1.1.1",
|
||||||
|
"cluster-key-slot": "^1.1.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"denque": "^2.1.0",
|
||||||
|
"lodash.defaults": "^4.2.0",
|
||||||
|
"lodash.isarguments": "^3.1.0",
|
||||||
|
"redis-errors": "^1.2.0",
|
||||||
|
"redis-parser": "^3.0.0",
|
||||||
|
"standard-as-callback": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.22.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/ioredis"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-binary-path": {
|
"node_modules/is-binary-path": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
@ -1290,6 +1371,15 @@
|
|||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/laravel-echo": {
|
||||||
|
"version": "1.15.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-1.15.3.tgz",
|
||||||
|
"integrity": "sha512-SRXzccaat6w4qKgZ4/rjFKr3nJfVxB+ly4V0MEJNIF1/TpERNXepo3uk7NnOjBGsiV/np1fl2XitAzW4Sa1s/w==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/laravel-vite-plugin": {
|
"node_modules/laravel-vite-plugin": {
|
||||||
"version": "0.8.1",
|
"version": "0.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.8.1.tgz",
|
||||||
@ -1324,6 +1414,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
||||||
"integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q=="
|
"integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.defaults": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isarguments": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
|
||||||
|
},
|
||||||
"node_modules/lodash.isplainobject": {
|
"node_modules/lodash.isplainobject": {
|
||||||
"version": "4.0.6",
|
"version": "4.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
@ -1398,6 +1498,11 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
},
|
||||||
"node_modules/mz": {
|
"node_modules/mz": {
|
||||||
"version": "2.7.0",
|
"version": "2.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||||
@ -1409,9 +1514,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.6",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -1518,9 +1623,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.31",
|
"version": "8.4.32",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
|
||||||
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
"integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -1536,7 +1641,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
@ -1647,6 +1752,15 @@
|
|||||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/pusher-js": {
|
||||||
|
"version": "8.4.0-rc2",
|
||||||
|
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.4.0-rc2.tgz",
|
||||||
|
"integrity": "sha512-d87GjOEEl9QgO5BWmViSqW0LOzPvybvX6WA9zLUstNdB57jVJuR27zHkRnrav2a3+zAMlHbP2Og8wug+rG8T+g==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tweetnacl": "^1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
@ -1685,6 +1799,25 @@
|
|||||||
"node": ">=8.10.0"
|
"node": ">=8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/redis-errors": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/redis-parser": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
|
||||||
|
"dependencies": {
|
||||||
|
"redis-errors": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.2",
|
"version": "1.22.2",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
|
||||||
@ -1775,6 +1908,11 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/standard-as-callback": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
|
||||||
|
},
|
||||||
"node_modules/sucrase": {
|
"node_modules/sucrase": {
|
||||||
"version": "3.32.0",
|
"version": "3.32.0",
|
||||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
|
||||||
@ -1807,10 +1945,15 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tabbable": {
|
||||||
|
"version": "5.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz",
|
||||||
|
"integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA=="
|
||||||
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.3.5",
|
"version": "3.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.6.tgz",
|
||||||
"integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==",
|
"integrity": "sha512-AKjF7qbbLvLaPieoKeTjG1+FyNZT6KaJMJPFeQyLfIp7l82ggH1fbHJSsYIvnbTFQOlkh+gBYpyby5GT1LIdLw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
@ -1886,6 +2029,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
||||||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
|
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/tweetnacl": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.0.13",
|
"version": "1.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
||||||
@ -1922,9 +2071,9 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz",
|
||||||
"integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==",
|
"integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.18.10",
|
"esbuild": "^0.18.10",
|
||||||
@ -1987,16 +2136,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue": {
|
"node_modules/vue": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.10.tgz",
|
||||||
"integrity": "sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==",
|
"integrity": "sha512-zg6SIXZdTBwiqCw/1p+m04VyHjLfwtjwz8N57sPaBhEex31ND0RYECVOC1YrRwMRmxFf5T1dabl6SGUbMKKuVw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.3.8",
|
"@vue/compiler-dom": "3.3.10",
|
||||||
"@vue/compiler-sfc": "3.3.8",
|
"@vue/compiler-sfc": "3.3.10",
|
||||||
"@vue/runtime-dom": "3.3.8",
|
"@vue/runtime-dom": "3.3.10",
|
||||||
"@vue/server-renderer": "3.3.8",
|
"@vue/server-renderer": "3.3.10",
|
||||||
"@vue/shared": "3.3.8"
|
"@vue/shared": "3.3.10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "*"
|
"typescript": "*"
|
||||||
@ -2008,9 +2157,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue/node_modules/@vue/shared": {
|
"node_modules/vue/node_modules/@vue/shared": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||||
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==",
|
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/wrappy": {
|
"node_modules/wrappy": {
|
||||||
|
18
package.json
18
package.json
@ -6,19 +6,23 @@
|
|||||||
"build": "vite build"
|
"build": "vite build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "4.5.0",
|
"@vitejs/plugin-vue": "4.5.1",
|
||||||
"autoprefixer": "10.4.16",
|
"autoprefixer": "10.4.16",
|
||||||
"axios": "1.6.2",
|
"axios": "1.6.2",
|
||||||
|
"laravel-echo": "1.15.3",
|
||||||
"laravel-vite-plugin": "0.8.1",
|
"laravel-vite-plugin": "0.8.1",
|
||||||
"postcss": "8.4.31",
|
"postcss": "8.4.32",
|
||||||
"tailwindcss": "3.3.5",
|
"pusher-js": "8.4.0-rc2",
|
||||||
"vite": "4.5.0",
|
"tailwindcss": "3.3.6",
|
||||||
"vue": "3.3.8"
|
"vite": "4.5.1",
|
||||||
|
"vue": "3.3.10"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@alpinejs/focus": "^3.13.3",
|
||||||
"@tailwindcss/typography": "0.5.10",
|
"@tailwindcss/typography": "0.5.10",
|
||||||
"alpinejs": "3.13.2",
|
"alpinejs": "3.13.3",
|
||||||
"daisyui": "4.3.1",
|
"daisyui": "4.4.19",
|
||||||
|
"ioredis": "5.3.2",
|
||||||
"tailwindcss-scrollbar": "0.1.0"
|
"tailwindcss-scrollbar": "0.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
public/js/echo.js
Normal file
2
public/js/echo.js
Normal file
File diff suppressed because one or more lines are too long
10
public/js/pusher.js
Normal file
10
public/js/pusher.js
Normal file
File diff suppressed because one or more lines are too long
2
public/vendor/horizon/app.js
vendored
2
public/vendor/horizon/app.js
vendored
File diff suppressed because one or more lines are too long
2
public/vendor/horizon/mix-manifest.json
vendored
2
public/vendor/horizon/mix-manifest.json
vendored
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"/app.js": "/app.js?id=ff1533ec4a7afad65c5bd7bcc2cc7d7b",
|
"/app.js": "/app.js?id=79bae40dcb18de9ca1b5d0008c577471",
|
||||||
"/app-dark.css": "/app-dark.css?id=15c72df05e2b1147fa3e4b0670cfb435",
|
"/app-dark.css": "/app-dark.css?id=15c72df05e2b1147fa3e4b0670cfb435",
|
||||||
"/app.css": "/app.css?id=4d6a1a7fe095eedc2cb2a4ce822ea8a5",
|
"/app.css": "/app.css?id=4d6a1a7fe095eedc2cb2a4ce822ea8a5",
|
||||||
"/img/favicon.png": "/img/favicon.png?id=1542bfe8a0010dcbee710da13cce367f",
|
"/img/favicon.png": "/img/favicon.png?id=1542bfe8a0010dcbee710da13cce367f",
|
||||||
|
@ -17,6 +17,9 @@ .scrollbar {
|
|||||||
.main {
|
.main {
|
||||||
@apply pt-4 pl-24 pr-10 mx-auto;
|
@apply pt-4 pl-24 pr-10 mx-auto;
|
||||||
}
|
}
|
||||||
|
.custom-modal {
|
||||||
|
@apply flex flex-col gap-2 px-8 py-4 border bg-base-100 border-coolgray-200;
|
||||||
|
}
|
||||||
.label-text,
|
.label-text,
|
||||||
label {
|
label {
|
||||||
@apply text-neutral-400;
|
@apply text-neutral-400;
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import Alpine from "alpinejs";
|
import Alpine from "alpinejs";
|
||||||
|
import focus from '@alpinejs/focus';
|
||||||
import { createApp } from "vue";
|
import { createApp } from "vue";
|
||||||
import MagicBar from "./components/MagicBar.vue";
|
import MagicBar from "./components/MagicBar.vue";
|
||||||
import Toaster from "../../vendor/masmerise/livewire-toaster/resources/js";
|
import Toaster from "../../vendor/masmerise/livewire-toaster/resources/js";
|
||||||
|
import "../../vendor/wire-elements/modal/resources/js/modal";
|
||||||
|
|
||||||
|
Alpine.plugin(focus);
|
||||||
Alpine.plugin(Toaster);
|
Alpine.plugin(Toaster);
|
||||||
|
|
||||||
window.Alpine = Alpine;
|
window.Alpine = Alpine;
|
||||||
@ -12,3 +14,6 @@ Alpine.start();
|
|||||||
const app = createApp({});
|
const app = createApp({});
|
||||||
app.component("magic-bar", MagicBar);
|
app.component("magic-bar", MagicBar);
|
||||||
app.mount("#vue");
|
app.mount("#vue");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,14 +3,18 @@
|
|||||||
href="{{ route('project.application.configuration', $parameters) }}">
|
href="{{ route('project.application.configuration', $parameters) }}">
|
||||||
<button>Configuration</button>
|
<button>Configuration</button>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('project.application.deployments') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('project.application.command') ? 'text-white' : '' }}"
|
||||||
href="{{ route('project.application.deployments', $parameters) }}">
|
href="{{ route('project.application.command', $parameters) }}">
|
||||||
<button>Deployments</button>
|
<button>Execute Command</button>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('project.application.logs') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('project.application.logs') ? 'text-white' : '' }}"
|
||||||
href="{{ route('project.application.logs', $parameters) }}">
|
href="{{ route('project.application.logs', $parameters) }}">
|
||||||
<button>Logs</button>
|
<button>Logs</button>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="{{ request()->routeIs('project.application.deployments') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('project.application.deployments', $parameters) }}">
|
||||||
|
<button>Deployments</button>
|
||||||
|
</a>
|
||||||
<x-applications.links :application="$application" />
|
<x-applications.links :application="$application" />
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
@if ($application->build_pack === 'dockercompose' && is_null($application->docker_compose_raw))
|
@if ($application->build_pack === 'dockercompose' && is_null($application->docker_compose_raw))
|
||||||
@ -45,6 +49,19 @@ class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400"
|
|||||||
</svg>
|
</svg>
|
||||||
Restart
|
Restart
|
||||||
</button>
|
</button>
|
||||||
|
@if (isDev())
|
||||||
|
<button title="Restart without rebuilding" wire:click='restartNew'
|
||||||
|
class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
||||||
|
<svg class="w-5 h-5 text-warning" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
stroke-width="2">
|
||||||
|
<path d="M19.933 13.041a8 8 0 1 1-9.925-8.788c3.899-1 7.935 1.007 9.425 4.747" />
|
||||||
|
<path d="M20 4v5h-5" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Restart (new)
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
@endif
|
@endif
|
||||||
<button wire:click='stop' class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
<button wire:click='stop' class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24" stroke-width="2"
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24" stroke-width="2"
|
||||||
@ -66,6 +83,18 @@ class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400"
|
|||||||
</svg>
|
</svg>
|
||||||
Deploy
|
Deploy
|
||||||
</button>
|
</button>
|
||||||
|
@if (isDev())
|
||||||
|
<button wire:click='deployNew'
|
||||||
|
class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-warning" viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M7 4v16l13 -8z" />
|
||||||
|
</svg>
|
||||||
|
Deploy (new)
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
href="{{ route('project.database.configuration', $parameters) }}">
|
href="{{ route('project.database.configuration', $parameters) }}">
|
||||||
<button>Configuration</button>
|
<button>Configuration</button>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="{{ request()->routeIs('project.database.command') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('project.database.command', $parameters) }}">
|
||||||
|
<button>Execute Command</button>
|
||||||
|
</a>
|
||||||
<a class="{{ request()->routeIs('project.database.logs') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('project.database.logs') ? 'text-white' : '' }}"
|
||||||
href="{{ route('project.database.logs', $parameters) }}">
|
href="{{ route('project.database.logs', $parameters) }}">
|
||||||
<button>Logs</button>
|
<button>Logs</button>
|
||||||
|
@ -38,7 +38,8 @@ class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400"
|
|||||||
</button>
|
</button>
|
||||||
@endif
|
@endif
|
||||||
@if (serviceStatus($service) === 'exited')
|
@if (serviceStatus($service) === 'exited')
|
||||||
<button wire:click='stop(true)' class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
<button wire:click='stop(true)'
|
||||||
|
class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
||||||
<svg class="w-5 h-5 " viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
<svg class="w-5 h-5 " viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill="red" d="M26 20h-6v-2h6zm4 8h-6v-2h6zm-2-4h-6v-2h6z" />
|
<path fill="red" d="M26 20h-6v-2h6zm4 8h-6v-2h6zm-2-4h-6v-2h6z" />
|
||||||
<path fill="red"
|
<path fill="red"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
@props([
|
@props([
|
||||||
'status' => 'Degraded',
|
'status' => 'Degraded',
|
||||||
])
|
])
|
||||||
<x-loading wire:loading.delay />
|
<x-loading wire:loading.delay.longer />
|
||||||
<div class="flex items-center gap-2" wire:loading.remove.delay.longer>
|
<div class="flex items-center gap-2" wire:loading.remove.delay.longer>
|
||||||
<div class="badge badge-warning badge-xs"></div>
|
<div class="badge badge-warning badge-xs"></div>
|
||||||
<div class="text-xs font-medium tracking-wide text-warning">{{ Str::headline($status) }}</div>
|
<div class="text-xs font-medium tracking-wide text-warning">{{ Str::headline($status) }}</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
@props([
|
@props([
|
||||||
'status' => 'Restarting',
|
'status' => 'Restarting',
|
||||||
])
|
])
|
||||||
<x-loading wire:loading.delay />
|
<x-loading wire:loading.delay.longer />
|
||||||
<div class="flex items-center gap-2" wire:loading.remove.delay.longer>
|
<div class="flex items-center gap-2" wire:loading.remove.delay.longer>
|
||||||
<div class="badge badge-warning badge-xs"></div>
|
<div class="badge badge-warning badge-xs"></div>
|
||||||
<div class="text-xs font-medium tracking-wide text-warning">{{ Str::headline($status) }}</div>
|
<div class="text-xs font-medium tracking-wide text-warning">{{ Str::headline($status) }}</div>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
@section('body')
|
@section('body')
|
||||||
@parent
|
@parent
|
||||||
<x-navbar />
|
<x-navbar />
|
||||||
<div class="fixed z-50 top-[4.5rem] left-4" id="vue">
|
<div class="fixed z-30 top-[4.5rem] left-4" id="vue">
|
||||||
<magic-bar></magic-bar>
|
<magic-bar></magic-bar>
|
||||||
</div>
|
</div>
|
||||||
<livewire:sponsorship />
|
<livewire:sponsorship />
|
||||||
|
@ -24,11 +24,20 @@
|
|||||||
@if (config('app.name') == 'Coolify Cloud')
|
@if (config('app.name') == 'Coolify Cloud')
|
||||||
<script defer data-domain="app.coolify.io" src="https://analytics.coollabs.io/js/plausible.js"></script>
|
<script defer data-domain="app.coolify.io" src="https://analytics.coollabs.io/js/plausible.js"></script>
|
||||||
@endif
|
@endif
|
||||||
|
@auth
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/laravel-echo/1.15.3/echo.iife.min.js"
|
||||||
|
integrity="sha512-aPAh2oRUr3ALz2MwVWkd6lmdgBQC0wSr0R++zclNjXZreT/JrwDPZQwA/p6R3wOCTcXKIHgA9pQGEQBWQmdLaA=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/pusher/8.3.0/pusher.min.js"
|
||||||
|
integrity="sha512-tXL5mrkSoP49uQf2jO0LbvzMyFgki//znmq0wYXGq94gVF6TU0QlrSbwGuPpKTeN1mIjReeqKZ4/NJPjHN1d2Q=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
@endauth
|
||||||
</head>
|
</head>
|
||||||
@section('body')
|
@section('body')
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@livewireScripts
|
@livewireScripts
|
||||||
|
@livewire('livewire-ui-modal')
|
||||||
<dialog id="help" class="modal">
|
<dialog id="help" class="modal">
|
||||||
<livewire:help />
|
<livewire:help />
|
||||||
<form method="dialog" class="modal-backdrop">
|
<form method="dialog" class="modal-backdrop">
|
||||||
@ -37,7 +46,47 @@
|
|||||||
</dialog>
|
</dialog>
|
||||||
<x-toaster-hub />
|
<x-toaster-hub />
|
||||||
<x-version class="fixed left-2 bottom-1" />
|
<x-version class="fixed left-2 bottom-1" />
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@auth
|
||||||
|
window.Pusher = Pusher;
|
||||||
|
window.Echo = new Echo({
|
||||||
|
broadcaster: 'pusher',
|
||||||
|
cluster: "{{ env('PUSHER_HOST') }}" || window.location.hostname,
|
||||||
|
key: "{{ env('PUSHER_APP_KEY') }}" || 'coolify',
|
||||||
|
wsHost: "{{ env('PUSHER_HOST') }}" || window.location.hostname,
|
||||||
|
wsPort: "{{ env('PUSHER_PORT') }}" || 6001,
|
||||||
|
wssPort: "{{ env('PUSHER_PORT') }}" || 6001,
|
||||||
|
forceTLS: false,
|
||||||
|
encrypted: true,
|
||||||
|
enableStats: false,
|
||||||
|
enableLogging: true,
|
||||||
|
enabledTransports: ['ws', 'wss'],
|
||||||
|
});
|
||||||
|
|
||||||
|
if ("{{ auth()->user()->id }}" == 0) {
|
||||||
|
let checkPusherInterval = null;
|
||||||
|
let checkNumber = 0;
|
||||||
|
let errorMessage = "Coolify could not connect to the new realtime service introduced in beta.154.<br>Please check the related <a href='https://coolify.io/docs/cloudflare-tunnels' target='_blank'>documentation</a> or get help on <a href='https://coollabs.io/discord' target='_blank'>Discord</a>.";
|
||||||
|
checkPusherInterval = setInterval(() => {
|
||||||
|
if (window.Echo) {
|
||||||
|
if (window.Echo.connector.pusher.connection.state !== 'connected') {
|
||||||
|
checkNumber++;
|
||||||
|
if (checkNumber > 5) {
|
||||||
|
clearInterval(checkPusherInterval);
|
||||||
|
Livewire.emit('error', errorMessage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Coolify is now connected to the new realtime service introduced in beta.154.');
|
||||||
|
clearInterval(checkPusherInterval);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clearInterval(checkPusherInterval);
|
||||||
|
Livewire.emit('error', errorMessage);
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
@endauth
|
||||||
let checkHealthInterval = null;
|
let checkHealthInterval = null;
|
||||||
let checkIfIamDeadInterval = null;
|
let checkIfIamDeadInterval = null;
|
||||||
|
|
||||||
|
32
resources/views/livewire/modal/edit-compose.blade.php
Normal file
32
resources/views/livewire/modal/edit-compose.blade.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<form x-data="{ raw: true }" class="custom-modal" wire:submit.prevent='submit'>
|
||||||
|
<div class="flex items-end gap-2">
|
||||||
|
<h1>Docker Compose</h1>
|
||||||
|
<div x-cloak x-show="raw">
|
||||||
|
<x-forms.button class="w-64" @click.prevent="raw = !raw">Show Deployable Compose</x-forms.button>
|
||||||
|
</div>
|
||||||
|
<div x-cloak x-show="raw === false">
|
||||||
|
<x-forms.button class="w-64" @click.prevent="raw = !raw">Show Source
|
||||||
|
Compose</x-forms.button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>Volume names are updated upon save. The service UUID will be added as a prefix to all volumes, to prevent
|
||||||
|
name collision. <br>To see the actual volume names, check the Deployable Compose file, or go to Storage
|
||||||
|
menu.</div>
|
||||||
|
|
||||||
|
<div x-cloak x-show="raw" class="font-mono">
|
||||||
|
<x-forms.textarea rows="20" id="service.docker_compose_raw">
|
||||||
|
</x-forms.textarea>
|
||||||
|
</div>
|
||||||
|
<div x-cloak x-show="raw === false" class="font-mono">
|
||||||
|
<x-forms.textarea rows="20" readonly id="service.docker_compose">
|
||||||
|
</x-forms.textarea>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end w-full gap-2">
|
||||||
|
<x-forms.button class="w-64" type="submit">
|
||||||
|
Save
|
||||||
|
</x-forms.button>
|
||||||
|
<x-forms.button wire:click='closeModal'>
|
||||||
|
Close
|
||||||
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
|
</form>
|
@ -1,30 +0,0 @@
|
|||||||
<dialog id="composeModal" class="modal" x-data="{ raw: true }" wire:ignore.self>
|
|
||||||
<form method="dialog" class="flex flex-col gap-2 rounded max-w-7xl modal-box" wire:submit.prevent='submit'>
|
|
||||||
<div class="flex items-end gap-2">
|
|
||||||
<h1>Docker Compose</h1>
|
|
||||||
<div x-cloak x-show="raw">
|
|
||||||
<x-forms.button class="w-64" @click.prevent="raw = !raw">Show Deployable Compose</x-forms.button>
|
|
||||||
</div>
|
|
||||||
<div x-cloak x-show="raw === false">
|
|
||||||
<x-forms.button class="w-64" @click.prevent="raw = !raw">Show Source
|
|
||||||
Compose</x-forms.button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>Volume names are updated upon save. The service UUID will be added as a prefix to all volumes, to prevent name collision. <br>To see the actual volume names, check the Deployable Compose file, or go to Storage menu.</div>
|
|
||||||
|
|
||||||
<div x-cloak x-show="raw">
|
|
||||||
<x-forms.textarea rows="20" id="raw">
|
|
||||||
</x-forms.textarea>
|
|
||||||
</div>
|
|
||||||
<div x-cloak x-show="raw === false">
|
|
||||||
<x-forms.textarea rows="20" readonly id="actual">
|
|
||||||
</x-forms.textarea>
|
|
||||||
</div>
|
|
||||||
<x-forms.button onclick="composeModal.close()" type="submit">
|
|
||||||
Save
|
|
||||||
</x-forms.button>
|
|
||||||
</form>
|
|
||||||
<form method="dialog" class="modal-backdrop">
|
|
||||||
<button>close</button>
|
|
||||||
</form>
|
|
||||||
</dialog>
|
|
@ -1,6 +1,5 @@
|
|||||||
<div x-data="{ raw: true, activeTab: window.location.hash ? window.location.hash.substring(1) : 'service-stack' }" x-init="$wire.checkStatus" wire:poll.10000ms="checkStatus">
|
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'service-stack' }" x-init="$wire.checkStatus" wire:poll.10000ms="checkStatus">
|
||||||
<livewire:project.service.navbar :service="$service" :parameters="$parameters" :query="$query" />
|
<livewire:project.service.navbar :service="$service" :parameters="$parameters" :query="$query" />
|
||||||
<livewire:project.service.compose-modal :raw="$service->docker_compose_raw" :actual="$service->docker_compose" />
|
|
||||||
<div class="flex h-full pt-6">
|
<div class="flex h-full pt-6">
|
||||||
<div class="flex flex-col items-start gap-4 min-w-fit">
|
<div class="flex flex-col items-start gap-4 min-w-fit">
|
||||||
<a target="_blank" href="{{ $service->documentation() }}">Documentation <x-external-link /></a>
|
<a target="_blank" href="{{ $service->documentation() }}">Documentation <x-external-link /></a>
|
||||||
@ -8,6 +7,10 @@
|
|||||||
@click.prevent="activeTab = 'service-stack';
|
@click.prevent="activeTab = 'service-stack';
|
||||||
window.location.hash = 'service-stack'"
|
window.location.hash = 'service-stack'"
|
||||||
href="#">Service Stack</a>
|
href="#">Service Stack</a>
|
||||||
|
<a :class="activeTab === 'execute-command' && 'text-white'"
|
||||||
|
@click.prevent="activeTab = 'execute-command';
|
||||||
|
window.location.hash = 'execute-command'"
|
||||||
|
href="#">Execute Command</a>
|
||||||
<a :class="activeTab === 'storages' && 'text-white'"
|
<a :class="activeTab === 'storages' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'storages';
|
@click.prevent="activeTab = 'storages';
|
||||||
window.location.hash = 'storages'"
|
window.location.hash = 'storages'"
|
||||||
@ -113,6 +116,9 @@ class="hover:text-warning">Logs</span></a>
|
|||||||
<div x-cloak x-show="activeTab === 'webhooks'">
|
<div x-cloak x-show="activeTab === 'webhooks'">
|
||||||
<livewire:project.shared.webhooks :resource="$service" />
|
<livewire:project.shared.webhooks :resource="$service" />
|
||||||
</div>
|
</div>
|
||||||
|
<div x-cloak x-show="activeTab === 'execute-command'">
|
||||||
|
<livewire:project.shared.execute-container-command :resource="$service" />
|
||||||
|
</div>
|
||||||
<div x-cloak x-show="activeTab === 'environment-variables'">
|
<div x-cloak x-show="activeTab === 'environment-variables'">
|
||||||
<div x-cloak x-show="activeTab === 'environment-variables'">
|
<div x-cloak x-show="activeTab === 'environment-variables'">
|
||||||
<livewire:project.shared.environment-variable.all :resource="$service" />
|
<livewire:project.shared.environment-variable.all :resource="$service" />
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
<div>Configuration</div>
|
<div>Configuration</div>
|
||||||
</div>
|
</div>
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
<x-forms.button class="w-64" onclick="composeModal.showModal()">Edit Compose
|
<x-forms.button class="w-64"
|
||||||
|
onclick="Livewire.emit('openModal', 'modals.edit-compose',{{ json_encode(['serviceId' => $service->id]) }})">Edit
|
||||||
|
Compose
|
||||||
File</x-forms.button>
|
File</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
server <span class="px-1 text-warning">{{ data_get($resource, 'destination.server.name') }}</span>
|
server <span class="px-1 text-warning">{{ data_get($resource, 'destination.server.name') }}</span>
|
||||||
in <span class="px-1 text-warning"> {{ data_get($resource, 'destination.network') }} </span> network.</a>
|
in <span class="px-1 text-warning"> {{ data_get($resource, 'destination.network') }} </span> network.</a>
|
||||||
</div>
|
</div>
|
||||||
{{-- {{$resource->additional_destinations}} --}}
|
{{-- Additonal Destinations:
|
||||||
|
{{$resource->additional_destinations}} --}}
|
||||||
{{-- @if (count($servers) > 0)
|
{{-- @if (count($servers) > 0)
|
||||||
<div>
|
<div>
|
||||||
<h3>Additional Servers</h3>
|
<h3>Additional Servers</h3>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
class="font-bold text-warning">({{ $env->key }})</span>?</p>
|
class="font-bold text-warning">({{ $env->key }})</span>?</p>
|
||||||
</x-slot:modalBody>
|
</x-slot:modalBody>
|
||||||
</x-modal>
|
</x-modal>
|
||||||
<form wire:submit.prevent='submit' class="flex flex-col items-center gap-2 xl:flex-row">
|
<form wire:submit.prevent='submit' class="flex flex-col gap-2 p-4 m-2 border lg:items-center border-coolgray-300 lg:m-0 lg:p-0 lg:border-0 lg:flex-row">
|
||||||
@if ($isLocked)
|
@if ($isLocked)
|
||||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
<div>
|
||||||
|
@if ($type === 'application')
|
||||||
|
<h1>Execute Command</h1>
|
||||||
|
<livewire:project.application.heading :application="$resource" />
|
||||||
|
@elseif ($type === 'database')
|
||||||
|
<h1>Execute Command</h1>
|
||||||
|
<livewire:project.database.heading :database="$resource" />
|
||||||
|
@elseif ($type === 'service')
|
||||||
|
<h2>Execute Command</h2>
|
||||||
|
@endif
|
||||||
|
@if (count($containers) > 0)
|
||||||
|
<form class="flex flex-col gap-2 pt-4" wire:submit.prevent='runCommand'>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<x-forms.input placeholder="ls -l" autofocus id="command" label="Command" required />
|
||||||
|
<x-forms.input id="workDir" label="Working directory" />
|
||||||
|
</div>
|
||||||
|
<x-forms.select label="Container" id="container" required>
|
||||||
|
<option disabled selected>Select container</option>
|
||||||
|
@foreach ($containers as $container)
|
||||||
|
<option value="{{ $container }}">{{ $container }}</option>
|
||||||
|
@endforeach
|
||||||
|
</x-forms.select>
|
||||||
|
<x-forms.button type="submit">Run</x-forms.button>
|
||||||
|
</form>
|
||||||
|
@else
|
||||||
|
<div class="pt-4">No containers are not running.</div>
|
||||||
|
@endif
|
||||||
|
<div class="container w-full pt-10 mx-auto">
|
||||||
|
<livewire:activity-monitor header="Command output" />
|
||||||
|
</div>
|
||||||
|
</div>
|
57
resources/views/vendor/livewire-ui-modal/modal.blade.php
vendored
Normal file
57
resources/views/vendor/livewire-ui-modal/modal.blade.php
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<div>
|
||||||
|
@isset($jsPath)
|
||||||
|
<script>{!! file_get_contents($jsPath) !!}</script>
|
||||||
|
@endisset
|
||||||
|
@isset($cssPath)
|
||||||
|
<style>{!! file_get_contents($cssPath) !!}</style>
|
||||||
|
@endisset
|
||||||
|
|
||||||
|
<div
|
||||||
|
x-data="LivewireUIModal()"
|
||||||
|
x-init="init()"
|
||||||
|
x-on:close.stop="setShowPropertyTo(false)"
|
||||||
|
x-on:keydown.escape.window="closeModalOnEscape()"
|
||||||
|
x-show="show"
|
||||||
|
class="fixed inset-0 z-40 overflow-y-auto"
|
||||||
|
style="display: none;"
|
||||||
|
>
|
||||||
|
<div class="flex items-end justify-center px-4 pt-4 pb-10 text-center sm:block sm:p-0">
|
||||||
|
<div
|
||||||
|
x-show="show"
|
||||||
|
x-on:click="closeModalOnClickAway()"
|
||||||
|
x-transition:enter="ease-out duration-300"
|
||||||
|
x-transition:enter-start="opacity-0"
|
||||||
|
x-transition:enter-end="opacity-100"
|
||||||
|
x-transition:leave="ease-in duration-200"
|
||||||
|
x-transition:leave-start="opacity-100"
|
||||||
|
x-transition:leave-end="opacity-0"
|
||||||
|
class="fixed inset-0 transition-all transform"
|
||||||
|
>
|
||||||
|
<div class="absolute inset-0 bg-black opacity-70"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span> --}}
|
||||||
|
|
||||||
|
<div
|
||||||
|
x-show="show && showActiveComponent"
|
||||||
|
x-transition:enter="ease-out duration-200"
|
||||||
|
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
|
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
|
||||||
|
x-transition:leave="ease-in duration-200"
|
||||||
|
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
|
||||||
|
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
|
class="w-full overflow-hidden text-left align-bottom transition-all transform sm:my-8 sm:align-middle sm:w-full"
|
||||||
|
id="modal-container"
|
||||||
|
x-trap.noscroll.inert="show && showActiveComponent"
|
||||||
|
aria-modal="true"
|
||||||
|
>
|
||||||
|
@forelse($components as $id => $component)
|
||||||
|
<div class="sm:mx-20" x-show.immediate="activeComponent == '{{ $id }}'" x-ref="{{ $id }}" wire:key="{{ $id }}">
|
||||||
|
@livewire($component['name'], $component['attributes'], key($id))
|
||||||
|
</div>
|
||||||
|
@empty
|
||||||
|
@endforelse
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -11,6 +11,13 @@
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
|
use App\Models\Application;
|
||||||
// return (int) $user->id === (int) $id;
|
use App\Models\User;
|
||||||
// });
|
use Illuminate\Support\Facades\Broadcast;
|
||||||
|
|
||||||
|
Broadcast::channel('custom.{teamId}', function (User $user, int $teamId) {
|
||||||
|
if ($user->teams->pluck('id')->contains($teamId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
use App\Http\Livewire\Dev\Compose as Compose;
|
use App\Http\Livewire\Dev\Compose as Compose;
|
||||||
use App\Http\Livewire\Dashboard;
|
use App\Http\Livewire\Dashboard;
|
||||||
use App\Http\Livewire\Project\CloneProject;
|
use App\Http\Livewire\Project\CloneProject;
|
||||||
|
use App\Http\Livewire\Project\Shared\ExecuteContainerCommand;
|
||||||
use App\Http\Livewire\Project\Shared\Logs;
|
use App\Http\Livewire\Project\Shared\Logs;
|
||||||
use App\Http\Livewire\Security\ApiTokens;
|
use App\Http\Livewire\Security\ApiTokens;
|
||||||
use App\Http\Livewire\Server\All;
|
use App\Http\Livewire\Server\All;
|
||||||
@ -42,6 +43,16 @@
|
|||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
Route::get('/dev/compose', Compose::class)->name('dev.compose');
|
Route::get('/dev/compose', Compose::class)->name('dev.compose');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Route::get('/api/v1/test/realtime', function () {
|
||||||
|
if (auth()->user()?->currentTeam()->id !== 0) {
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
event(new \App\Events\TestEvent());
|
||||||
|
return 'Look at your other tab.';
|
||||||
|
})->middleware('auth');
|
||||||
|
|
||||||
|
|
||||||
Route::post('/forgot-password', function (Request $request) {
|
Route::post('/forgot-password', function (Request $request) {
|
||||||
if (is_transactional_emails_active()) {
|
if (is_transactional_emails_active()) {
|
||||||
$arrayOfRequest = $request->only(Fortify::email());
|
$arrayOfRequest = $request->only(Fortify::email());
|
||||||
@ -111,18 +122,21 @@
|
|||||||
)->name('project.application.deployment');
|
)->name('project.application.deployment');
|
||||||
|
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}/logs', Logs::class)->name('project.application.logs');
|
Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}/logs', Logs::class)->name('project.application.logs');
|
||||||
|
Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}/command', ExecuteContainerCommand::class)->name('project.application.command');
|
||||||
|
|
||||||
// Databases
|
// Databases
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}', [DatabaseController::class, 'configuration'])->name('project.database.configuration');
|
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}', [DatabaseController::class, 'configuration'])->name('project.database.configuration');
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/backups', [DatabaseController::class, 'backups'])->name('project.database.backups.all');
|
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/backups', [DatabaseController::class, 'backups'])->name('project.database.backups.all');
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/backups/{backup_uuid}', [DatabaseController::class, 'executions'])->name('project.database.backups.executions');
|
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/backups/{backup_uuid}', [DatabaseController::class, 'executions'])->name('project.database.backups.executions');
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/logs', Logs::class)->name('project.database.logs');
|
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/logs', Logs::class)->name('project.database.logs');
|
||||||
|
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/command', ExecuteContainerCommand::class)->name('project.database.command');
|
||||||
|
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}', ServiceIndex::class)->name('project.service.configuration');
|
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}', ServiceIndex::class)->name('project.service.configuration');
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/{service_name}', ServiceShow::class)->name('project.service.show');
|
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/{service_name}', ServiceShow::class)->name('project.service.show');
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/{service_name}/logs', Logs::class)->name('project.service.logs');
|
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/{service_name}/logs', Logs::class)->name('project.service.logs');
|
||||||
|
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/command', ExecuteContainerCommand::class)->name('project.service.command');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['auth'])->group(function () {
|
Route::middleware(['auth'])->group(function () {
|
||||||
|
@ -137,6 +137,9 @@ if [ ! -f /data/coolify/source/.env ]; then
|
|||||||
sed -i "s|APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
sed -i "s|APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||||
sed -i "s|DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
sed -i "s|DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||||
sed -i "s|REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
sed -i "s|REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||||
|
sed -i "s|PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||||
|
sed -i "s|PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||||
|
sed -i "s|PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Merge .env and .env.production. New values will be added to .env
|
# Merge .env and .env.production. New values will be added to .env
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
## Do not modify this file. You will lost the ability to autoupdate!
|
## Do not modify this file. You will lost the ability to autoupdate!
|
||||||
|
|
||||||
###########
|
VERSION="1.0.4"
|
||||||
## Always run "php artisan app:sync-to-bunny-cdn --env=secrets" if you update this file.
|
|
||||||
###########
|
|
||||||
|
|
||||||
VERSION="1.0.1"
|
|
||||||
CDN="https://cdn.coollabs.io/coolify"
|
CDN="https://cdn.coollabs.io/coolify"
|
||||||
|
|
||||||
curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
||||||
@ -15,8 +11,26 @@ curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
|||||||
# Merge .env and .env.production. New values will be added to .env
|
# Merge .env and .env.production. New values will be added to .env
|
||||||
sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' >/data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env
|
sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' >/data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env
|
||||||
|
|
||||||
|
# Check if PUSHER_APP_ID or PUSHER_APP_KEY or PUSHER_APP_SECRET is empty in /data/coolify/source/.env
|
||||||
|
if grep -q "PUSHER_APP_ID=$" /data/coolify/source/.env; then
|
||||||
|
sed -i "s|PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q "PUSHER_APP_KEY=$" /data/coolify/source/.env; then
|
||||||
|
sed -i "s|PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q "PUSHER_APP_SECRET=$" /data/coolify/source/.env; then
|
||||||
|
sed -i "s|PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||||
|
fi
|
||||||
|
|
||||||
# Make sure coolify network exists
|
# Make sure coolify network exists
|
||||||
docker network create --attachable coolify 2>/dev/null
|
docker network create --attachable coolify 2>/dev/null
|
||||||
# docker network create --attachable --driver=overlay coolify-overlay 2>/dev/null
|
# docker network create --attachable --driver=overlay coolify-overlay 2>/dev/null
|
||||||
|
|
||||||
|
if [ -f /data/coolify/source/docker-compose.custom.yml ]; then
|
||||||
|
echo "docker-compose.custom.yml detected."
|
||||||
|
docker run --pull always -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper bash -c "LATEST_IMAGE=${1:-} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml -f /data/coolify/source/docker-compose.custom.yml up -d --pull always --remove-orphans --force-recreate"
|
||||||
|
else
|
||||||
docker run --pull always -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper bash -c "LATEST_IMAGE=${1:-} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml up -d --pull always --remove-orphans --force-recreate"
|
docker run --pull always -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper bash -c "LATEST_IMAGE=${1:-} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml up -d --pull always --remove-orphans --force-recreate"
|
||||||
|
fi
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: [
|
content: [
|
||||||
|
'./vendor/wire-elements/modal/resources/views/*.blade.php',
|
||||||
|
'./storage/framework/views/*.php',
|
||||||
"./resources/**/*.blade.php",
|
"./resources/**/*.blade.php",
|
||||||
"./app/**/*.php",
|
"./app/**/*.php",
|
||||||
"./resources/**/*.js",
|
"./resources/**/*.js",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"version": "3.12.36"
|
"version": "3.12.36"
|
||||||
},
|
},
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.153"
|
"version": "4.0.0-beta.154"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user