mirror of
https://github.com/vitodeploy/vito.git
synced 2025-07-05 16:02:34 +00:00
Add workers to servers (#547)
This commit is contained in:
@ -94,8 +94,8 @@ protected function getHeaderActions(): array
|
||||
->requiresConfirmation()
|
||||
->modalDescription('This will create databases that exist on the server but not in Vito.')
|
||||
->modalSubmitActionLabel('Sync')
|
||||
->action(function () {
|
||||
run_action($this, function () {
|
||||
->action(function (): void {
|
||||
run_action($this, function (): void {
|
||||
app(SyncDatabases::class)->sync($this->server);
|
||||
|
||||
$this->dispatch('$refresh');
|
||||
|
@ -38,8 +38,8 @@ protected function getHeaderActions(): array
|
||||
->requiresConfirmation()
|
||||
->modalDescription('This will create db users that exist on the server but not in Vito.')
|
||||
->modalSubmitActionLabel('Sync')
|
||||
->action(function () {
|
||||
run_action($this, function () {
|
||||
->action(function (): void {
|
||||
run_action($this, function (): void {
|
||||
app(SyncDatabaseUsers::class)->sync($this->server);
|
||||
|
||||
$this->dispatch('$refresh');
|
||||
|
@ -12,6 +12,7 @@
|
||||
use App\Models\Site;
|
||||
use App\Models\SshKey;
|
||||
use App\Models\User;
|
||||
use App\Models\Worker;
|
||||
use App\Web\Components\Page as BasePage;
|
||||
use App\Web\Pages\Servers\Console\Index as ConsoleIndex;
|
||||
use App\Web\Pages\Servers\CronJobs\Index as CronJobsIndex;
|
||||
@ -28,6 +29,7 @@
|
||||
use App\Web\Pages\Servers\SSHKeys\Index as SshKeysIndex;
|
||||
use App\Web\Pages\Servers\View as ServerView;
|
||||
use App\Web\Pages\Servers\Widgets\ServerSummary;
|
||||
use App\Web\Pages\Servers\Workers\Index as WorkersIndex;
|
||||
use Filament\Navigation\NavigationItem;
|
||||
|
||||
abstract class Page extends BasePage
|
||||
@ -99,6 +101,13 @@ public function getSubNavigation(): array
|
||||
->url(CronJobsIndex::getUrl(parameters: ['server' => $this->server]));
|
||||
}
|
||||
|
||||
if ($user->can('viewAny', [Worker::class, $this->server])) {
|
||||
$items[] = NavigationItem::make(WorkersIndex::getNavigationLabel())
|
||||
->icon('heroicon-o-queue-list')
|
||||
->isActiveWhen(fn () => request()->routeIs(WorkersIndex::getRouteName().'*'))
|
||||
->url(WorkersIndex::getUrl(parameters: ['server' => $this->server]));
|
||||
}
|
||||
|
||||
if ($user->can('viewAnyServer', [SshKey::class, $this->server])) {
|
||||
$items[] = NavigationItem::make(SshKeysIndex::getNavigationLabel())
|
||||
->icon('heroicon-o-key')
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites;
|
||||
|
||||
use App\Models\Queue;
|
||||
use App\Models\ServerLog;
|
||||
use App\Models\Site;
|
||||
use App\Models\Ssl;
|
||||
use App\Models\User;
|
||||
use App\Models\Worker;
|
||||
use App\Web\Contracts\HasSecondSubNav;
|
||||
use App\Web\Pages\Servers\Page as BasePage;
|
||||
use App\Web\Pages\Servers\Sites\Widgets\SiteSummary;
|
||||
@ -45,11 +45,11 @@ public function getSecondSubNavigation(): array
|
||||
]));
|
||||
}
|
||||
|
||||
if ($user->can('viewAny', [Queue::class, $this->site, $this->server])) {
|
||||
$items[] = NavigationItem::make(Pages\Queues\Index::getNavigationLabel())
|
||||
if ($user->can('viewAny', [Worker::class, $this->server, $this->site])) {
|
||||
$items[] = NavigationItem::make(Pages\Workers\Index::getNavigationLabel())
|
||||
->icon('heroicon-o-queue-list')
|
||||
->isActiveWhen(fn () => request()->routeIs(Pages\Queues\Index::getRouteName()))
|
||||
->url(Pages\Queues\Index::getUrl(parameters: [
|
||||
->isActiveWhen(fn () => request()->routeIs(Pages\Workers\Index::getRouteName()))
|
||||
->url(Pages\Workers\Index::getUrl(parameters: [
|
||||
'server' => $this->server,
|
||||
'site' => $this->site,
|
||||
]));
|
||||
|
@ -1,79 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites\Pages\Queues;
|
||||
|
||||
use App\Actions\Queue\CreateQueue;
|
||||
use App\Models\Queue;
|
||||
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
|
||||
{
|
||||
protected static ?string $slug = 'servers/{server}/sites/{site}/queues';
|
||||
|
||||
protected static ?string $title = 'Queues';
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->authorize('viewAny', [Queue::class, $this->site, $this->server]);
|
||||
}
|
||||
|
||||
public function getWidgets(): array
|
||||
{
|
||||
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')
|
||||
->openUrlInNewTab(),
|
||||
CreateAction::make('create')
|
||||
->icon('heroicon-o-plus')
|
||||
->createAnother(false)
|
||||
->modalWidth(MaxWidth::ExtraLarge)
|
||||
->label('New Queue')
|
||||
->form([
|
||||
TextInput::make('command')
|
||||
->rules(CreateQueue::rules($this->site)['command'])
|
||||
->helperText('Example: php /home/vito/your-site/artisan queue:work'),
|
||||
Select::make('user')
|
||||
->rules(fn (callable $get) => CreateQueue::rules($this->site)['user'])
|
||||
->options([
|
||||
'root' => 'root',
|
||||
$this->site->user => $this->site->user,
|
||||
]),
|
||||
TextInput::make('numprocs')
|
||||
->default(1)
|
||||
->rules(CreateQueue::rules($this->site)['numprocs'])
|
||||
->helperText('Number of processes'),
|
||||
Grid::make()
|
||||
->schema([
|
||||
Checkbox::make('auto_start')
|
||||
->default(false),
|
||||
Checkbox::make('auto_restart')
|
||||
->default(false),
|
||||
]),
|
||||
])
|
||||
->using(function (array $data): void {
|
||||
run_action($this, function () use ($data): void {
|
||||
app(CreateQueue::class)->create($this->site, $data);
|
||||
|
||||
$this->dispatch('$refresh');
|
||||
});
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
53
app/Web/Pages/Servers/Sites/Pages/Workers/Index.php
Normal file
53
app/Web/Pages/Servers/Sites/Pages/Workers/Index.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites\Pages\Workers;
|
||||
|
||||
use App\Models\Worker;
|
||||
use App\Web\Pages\Servers\Sites\Page;
|
||||
use App\Web\Pages\Servers\Workers\Actions\Create;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Support\Enums\MaxWidth;
|
||||
|
||||
class Index extends Page
|
||||
{
|
||||
protected static ?string $slug = 'servers/{server}/sites/{site}/workers';
|
||||
|
||||
protected static ?string $title = 'Workers';
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->authorize('viewAny', [Worker::class, $this->server, $this->site]);
|
||||
}
|
||||
|
||||
public function getWidgets(): array
|
||||
{
|
||||
return [
|
||||
[Widgets\WorkersList::class, [
|
||||
'server' => $this->server,
|
||||
'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/servers/workers')
|
||||
->openUrlInNewTab(),
|
||||
CreateAction::make('create')
|
||||
->icon('heroicon-o-plus')
|
||||
->createAnother(false)
|
||||
->modalWidth(MaxWidth::ExtraLarge)
|
||||
->label('New Worker')
|
||||
->form(Create::form($this->server, $this->site))
|
||||
->using(fn (array $data) => run_action($this, function () use ($data): void {
|
||||
Create::action($this, $data, $this->server, $this->site);
|
||||
})),
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites\Pages\Workers\Widgets;
|
||||
|
||||
class WorkersList extends \App\Web\Pages\Servers\Workers\Widgets\WorkersList {}
|
55
app/Web/Pages/Servers/Workers/Actions/Create.php
Normal file
55
app/Web/Pages/Servers/Workers/Actions/Create.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Workers\Actions;
|
||||
|
||||
use App\Actions\Worker\CreateWorker;
|
||||
use App\Models\Server;
|
||||
use App\Models\Site;
|
||||
use Filament\Forms\Components\Checkbox;
|
||||
use Filament\Forms\Components\Grid;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Livewire\Component;
|
||||
|
||||
class Create
|
||||
{
|
||||
/**
|
||||
* @return array<int, mixed>
|
||||
*/
|
||||
public static function form(Server $server, ?Site $site = null): array
|
||||
{
|
||||
return [
|
||||
TextInput::make('command')
|
||||
->rules(CreateWorker::rules($server, $site)['command'])
|
||||
->helperText('Example: php /home/vito/your-site/artisan queue:work'),
|
||||
Select::make('user')
|
||||
->rules(fn (callable $get) => CreateWorker::rules($server, $site)['user'])
|
||||
->options($server->getSshUsers()),
|
||||
TextInput::make('numprocs')
|
||||
->default(1)
|
||||
->rules(CreateWorker::rules($server, $site)['numprocs'])
|
||||
->helperText('Number of processes'),
|
||||
Grid::make()
|
||||
->schema([
|
||||
Checkbox::make('auto_start')
|
||||
->default(false),
|
||||
Checkbox::make('auto_restart')
|
||||
->default(false),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
public static function action(Component $component, array $data, Server $server, ?Site $site = null): void
|
||||
{
|
||||
app(CreateWorker::class)->create(
|
||||
$server,
|
||||
$data,
|
||||
$site
|
||||
);
|
||||
|
||||
$component->dispatch('$refresh');
|
||||
}
|
||||
}
|
50
app/Web/Pages/Servers/Workers/Index.php
Normal file
50
app/Web/Pages/Servers/Workers/Index.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Workers;
|
||||
|
||||
use App\Models\Worker;
|
||||
use App\Web\Pages\Servers\Page;
|
||||
use App\Web\Pages\Servers\Workers\Actions\Create;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Support\Enums\MaxWidth;
|
||||
|
||||
class Index extends Page
|
||||
{
|
||||
protected static ?string $slug = 'servers/{server}/workers';
|
||||
|
||||
protected static ?string $title = 'Workers';
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->authorize('viewAny', [Worker::class, $this->server]);
|
||||
}
|
||||
|
||||
public function getWidgets(): array
|
||||
{
|
||||
return [
|
||||
[Widgets\WorkersList::class, ['server' => $this->server]],
|
||||
];
|
||||
}
|
||||
|
||||
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/servers/workers')
|
||||
->openUrlInNewTab(),
|
||||
CreateAction::make('create')
|
||||
->icon('heroicon-o-plus')
|
||||
->createAnother(false)
|
||||
->modalWidth(MaxWidth::ExtraLarge)
|
||||
->label('New Worker')
|
||||
->form(Create::form($this->server))
|
||||
->using(fn (array $data) => run_action($this, function () use ($data): void {
|
||||
Create::action($this, $data, $this->server);
|
||||
})),
|
||||
];
|
||||
}
|
||||
}
|
@ -1,14 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites\Pages\Queues\Widgets;
|
||||
namespace App\Web\Pages\Servers\Workers\Widgets;
|
||||
|
||||
use App\Actions\Queue\DeleteQueue;
|
||||
use App\Actions\Queue\EditQueue;
|
||||
use App\Actions\Queue\GetQueueLogs;
|
||||
use App\Actions\Queue\ManageQueue;
|
||||
use App\Models\Queue;
|
||||
use App\Actions\Worker\DeleteWorker;
|
||||
use App\Actions\Worker\EditWorker;
|
||||
use App\Actions\Worker\GetWorkerLogs;
|
||||
use App\Actions\Worker\ManageWorker;
|
||||
use App\Models\Server;
|
||||
use App\Models\Site;
|
||||
use App\Models\User;
|
||||
use App\Models\Worker;
|
||||
use Filament\Forms\Components\Checkbox;
|
||||
use Filament\Forms\Components\Grid;
|
||||
use Filament\Forms\Components\Select;
|
||||
@ -24,9 +25,11 @@
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\View\ComponentAttributeBag;
|
||||
|
||||
class QueuesList extends Widget
|
||||
class WorkersList extends Widget
|
||||
{
|
||||
public Site $site;
|
||||
public Server $server;
|
||||
|
||||
public ?Site $site = null;
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
@ -34,11 +37,17 @@ class QueuesList extends Widget
|
||||
protected $listeners = ['$refresh'];
|
||||
|
||||
/**
|
||||
* @return Builder<Queue>
|
||||
* @return Builder<Worker>
|
||||
*/
|
||||
protected function getTableQuery(): Builder
|
||||
{
|
||||
return Queue::query()->where('site_id', $this->site->id);
|
||||
return Worker::query()
|
||||
->where('server_id', $this->server->id)
|
||||
->where(function (Builder $query): void {
|
||||
if ($this->site instanceof \App\Models\Site) {
|
||||
$query->where('site_id', $this->site->id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected function getTableColumns(): array
|
||||
@ -47,16 +56,16 @@ protected function getTableColumns(): array
|
||||
TextColumn::make('command')
|
||||
->limit(20)
|
||||
->copyable()
|
||||
->tooltip(fn (Queue $record) => $record->command)
|
||||
->tooltip(fn (Worker $record) => $record->command)
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('created_at')
|
||||
->formatStateUsing(fn (Queue $record) => $record->created_at_by_timezone)
|
||||
->formatStateUsing(fn (Worker $record) => $record->created_at_by_timezone)
|
||||
->sortable(),
|
||||
TextColumn::make('status')
|
||||
->label('Status')
|
||||
->badge()
|
||||
->color(fn (Queue $record) => Queue::$statusColors[$record->status])
|
||||
->color(fn (Worker $record) => Worker::$statusColors[$record->status])
|
||||
->searchable()
|
||||
->sortable(),
|
||||
];
|
||||
@ -86,12 +95,12 @@ private function operationAction(string $type, string $icon): Action
|
||||
$user = auth()->user();
|
||||
|
||||
return Action::make($type)
|
||||
->authorize(fn (Queue $record) => $user->can('update', [$record, $this->site, $this->site->server]))
|
||||
->label(ucfirst($type).' queue')
|
||||
->authorize(fn (Worker $record) => $user->can('update', [$record, $this->server, $this->site]))
|
||||
->label(ucfirst($type).' worker')
|
||||
->icon($icon)
|
||||
->action(function (Queue $record) use ($type): void {
|
||||
->action(function (Worker $record) use ($type): void {
|
||||
run_action($this, function () use ($record, $type): void {
|
||||
app(ManageQueue::class)->$type($record);
|
||||
app(ManageWorker::class)->$type($record);
|
||||
$this->dispatch('$refresh');
|
||||
});
|
||||
});
|
||||
@ -104,10 +113,10 @@ private function logsAction(): Action
|
||||
|
||||
return Action::make('logs')
|
||||
->icon('heroicon-o-eye')
|
||||
->authorize(fn (Queue $record) => $user->can('view', [$record, $this->site, $this->site->server]))
|
||||
->authorize(fn (Worker $record) => $user->can('view', [$record, $this->server, $this->site]))
|
||||
->modalHeading('View Log')
|
||||
->modalContent(fn (Queue $record) => view('components.console-view', [
|
||||
'slot' => app(GetQueueLogs::class)->getLogs($record),
|
||||
->modalContent(fn (Worker $record) => view('components.console-view', [
|
||||
'slot' => app(GetWorkerLogs::class)->getLogs($record),
|
||||
'attributes' => new ComponentAttributeBag,
|
||||
]))
|
||||
->modalSubmitAction(false)
|
||||
@ -121,9 +130,9 @@ private function editAction(): Action
|
||||
|
||||
return EditAction::make('edit')
|
||||
->icon('heroicon-o-pencil-square')
|
||||
->authorize(fn (Queue $record) => $user->can('update', [$record, $this->site, $this->site->server]))
|
||||
->authorize(fn (Worker $record) => $user->can('update', [$record, $this->server, $this->site]))
|
||||
->modalWidth(MaxWidth::ExtraLarge)
|
||||
->fillForm(fn (Queue $record): array => [
|
||||
->fillForm(fn (Worker $record): array => [
|
||||
'command' => $record->command,
|
||||
'user' => $record->user,
|
||||
'numprocs' => $record->numprocs,
|
||||
@ -132,17 +141,17 @@ private function editAction(): Action
|
||||
])
|
||||
->form([
|
||||
TextInput::make('command')
|
||||
->rules(EditQueue::rules($this->site->server)['command'])
|
||||
->rules(EditWorker::rules($this->server, $this->site)['command'])
|
||||
->helperText('Example: php /home/vito/your-site/artisan queue:work'),
|
||||
Select::make('user')
|
||||
->rules(fn (callable $get) => EditQueue::rules($this->site->server)['user'])
|
||||
->rules(fn (callable $get) => EditWorker::rules($this->server, $this->site)['user'])
|
||||
->options([
|
||||
'vito' => $this->site->server->ssh_user,
|
||||
'vito' => $this->server->ssh_user,
|
||||
'root' => 'root',
|
||||
]),
|
||||
TextInput::make('numprocs')
|
||||
->default(1)
|
||||
->rules(EditQueue::rules($this->site->server)['numprocs'])
|
||||
->rules(EditWorker::rules($this->server, $this->site)['numprocs'])
|
||||
->helperText('Number of processes'),
|
||||
Grid::make()
|
||||
->schema([
|
||||
@ -152,9 +161,9 @@ private function editAction(): Action
|
||||
->default(false),
|
||||
]),
|
||||
])
|
||||
->using(function (Queue $record, array $data): void {
|
||||
->using(function (Worker $record, array $data): void {
|
||||
run_action($this, function () use ($record, $data): void {
|
||||
app(EditQueue::class)->edit($record, $data);
|
||||
app(EditWorker::class)->edit($record, $data);
|
||||
$this->dispatch('$refresh');
|
||||
});
|
||||
});
|
||||
@ -167,10 +176,10 @@ private function deleteAction(): Action
|
||||
|
||||
return DeleteAction::make('delete')
|
||||
->icon('heroicon-o-trash')
|
||||
->authorize(fn (Queue $record) => $user->can('delete', [$record, $this->site, $this->site->server]))
|
||||
->using(function (Queue $record): void {
|
||||
->authorize(fn (Worker $record) => $user->can('delete', [$record, $this->server, $this->site]))
|
||||
->using(function (Worker $record): void {
|
||||
run_action($this, function () use ($record): void {
|
||||
app(DeleteQueue::class)->delete($record);
|
||||
app(DeleteWorker::class)->delete($record);
|
||||
$this->dispatch('$refresh');
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user