mirror of
https://github.com/vitodeploy/vito.git
synced 2025-07-04 15:32:35 +00:00
- 2.x - sites (wip)
- improved ssh error handling - database soft deletes
This commit is contained in:
@ -2,24 +2,28 @@
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Actions\Site\CreateSite;
|
||||
use App\Enums\SiteType;
|
||||
use App\Models\Site;
|
||||
use App\Web\Components\Page;
|
||||
use App\Web\Traits\PageHasServer;
|
||||
use Filament\Actions\CreateAction;
|
||||
use App\Models\SourceControl;
|
||||
use App\Web\Pages\Settings\SourceControls\Actions\Create;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Forms\Components\Checkbox;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TagsInput;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Get;
|
||||
use Filament\Forms\Set;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Support\Enums\MaxWidth;
|
||||
use Throwable;
|
||||
|
||||
class Index extends Page
|
||||
class Index extends \App\Web\Pages\Servers\Page
|
||||
{
|
||||
use PageHasServer;
|
||||
|
||||
protected static ?string $slug = 'servers/{server}/sites';
|
||||
|
||||
protected static bool $shouldRegisterNavigation = false;
|
||||
|
||||
protected static ?string $title = 'Sites';
|
||||
|
||||
public Server $server;
|
||||
|
||||
public static function canAccess(): bool
|
||||
{
|
||||
return auth()->user()?->can('viewAny', [Site::class, static::getServerFromRoute()]) ?? false;
|
||||
@ -35,11 +39,107 @@ public function getWidgets(): array
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make()
|
||||
->authorize(fn () => auth()->user()?->can('create', [Site::class, $this->server]))
|
||||
->createAnother(false)
|
||||
Action::make('read-the-docs')
|
||||
->label('Read the Docs')
|
||||
->icon('heroicon-o-document-text')
|
||||
->color('gray')
|
||||
->url('https://vitodeploy.com/sites/create-site.html')
|
||||
->openUrlInNewTab(),
|
||||
Action::make('create')
|
||||
->label('Create a Site')
|
||||
->icon('heroicon-o-plus'),
|
||||
->icon('heroicon-o-plus')
|
||||
->authorize(fn () => auth()->user()?->can('create', [Site::class, $this->server]))
|
||||
->modalWidth(MaxWidth::FiveExtraLarge)
|
||||
->slideOver()
|
||||
->form([
|
||||
Select::make('type')
|
||||
->options(
|
||||
collect(config('core.site_types'))->mapWithKeys(fn ($type) => [$type => $type])
|
||||
)
|
||||
->reactive()
|
||||
->afterStateUpdated(function (?string $state, Set $set) {
|
||||
if ($state === SiteType::LARAVEL) {
|
||||
$set('web_directory', 'public');
|
||||
} else {
|
||||
$set('web_directory', '');
|
||||
}
|
||||
})
|
||||
->rules(fn (Get $get) => CreateSite::rules($this->server, $get())['type']),
|
||||
TextInput::make('domain')
|
||||
->rules(fn (Get $get) => CreateSite::rules($this->server, $get())['domain']),
|
||||
TagsInput::make('aliases')
|
||||
->splitKeys(['Enter', 'Tab', ' ', ','])
|
||||
->placeholder('Type and press enter to add an alias')
|
||||
->nestedRecursiveRules(CreateSite::rules($this->server, [])['aliases.*']),
|
||||
Select::make('php_version')
|
||||
->label('PHP Version')
|
||||
->options(collect($this->server->installedPHPVersions())->mapWithKeys(fn ($version) => [$version => $version]))
|
||||
->visible(fn (Get $get) => isset(CreateSite::rules($this->server, $get())['php_version']))
|
||||
->rules(fn (Get $get) => CreateSite::rules($this->server, $get())['php_version']),
|
||||
TextInput::make('web_directory')
|
||||
->placeholder('For / leave empty')
|
||||
->rules(fn (Get $get) => CreateSite::rules($this->server, $get())['web_directory'])
|
||||
->visible(fn (Get $get) => isset(CreateSite::rules($this->server, $get())['web_directory']))
|
||||
->helperText(
|
||||
sprintf(
|
||||
'The relative path of your website from /home/%s/your-domain/',
|
||||
$this->server->ssh_user
|
||||
)
|
||||
),
|
||||
Select::make('source_control')
|
||||
->label('Source Control')
|
||||
->rules(fn (Get $get) => CreateSite::rules($this->server, $get())['source_control'])
|
||||
->options(
|
||||
SourceControl::getByProjectId(auth()->user()->current_project_id)
|
||||
->pluck('profile', 'id')
|
||||
)
|
||||
->suffixAction(
|
||||
\Filament\Forms\Components\Actions\Action::make('connect')
|
||||
->form(Create::form())
|
||||
->modalHeading('Connect to a source control')
|
||||
->modalSubmitActionLabel('Connect')
|
||||
->icon('heroicon-o-wifi')
|
||||
->tooltip('Connect to a source control')
|
||||
->modalWidth(MaxWidth::Large)
|
||||
->authorize(fn () => auth()->user()->can('create', SourceControl::class))
|
||||
->action(fn (array $data) => Create::action($data))
|
||||
)
|
||||
->placeholder('Select source control')
|
||||
->live()
|
||||
->visible(fn (Get $get) => isset(CreateSite::rules($this->server, $get())['source_control'])),
|
||||
TextInput::make('repository')
|
||||
->placeholder('organization/repository')
|
||||
->rules(fn (Get $get) => CreateSite::rules($this->server, $get())['repository'])
|
||||
->visible(fn (Get $get) => isset(CreateSite::rules($this->server, $get())['repository'])),
|
||||
TextInput::make('branch')
|
||||
->placeholder('main')
|
||||
->rules(fn (Get $get) => CreateSite::rules($this->server, $get())['branch'])
|
||||
->visible(fn (Get $get) => isset(CreateSite::rules($this->server, $get())['branch'])),
|
||||
Checkbox::make('composer')
|
||||
->label('Run `composer install --no-dev`')
|
||||
->default(false)
|
||||
->visible(fn (Get $get) => isset(CreateSite::rules($this->server, $get())['composer'])),
|
||||
])
|
||||
->action(function (array $data) {
|
||||
$this->authorize('create', [Site::class, $this->server]);
|
||||
|
||||
$this->validate();
|
||||
|
||||
try {
|
||||
$site = app(CreateSite::class)->create($this->server, $data);
|
||||
|
||||
$this->redirect(\App\Web\Pages\Servers\Sites\View::getUrl([
|
||||
'server' => $this->server,
|
||||
'site' => $site,
|
||||
]));
|
||||
} catch (Throwable $e) {
|
||||
Notification::make()
|
||||
->title($e->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
}
|
||||
})
|
||||
->modalSubmitActionLabel('Create Site'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
83
app/Web/Pages/Servers/Sites/Page.php
Normal file
83
app/Web/Pages/Servers/Sites/Page.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites;
|
||||
|
||||
use App\Models\Site;
|
||||
use App\Web\Contracts\HasSecondSubNav;
|
||||
use App\Web\Pages\Servers\Page as BasePage;
|
||||
use App\Web\Pages\Servers\Sites\Widgets\SiteSummary;
|
||||
use Filament\Navigation\NavigationGroup;
|
||||
use Filament\Navigation\NavigationItem;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
abstract class Page extends BasePage implements HasSecondSubNav
|
||||
{
|
||||
public Site $site;
|
||||
|
||||
public function getSecondSubNavigation(): array
|
||||
{
|
||||
$items = [];
|
||||
|
||||
if (View::canAccess()) {
|
||||
$items[] = NavigationItem::make(View::getNavigationLabel())
|
||||
->icon('heroicon-o-globe-alt')
|
||||
->isActiveWhen(fn () => request()->routeIs(View::getRouteName()))
|
||||
->url(View::getUrl(parameters: [
|
||||
'server' => $this->server,
|
||||
'site' => $this->site,
|
||||
]));
|
||||
}
|
||||
|
||||
if (Pages\SSL\Index::canAccess()) {
|
||||
$items[] = NavigationItem::make(Pages\SSL\Index::getNavigationLabel())
|
||||
->icon('heroicon-o-lock-closed')
|
||||
->isActiveWhen(fn () => request()->routeIs(Pages\SSL\Index::getRouteName()))
|
||||
->url(Pages\SSL\Index::getUrl(parameters: [
|
||||
'server' => $this->server,
|
||||
'site' => $this->site,
|
||||
]));
|
||||
}
|
||||
|
||||
if (Pages\Queues\Index::canAccess()) {
|
||||
$items[] = NavigationItem::make(Pages\Queues\Index::getNavigationLabel())
|
||||
->icon('heroicon-o-queue-list')
|
||||
->isActiveWhen(fn () => request()->routeIs(Pages\Queues\Index::getRouteName()))
|
||||
->url(Pages\Queues\Index::getUrl(parameters: [
|
||||
'server' => $this->server,
|
||||
'site' => $this->site,
|
||||
]));
|
||||
}
|
||||
|
||||
return [
|
||||
NavigationGroup::make()
|
||||
->items($items),
|
||||
];
|
||||
}
|
||||
|
||||
protected function getHeaderWidgets(): array
|
||||
{
|
||||
return array_merge(parent::getHeaderWidgets(), [
|
||||
SiteSummary::make(['site' => $this->site]),
|
||||
]);
|
||||
}
|
||||
|
||||
protected static function getSiteFromRoute(): ?Site
|
||||
{
|
||||
$site = request()->route('site');
|
||||
|
||||
if (! $site) {
|
||||
$site = Route::getRoutes()->match(Request::create(url()->previous()))->parameter('site');
|
||||
}
|
||||
|
||||
if ($site instanceof Site) {
|
||||
return $site;
|
||||
}
|
||||
|
||||
if ($site) {
|
||||
return Site::query()->find($site);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
22
app/Web/Pages/Servers/Sites/Pages/Queues/Index.php
Normal file
22
app/Web/Pages/Servers/Sites/Pages/Queues/Index.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites\Pages\Queues;
|
||||
|
||||
use App\Web\Pages\Servers\Sites\Page;
|
||||
|
||||
class Index extends Page
|
||||
{
|
||||
protected static ?string $slug = 'servers/{server}/sites/{site}/queues';
|
||||
|
||||
protected static ?string $title = 'Queues';
|
||||
|
||||
public static function canAccess(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getWidgets(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
22
app/Web/Pages/Servers/Sites/Pages/SSL/Index.php
Normal file
22
app/Web/Pages/Servers/Sites/Pages/SSL/Index.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites\Pages\SSL;
|
||||
|
||||
use App\Web\Pages\Servers\Sites\Page;
|
||||
|
||||
class Index extends Page
|
||||
{
|
||||
protected static ?string $slug = 'servers/{server}/sites/{site}/ssl';
|
||||
|
||||
protected static ?string $title = 'SSL';
|
||||
|
||||
public static function canAccess(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getWidgets(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
198
app/Web/Pages/Servers/Sites/View.php
Normal file
198
app/Web/Pages/Servers/Sites/View.php
Normal file
@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites;
|
||||
|
||||
use App\Actions\Site\Deploy;
|
||||
use App\Actions\Site\UpdateBranch;
|
||||
use App\Actions\Site\UpdateDeploymentScript;
|
||||
use App\Actions\Site\UpdateEnv;
|
||||
use App\Enums\SiteFeature;
|
||||
use App\Models\ServerLog;
|
||||
use App\Web\Fields\CodeEditorField;
|
||||
use App\Web\Pages\Servers\Logs\Widgets\LogsList;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\ActionGroup;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Support\Enums\IconPosition;
|
||||
use Filament\Support\Enums\MaxWidth;
|
||||
use Livewire\Attributes\On;
|
||||
|
||||
class View extends Page
|
||||
{
|
||||
protected static ?string $slug = 'servers/{server}/sites/{site}';
|
||||
|
||||
protected static ?string $title = 'Application';
|
||||
|
||||
public string $previousStatus;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->previousStatus = $this->site->status;
|
||||
}
|
||||
|
||||
public static function canAccess(): bool
|
||||
{
|
||||
return auth()->user()?->can('view', [static::getSiteFromRoute(), static::getServerFromRoute()]) ?? false;
|
||||
}
|
||||
|
||||
#[On('$refresh')]
|
||||
public function refresh(): void
|
||||
{
|
||||
$currentStatus = $this->site->refresh()->status;
|
||||
|
||||
if ($this->previousStatus !== $currentStatus) {
|
||||
$this->redirect(static::getUrl(parameters: [
|
||||
'server' => $this->server,
|
||||
'site' => $this->site,
|
||||
]));
|
||||
}
|
||||
|
||||
$this->previousStatus = $currentStatus;
|
||||
}
|
||||
|
||||
public function getWidgets(): array
|
||||
{
|
||||
$widgets = [];
|
||||
|
||||
if ($this->site->isInstalling()) {
|
||||
$widgets[] = [Widgets\Installing::class, ['site' => $this->site]];
|
||||
if (auth()->user()->can('viewAny', [ServerLog::class, $this->server])) {
|
||||
$widgets[] = [
|
||||
LogsList::class, [
|
||||
'server' => $this->server,
|
||||
'site' => $this->site,
|
||||
'label' => 'Logs',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $widgets;
|
||||
}
|
||||
|
||||
public function getHeaderActions(): array
|
||||
{
|
||||
$actions = [];
|
||||
$actionsGroup = [];
|
||||
|
||||
if (in_array(SiteFeature::DEPLOYMENT, $this->site->type()->supportedFeatures())) {
|
||||
$actions[] = $this->deployAction();
|
||||
$actionsGroup[] = $this->deploymentScriptAction();
|
||||
}
|
||||
|
||||
if (in_array(SiteFeature::ENV, $this->site->type()->supportedFeatures())) {
|
||||
$actionsGroup[] = $this->dotEnvAction();
|
||||
}
|
||||
|
||||
$actionsGroup[] = $this->branchAction();
|
||||
|
||||
$actions[] = ActionGroup::make($actionsGroup)
|
||||
->button()
|
||||
->color('gray')
|
||||
->icon('heroicon-o-chevron-up-down')
|
||||
->iconPosition(IconPosition::After)
|
||||
->dropdownPlacement('bottom-end');
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function getSecondSubNavigation(): array
|
||||
{
|
||||
if ($this->site->isInstalling()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return parent::getSecondSubNavigation();
|
||||
}
|
||||
|
||||
private function deployAction(): Action
|
||||
{
|
||||
return Action::make('deploy')
|
||||
->icon('heroicon-o-rocket-launch')
|
||||
->action(function () {
|
||||
run_action($this, function () {
|
||||
app(Deploy::class)->run($this->site);
|
||||
|
||||
Notification::make()
|
||||
->success()
|
||||
->title('Deployment started!')
|
||||
->send();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private function deploymentScriptAction(): Action
|
||||
{
|
||||
return Action::make('deployment-script')
|
||||
->label('Deployment Script')
|
||||
->modalSubmitActionLabel('Save')
|
||||
->modalHeading('Update Deployment Script')
|
||||
->form([
|
||||
CodeEditorField::make('script')
|
||||
->default($this->site->deploymentScript?->content)
|
||||
->rules(UpdateDeploymentScript::rules()['script']),
|
||||
])
|
||||
->action(function (array $data) {
|
||||
run_action($this, function () use ($data) {
|
||||
app(UpdateDeploymentScript::class)->update($this->site, $data);
|
||||
|
||||
Notification::make()
|
||||
->success()
|
||||
->title('Deployment script updated!')
|
||||
->send();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private function dotEnvAction(): Action
|
||||
{
|
||||
return Action::make('dot-env')
|
||||
->label('Update .env')
|
||||
->modalSubmitActionLabel('Save')
|
||||
->modalHeading('Update .env file')
|
||||
->form([
|
||||
CodeEditorField::make('env')
|
||||
->formatStateUsing(function () {
|
||||
return $this->site->getEnv();
|
||||
})
|
||||
->rules([
|
||||
'env' => 'required',
|
||||
]),
|
||||
])
|
||||
->action(function (array $data) {
|
||||
run_action($this, function () use ($data) {
|
||||
app(UpdateEnv::class)->update($this->site, $data);
|
||||
|
||||
Notification::make()
|
||||
->success()
|
||||
->title('.env updated!')
|
||||
->send();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private function branchAction(): Action
|
||||
{
|
||||
return Action::make('branch')
|
||||
->label('Branch')
|
||||
->modalSubmitActionLabel('Save')
|
||||
->modalHeading('Change branch')
|
||||
->modalWidth(MaxWidth::Medium)
|
||||
->form([
|
||||
TextInput::make('branch')
|
||||
->default($this->site->branch)
|
||||
->rules(UpdateBranch::rules()['branch']),
|
||||
])
|
||||
->action(function (array $data) {
|
||||
run_action($this, function () use ($data) {
|
||||
app(UpdateBranch::class)->update($this->site, $data);
|
||||
|
||||
Notification::make()
|
||||
->success()
|
||||
->title('Branch updated!')
|
||||
->send();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
57
app/Web/Pages/Servers/Sites/Widgets/Installing.php
Normal file
57
app/Web/Pages/Servers/Sites/Widgets/Installing.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites\Widgets;
|
||||
|
||||
use App\Models\Site;
|
||||
use Filament\Forms\Concerns\InteractsWithForms;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Infolists\Components\Section;
|
||||
use Filament\Infolists\Components\ViewEntry;
|
||||
use Filament\Infolists\Concerns\InteractsWithInfolists;
|
||||
use Filament\Infolists\Contracts\HasInfolists;
|
||||
use Filament\Infolists\Infolist;
|
||||
use Filament\Widgets\Widget;
|
||||
use Illuminate\View\ComponentAttributeBag;
|
||||
|
||||
class Installing extends Widget implements HasForms, HasInfolists
|
||||
{
|
||||
use InteractsWithForms;
|
||||
use InteractsWithInfolists;
|
||||
|
||||
protected $listeners = ['$refresh'];
|
||||
|
||||
protected static bool $isLazy = false;
|
||||
|
||||
protected static string $view = 'web.components.infolist';
|
||||
|
||||
public Site $site;
|
||||
|
||||
public function infolist(Infolist $infolist): Infolist
|
||||
{
|
||||
return $infolist
|
||||
->schema([
|
||||
Section::make()
|
||||
->heading('Installing Site')
|
||||
->icon(function () {
|
||||
if ($this->site->isInstallationFailed()) {
|
||||
return 'heroicon-o-x-circle';
|
||||
}
|
||||
|
||||
return view('filament::components.loading-indicator')
|
||||
->with('attributes', new ComponentAttributeBag([
|
||||
'class' => 'mr-2 size-[24px] text-primary-400',
|
||||
]));
|
||||
})
|
||||
->iconColor($this->site->isInstallationFailed() ? 'danger' : 'primary')
|
||||
->schema([
|
||||
ViewEntry::make('progress')
|
||||
->hiddenLabel()
|
||||
->view('components.progress-bar')
|
||||
->viewData([
|
||||
'value' => $this->site->progress,
|
||||
]),
|
||||
]),
|
||||
])
|
||||
->record($this->site->refresh());
|
||||
}
|
||||
}
|
55
app/Web/Pages/Servers/Sites/Widgets/SiteSummary.php
Normal file
55
app/Web/Pages/Servers/Sites/Widgets/SiteSummary.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Web\Pages\Servers\Sites\Widgets;
|
||||
|
||||
use App\Models\Site;
|
||||
use Filament\Forms\Concerns\InteractsWithForms;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Infolists\Components\Fieldset;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Infolists\Concerns\InteractsWithInfolists;
|
||||
use Filament\Infolists\Contracts\HasInfolists;
|
||||
use Filament\Infolists\Infolist;
|
||||
use Filament\Support\Enums\IconPosition;
|
||||
use Filament\Widgets\Widget;
|
||||
|
||||
class SiteSummary extends Widget implements HasForms, HasInfolists
|
||||
{
|
||||
use InteractsWithForms;
|
||||
use InteractsWithInfolists;
|
||||
|
||||
protected $listeners = ['$refresh'];
|
||||
|
||||
protected static bool $isLazy = false;
|
||||
|
||||
protected static string $view = 'web.components.infolist';
|
||||
|
||||
public Site $site;
|
||||
|
||||
public function infolist(Infolist $infolist): Infolist
|
||||
{
|
||||
return $infolist
|
||||
->schema([
|
||||
Fieldset::make('info')
|
||||
->label('Site Summary')
|
||||
->schema([
|
||||
TextEntry::make('domain')
|
||||
->icon('heroicon-o-clipboard-document')
|
||||
->iconPosition(IconPosition::After)
|
||||
->copyable(),
|
||||
TextEntry::make('path')
|
||||
->icon('heroicon-o-clipboard-document')
|
||||
->iconPosition(IconPosition::After)
|
||||
->copyable(),
|
||||
TextEntry::make('status')
|
||||
->label('Status')
|
||||
->badge()
|
||||
->color(static function ($state): string {
|
||||
return Site::$statusColors[$state];
|
||||
}),
|
||||
])
|
||||
->columns(3),
|
||||
])
|
||||
->record($this->site->refresh());
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\Site;
|
||||
use App\Web\Pages\Servers\View;
|
||||
use App\Web\Pages\Servers\Sites\View;
|
||||
use Filament\Tables\Actions\Action;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
@ -28,11 +28,12 @@ protected function getTableColumns(): array
|
||||
TextColumn::make('id')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('server.name')
|
||||
TextColumn::make('domain')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('domain')
|
||||
->searchable(),
|
||||
TextColumn::make('created_at')
|
||||
->formatStateUsing(fn (Site $record) => $record->created_at_by_timezone)
|
||||
->sortable(),
|
||||
TextColumn::make('status')
|
||||
->label('Status')
|
||||
->badge()
|
||||
@ -45,13 +46,13 @@ protected function getTableColumns(): array
|
||||
public function getTable(): Table
|
||||
{
|
||||
return $this->table
|
||||
// ->recordUrl(fn (Server $record) => View::getUrl(parameters: ['server' => $record]))
|
||||
->recordUrl(fn (Site $record) => View::getUrl(parameters: ['server' => $this->server, 'site' => $record]))
|
||||
->actions([
|
||||
// Action::make('settings')
|
||||
// ->label('Settings')
|
||||
// ->icon('heroicon-o-cog-6-tooth')
|
||||
// ->authorize(fn ($record) => auth()->user()->can('update', $record))
|
||||
// ->url(fn (Server $record) => '/'),
|
||||
Action::make('settings')
|
||||
->label('Settings')
|
||||
->icon('heroicon-o-cog-6-tooth')
|
||||
->authorize(fn (Site $record) => auth()->user()->can('update', [$record, $this->server]))
|
||||
->url(fn (Site $record) => '/'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user