This commit is contained in:
Bozhidar 2024-09-13 13:08:48 +03:00
parent 912b209934
commit 830ee55ddd
6 changed files with 206 additions and 554 deletions

View file

@ -0,0 +1,198 @@
<?php
namespace Modules\Customer\App\Filament\Pages;
use App\Models\Domain;
use App\Models\FileItem;
use App\Models\HostingSubscription;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Pages\Page;
use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\ActionGroup;
use Filament\Tables\Actions\BulkAction;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\HeaderActionsPosition;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Number;
use Livewire\Attributes\Url;
use Livewire\Component;
class FileManager extends Page implements HasForms, HasTable
{
use InteractsWithTable;
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-folder';
protected static string $view = 'customer::filament.pages.file-manager';
protected static ?string $navigationGroup = 'Hosting';
protected static ?int $navigationSort = 3;
public string $disk = 'local';
#[Url(except: '')]
public string $path = '';
protected $listeners = ['updatePath' => '$refresh'];
public function table(Table $table): Table
{
$findDomain = Domain::select(['home_root', 'hosting_subscription_id', 'is_main'])
// ->where('hosting_subscription_id', $this->record->id)
->where('is_main',1)
->first();
$this->disk = $findDomain->home_root;
$storage = Storage::build([
'driver' => 'local',
'throw' => false,
'root' => $this->disk,
]);
return $table
// ->deferLoading()
->heading($this->disk .'/'. $this->path ?: 'Root')
->query(
FileItem::queryForDiskAndPath($this->disk, $this->path)
)
->paginated(false)
->columns([
TextColumn::make('name')
->icon(fn ($record): string => match ($record->type) {
'Folder' => 'heroicon-o-folder',
default => 'heroicon-o-document'
})
->iconColor(fn ($record): string => match ($record->type) {
'Folder' => 'warning',
default => 'gray',
})
->action(function (FileItem $record) {
if ($record->isFolder()) {
$this->path = $record->path;
$this->dispatch('updatePath');
}
}),
TextColumn::make('dateModified')
->dateTime(),
TextColumn::make('size')
->formatStateUsing(fn ($state) => $state ? Number::fileSize($state) : '0.0KB'),
TextColumn::make('type'),
])
->actions([
ActionGroup::make([
// ViewAction::make('open')
// ->label('Open')
// ->hidden(fn (FileItem $record): bool => ! $record->canOpen())
// ->url(fn (FileItem $record): string => $storage->url($record->path))
// ->openUrlInNewTab(),
Action::make('download')
->label('Download')
->icon('heroicon-o-document-arrow-down')
->hidden(fn (FileItem $record): bool => $record->isFolder())
->action(fn (FileItem $record) => $storage->download($record->path)),
DeleteAction::make('delete')
->successNotificationTitle('File deleted')
->hidden(fn (FileItem $record): bool => $record->isPreviousPath())
->action(function (FileItem $record, Action $action) {
if ($record->delete()) {
$action->sendSuccessNotification();
}
}),
]),
])
->bulkActions([
BulkAction::make('delete')
->icon('heroicon-o-trash')
->color('danger')
->requiresConfirmation()
->successNotificationTitle('Files deleted')
->deselectRecordsAfterCompletion()
->action(function (Collection $records, BulkAction $action) {
$records->each(fn (FileItem $record) => $record->delete());
$action->sendSuccessNotification();
}),
])
->checkIfRecordIsSelectableUsing(fn (FileItem $record): bool => ! $record->isPreviousPath())
->headerActionsPosition(HeaderActionsPosition::Bottom)
->headerActions([
// Action::make('home')
// ->label('Home')
// ->action(fn () => $this->path = '')
// ->icon('heroicon-o-home'),
//
// Action::make('back')
// ->label('Back')
// ->action(fn () => $this->path = dirname($this->path))
// ->icon('heroicon-o-arrow-left'),
Action::make('create_folder')
->label('Create Folder')
->icon('heroicon-o-folder-plus')
->form([
TextInput::make('name')
->label('Folder name')
->placeholder('Folder name')
->required(),
])
->successNotificationTitle('Folder created')
->action(function (array $data, Component $livewire, Action $action) use($storage) : void {
$storage->makeDirectory($livewire->path.'/'.$data['name']);
$this->resetTable();
$action->sendSuccessNotification();
}),
Action::make('create_file')
->label('Create File')
->icon('heroicon-o-document-plus')
->form([
TextInput::make('file_name')
->label('File name')
->placeholder('File name')
->required(),
Textarea::make('file_content')
->label('Content')
->required(),
])
->successNotificationTitle('File created')
->action(function (array $data, Component $livewire, Action $action) use($storage) : void {
$storage->put($livewire->path.'/'.$data['file_name'], $data['file_content']);
$this->resetTable();
$action->sendSuccessNotification();
}),
Action::make('upload_file')
->label('Upload files')
->icon('heroicon-o-document-arrow-up')
->color('info')
->form([
FileUpload::make('files')
->required()
->multiple()
->previewable(false)
->preserveFilenames()
->disk($this->disk)
->directory($this->path),
]),
]);
}
}

