diff --git a/app/Actions/Queue/CreateQueue.php b/app/Actions/Queue/CreateQueue.php
index 29809ba..68efde0 100644
--- a/app/Actions/Queue/CreateQueue.php
+++ b/app/Actions/Queue/CreateQueue.php
@@ -6,7 +6,7 @@
use App\Models\Queue;
use App\Models\Server;
use App\Models\Site;
-use Illuminate\Support\Facades\Validator;
+use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
class CreateQueue
@@ -16,15 +16,13 @@ class CreateQueue
*/
public function create(mixed $queueable, array $input): void
{
- $this->validate($input);
-
$queue = new Queue([
'server_id' => $queueable instanceof Server ? $queueable->id : $queueable->server_id,
'site_id' => $queueable instanceof Site ? $queueable->id : null,
'command' => $input['command'],
'user' => $input['user'],
- 'auto_start' => $input['auto_start'],
- 'auto_restart' => $input['auto_restart'],
+ 'auto_start' => $input['auto_start'] ? 1 : 0,
+ 'auto_restart' => $input['auto_restart'] ? 1 : 0,
'numprocs' => $input['numprocs'],
'status' => QueueStatus::CREATING,
]);
@@ -48,26 +46,18 @@ public function create(mixed $queueable, array $input): void
})->onConnection('ssh');
}
- /**
- * @throws ValidationException
- */
- protected function validate(array $input): void
+ public static function rules(Server $server): array
{
- $rules = [
+ return [
'command' => [
'required',
],
'user' => [
'required',
- 'in:root,'.config('core.ssh_user'),
- ],
- 'auto_start' => [
- 'required',
- 'in:0,1',
- ],
- 'auto_restart' => [
- 'required',
- 'in:0,1',
+ Rule::in([
+ 'root',
+ $server->ssh_user,
+ ]),
],
'numprocs' => [
'required',
@@ -75,7 +65,5 @@ protected function validate(array $input): void
'min:1',
],
];
-
- Validator::make($input, $rules)->validate();
}
}
diff --git a/app/Actions/Queue/DeleteQueue.php b/app/Actions/Queue/DeleteQueue.php
index 03af4af..eb6a152 100644
--- a/app/Actions/Queue/DeleteQueue.php
+++ b/app/Actions/Queue/DeleteQueue.php
@@ -3,12 +3,15 @@
namespace App\Actions\Queue;
use App\Models\Queue;
+use App\SSH\Services\ProcessManager\ProcessManager;
class DeleteQueue
{
public function delete(Queue $queue): void
{
- $queue->server->processManager()->handler()->delete($queue->id, $queue->site_id);
+ /** @var ProcessManager $processManager */
+ $processManager = $queue->server->processManager()->handler();
+ $processManager->delete($queue->id, $queue->site_id);
$queue->delete();
}
}
diff --git a/app/Actions/Queue/EditQueue.php b/app/Actions/Queue/EditQueue.php
new file mode 100644
index 0000000..a035e99
--- /dev/null
+++ b/app/Actions/Queue/EditQueue.php
@@ -0,0 +1,72 @@
+fill([
+ 'command' => $input['command'],
+ 'user' => $input['user'],
+ 'auto_start' => $input['auto_start'] ? 1 : 0,
+ 'auto_restart' => $input['auto_restart'] ? 1 : 0,
+ 'numprocs' => $input['numprocs'],
+ 'status' => QueueStatus::RESTARTING,
+ ]);
+ $queue->save();
+
+ dispatch(function () use ($queue) {
+ /** @var ProcessManager $processManager */
+ $processManager = $queue->server->processManager()->handler();
+ $processManager->delete($queue->id, $queue->site_id);
+
+ $processManager->create(
+ $queue->id,
+ $queue->command,
+ $queue->user,
+ $queue->auto_start,
+ $queue->auto_restart,
+ $queue->numprocs,
+ $queue->getLogFile(),
+ $queue->site_id
+ );
+ $queue->status = QueueStatus::RUNNING;
+ $queue->save();
+ })->catch(function () use ($queue) {
+ $queue->status = QueueStatus::FAILED;
+ $queue->save();
+ })->onConnection('ssh');
+ }
+
+ public static function rules(Server $server): array
+ {
+ return [
+ 'command' => [
+ 'required',
+ ],
+ 'user' => [
+ 'required',
+ Rule::in([
+ 'root',
+ $server->ssh_user,
+ ]),
+ ],
+ 'numprocs' => [
+ 'required',
+ 'numeric',
+ 'min:1',
+ ],
+ ];
+ }
+}
diff --git a/app/Actions/SSL/CreateSSL.php b/app/Actions/SSL/CreateSSL.php
index 427540f..d67e126 100644
--- a/app/Actions/SSL/CreateSSL.php
+++ b/app/Actions/SSL/CreateSSL.php
@@ -4,10 +4,10 @@
use App\Enums\SslStatus;
use App\Enums\SslType;
+use App\Models\ServerLog;
use App\Models\Site;
use App\Models\Ssl;
use App\SSH\Services\Webserver\Webserver;
-use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
@@ -18,7 +18,10 @@ class CreateSSL
*/
public function create(Site $site, array $input): void
{
- $this->validate($input);
+ $site->ssls()
+ ->where('type', $input['type'])
+ ->where('status', SslStatus::FAILED)
+ ->delete();
$ssl = new Ssl([
'site_id' => $site->id,
@@ -32,6 +35,7 @@ public function create(Site $site, array $input): void
if (isset($input['aliases']) && $input['aliases']) {
$ssl->domains = array_merge($ssl->domains, $site->aliases);
}
+ $ssl->log_id = ServerLog::log($site->server, 'create-ssl', '', $site)->id;
$ssl->save();
dispatch(function () use ($site, $ssl) {
@@ -47,10 +51,7 @@ public function create(Site $site, array $input): void
})->onConnection('ssh');
}
- /**
- * @throws ValidationException
- */
- protected function validate(array $input): void
+ public static function rules(array $input): array
{
$rules = [
'type' => [
@@ -61,9 +62,13 @@ protected function validate(array $input): void
if (isset($input['type']) && $input['type'] == SslType::CUSTOM) {
$rules['certificate'] = 'required';
$rules['private'] = 'required';
- $rules['expires_at'] = 'required|date_format:Y-m-d|after_or_equal:'.now();
+ $rules['expires_at'] = [
+ 'required',
+ 'date_format:Y-m-d',
+ 'after_or_equal:'.now(),
+ ];
}
- Validator::make($input, $rules)->validate();
+ return $rules;
}
}
diff --git a/app/Actions/SSL/DeleteSSL.php b/app/Actions/SSL/DeleteSSL.php
index 82e06e8..12a4caf 100644
--- a/app/Actions/SSL/DeleteSSL.php
+++ b/app/Actions/SSL/DeleteSSL.php
@@ -3,12 +3,15 @@
namespace App\Actions\SSL;
use App\Models\Ssl;
+use App\SSH\Services\Webserver\Webserver;
class DeleteSSL
{
public function delete(Ssl $ssl): void
{
- $ssl->site->server->webserver()->handler()->removeSSL($ssl);
+ /** @var Webserver $webserver */
+ $webserver = $ssl->site->server->webserver()->handler();
+ $webserver->removeSSL($ssl);
$ssl->delete();
}
}
diff --git a/app/Helpers/SSH.php b/app/Helpers/SSH.php
index 4b872f7..6322894 100755
--- a/app/Helpers/SSH.php
+++ b/app/Helpers/SSH.php
@@ -51,7 +51,7 @@ public function init(Server $server, ?string $asUser = null): self
return $this;
}
- public function setLog(ServerLog $log): self
+ public function setLog(?ServerLog $log): self
{
$this->log = $log;
@@ -93,7 +93,6 @@ public function connect(bool $sftp = false): void
*/
public function exec(string $command, string $log = '', ?int $siteId = null, ?bool $stream = false, ?callable $streamCallback = null): string
{
- ds($command);
if (! $this->log && $log) {
$this->log = ServerLog::make($this->server, $log);
if ($siteId) {
diff --git a/app/Models/Queue.php b/app/Models/Queue.php
index 56aeb56..c98fd50 100644
--- a/app/Models/Queue.php
+++ b/app/Models/Queue.php
@@ -2,6 +2,7 @@
namespace App\Models;
+use App\Enums\QueueStatus;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -45,6 +46,17 @@ class Queue extends AbstractModel
'redirect_stderr' => 'boolean',
];
+ public static array $statusColors = [
+ QueueStatus::RUNNING => 'success',
+ QueueStatus::CREATING => 'warning',
+ QueueStatus::DELETING => 'warning',
+ QueueStatus::FAILED => 'danger',
+ QueueStatus::STARTING => 'warning',
+ QueueStatus::STOPPING => 'warning',
+ QueueStatus::RESTARTING => 'warning',
+ QueueStatus::STOPPED => 'gray',
+ ];
+
public function getServerIdAttribute(int $value): int
{
if (! $value) {
diff --git a/app/Models/ServerLog.php b/app/Models/ServerLog.php
index 33728d3..730357a 100755
--- a/app/Models/ServerLog.php
+++ b/app/Models/ServerLog.php
@@ -114,7 +114,7 @@ public function getContent($lines = null): ?string
return '';
}
- public static function log(Server $server, string $type, string $content, ?Site $site = null): void
+ public static function log(Server $server, string $type, string $content, ?Site $site = null): static
{
$log = new static([
'server_id' => $server->id,
@@ -125,6 +125,8 @@ public static function log(Server $server, string $type, string $content, ?Site
]);
$log->save();
$log->write($content);
+
+ return $log;
}
public static function make(Server $server, string $type): ServerLog
diff --git a/app/Models/Ssl.php b/app/Models/Ssl.php
index 990f950..cb16017 100644
--- a/app/Models/Ssl.php
+++ b/app/Models/Ssl.php
@@ -2,6 +2,7 @@
namespace App\Models;
+use App\Enums\SslStatus;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -18,6 +19,8 @@
* @property Site $site
* @property string $ca_path
* @property ?array $domains
+ * @property int $log_id
+ * @property ?ServerLog $log
*/
class Ssl extends AbstractModel
{
@@ -32,6 +35,7 @@ class Ssl extends AbstractModel
'expires_at',
'status',
'domains',
+ 'log_id',
];
protected $casts = [
@@ -41,6 +45,14 @@ class Ssl extends AbstractModel
'ca' => 'encrypted',
'expires_at' => 'datetime',
'domains' => 'array',
+ 'log_id' => 'integer',
+ ];
+
+ public static array $statusColors = [
+ SslStatus::CREATED => 'success',
+ SslStatus::CREATING => 'warning',
+ SslStatus::DELETING => 'warning',
+ SslStatus::FAILED => 'danger',
];
public function site(): BelongsTo
@@ -126,4 +138,9 @@ public function getDomains(): array
return $this->domains;
}
+
+ public function log(): BelongsTo
+ {
+ return $this->belongsTo(ServerLog::class);
+ }
}
diff --git a/app/Policies/QueuePolicy.php b/app/Policies/QueuePolicy.php
new file mode 100644
index 0000000..e9ceca2
--- /dev/null
+++ b/app/Policies/QueuePolicy.php
@@ -0,0 +1,55 @@
+isAdmin() || $server->project->users->contains($user)) &&
+ $server->isReady() &&
+ $site->isReady();
+ }
+
+ public function view(User $user, Queue $queue, Site $site, Server $server): bool
+ {
+ return ($user->isAdmin() || $server->project->users->contains($user)) &&
+ $site->server_id === $server->id &&
+ $server->isReady() &&
+ $site->isReady() &&
+ $queue->site_id === $site->id;
+ }
+
+ public function create(User $user, Site $site, Server $server): bool
+ {
+ return ($user->isAdmin() || $server->project->users->contains($user)) &&
+ $server->isReady() &&
+ $site->isReady();
+ }
+
+ public function update(User $user, Queue $queue, Site $site, Server $server): bool
+ {
+ return ($user->isAdmin() || $server->project->users->contains($user)) &&
+ $site->server_id === $server->id &&
+ $server->isReady() &&
+ $site->isReady() &&
+ $queue->site_id === $site->id;
+ }
+
+ public function delete(User $user, Queue $queue, Site $site, Server $server): bool
+ {
+ return ($user->isAdmin() || $server->project->users->contains($user)) &&
+ $site->server_id === $server->id &&
+ $server->isReady() &&
+ $site->isReady() &&
+ $queue->site_id === $site->id;
+ }
+}
diff --git a/app/Policies/ServicePolicy.php b/app/Policies/ServicePolicy.php
index e4d7f8d..d14e896 100644
--- a/app/Policies/ServicePolicy.php
+++ b/app/Policies/ServicePolicy.php
@@ -2,7 +2,6 @@
namespace App\Policies;
-use App\Enums\ServiceStatus;
use App\Models\Server;
use App\Models\Service;
use App\Models\User;
@@ -36,52 +35,4 @@ public function delete(User $user, Service $service): bool
{
return ($user->isAdmin() || $service->server->project->users->contains($user)) && $service->server->isReady();
}
-
- public function start(User $user, Service $service): bool
- {
- return ($user->isAdmin() || $service->server->project->users->contains($user)) &&
- $service->server->isReady() &&
- in_array($service->status, [
- ServiceStatus::STOPPED,
- ServiceStatus::FAILED,
- ]);
- }
-
- public function stop(User $user, Service $service): bool
- {
- return ($user->isAdmin() || $service->server->project->users->contains($user)) &&
- $service->server->isReady() &&
- in_array($service->status, [
- ServiceStatus::READY,
- ServiceStatus::FAILED,
- ]);
- }
-
- public function restart(User $user, Service $service): bool
- {
- return ($user->isAdmin() || $service->server->project->users->contains($user)) &&
- $service->server->isReady() &&
- in_array($service->status, [
- ServiceStatus::READY,
- ServiceStatus::FAILED,
- ServiceStatus::STOPPED,
- ]);
- }
-
- public function enable(User $user, Service $service): bool
- {
- return ($user->isAdmin() || $service->server->project->users->contains($user)) &&
- $service->server->isReady() &&
- $service->status == ServiceStatus::DISABLED;
- }
-
- public function disable(User $user, Service $service): bool
- {
- return ($user->isAdmin() || $service->server->project->users->contains($user)) &&
- $service->server->isReady() &&
- in_array($service->status, [
- ServiceStatus::READY,
- ServiceStatus::STOPPED,
- ]);
- }
}
diff --git a/app/Policies/SslPolicy.php b/app/Policies/SslPolicy.php
new file mode 100644
index 0000000..2e7c677
--- /dev/null
+++ b/app/Policies/SslPolicy.php
@@ -0,0 +1,55 @@
+isAdmin() || $server->project->users->contains($user)) &&
+ $server->isReady() &&
+ $site->isReady();
+ }
+
+ public function view(User $user, Ssl $ssl, Site $site, Server $server): bool
+ {
+ return ($user->isAdmin() || $server->project->users->contains($user)) &&
+ $site->server_id === $server->id &&
+ $server->isReady() &&
+ $site->isReady() &&
+ $ssl->site_id === $site->id;
+ }
+
+ public function create(User $user, Site $site, Server $server): bool
+ {
+ return ($user->isAdmin() || $server->project->users->contains($user)) &&
+ $server->isReady() &&
+ $site->isReady();
+ }
+
+ public function update(User $user, Ssl $ssl, Site $site, Server $server): bool
+ {
+ return ($user->isAdmin() || $server->project->users->contains($user)) &&
+ $site->server_id === $server->id &&
+ $server->isReady() &&
+ $site->isReady() &&
+ $ssl->site_id === $site->id;
+ }
+
+ public function delete(User $user, Ssl $ssl, Site $site, Server $server): bool
+ {
+ return ($user->isAdmin() || $server->project->users->contains($user)) &&
+ $site->server_id === $server->id &&
+ $server->isReady() &&
+ $site->isReady() &&
+ $ssl->site_id === $site->id;
+ }
+}
diff --git a/app/SSH/Services/Webserver/Nginx.php b/app/SSH/Services/Webserver/Nginx.php
index aca3000..f1e749b 100755
--- a/app/SSH/Services/Webserver/Nginx.php
+++ b/app/SSH/Services/Webserver/Nginx.php
@@ -2,6 +2,7 @@
namespace App\SSH\Services\Webserver;
+use App\Exceptions\SSHError;
use App\Exceptions\SSLCreationException;
use App\Models\Site;
use App\Models\Ssl;
@@ -113,7 +114,7 @@ public function changePHPVersion(Site $site, $version): void
}
/**
- * @throws SSLCreationException
+ * @throws SSHError
*/
public function setupSSL(Ssl $ssl): void
{
@@ -136,7 +137,7 @@ public function setupSSL(Ssl $ssl): void
'pk_path' => $ssl->getPkPath(),
]);
}
- $result = $this->service->server->ssh()->exec(
+ $result = $this->service->server->ssh()->setLog($ssl->log)->exec(
$command,
'create-ssl',
$ssl->site_id
diff --git a/app/Support/helpers.php b/app/Support/helpers.php
index 884724b..735f92b 100755
--- a/app/Support/helpers.php
+++ b/app/Support/helpers.php
@@ -2,6 +2,7 @@
use App\Exceptions\SSHError;
use App\Helpers\HtmxResponse;
+use Filament\Notifications\Actions\Action;
use Filament\Notifications\Notification;
function generate_public_key($privateKeyPath, $publicKeyPath): void
@@ -67,6 +68,13 @@ function run_action(object $static, Closure $callback): void
->danger()
->title($e->getMessage())
->body($e->getLog()?->getContent(30))
+ ->actions([
+ Action::make('View Logs')
+ ->url(App\Web\Pages\Servers\Logs\Index::getUrl([
+ 'server' => $e->getLog()?->server_id,
+ ]))
+ ->openUrlInNewTab(),
+ ])
->send();
if (method_exists($static, 'halt')) {
diff --git a/app/Web/Pages/Servers/CronJobs/Index.php b/app/Web/Pages/Servers/CronJobs/Index.php
index 15e1fee..605ef50 100644
--- a/app/Web/Pages/Servers/CronJobs/Index.php
+++ b/app/Web/Pages/Servers/CronJobs/Index.php
@@ -56,7 +56,7 @@ protected function getHeaderActions(): array
Select::make('user')
->rules(fn (callable $get) => CreateCronJob::rules($get())['user'])
->options([
- 'vito' => 'vito',
+ 'vito' => $this->server->ssh_user,
'root' => 'root',
]),
Select::make('frequency')
diff --git a/app/Web/Pages/Servers/Index.php b/app/Web/Pages/Servers/Index.php
index 3d1ed06..41f40d8 100644
--- a/app/Web/Pages/Servers/Index.php
+++ b/app/Web/Pages/Servers/Index.php
@@ -16,7 +16,6 @@
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Support\Enums\MaxWidth;
-use Throwable;
class Index extends Page
{
@@ -228,21 +227,12 @@ protected function getHeaderActions(): array
]),
])
->modalSubmitActionLabel('Create')
- ->action(function ($input) {
- $this->authorize('create', Server::class);
-
- $this->validate();
-
- try {
- $server = app(CreateServerAction::class)->create(auth()->user(), $input);
+ ->action(function (array $data) {
+ run_action($this, function () use ($data) {
+ $server = app(CreateServerAction::class)->create(auth()->user(), $data);
$this->redirect(View::getUrl(['server' => $server]));
- } catch (Throwable $e) {
- Notification::make()
- ->title($e->getMessage())
- ->danger()
- ->send();
- }
+ });
}),
];
}
diff --git a/app/Web/Pages/Servers/Logs/Widgets/LogsList.php b/app/Web/Pages/Servers/Logs/Widgets/LogsList.php
index ac52f16..5523fa1 100644
--- a/app/Web/Pages/Servers/Logs/Widgets/LogsList.php
+++ b/app/Web/Pages/Servers/Logs/Widgets/LogsList.php
@@ -26,6 +26,8 @@ class LogsList extends Widget
public ?string $label = '';
+ protected $listeners = ['$refresh'];
+
protected function getTableQuery(): Builder
{
return ServerLog::query()
diff --git a/app/Web/Pages/Servers/Services/Widgets/ServicesList.php b/app/Web/Pages/Servers/Services/Widgets/ServicesList.php
index 3219815..76438c7 100644
--- a/app/Web/Pages/Servers/Services/Widgets/ServicesList.php
+++ b/app/Web/Pages/Servers/Services/Widgets/ServicesList.php
@@ -11,7 +11,7 @@
use Filament\Notifications\Notification;
use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\ActionGroup;
-use Filament\Tables\Columns\ImageColumn;
+use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Filament\Widgets\TableWidget;
@@ -33,9 +33,10 @@ protected function getTableQuery(): Builder
protected function getTableColumns(): array
{
return [
- ImageColumn::make('image_url')
+ IconColumn::make('id')
->label('Service')
- ->size(24),
+ ->icon(fn (Service $record) => 'icon-'.$record->name)
+ ->width(24),
TextColumn::make('name')
->sortable(),
TextColumn::make('version')
@@ -59,21 +60,22 @@ public function getTable(): Table
return $this->table
->actions([
ActionGroup::make([
- $this->serviceAction('start'),
- $this->serviceAction('stop'),
- $this->serviceAction('restart'),
- $this->serviceAction('disable'),
- $this->serviceAction('enable'),
+ $this->serviceAction('start', 'heroicon-o-play'),
+ $this->serviceAction('stop', 'heroicon-o-stop'),
+ $this->serviceAction('restart', 'heroicon-o-arrow-path'),
+ $this->serviceAction('disable', 'heroicon-o-x-mark'),
+ $this->serviceAction('enable', 'heroicon-o-check'),
$this->uninstallAction(),
]),
]);
}
- private function serviceAction(string $type): Action
+ private function serviceAction(string $type, string $icon): Action
{
return Action::make($type)
- ->authorize(fn (Service $service) => auth()->user()?->can($type, $service))
+ ->authorize(fn (Service $service) => auth()->user()?->can('update', $service))
->label(ucfirst($type).' Service')
+ ->icon($icon)
->action(function (Service $service) use ($type) {
try {
app(Manage::class)->$type($service);
@@ -95,6 +97,7 @@ private function uninstallAction(): Action
return Action::make('uninstall')
->authorize(fn (Service $service) => auth()->user()?->can('delete', $service))
->label('Uninstall Service')
+ ->icon('heroicon-o-trash')
->color('danger')
->requiresConfirmation()
->action(function (Service $service) {
diff --git a/app/Web/Pages/Servers/Sites/Pages/Queues/Index.php b/app/Web/Pages/Servers/Sites/Pages/Queues/Index.php
index e711b07..f6c9f5f 100644
--- a/app/Web/Pages/Servers/Sites/Pages/Queues/Index.php
+++ b/app/Web/Pages/Servers/Sites/Pages/Queues/Index.php
@@ -2,7 +2,15 @@
namespace App\Web\Pages\Servers\Sites\Pages\Queues;
+use App\Actions\Queue\CreateQueue;
use App\Web\Pages\Servers\Sites\Page;
+use Filament\Actions\Action;
+use Filament\Actions\CreateAction;
+use Filament\Forms\Components\Checkbox;
+use Filament\Forms\Components\Grid;
+use Filament\Forms\Components\Select;
+use Filament\Forms\Components\TextInput;
+use Filament\Support\Enums\MaxWidth;
class Index extends Page
{
@@ -17,6 +25,54 @@ public static function canAccess(): bool
public function getWidgets(): array
{
- return [];
+ return [
+ [Widgets\QueuesList::class, ['site' => $this->site]],
+ ];
+ }
+
+ protected function getHeaderActions(): array
+ {
+ return [
+ Action::make('read-the-docs')
+ ->label('Read the Docs')
+ ->icon('heroicon-o-document-text')
+ ->color('gray')
+ ->url('https://vitodeploy.com/sites/queues.html')
+ ->openUrlInNewTab(),
+ CreateAction::make('create')
+ ->icon('heroicon-o-plus')
+ ->createAnother(false)
+ ->modalWidth(MaxWidth::ExtraLarge)
+ ->label('New Queue')
+ ->form([
+ TextInput::make('command')
+ ->rules(CreateQueue::rules($this->server)['command'])
+ ->helperText('Example: php /home/vito/your-site/artisan queue:work'),
+ Select::make('user')
+ ->rules(fn (callable $get) => CreateQueue::rules($this->server)['user'])
+ ->options([
+ 'vito' => $this->server->ssh_user,
+ 'root' => 'root',
+ ]),
+ TextInput::make('numprocs')
+ ->default(1)
+ ->rules(CreateQueue::rules($this->server)['numprocs'])
+ ->helperText('Number of processes'),
+ Grid::make()
+ ->schema([
+ Checkbox::make('auto_start')
+ ->default(false),
+ Checkbox::make('auto_restart')
+ ->default(false),
+ ]),
+ ])
+ ->using(function (array $data) {
+ run_action($this, function () use ($data) {
+ app(CreateQueue::class)->create($this->site, $data);
+
+ $this->dispatch('$refresh');
+ });
+ }),
+ ];
}
}
diff --git a/app/Web/Pages/Servers/Sites/Pages/Queues/Widgets/QueuesList.php b/app/Web/Pages/Servers/Sites/Pages/Queues/Widgets/QueuesList.php
new file mode 100644
index 0000000..23eb5cf
--- /dev/null
+++ b/app/Web/Pages/Servers/Sites/Pages/Queues/Widgets/QueuesList.php
@@ -0,0 +1,160 @@
+where('site_id', $this->site->id);
+ }
+
+ protected static ?string $heading = '';
+
+ protected function getTableColumns(): array
+ {
+ return [
+ TextColumn::make('command')
+ ->limit(20)
+ ->copyable()
+ ->tooltip(fn (Queue $record) => $record->command)
+ ->searchable()
+ ->sortable(),
+ TextColumn::make('created_at')
+ ->formatStateUsing(fn (Queue $record) => $record->created_at_by_timezone)
+ ->sortable(),
+ TextColumn::make('status')
+ ->label('Status')
+ ->badge()
+ ->color(fn (Queue $record) => Queue::$statusColors[$record->status])
+ ->searchable()
+ ->sortable(),
+ ];
+ }
+
+ public function getTable(): Table
+ {
+ return $this->table
+ ->actions([
+ ActionGroup::make([
+ $this->editAction(),
+ $this->operationAction('start', 'heroicon-o-play'),
+ $this->operationAction('stop', 'heroicon-o-stop'),
+ $this->operationAction('restart', 'heroicon-o-arrow-path'),
+ $this->logsAction(),
+ $this->deleteAction(),
+ ]),
+ ]);
+ }
+
+ private function operationAction(string $type, string $icon): Action
+ {
+ return Action::make($type)
+ ->authorize(fn (Queue $record) => auth()->user()->can('update', [$record, $this->site, $this->site->server]))
+ ->label(ucfirst($type).' queue')
+ ->icon($icon)
+ ->action(function (Queue $record) use ($type) {
+ run_action($this, function () use ($record, $type) {
+ app(ManageQueue::class)->$type($record);
+ $this->dispatch('$refresh');
+ });
+ });
+ }
+
+ private function logsAction(): Action
+ {
+ return Action::make('logs')
+ ->icon('heroicon-o-eye')
+ ->authorize(fn (Queue $record) => auth()->user()->can('view', [$record, $this->site, $this->site->server]))
+ ->modalHeading('View Log')
+ ->modalContent(function (Queue $record) {
+ return view('components.console-view', [
+ 'slot' => app(GetQueueLogs::class)->getLogs($record),
+ 'attributes' => new ComponentAttributeBag,
+ ]);
+ })
+ ->modalSubmitAction(false)
+ ->modalCancelActionLabel('Close');
+ }
+
+ private function editAction(): Action
+ {
+ return EditAction::make('edit')
+ ->icon('heroicon-o-pencil-square')
+ ->authorize(fn (Queue $record) => auth()->user()->can('update', [$record, $this->site, $this->site->server]))
+ ->modalWidth(MaxWidth::ExtraLarge)
+ ->fillForm(fn (Queue $record) => [
+ 'command' => $record->command,
+ 'user' => $record->user,
+ 'numprocs' => $record->numprocs,
+ 'auto_start' => $record->auto_start,
+ 'auto_restart' => $record->auto_restart,
+ ])
+ ->form([
+ TextInput::make('command')
+ ->rules(EditQueue::rules($this->site->server)['command'])
+ ->helperText('Example: php /home/vito/your-site/artisan queue:work'),
+ Select::make('user')
+ ->rules(fn (callable $get) => EditQueue::rules($this->site->server)['user'])
+ ->options([
+ 'vito' => $this->site->server->ssh_user,
+ 'root' => 'root',
+ ]),
+ TextInput::make('numprocs')
+ ->default(1)
+ ->rules(EditQueue::rules($this->site->server)['numprocs'])
+ ->helperText('Number of processes'),
+ Grid::make()
+ ->schema([
+ Checkbox::make('auto_start')
+ ->default(false),
+ Checkbox::make('auto_restart')
+ ->default(false),
+ ]),
+ ])
+ ->using(function (Queue $record, array $data) {
+ run_action($this, function () use ($record, $data) {
+ app(EditQueue::class)->edit($record, $data);
+ $this->dispatch('$refresh');
+ });
+ });
+ }
+
+ private function deleteAction(): Action
+ {
+ return DeleteAction::make('delete')
+ ->icon('heroicon-o-trash')
+ ->authorize(fn (Queue $record) => auth()->user()->can('delete', [$record, $this->site, $this->site->server]))
+ ->using(function (Queue $record) {
+ run_action($this, function () use ($record) {
+ app(DeleteQueue::class)->delete($record);
+ $this->dispatch('$refresh');
+ });
+ });
+ }
+}
diff --git a/app/Web/Pages/Servers/Sites/Pages/SSL/Index.php b/app/Web/Pages/Servers/Sites/Pages/SSL/Index.php
index b0a0af8..a9fe904 100644
--- a/app/Web/Pages/Servers/Sites/Pages/SSL/Index.php
+++ b/app/Web/Pages/Servers/Sites/Pages/SSL/Index.php
@@ -2,7 +2,17 @@
namespace App\Web\Pages\Servers\Sites\Pages\SSL;
+use App\Actions\SSL\CreateSSL;
+use App\Models\Ssl;
use App\Web\Pages\Servers\Sites\Page;
+use Filament\Actions\Action;
+use Filament\Actions\CreateAction;
+use Filament\Forms\Components\Checkbox;
+use Filament\Forms\Components\DatePicker;
+use Filament\Forms\Components\Select;
+use Filament\Forms\Components\Textarea;
+use Filament\Forms\Get;
+use Filament\Support\Enums\MaxWidth;
class Index extends Page
{
@@ -12,11 +22,60 @@ class Index extends Page
public static function canAccess(): bool
{
- return true;
+ return auth()->user()?->can('viewAny', [Ssl::class, static::getSiteFromRoute(), static::getServerFromRoute()]) ?? false;
}
public function getWidgets(): array
{
- return [];
+ return [
+ [Widgets\SslsList::class, ['site' => $this->site]],
+ ];
+ }
+
+ protected function getHeaderActions(): array
+ {
+ return [
+ Action::make('read-the-docs')
+ ->label('Read the Docs')
+ ->icon('heroicon-o-document-text')
+ ->color('gray')
+ ->url('https://vitodeploy.com/sites/ssl.html')
+ ->openUrlInNewTab(),
+ CreateAction::make('create')
+ ->label('New Certificate')
+ ->icon('heroicon-o-lock-closed')
+ ->form([
+ Select::make('type')
+ ->options(
+ collect(config('core.ssl_types'))->mapWithKeys(fn ($type) => [$type => $type])
+ )
+ ->rules(fn (Get $get) => CreateSSL::rules($get())['type'])
+ ->reactive(),
+ Textarea::make('certificate')
+ ->rows(5)
+ ->rules(fn (Get $get) => CreateSSL::rules($get())['certificate'])
+ ->visible(fn (Get $get) => $get('type') === 'custom'),
+ Textarea::make('private')
+ ->label('Private Key')
+ ->rows(5)
+ ->rules(fn (Get $get) => CreateSSL::rules($get())['private'])
+ ->visible(fn (Get $get) => $get('type') === 'custom'),
+ DatePicker::make('expires_at')
+ ->format('Y-m-d')
+ ->rules(fn (Get $get) => CreateSSL::rules($get())['expires_at'])
+ ->visible(fn (Get $get) => $get('type') === 'custom'),
+ Checkbox::make('aliases')
+ ->label("Set SSL for site's aliases as well"),
+ ])
+ ->createAnother(false)
+ ->modalWidth(MaxWidth::Large)
+ ->using(function (array $data) {
+ run_action($this, function () use ($data) {
+ app(CreateSSL::class)->create($this->site, $data);
+
+ $this->dispatch('$refresh');
+ });
+ }),
+ ];
}
}
diff --git a/app/Web/Pages/Servers/Sites/Pages/SSL/Widgets/SslsList.php b/app/Web/Pages/Servers/Sites/Pages/SSL/Widgets/SslsList.php
new file mode 100644
index 0000000..0da2e86
--- /dev/null
+++ b/app/Web/Pages/Servers/Sites/Pages/SSL/Widgets/SslsList.php
@@ -0,0 +1,81 @@
+where('site_id', $this->site->id);
+ }
+
+ protected static ?string $heading = '';
+
+ protected function getTableColumns(): array
+ {
+ return [
+ TextColumn::make('type')
+ ->searchable()
+ ->sortable(),
+ TextColumn::make('created_at')
+ ->formatStateUsing(fn (Ssl $record) => $record->created_at_by_timezone)
+ ->sortable(),
+ TextColumn::make('expires_at')
+ ->formatStateUsing(fn (Ssl $record) => $record->getDateTimeByTimezone($record->expires_at))
+ ->sortable(),
+ TextColumn::make('status')
+ ->label('Status')
+ ->badge()
+ ->color(fn (Ssl $record) => Ssl::$statusColors[$record->status])
+ ->searchable()
+ ->sortable(),
+ ];
+ }
+
+ public function getTable(): Table
+ {
+ return $this->table
+ ->actions([
+ Action::make('logs')
+ ->hiddenLabel()
+ ->tooltip('Logs')
+ ->icon('heroicon-o-eye')
+ ->authorize(fn (Ssl $record) => auth()->user()->can('view', [$record, $this->site, $this->site->server]))
+ ->modalHeading('View Log')
+ ->modalContent(function (Ssl $record) {
+ return view('components.console-view', [
+ 'slot' => $record->log?->getContent(),
+ 'attributes' => new ComponentAttributeBag,
+ ]);
+ })
+ ->modalSubmitAction(false)
+ ->modalCancelActionLabel('Close'),
+ DeleteAction::make('delete')
+ ->hiddenLabel()
+ ->tooltip('Delete')
+ ->icon('heroicon-o-trash')
+ ->authorize(fn (Ssl $record) => auth()->user()->can('delete', [$record, $this->site, $this->site->server]))
+ ->using(function (Ssl $record) {
+ run_action($this, function () use ($record) {
+ app(DeleteSSL::class)->delete($record);
+ $this->dispatch('$refresh');
+ });
+ }),
+ ]);
+ }
+}
diff --git a/app/Web/Pages/Servers/Sites/Settings.php b/app/Web/Pages/Servers/Sites/Settings.php
index f9ea36c..b6365f7 100644
--- a/app/Web/Pages/Servers/Sites/Settings.php
+++ b/app/Web/Pages/Servers/Sites/Settings.php
@@ -2,6 +2,7 @@
namespace App\Web\Pages\Servers\Sites;
+use App\Actions\Site\DeleteSite;
use App\SSH\Services\Webserver\Webserver;
use App\Web\Fields\CodeEditorField;
use Filament\Actions\Action;
@@ -40,16 +41,23 @@ private function deleteAction(): Action
{
return DeleteAction::make()
->icon('heroicon-o-trash')
- ->record($this->server)
+ ->record($this->site)
->modalHeading('Delete Site')
- ->modalDescription('Once your site is deleted, all of its resources and data will be permanently deleted and can\'t be restored');
+ ->modalDescription('Once your site is deleted, all of its resources and data will be permanently deleted and can\'t be restored')
+ ->using(function () {
+ run_action($this, function () {
+ app(DeleteSite::class)->delete($this->site);
+
+ $this->redirect(Index::getUrl(['server' => $this->server]));
+ });
+ });
}
private function vhostAction(): Action
{
return Action::make('vhost')
->color('gray')
- ->icon('si-nginx')
+ ->icon('icon-nginx')
->label('VHost')
->modalSubmitActionLabel('Save')
->form([
diff --git a/app/Web/Pages/Servers/Sites/View.php b/app/Web/Pages/Servers/Sites/View.php
index e00b5b0..5647e71 100644
--- a/app/Web/Pages/Servers/Sites/View.php
+++ b/app/Web/Pages/Servers/Sites/View.php
@@ -79,11 +79,19 @@ public function getWidgets(): array
public function getHeaderActions(): array
{
- $actions = [];
+ $actions = [
+ Action::make('read-the-docs')
+ ->label('Read the Docs')
+ ->icon('heroicon-o-document-text')
+ ->color('gray')
+ ->url('https://vitodeploy.com/sites/application.html')
+ ->openUrlInNewTab(),
+ ];
$actionsGroup = [];
if (in_array(SiteFeature::DEPLOYMENT, $this->site->type()->supportedFeatures())) {
$actions[] = $this->deployAction();
+ $actionsGroup[] = $this->autoDeploymentAction();
$actionsGroup[] = $this->deploymentScriptAction();
}
@@ -130,6 +138,27 @@ private function deployAction(): Action
});
}
+ private function autoDeploymentAction(): Action
+ {
+ return Action::make('auto-deployment')
+ ->label(fn () => $this->site->isAutoDeployment() ? 'Disable Auto Deployment' : 'Enable Auto Deployment')
+ ->modalHeading(fn () => $this->site->isAutoDeployment() ? 'Disable Auto Deployment' : 'Enable Auto Deployment')
+ ->modalIconColor(fn () => $this->site->isAutoDeployment() ? 'red' : 'green')
+ ->requiresConfirmation()
+ ->action(function () {
+ run_action($this, function () {
+ $this->site->isAutoDeployment()
+ ? $this->site->disableAutoDeployment()
+ : $this->site->enableAutoDeployment();
+
+ Notification::make()
+ ->success()
+ ->title('Auto deployment '.($this->site->isAutoDeployment() ? 'disabled' : 'enabled').'!')
+ ->send();
+ });
+ });
+ }
+
private function deploymentScriptAction(): Action
{
return Action::make('deployment-script')
diff --git a/app/Web/Pages/Servers/Sites/Widgets/SitesList.php b/app/Web/Pages/Servers/Sites/Widgets/SitesList.php
index 68d74d1..b94df30 100644
--- a/app/Web/Pages/Servers/Sites/Widgets/SitesList.php
+++ b/app/Web/Pages/Servers/Sites/Widgets/SitesList.php
@@ -7,6 +7,7 @@
use App\Web\Pages\Servers\Sites\Settings;
use App\Web\Pages\Servers\Sites\View;
use Filament\Tables\Actions\Action;
+use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Filament\Widgets\TableWidget as Widget;
@@ -26,6 +27,10 @@ protected function getTableQuery(): Builder
protected function getTableColumns(): array
{
return [
+ IconColumn::make('type')
+ ->icon(fn (Site $record) => 'icon-'.$record->type)
+ ->tooltip(fn (Site $record) => $record->type)
+ ->width(24),
TextColumn::make('domain')
->searchable()
->sortable(),
diff --git a/app/Web/Pages/Servers/Widgets/ServersList.php b/app/Web/Pages/Servers/Widgets/ServersList.php
index e839f06..517b53a 100644
--- a/app/Web/Pages/Servers/Widgets/ServersList.php
+++ b/app/Web/Pages/Servers/Widgets/ServersList.php
@@ -6,6 +6,7 @@
use App\Web\Pages\Servers\Settings;
use App\Web\Pages\Servers\View;
use Filament\Tables\Actions\Action;
+use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Filament\Widgets\TableWidget as Widget;
@@ -23,6 +24,10 @@ protected function getTableQuery(): Builder
protected function getTableColumns(): array
{
return [
+ IconColumn::make('provider')
+ ->icon(fn (Server $record) => 'icon-'.$record->provider)
+ ->tooltip(fn (Server $record) => $record->provider)
+ ->width(24),
TextColumn::make('name')
->searchable()
->sortable(),
diff --git a/app/Web/Pages/Settings/ServerProviders/Widgets/ServerProvidersList.php b/app/Web/Pages/Settings/ServerProviders/Widgets/ServerProvidersList.php
index 8f1cf4f..dc2b3cf 100644
--- a/app/Web/Pages/Settings/ServerProviders/Widgets/ServerProvidersList.php
+++ b/app/Web/Pages/Settings/ServerProviders/Widgets/ServerProvidersList.php
@@ -8,7 +8,7 @@
use Filament\Support\Enums\MaxWidth;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\EditAction;
-use Filament\Tables\Columns\ImageColumn;
+use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Filament\Widgets\TableWidget as Widget;
@@ -26,9 +26,9 @@ protected function getTableQuery(): Builder
protected function getTableColumns(): array
{
return [
- ImageColumn::make('image_url')
- ->label('Provider')
- ->size(24),
+ IconColumn::make('provider')
+ ->icon(fn (ServerProvider $record) => 'icon-'.$record->provider)
+ ->width(24),
TextColumn::make('name')
->default(fn ($record) => $record->profile)
->label('Name')
diff --git a/app/Web/Pages/Settings/SourceControls/Widgets/SourceControlsList.php b/app/Web/Pages/Settings/SourceControls/Widgets/SourceControlsList.php
index 3c6e3ec..9126dcc 100644
--- a/app/Web/Pages/Settings/SourceControls/Widgets/SourceControlsList.php
+++ b/app/Web/Pages/Settings/SourceControls/Widgets/SourceControlsList.php
@@ -8,7 +8,7 @@
use Filament\Support\Enums\MaxWidth;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\EditAction;
-use Filament\Tables\Columns\ImageColumn;
+use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Filament\Widgets\TableWidget as Widget;
@@ -28,9 +28,9 @@ protected function getTableQuery(): Builder
protected function getTableColumns(): array
{
return [
- ImageColumn::make('image_url')
- ->label('Provider')
- ->size(24),
+ IconColumn::make('provider')
+ ->icon(fn (SourceControl $record) => 'icon-'.$record->provider)
+ ->width(24),
TextColumn::make('name')
->default(fn (SourceControl $record) => $record->profile)
->label('Name')
diff --git a/app/Web/Pages/Settings/StorageProviders/Widgets/StorageProvidersList.php b/app/Web/Pages/Settings/StorageProviders/Widgets/StorageProvidersList.php
index a224ad6..7e6591d 100644
--- a/app/Web/Pages/Settings/StorageProviders/Widgets/StorageProvidersList.php
+++ b/app/Web/Pages/Settings/StorageProviders/Widgets/StorageProvidersList.php
@@ -8,7 +8,7 @@
use Filament\Support\Enums\MaxWidth;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\EditAction;
-use Filament\Tables\Columns\ImageColumn;
+use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Filament\Widgets\TableWidget as Widget;
@@ -26,11 +26,12 @@ protected function getTableQuery(): Builder
protected function getTableColumns(): array
{
return [
- ImageColumn::make('image_url')
- ->label('Provider')
- ->size(24),
+ IconColumn::make('provider')
+ ->icon(fn (StorageProvider $record) => 'icon-'.$record->provider)
+ ->tooltip(fn (StorageProvider $record) => $record->provider)
+ ->width(24),
TextColumn::make('name')
- ->default(fn ($record) => $record->profile)
+ ->default(fn (StorageProvider $record) => $record->profile)
->label('Name')
->searchable()
->sortable(),
diff --git a/app/Web/Pages/Settings/Tags/Actions/EditTags.php b/app/Web/Pages/Settings/Tags/Actions/EditTags.php
index b79600e..0357625 100644
--- a/app/Web/Pages/Settings/Tags/Actions/EditTags.php
+++ b/app/Web/Pages/Settings/Tags/Actions/EditTags.php
@@ -5,57 +5,91 @@
use App\Actions\Tag\SyncTags;
use App\Models\Server;
use App\Models\Site;
+use Filament\Forms\Components\Actions\Action as FormAction;
use Filament\Forms\Components\Select;
-use Filament\Infolists\Components\Actions\Action;
+use Filament\Infolists\Components\Actions\Action as InfolistAction;
use Filament\Notifications\Notification;
use Filament\Support\Enums\MaxWidth;
+use Filament\Tables\Actions\Action as TableAction;
class EditTags
{
/**
* @param Site|Server $taggable
*/
- public static function infolist(mixed $taggable): Action
+ public static function infolist(mixed $taggable): InfolistAction
{
- return Action::make('edit_tags')
+ return InfolistAction::make('edit_tags')
->icon('heroicon-o-pencil-square')
->tooltip('Edit Tags')
->hiddenLabel()
->modalSubmitActionLabel('Save')
->modalHeading('Edit Tags')
->modalWidth(MaxWidth::Medium)
- ->form([
- Select::make('tags')
- ->default($taggable->tags()->pluck('tags.id')->toArray())
- ->options(function () {
- return auth()->user()->currentProject->tags()->pluck('name', 'id')->toArray();
- })
- ->nestedRecursiveRules(SyncTags::rules(auth()->user()->currentProject->id)['tags.*'])
- ->suffixAction(
- \Filament\Forms\Components\Actions\Action::make('create_tag')
- ->icon('heroicon-o-plus')
- ->tooltip('Create a new tag')
- ->modalSubmitActionLabel('Create')
- ->modalHeading('Create Tag')
- ->modalWidth(MaxWidth::Medium)
- ->form(Create::form())
- ->action(function (array $data) {
- Create::action($data);
- }),
- )
- ->multiple(),
- ])
- ->action(function (array $data) use ($taggable) {
- app(SyncTags::class)->sync(auth()->user(), [
- 'taggable_id' => $taggable->id,
- 'taggable_type' => get_class($taggable),
- 'tags' => $data['tags'],
- ]);
+ ->form(static::form($taggable))
+ ->action(static::action($taggable));
+ }
- Notification::make()
- ->success()
- ->title('Tags updated!')
- ->send();
- });
+ /**
+ * @param Site|Server $taggable
+ */
+ public static function table(mixed $taggable): TableAction
+ {
+ return TableAction::make('edit_tags')
+ ->icon('heroicon-o-pencil-square')
+ ->tooltip('Edit Tags')
+ ->hiddenLabel()
+ ->modalSubmitActionLabel('Save')
+ ->modalHeading('Edit Tags')
+ ->modalWidth(MaxWidth::Medium)
+ ->form(static::form($taggable))
+ ->action(static::action($taggable));
+ }
+
+ /**
+ * @param Site|Server $taggable
+ */
+ private static function form(mixed $taggable): array
+ {
+ return [
+ Select::make('tags')
+ ->default($taggable->tags()->pluck('tags.id')->toArray())
+ ->options(function () {
+ return auth()->user()->currentProject->tags()->pluck('name', 'id')->toArray();
+ })
+ ->nestedRecursiveRules(SyncTags::rules(auth()->user()->currentProject->id)['tags.*'])
+ ->suffixAction(
+ FormAction::make('create_tag')
+ ->icon('heroicon-o-plus')
+ ->tooltip('Create a new tag')
+ ->modalSubmitActionLabel('Create')
+ ->modalHeading('Create Tag')
+ ->modalWidth(MaxWidth::Medium)
+ ->form(Create::form())
+ ->action(function (array $data) {
+ Create::action($data);
+ }),
+ )
+ ->multiple(),
+ ];
+ }
+
+ /**
+ * @param Site|Server $taggable
+ */
+ private static function action(mixed $taggable): \Closure
+ {
+ return function (array $data) use ($taggable) {
+ app(SyncTags::class)->sync(auth()->user(), [
+ 'taggable_id' => $taggable->id,
+ 'taggable_type' => get_class($taggable),
+ 'tags' => $data['tags'],
+ ]);
+
+ Notification::make()
+ ->success()
+ ->title('Tags updated!')
+ ->send();
+ };
}
}
diff --git a/composer.json b/composer.json
index 84d580a..1f1faac 100644
--- a/composer.json
+++ b/composer.json
@@ -8,7 +8,6 @@
"php": "^8.2",
"ext-ftp": "*",
"aws/aws-sdk-php": "^3.158",
- "codeat3/blade-simple-icons": "^5.10",
"filament/filament": "^3.2",
"laravel/fortify": "^1.17",
"laravel/framework": "^11.0",
diff --git a/composer.lock b/composer.lock
index 28a05a1..6705c29 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "12a4dd2d7ef0bd63bdd94c2ab1ba72e1",
+ "content-hash": "616d8813a66d4a67234d11ebe6f90d67",
"packages": [
{
"name": "anourvalar/eloquent-serialize",
@@ -557,77 +557,6 @@
],
"time": "2024-02-09T16:56:22+00:00"
},
- {
- "name": "codeat3/blade-simple-icons",
- "version": "5.10.0",
- "source": {
- "type": "git",
- "url": "https://github.com/codeat3/blade-simple-icons.git",
- "reference": "2e6c78bca0200b008e23c60cd481ab750267ed9a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/codeat3/blade-simple-icons/zipball/2e6c78bca0200b008e23c60cd481ab750267ed9a",
- "reference": "2e6c78bca0200b008e23c60cd481ab750267ed9a",
- "shasum": ""
- },
- "require": {
- "blade-ui-kit/blade-icons": "^1.1",
- "illuminate/support": "^8.0|^9.0|^10.0|^11.0",
- "php": "^7.4|^8.0"
- },
- "require-dev": {
- "codeat3/blade-icon-generation-helpers": "^0.8",
- "codeat3/phpcs-styles": "^1.0",
- "orchestra/testbench": "^6.0|^7.0|^8.0|^9.0",
- "phpunit/phpunit": "^9.0|^10.5|^11.0"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Codeat3\\BladeSimpleIcons\\BladeSimpleIconsServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "Codeat3\\BladeSimpleIcons\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Swapnil Sarwe",
- "homepage": "https://swapnilsarwe.com"
- },
- {
- "name": "Dries Vints",
- "homepage": "https://driesvints.com"
- }
- ],
- "description": "A package to easily make use of \"Simple Icons\" in your Laravel Blade views. ",
- "homepage": "https://github.com/codeat3/blade-simple-icons",
- "keywords": [
- "blade",
- "laravel",
- "simpleicons"
- ],
- "support": {
- "issues": "https://github.com/codeat3/blade-simple-icons/issues",
- "source": "https://github.com/codeat3/blade-simple-icons/tree/5.10.0"
- },
- "funding": [
- {
- "url": "https://github.com/swapnilsarwe",
- "type": "github"
- }
- ],
- "time": "2024-09-21T14:06:07+00:00"
- },
{
"name": "danharrin/date-format-converter",
"version": "v0.3.1",
diff --git a/config/blade-icons.php b/config/blade-icons.php
new file mode 100644
index 0000000..d026e51
--- /dev/null
+++ b/config/blade-icons.php
@@ -0,0 +1,183 @@
+ [
+
+ 'default' => [
+
+ /*
+ |-----------------------------------------------------------------
+ | Icons Path
+ |-----------------------------------------------------------------
+ |
+ | Provide the relative path from your app root to your SVG icons
+ | directory. Icons are loaded recursively so there's no need to
+ | list every sub-directory.
+ |
+ | Relative to the disk root when the disk option is set.
+ |
+ */
+
+ 'path' => 'resources/svg',
+
+ /*
+ |-----------------------------------------------------------------
+ | Filesystem Disk
+ |-----------------------------------------------------------------
+ |
+ | Optionally, provide a specific filesystem disk to read
+ | icons from. When defining a disk, the "path" option
+ | starts relatively from the disk root.
+ |
+ */
+
+ 'disk' => '',
+
+ /*
+ |-----------------------------------------------------------------
+ | Default Prefix
+ |-----------------------------------------------------------------
+ |
+ | This config option allows you to define a default prefix for
+ | your icons. The dash separator will be applied automatically
+ | to every icon name. It's required and needs to be unique.
+ |
+ */
+
+ 'prefix' => 'icon',
+
+ /*
+ |-----------------------------------------------------------------
+ | Fallback Icon
+ |-----------------------------------------------------------------
+ |
+ | This config option allows you to define a fallback
+ | icon when an icon in this set cannot be found.
+ |
+ */
+
+ 'fallback' => '',
+
+ /*
+ |-----------------------------------------------------------------
+ | Default Set Classes
+ |-----------------------------------------------------------------
+ |
+ | This config option allows you to define some classes which
+ | will be applied by default to all icons within this set.
+ |
+ */
+
+ 'class' => '',
+
+ /*
+ |-----------------------------------------------------------------
+ | Default Set Attributes
+ |-----------------------------------------------------------------
+ |
+ | This config option allows you to define some attributes which
+ | will be applied by default to all icons within this set.
+ |
+ */
+
+ 'attributes' => [
+ // 'width' => 50,
+ // 'height' => 50,
+ ],
+
+ ],
+
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Global Default Classes
+ |--------------------------------------------------------------------------
+ |
+ | This config option allows you to define some classes which
+ | will be applied by default to all icons.
+ |
+ */
+
+ 'class' => '',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Global Default Attributes
+ |--------------------------------------------------------------------------
+ |
+ | This config option allows you to define some attributes which
+ | will be applied by default to all icons.
+ |
+ */
+
+ 'attributes' => [
+ // 'width' => 50,
+ // 'height' => 50,
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Global Fallback Icon
+ |--------------------------------------------------------------------------
+ |
+ | This config option allows you to define a global fallback
+ | icon when an icon in any set cannot be found. It can
+ | reference any icon from any configured set.
+ |
+ */
+
+ 'fallback' => '',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Components
+ |--------------------------------------------------------------------------
+ |
+ | These config options allow you to define some
+ | settings related to Blade Components.
+ |
+ */
+
+ 'components' => [
+
+ /*
+ |----------------------------------------------------------------------
+ | Disable Components
+ |----------------------------------------------------------------------
+ |
+ | This config option allows you to disable Blade components
+ | completely. It's useful to avoid performance problems
+ | when working with large icon libraries.
+ |
+ */
+
+ 'disabled' => false,
+
+ /*
+ |----------------------------------------------------------------------
+ | Default Icon Component Name
+ |----------------------------------------------------------------------
+ |
+ | This config option allows you to define the name
+ | for the default Icon class component.
+ |
+ */
+
+ 'default' => 'icon',
+
+ ],
+
+];
diff --git a/database/migrations/2024_10_06_091631_add_log_id_to_ssls.php b/database/migrations/2024_10_06_091631_add_log_id_to_ssls.php
new file mode 100644
index 0000000..f99bf4c
--- /dev/null
+++ b/database/migrations/2024_10_06_091631_add_log_id_to_ssls.php
@@ -0,0 +1,22 @@
+unsignedInteger('log_id')->nullable();
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::table('ssls', function (Blueprint $table) {
+ $table->dropColumn('log_id');
+ });
+ }
+};
diff --git a/public/static/images/digital-ocean.svg b/public/static/images/digital-ocean.svg
deleted file mode 100755
index 083b8d9..0000000
--- a/public/static/images/digital-ocean.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
diff --git a/public/static/images/mysql.svg b/public/static/images/mysql.svg
deleted file mode 100644
index 34358d2..0000000
--- a/public/static/images/mysql.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
diff --git a/public/static/images/nginx.svg b/public/static/images/nginx.svg
deleted file mode 100644
index 38bc663..0000000
--- a/public/static/images/nginx.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
diff --git a/public/static/images/php-blank.svg b/public/static/images/php-blank.svg
deleted file mode 100644
index bf57d7c..0000000
--- a/public/static/images/php-blank.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
diff --git a/public/static/images/php.svg b/public/static/images/php.svg
index bf57d7c..4752a6f 100644
--- a/public/static/images/php.svg
+++ b/public/static/images/php.svg
@@ -1,37 +1,119 @@
-
-