View file

@ -0,0 +1,7 @@
<x-filament-panels::page>
<div>
{{ $this->table }}
</div>
</x-filament-panels::page>

View file

@ -190,11 +190,7 @@ class HostingSubscriptionResource extends Resource
{
return $page->generateNavigationItems([
// Pages\ViewHos::class,
Pages\EditHostingSubscription::class,
Pages\ManageHostingSubscriptionDatabases::class,
Pages\ManageHostingSubscriptionBackups::class,
// Pages\ManageHostingSubscriptionFtpAccounts::class,
Pages\ManageHostingSubscriptionFileManager::class
Pages\EditHostingSubscription::class
]);
}
@ -208,15 +204,9 @@ class HostingSubscriptionResource extends Resource
public static function getPages(): array
{
return [
// 'index' => Pages\ManageHostingSubscriptions::route('/'),
'index' => Pages\ListHostingSubscriptions::route('/'),
'create' => Pages\CreateHostingSubscription::route('/create'),
'edit' => Pages\EditHostingSubscription::route('/{record}/edit'),
// 'view' => Pages\ViewHostingSubscription::route('/{record}'),
'databases' => Pages\ManageHostingSubscriptionDatabases::route('/{record}/databases'),
'backups' => Pages\ManageHostingSubscriptionBackups::route('/{record}/backups'),
// 'ftp-accounts' => Pages\ManageHostingSubscriptionFtpAccounts::route('/{record}/ftp-accounts'),
'file-manager' => Pages\ManageHostingSubscriptionFileManager::route('/{record}/file-manager'),
];
}

View file

@ -1,194 +0,0 @@
<?php
namespace app\Filament\Resources\HostingSubscriptionResource\Pages;
use App\Filament\Resources\Blog\PostResource;
use App\Filament\Resources\HostingSubscriptionResource;
use App\Models\DatabaseUser;
use App\Models\RemoteDatabaseServer;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Infolists\Components\IconEntry;
use Filament\Infolists\Components\TextEntry;
use Filament\Infolists\Infolist;
use Filament\Resources\Pages\ManageRelatedRecords;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Contracts\Support\Htmlable;
class ManageHostingSubscriptionDatabases extends ManageRelatedRecords
{
protected static string $resource = HostingSubscriptionResource::class;
protected static string $relationship = 'databases';
protected static ?string $navigationIcon = 'heroicon-o-circle-stack';
public function getTitle(): string | Htmlable
{
$recordTitle = $this->getRecordTitle();
$recordTitle = $recordTitle instanceof Htmlable ? $recordTitle->toHtml() : $recordTitle;
return "Manage {$recordTitle} Databases";
}
public function getBreadcrumb(): string
{
return 'Databases';
}
public static function getNavigationLabel(): string
{
return 'Databases';
}
public function form(Form $form): Form
{
$systemUsername = $this->record->system_username;
return $form
->schema([
Forms\Components\ToggleButtons::make('is_remote_database_server')
->default(0)
->disabled(function ($record) {
return $record;
})
->live()
->options([
0 => 'Internal',
1 => 'Remote Database Server',
])->inline(),
Forms\Components\Select::make('remote_database_server_id')
->label('Remote Database Server')
->hidden(fn(Forms\Get $get): bool => '1' !== $get('is_remote_database_server'))
->options(
RemoteDatabaseServer::all()->pluck('name', 'id')
),
Forms\Components\TextInput::make('database_name')
->prefix($systemUsername.'_')
->disabled(function ($record) {
return $record;
})
->label('Database Name')
->required(),
Forms\Components\Repeater::make('databaseUsers')
->relationship('databaseUsers')
->schema([
Forms\Components\TextInput::make('username')
->disabled(function ($record) {
return $record;
})
->prefix(function ($record) use($systemUsername) {
if ($record) {
return $record->username_prefix;
}
return $systemUsername.'_';
})
->required(),
Forms\Components\TextInput::make('password')
->disabled(function ($record) {
return $record;
})
//->password()
->required(),
])
->columns(2)
])
->columns(1);
}
public function infolist(Infolist $infolist): Infolist
{
return $infolist
->columns(1)
->schema([
TextEntry::make('database_name')->label('Database Name'),
]);
}
public function table(Table $table): Table
{
$systemUsername = $this->record->system_username;
return $table
->recordTitleAttribute('database_name')
->columns([
Tables\Columns\TextColumn::make('database_name')
->prefix(function ($record) {
return $record->database_name_prefix;
})
->label('Database Name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('databaseUsers.username')
->label('Database Users')
->listWithLineBreaks()
->limitList(2)
->expandableLimitedList(),
Tables\Columns\TextColumn::make('is_remote_database_server')
->badge()
->state(fn($record) => $record->is_remote_database_server ? 'Remote Database Server' : 'Internal Database Server')
->label('Database Server')
->sortable(),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
// Tables\Actions\Action::make('Create Database User')
// ->modal('create-database-user')
// ->form([
//
// Forms\Components\Select::make('database_id')
// ->label('Database')
// ->default($this->record->databases->first()?->id)
// ->options(
// $this->record->databases->pluck('database_name', 'id')
// )
// ->required(),
//
// Forms\Components\TextInput::make('username')
// ->prefix(function () use($systemUsername) {
// return $systemUsername;
// })
// ->label('Username')
// ->required(),
//
// Forms\Components\TextInput::make('password')
// ->password()
// ->label('Password')
// ->required(),
// ])
// ->afterFormValidated(function ($data) {
//
// $newDatabaseUser = new DatabaseUser();
// $newDatabaseUser->username = $data['username'];
// $newDatabaseUser->password = $data['password'];
// $newDatabaseUser->database_id = $data['database_id'];
// $newDatabaseUser->save();
//
// }),
])
->actions([
// Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->groupedBulkActions([
Tables\Actions\DeleteBulkAction::make(),
]);
}
}

View file

@ -1,215 +0,0 @@
<?php
namespace App\Filament\Resources\HostingSubscriptionResource\Pages;
use App\Filament\Resources\HostingSubscriptionResource;
use App\Models\Domain;
use App\Models\FileItem;
use App\Models\HostingSubscription;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Pages\ManageRelatedRecords;
use Filament\Resources\Pages\ViewRecord;
use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\ActionGroup;
use Filament\Tables\Actions\BulkAction;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\HeaderActionsPosition;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Number;
use Livewire\Attributes\Url;
use Livewire\Component;
class ManageHostingSubscriptionFileManager extends ViewRecord implements HasTable
{
use InteractsWithTable;
protected static string $resource = HostingSubscriptionResource::class;
protected static string $relationship = 'fileManager';
protected static ?string $navigationIcon = 'heroicon-o-folder-open';
protected static string $view = 'filament.pages.file-manager';
public string $disk = 'local';
#[Url(except: '')]
public string $path = '';
protected $listeners = ['updatePath' => '$refresh'];
public function getTitle(): string|Htmlable
{
$recordTitle = $this->getRecordTitle();
$recordTitle = $recordTitle instanceof Htmlable ? $recordTitle->toHtml() : $recordTitle;
return "File Manager {$recordTitle} ";
}
public function getBreadcrumb(): string
{
return 'File Manager';
}
public static function getNavigationLabel(): string
{
return 'File Manager';
}
public function table(Table $table): Table
{
$findDomain = Domain::select(['home_root', 'hosting_subscription_id', 'is_main'])
->where('hosting_subscription_id', $this->record->id)
->where('is_main',1)->first();
$this->disk = $findDomain->home_root;
$storage = Storage::build([
'driver' => 'local',
'throw' => false,
'root' => $this->disk,
]);
return $table
// ->deferLoading()
->heading($this->disk .'/'. $this->path ?: 'Root')
->query(
FileItem::queryForDiskAndPath($this->disk, $this->path)
)
->paginated(false)
->columns([
TextColumn::make('name')
->icon(fn ($record): string => match ($record->type) {
'Folder' => 'heroicon-o-folder',
default => 'heroicon-o-document'
})
->iconColor(fn ($record): string => match ($record->type) {
'Folder' => 'warning',
default => 'gray',
})
->action(function (FileItem $record) {
if ($record->isFolder()) {
$this->path = $record->path;
$this->dispatch('updatePath');
}
}),
TextColumn::make('dateModified')
->dateTime(),
TextColumn::make('size')
->formatStateUsing(fn ($state) => $state ? Number::fileSize($state) : '0.0KB'),
TextColumn::make('type'),
])
->actions([
ActionGroup::make([
// ViewAction::make('open')
// ->label('Open')
// ->hidden(fn (FileItem $record): bool => ! $record->canOpen())
// ->url(fn (FileItem $record): string => $storage->url($record->path))
// ->openUrlInNewTab(),
Action::make('download')
->label('Download')
->icon('heroicon-o-document-arrow-down')
->hidden(fn (FileItem $record): bool => $record->isFolder())
->action(fn (FileItem $record) => $storage->download($record->path)),
DeleteAction::make('delete')
->successNotificationTitle('File deleted')
->hidden(fn (FileItem $record): bool => $record->isPreviousPath())
->action(function (FileItem $record, Action $action) {
if ($record->delete()) {
$action->sendSuccessNotification();
}
}),
]),
])
->bulkActions([
BulkAction::make('delete')
->icon('heroicon-o-trash')
->color('danger')
->requiresConfirmation()
->successNotificationTitle('Files deleted')
->deselectRecordsAfterCompletion()
->action(function (Collection $records, BulkAction $action) {
$records->each(fn (FileItem $record) => $record->delete());
$action->sendSuccessNotification();
}),
])
->checkIfRecordIsSelectableUsing(fn (FileItem $record): bool => ! $record->isPreviousPath())
->headerActionsPosition(HeaderActionsPosition::Bottom)
->headerActions([
// Action::make('home')
// ->label('Home')
// ->action(fn () => $this->path = '')
// ->icon('heroicon-o-home'),
//
// Action::make('back')
// ->label('Back')
// ->action(fn () => $this->path = dirname($this->path))
// ->icon('heroicon-o-arrow-left'),
Action::make('create_folder')
->label('Create Folder')
->icon('heroicon-o-folder-plus')
->form([
TextInput::make('name')
->label('Folder name')
->placeholder('Folder name')
->required(),
])
->successNotificationTitle('Folder created')
->action(function (array $data, Component $livewire, Action $action) use($storage) : void {
$storage->makeDirectory($livewire->path.'/'.$data['name']);
$this->resetTable();
$action->sendSuccessNotification();
}),
Action::make('create_file')
->label('Create File')
->icon('heroicon-o-document-plus')
->form([
TextInput::make('file_name')
->label('File name')
->placeholder('File name')
->required(),
Textarea::make('file_content')
->label('Content')
->required(),
])
->successNotificationTitle('File created')
->action(function (array $data, Component $livewire, Action $action) use($storage) : void {
$storage->put($livewire->path.'/'.$data['file_name'], $data['file_content']);
$this->resetTable();
$action->sendSuccessNotification();
}),
Action::make('upload_file')
->label('Upload files')
->icon('heroicon-o-document-arrow-up')
->color('info')
->form([
FileUpload::make('files')
->required()
->multiple()
->previewable(false)
->preserveFilenames()
->disk($this->disk)
->directory($this->path),
]),
]);
}
}

View file

@ -1,134 +0,0 @@
<?php
namespace app\Filament\Resources\HostingSubscriptionResource\Pages;
use App\BackupStorage;
use App\Filament\Enums\BackupStatus;
use App\Filament\Enums\HostingSubscriptionBackupType;
use App\Filament\Resources\Blog\PostResource;
use App\Filament\Resources\HostingSubscriptionResource;
use App\Models\Backup;
use App\Models\DatabaseUser;
use App\Models\HostingSubscriptionBackup;
use App\Models\RemoteDatabaseServer;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Infolists\Components\IconEntry;
use Filament\Infolists\Components\TextEntry;
use Filament\Infolists\Infolist;
use Filament\Resources\Pages\ManageRelatedRecords;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\Carbon;
use JaOcero\RadioDeck\Forms\Components\RadioDeck;
class ManageHostingSubscriptionFtpAccounts extends ManageRelatedRecords
{
protected static string $resource = HostingSubscriptionResource::class;
protected static string $relationship = 'ftpAccounts';
protected static ?string $navigationIcon = 'heroicon-o-inbox-stack';
public function getTitle(): string|Htmlable
{
$recordTitle = $this->getRecordTitle();
$recordTitle = $recordTitle instanceof Htmlable ? $recordTitle->toHtml() : $recordTitle;
return "Manage {$recordTitle} FTP Accounts";
}
public function getBreadcrumb(): string
{
return 'FTP Accounts';
}
public static function getNavigationLabel(): string
{
return 'FTP Accounts';
}
public function form(Form $form): Form
{
$systemUsername = $this->record->system_username;
return $form
->schema([
Forms\Components\TextInput::make('username')
->label('Username')
->required(),
Forms\Components\TextInput::make('password')
->label('Password')
->required(),
Forms\Components\TextInput::make('confirm_password')
->label('Confirm Password')
->same('password')
->required(),
Forms\Components\TextInput::make('path')
->label('Home Directory')
->prefix('/home/' . $systemUsername . '/')
->required(),
Forms\Components\TextInput::make('quota')
->label('Quota'),
Forms\Components\Toggle::make('unlimited_quota')
->label('Unlimited Quota')
->default(false),
])
->columns(1);
}
public function infolist(Infolist $infolist): Infolist
{
return $infolist
->columns(1)
->schema([
//TextEntry::make('id')->label('id'),
TextEntry::make('username')->label('Username'),
TextEntry::make('path')->label('Home Directory'),
TextEntry::make('quota')->label('Quota'),
IconEntry::make('unlimited_quota')->label('Unlimited Quota'),
]);
}
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('username')
->columns([
Tables\Columns\TextColumn::make('username')
->label('Username'),
Tables\Columns\TextColumn::make('path')
->label('Home Directory')
->default('/'),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
//
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->groupedBulkActions([
Tables\Actions\DeleteBulkAction::make(),
]);
}
}