mirror of
https://github.com/pelican-dev/panel.git
synced 2025-11-08 14:39:35 +01:00
Merge branch 'main' into vehikl/singleton
This commit is contained in:
commit
234cdda1e1
@ -18,6 +18,17 @@ class QueueWorkerServiceCommand extends Command
|
|||||||
|
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
|
if (@file_exists('/.dockerenv')) {
|
||||||
|
$result = Process::run('supervisorctl restart queue-worker');
|
||||||
|
if ($result->failed()) {
|
||||||
|
$this->error('Error restarting service: ' . $result->errorOutput());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->line('Queue worker service file updated successfully.');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
$serviceName = $this->option('service-name') ?? $this->ask('Queue worker service name', 'pelican-queue');
|
$serviceName = $this->option('service-name') ?? $this->ask('Queue worker service name', 'pelican-queue');
|
||||||
$path = '/etc/systemd/system/' . $serviceName . '.service';
|
$path = '/etc/systemd/system/' . $serviceName . '.service';
|
||||||
|
|
||||||
|
|||||||
@ -88,7 +88,7 @@ enum ContainerStatus: string implements HasColor, HasIcon, HasLabel
|
|||||||
|
|
||||||
public function isStartable(): bool
|
public function isStartable(): bool
|
||||||
{
|
{
|
||||||
return !in_array($this, [ContainerStatus::Running, ContainerStatus::Starting, ContainerStatus::Stopping, ContainerStatus::Restarting]);
|
return !in_array($this, [ContainerStatus::Running, ContainerStatus::Starting, ContainerStatus::Stopping, ContainerStatus::Restarting, ContainerStatus::Missing]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isRestartable(): bool
|
public function isRestartable(): bool
|
||||||
@ -97,18 +97,16 @@ enum ContainerStatus: string implements HasColor, HasIcon, HasLabel
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !in_array($this, [ContainerStatus::Offline]);
|
return !in_array($this, [ContainerStatus::Offline, ContainerStatus::Missing]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isStoppable(): bool
|
public function isStoppable(): bool
|
||||||
{
|
{
|
||||||
return !in_array($this, [ContainerStatus::Starting, ContainerStatus::Stopping, ContainerStatus::Restarting, ContainerStatus::Exited, ContainerStatus::Offline]);
|
return !in_array($this, [ContainerStatus::Starting, ContainerStatus::Stopping, ContainerStatus::Restarting, ContainerStatus::Exited, ContainerStatus::Offline, ContainerStatus::Missing]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isKillable(): bool
|
public function isKillable(): bool
|
||||||
{
|
{
|
||||||
// [ContainerStatus::Restarting, ContainerStatus::Removing, ContainerStatus::Dead, ContainerStatus::Created]
|
return !in_array($this, [ContainerStatus::Offline, ContainerStatus::Running, ContainerStatus::Exited, ContainerStatus::Missing]);
|
||||||
|
|
||||||
return !in_array($this, [ContainerStatus::Offline, ContainerStatus::Running, ContainerStatus::Exited]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,8 +27,16 @@ enum ServerState: string implements HasColor, HasIcon, HasLabel
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getColor(): string
|
public function getColor(bool $hex = false): string
|
||||||
{
|
{
|
||||||
|
if ($hex) {
|
||||||
|
return match ($this) {
|
||||||
|
self::Normal, self::Installing, self::RestoringBackup => '#2563EB',
|
||||||
|
self::Suspended => '#D97706',
|
||||||
|
self::InstallFailed, self::ReinstallFailed => '#EF4444',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return match ($this) {
|
return match ($this) {
|
||||||
self::Normal => 'primary',
|
self::Normal => 'primary',
|
||||||
self::Installing => 'primary',
|
self::Installing => 'primary',
|
||||||
|
|||||||
@ -147,6 +147,8 @@ class RoleResource extends Resource
|
|||||||
*/
|
*/
|
||||||
private static function makeSection(string $model, array $options): Section
|
private static function makeSection(string $model, array $options): Section
|
||||||
{
|
{
|
||||||
|
$model = ucwords($model);
|
||||||
|
|
||||||
$icon = null;
|
$icon = null;
|
||||||
|
|
||||||
if (class_exists('\App\Filament\Admin\Resources\\' . $model . 'Resource')) {
|
if (class_exists('\App\Filament\Admin\Resources\\' . $model . 'Resource')) {
|
||||||
|
|||||||
@ -9,12 +9,13 @@ use App\Filament\Server\Pages\Console;
|
|||||||
use App\Models\Permission;
|
use App\Models\Permission;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Repositories\Daemon\DaemonPowerRepository;
|
use App\Repositories\Daemon\DaemonPowerRepository;
|
||||||
use AymanAlhattami\FilamentContextMenu\Columns\ContextMenuTextColumn;
|
|
||||||
use Filament\Notifications\Notification;
|
use Filament\Notifications\Notification;
|
||||||
use Filament\Resources\Components\Tab;
|
use Filament\Resources\Components\Tab;
|
||||||
use Filament\Resources\Pages\ListRecords;
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
use Filament\Support\Enums\Alignment;
|
||||||
use Filament\Tables\Actions\Action;
|
use Filament\Tables\Actions\Action;
|
||||||
use Filament\Tables\Columns\ColumnGroup;
|
use Filament\Tables\Actions\ActionGroup;
|
||||||
|
use Filament\Tables\Columns\Column;
|
||||||
use Filament\Tables\Columns\Layout\Stack;
|
use Filament\Tables\Columns\Layout\Stack;
|
||||||
use Filament\Tables\Columns\TextColumn;
|
use Filament\Tables\Columns\TextColumn;
|
||||||
use Filament\Tables\Filters\SelectFilter;
|
use Filament\Tables\Filters\SelectFilter;
|
||||||
@ -38,121 +39,73 @@ class ListServers extends ListRecords
|
|||||||
$this->daemonPowerRepository = new DaemonPowerRepository();
|
$this->daemonPowerRepository = new DaemonPowerRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function table(Table $table): Table
|
/** @return Stack[] */
|
||||||
|
protected function gridColumns(): array
|
||||||
{
|
{
|
||||||
$baseQuery = auth()->user()->accessibleServers();
|
return [
|
||||||
|
Stack::make([
|
||||||
|
ServerEntryColumn::make('server_entry')
|
||||||
|
->searchable(['name']),
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
$menuOptions = function (Server $server) {
|
/** @return Column[] */
|
||||||
$status = $server->retrieveStatus();
|
protected function tableColumns(): array
|
||||||
|
{
|
||||||
return [
|
return [
|
||||||
Action::make('start')
|
TextColumn::make('condition')
|
||||||
->color('primary')
|
->label('Status')
|
||||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_CONTROL_START, $server))
|
|
||||||
->visible(fn () => $status->isStartable())
|
|
||||||
->dispatch('powerAction', ['server' => $server, 'action' => 'start'])
|
|
||||||
->icon('tabler-player-play-filled'),
|
|
||||||
Action::make('restart')
|
|
||||||
->color('gray')
|
|
||||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_CONTROL_RESTART, $server))
|
|
||||||
->visible(fn () => $status->isRestartable())
|
|
||||||
->dispatch('powerAction', ['server' => $server, 'action' => 'restart'])
|
|
||||||
->icon('tabler-refresh'),
|
|
||||||
Action::make('stop')
|
|
||||||
->color('danger')
|
|
||||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_CONTROL_STOP, $server))
|
|
||||||
->visible(fn () => $status->isStoppable())
|
|
||||||
->dispatch('powerAction', ['server' => $server, 'action' => 'stop'])
|
|
||||||
->icon('tabler-player-stop-filled'),
|
|
||||||
Action::make('kill')
|
|
||||||
->color('danger')
|
|
||||||
->tooltip('This can result in data corruption and/or data loss!')
|
|
||||||
->dispatch('powerAction', ['server' => $server, 'action' => 'kill'])
|
|
||||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_CONTROL_STOP, $server))
|
|
||||||
->visible(fn () => $status->isKillable())
|
|
||||||
->icon('tabler-alert-square'),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
$viewOne = [
|
|
||||||
ContextMenuTextColumn::make('condition')
|
|
||||||
->label('')
|
|
||||||
->default('unknown')
|
|
||||||
->wrap()
|
|
||||||
->badge()
|
->badge()
|
||||||
->alignCenter()
|
|
||||||
->tooltip(fn (Server $server) => $server->formatResource('uptime', type: ServerResourceType::Time))
|
->tooltip(fn (Server $server) => $server->formatResource('uptime', type: ServerResourceType::Time))
|
||||||
->icon(fn (Server $server) => $server->condition->getIcon())
|
->icon(fn (Server $server) => $server->condition->getIcon())
|
||||||
->color(fn (Server $server) => $server->condition->getColor())
|
->color(fn (Server $server) => $server->condition->getColor()),
|
||||||
->contextMenuActions($menuOptions)
|
TextColumn::make('name')
|
||||||
->enableContextMenu(fn (Server $server) => !$server->isInConflictState()),
|
->label('Server')
|
||||||
];
|
->description(fn (Server $server) => $server->description)
|
||||||
|
->grow()
|
||||||
$viewTwo = [
|
->searchable(),
|
||||||
ContextMenuTextColumn::make('name')
|
TextColumn::make('allocation.address')
|
||||||
->label('')
|
|
||||||
->size('md')
|
|
||||||
->searchable()
|
|
||||||
->contextMenuActions($menuOptions)
|
|
||||||
->enableContextMenu(fn (Server $server) => !$server->isInConflictState()),
|
|
||||||
ContextMenuTextColumn::make('allocation.address')
|
|
||||||
->label('')
|
->label('')
|
||||||
->badge()
|
->badge()
|
||||||
->copyable(request()->isSecure())
|
->visibleFrom('md')
|
||||||
->contextMenuActions($menuOptions)
|
->copyable(request()->isSecure()),
|
||||||
->enableContextMenu(fn (Server $server) => !$server->isInConflictState()),
|
|
||||||
];
|
|
||||||
|
|
||||||
$viewThree = [
|
|
||||||
TextColumn::make('cpuUsage')
|
TextColumn::make('cpuUsage')
|
||||||
->label('')
|
->label('Resources')
|
||||||
->icon('tabler-cpu')
|
->icon('tabler-cpu')
|
||||||
->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource('cpu', limit: true, type: ServerResourceType::Percentage, precision: 0))
|
->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource('cpu', limit: true, type: ServerResourceType::Percentage, precision: 0))
|
||||||
->state(fn (Server $server) => $server->formatResource('cpu_absolute', type: ServerResourceType::Percentage))
|
->state(fn (Server $server) => $server->formatResource('cpu_absolute', type: ServerResourceType::Percentage))
|
||||||
->color(fn (Server $server) => $this->getResourceColor($server, 'cpu')),
|
->color(fn (Server $server) => $this->getResourceColor($server, 'cpu')),
|
||||||
TextColumn::make('memoryUsage')
|
TextColumn::make('memoryUsage')
|
||||||
->label('')
|
->label('')
|
||||||
->icon('tabler-memory')
|
->icon('tabler-device-desktop-analytics')
|
||||||
->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource('memory', limit: true))
|
->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource('memory', limit: true))
|
||||||
->state(fn (Server $server) => $server->formatResource('memory_bytes'))
|
->state(fn (Server $server) => $server->formatResource('memory_bytes'))
|
||||||
->color(fn (Server $server) => $this->getResourceColor($server, 'memory')),
|
->color(fn (Server $server) => $this->getResourceColor($server, 'memory')),
|
||||||
TextColumn::make('diskUsage')
|
TextColumn::make('diskUsage')
|
||||||
->label('')
|
->label('')
|
||||||
->icon('tabler-device-floppy')
|
->icon('tabler-device-sd-card')
|
||||||
->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource('disk', limit: true))
|
->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource('disk', limit: true))
|
||||||
->state(fn (Server $server) => $server->formatResource('disk_bytes'))
|
->state(fn (Server $server) => $server->formatResource('disk_bytes'))
|
||||||
->color(fn (Server $server) => $this->getResourceColor($server, 'disk')),
|
->color(fn (Server $server) => $this->getResourceColor($server, 'disk')),
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function table(Table $table): Table
|
||||||
|
{
|
||||||
|
$baseQuery = auth()->user()->accessibleServers();
|
||||||
|
|
||||||
|
$usingGrid = (auth()->user()->getCustomization()['dashboard_layout'] ?? 'grid') === 'grid';
|
||||||
|
|
||||||
return $table
|
return $table
|
||||||
->paginated(false)
|
->paginated(false)
|
||||||
->query(fn () => $baseQuery)
|
->query(fn () => $baseQuery)
|
||||||
->poll('15s')
|
->poll('15s')
|
||||||
->columns(
|
->columns($usingGrid ? $this->gridColumns() : $this->tableColumns())
|
||||||
(auth()->user()->getCustomization()['dashboard_layout'] ?? 'grid') === 'grid'
|
->recordUrl(!$usingGrid ? (fn (Server $server) => Console::getUrl(panel: 'server', tenant: $server)) : null)
|
||||||
? [
|
->actions(!$usingGrid ? ActionGroup::make(static::getPowerActions()) : [])
|
||||||
Stack::make([
|
->actionsAlignment(Alignment::Center->value)
|
||||||
ServerEntryColumn::make('server_entry')
|
->contentGrid($usingGrid ? ['default' => 1, 'md' => 2] : null)
|
||||||
->searchable(['name']),
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
: [
|
|
||||||
ColumnGroup::make('Status')
|
|
||||||
->label('Status')
|
|
||||||
->columns($viewOne),
|
|
||||||
ColumnGroup::make('Server')
|
|
||||||
->label('Servers')
|
|
||||||
->columns($viewTwo),
|
|
||||||
ColumnGroup::make('Resources')
|
|
||||||
->label('Resources')
|
|
||||||
->columns($viewThree),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
->recordUrl(fn (Server $server) => Console::getUrl(panel: 'server', tenant: $server))
|
|
||||||
->contentGrid([
|
|
||||||
'default' => 1,
|
|
||||||
'md' => 2,
|
|
||||||
])
|
|
||||||
->emptyStateIcon('tabler-brand-docker')
|
->emptyStateIcon('tabler-brand-docker')
|
||||||
->emptyStateDescription('')
|
->emptyStateDescription('')
|
||||||
->emptyStateHeading(fn () => $this->activeTab === 'my' ? 'You don\'t own any servers!' : 'You don\'t have access to any servers!')
|
->emptyStateHeading(fn () => $this->activeTab === 'my' ? 'You don\'t own any servers!' : 'You don\'t have access to any servers!')
|
||||||
@ -195,36 +148,33 @@ class ListServers extends ListRecords
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getResourceColor(Server $server, string $resource): ?string
|
protected function getResourceColor(Server $server, string $resource): ?string
|
||||||
{
|
{
|
||||||
$current = null;
|
$current = null;
|
||||||
$limit = null;
|
$limit = null;
|
||||||
|
|
||||||
switch ($resource) {
|
switch ($resource) {
|
||||||
case 'cpu':
|
case 'cpu':
|
||||||
$current = $server->resources()['cpu_absolute'] ?? 0;
|
$current = $server->retrieveResources()['cpu_absolute'] ?? 0;
|
||||||
$limit = $server->cpu;
|
$limit = $server->cpu;
|
||||||
if ($server->cpu === 0) {
|
if ($server->cpu === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'memory':
|
case 'memory':
|
||||||
$current = $server->resources()['memory_bytes'] ?? 0;
|
$current = $server->retrieveResources()['memory_bytes'] ?? 0;
|
||||||
$limit = $server->memory * 2 ** 20;
|
$limit = $server->memory * 2 ** 20;
|
||||||
if ($server->memory === 0) {
|
if ($server->memory === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'disk':
|
case 'disk':
|
||||||
$current = $server->resources()['disk_bytes'] ?? 0;
|
$current = $server->retrieveResources()['disk_bytes'] ?? 0;
|
||||||
$limit = $server->disk * 2 ** 20;
|
$limit = $server->disk * 2 ** 20;
|
||||||
if ($server->disk === 0) {
|
if ($server->disk === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -238,7 +188,6 @@ class ListServers extends ListRecords
|
|||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[On('powerAction')]
|
#[On('powerAction')]
|
||||||
@ -253,6 +202,8 @@ class ListServers extends ListRecords
|
|||||||
->success()
|
->success()
|
||||||
->send();
|
->send();
|
||||||
|
|
||||||
|
cache()->forget("servers.$server->uuid.status");
|
||||||
|
|
||||||
$this->redirect(self::getUrl(['activeTab' => $this->activeTab]));
|
$this->redirect(self::getUrl(['activeTab' => $this->activeTab]));
|
||||||
} catch (ConnectionException) {
|
} catch (ConnectionException) {
|
||||||
Notification::make()
|
Notification::make()
|
||||||
@ -261,4 +212,36 @@ class ListServers extends ListRecords
|
|||||||
->send();
|
->send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Action[] */
|
||||||
|
public static function getPowerActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Action::make('start')
|
||||||
|
->color('primary')
|
||||||
|
->icon('tabler-player-play-filled')
|
||||||
|
->authorize(fn (Server $server) => auth()->user()->can(Permission::ACTION_CONTROL_START, $server))
|
||||||
|
->visible(fn (Server $server) => !$server->isInConflictState() & $server->retrieveStatus()->isStartable())
|
||||||
|
->dispatch('powerAction', fn (Server $server) => ['server' => $server, 'action' => 'start']),
|
||||||
|
Action::make('restart')
|
||||||
|
->color('gray')
|
||||||
|
->icon('tabler-reload')
|
||||||
|
->authorize(fn (Server $server) => auth()->user()->can(Permission::ACTION_CONTROL_RESTART, $server))
|
||||||
|
->visible(fn (Server $server) => !$server->isInConflictState() & $server->retrieveStatus()->isRestartable())
|
||||||
|
->dispatch('powerAction', fn (Server $server) => ['server' => $server, 'action' => 'restart']),
|
||||||
|
Action::make('stop')
|
||||||
|
->color('danger')
|
||||||
|
->icon('tabler-player-stop-filled')
|
||||||
|
->authorize(fn (Server $server) => auth()->user()->can(Permission::ACTION_CONTROL_STOP, $server))
|
||||||
|
->visible(fn (Server $server) => !$server->isInConflictState() & $server->retrieveStatus()->isStoppable())
|
||||||
|
->dispatch('powerAction', fn (Server $server) => ['server' => $server, 'action' => 'stop']),
|
||||||
|
Action::make('kill')
|
||||||
|
->color('danger')
|
||||||
|
->icon('tabler-alert-square')
|
||||||
|
->tooltip('This can result in data corruption and/or data loss!')
|
||||||
|
->authorize(fn (Server $server) => auth()->user()->can(Permission::ACTION_CONTROL_STOP, $server))
|
||||||
|
->visible(fn (Server $server) => !$server->isInConflictState() & $server->retrieveStatus()->isKillable())
|
||||||
|
->dispatch('powerAction', fn (Server $server) => ['server' => $server, 'action' => 'kill']),
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,7 @@ use Filament\Forms\Components\Textarea;
|
|||||||
use Filament\Forms\Components\TextInput;
|
use Filament\Forms\Components\TextInput;
|
||||||
use Filament\Forms\Components\ToggleButtons;
|
use Filament\Forms\Components\ToggleButtons;
|
||||||
use Filament\Forms\Get;
|
use Filament\Forms\Get;
|
||||||
|
use Filament\Forms\Set;
|
||||||
use Filament\Notifications\Notification;
|
use Filament\Notifications\Notification;
|
||||||
use Filament\Pages\Auth\EditProfile as BaseEditProfile;
|
use Filament\Pages\Auth\EditProfile as BaseEditProfile;
|
||||||
use Filament\Support\Colors\Color;
|
use Filament\Support\Colors\Color;
|
||||||
@ -405,30 +406,38 @@ class EditProfile extends BaseEditProfile
|
|||||||
})
|
})
|
||||||
->reactive()
|
->reactive()
|
||||||
->default('monospace')
|
->default('monospace')
|
||||||
->afterStateUpdated(fn ($state, callable $set) => $set('font_preview', $state)),
|
->afterStateUpdated(fn ($state, Set $set) => $set('font_preview', $state)),
|
||||||
Placeholder::make('font_preview')
|
Placeholder::make('font_preview')
|
||||||
->label(trans('profile.font_preview'))
|
->label(trans('profile.font_preview'))
|
||||||
->columnSpan(2)
|
->columnSpan(2)
|
||||||
->content(function (Get $get) {
|
->content(function (Get $get) {
|
||||||
$fontName = $get('console_font') ?? 'monospace';
|
$fontName = $get('console_font') ?? 'monospace';
|
||||||
$fontSize = $get('console_font_size') . 'px';
|
$fontSize = $get('console_font_size') . 'px';
|
||||||
$fontUrl = asset("storage/fonts/{$fontName}.ttf");
|
$style = <<<CSS
|
||||||
|
.preview-text {
|
||||||
|
font-family: $fontName;
|
||||||
|
font-size: $fontSize;
|
||||||
|
margin-top: 10px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
CSS;
|
||||||
|
if ($fontName !== 'monospace') {
|
||||||
|
$fontUrl = asset("storage/fonts/$fontName.ttf");
|
||||||
|
$style = <<<CSS
|
||||||
|
@font-face {
|
||||||
|
font-family: $fontName;
|
||||||
|
src: url("$fontUrl");
|
||||||
|
}
|
||||||
|
$style
|
||||||
|
CSS;
|
||||||
|
}
|
||||||
|
|
||||||
return new HtmlString(<<<HTML
|
return new HtmlString(<<<HTML
|
||||||
<style>
|
<style>
|
||||||
@font-face {
|
{$style}
|
||||||
font-family: "CustomPreviewFont";
|
</style>
|
||||||
src: url("$fontUrl");
|
<span class="preview-text">The quick blue pelican jumps over the lazy pterodactyl. :)</span>
|
||||||
}
|
HTML);
|
||||||
.preview-text {
|
|
||||||
font-family: "CustomPreviewFont";
|
|
||||||
font-size: $fontSize;
|
|
||||||
margin-top: 10px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<span class="preview-text">The quick blue pelican jumps over the lazy pterodactyl. :)</span>
|
|
||||||
HTML);
|
|
||||||
}),
|
}),
|
||||||
TextInput::make('console_graph_period')
|
TextInput::make('console_graph_period')
|
||||||
->label(trans('profile.graph_period'))
|
->label(trans('profile.graph_period'))
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use App\Repositories\Daemon\DaemonBackupRepository;
|
|||||||
use App\Services\Backups\DownloadLinkService;
|
use App\Services\Backups\DownloadLinkService;
|
||||||
use App\Filament\Components\Tables\Columns\BytesColumn;
|
use App\Filament\Components\Tables\Columns\BytesColumn;
|
||||||
use App\Filament\Components\Tables\Columns\DateTimeColumn;
|
use App\Filament\Components\Tables\Columns\DateTimeColumn;
|
||||||
|
use App\Services\Backups\DeleteBackupService;
|
||||||
use Filament\Facades\Filament;
|
use Filament\Facades\Filament;
|
||||||
use Filament\Forms\Components\Checkbox;
|
use Filament\Forms\Components\Checkbox;
|
||||||
use Filament\Forms\Components\Placeholder;
|
use Filament\Forms\Components\Placeholder;
|
||||||
@ -30,6 +31,7 @@ use Filament\Tables\Columns\IconColumn;
|
|||||||
use Filament\Tables\Columns\TextColumn;
|
use Filament\Tables\Columns\TextColumn;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class BackupResource extends Resource
|
class BackupResource extends Resource
|
||||||
@ -142,7 +144,7 @@ class BackupResource extends Resource
|
|||||||
->send();
|
->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$backup->is_successful && is_null($backup->completed_at)) { //TODO Change to Notifications
|
if (!$backup->is_successful && is_null($backup->completed_at)) {
|
||||||
return Notification::make()
|
return Notification::make()
|
||||||
->danger()
|
->danger()
|
||||||
->title('Backup Restore Failed')
|
->title('Backup Restore Failed')
|
||||||
@ -175,9 +177,26 @@ class BackupResource extends Resource
|
|||||||
->visible(fn (Backup $backup) => $backup->status === BackupStatus::Successful),
|
->visible(fn (Backup $backup) => $backup->status === BackupStatus::Successful),
|
||||||
DeleteAction::make('delete')
|
DeleteAction::make('delete')
|
||||||
->disabled(fn (Backup $backup) => $backup->is_locked)
|
->disabled(fn (Backup $backup) => $backup->is_locked)
|
||||||
->modalDescription(fn (Backup $backup) => 'Do you wish to delete, ' . $backup->name . '?')
|
->modalDescription(fn (Backup $backup) => 'Do you wish to delete ' . $backup->name . '?')
|
||||||
->modalSubmitActionLabel('Delete Backup')
|
->modalSubmitActionLabel('Delete Backup')
|
||||||
->action(fn (BackupController $backupController, Backup $backup, Request $request) => $backupController->delete($request, $server, $backup))
|
->action(function (Backup $backup, DeleteBackupService $deleteBackupService) {
|
||||||
|
try {
|
||||||
|
$deleteBackupService->handle($backup);
|
||||||
|
} catch (ConnectionException) {
|
||||||
|
Notification::make()
|
||||||
|
->title('Could not delete backup')
|
||||||
|
->body('Connection to node failed')
|
||||||
|
->danger()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Activity::event('server:backup.delete')
|
||||||
|
->subject($backup)
|
||||||
|
->property(['name' => $backup->name, 'failed' => !$backup->is_successful])
|
||||||
|
->log();
|
||||||
|
})
|
||||||
->visible(fn (Backup $backup) => $backup->status !== BackupStatus::InProgress),
|
->visible(fn (Backup $backup) => $backup->status !== BackupStatus::InProgress),
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api\Client\Servers;
|
|||||||
|
|
||||||
use App\Facades\Activity;
|
use App\Facades\Activity;
|
||||||
use App\Http\Controllers\Api\Client\ClientApiController;
|
use App\Http\Controllers\Api\Client\ClientApiController;
|
||||||
|
use App\Http\Requests\Api\Client\Servers\Settings\DescriptionServerRequest;
|
||||||
use App\Http\Requests\Api\Client\Servers\Settings\ReinstallServerRequest;
|
use App\Http\Requests\Api\Client\Servers\Settings\ReinstallServerRequest;
|
||||||
use App\Http\Requests\Api\Client\Servers\Settings\RenameServerRequest;
|
use App\Http\Requests\Api\Client\Servers\Settings\RenameServerRequest;
|
||||||
use App\Http\Requests\Api\Client\Servers\Settings\SetDockerImageRequest;
|
use App\Http\Requests\Api\Client\Servers\Settings\SetDockerImageRequest;
|
||||||
@ -34,24 +35,36 @@ class SettingsController extends ClientApiController
|
|||||||
public function rename(RenameServerRequest $request, Server $server): JsonResponse
|
public function rename(RenameServerRequest $request, Server $server): JsonResponse
|
||||||
{
|
{
|
||||||
$name = $request->input('name');
|
$name = $request->input('name');
|
||||||
$description = $request->has('description') ? (string) $request->input('description') : $server->description;
|
|
||||||
|
|
||||||
if ($server->name !== $name) {
|
$server->update(['name' => $name]);
|
||||||
|
|
||||||
|
if ($server->wasChanged('name')) {
|
||||||
Activity::event('server:settings.rename')
|
Activity::event('server:settings.rename')
|
||||||
->property(['old' => $server->name, 'new' => $name])
|
->property(['old' => $server->getOriginal('name'), 'new' => $name])
|
||||||
->log();
|
->log();
|
||||||
$server->name = $name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($server->description !== $description && config('panel.editable_server_descriptions')) {
|
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update server description
|
||||||
|
*/
|
||||||
|
public function description(DescriptionServerRequest $request, Server $server): JsonResponse
|
||||||
|
{
|
||||||
|
if (!config('panel.editable_server_descriptions')) {
|
||||||
|
return new JsonResponse([], Response::HTTP_FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
$description = $request->input('description');
|
||||||
|
$server->update(['description' => $description ?? '']);
|
||||||
|
|
||||||
|
if ($server->wasChanged('description')) {
|
||||||
Activity::event('server:settings.description')
|
Activity::event('server:settings.description')
|
||||||
->property(['old' => $server->description, 'new' => $description])
|
->property(['old' => $server->getOriginal('description'), 'new' => $description])
|
||||||
->log();
|
->log();
|
||||||
$server->description = $description;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$server->save();
|
|
||||||
|
|
||||||
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +93,7 @@ class SettingsController extends ClientApiController
|
|||||||
*/
|
*/
|
||||||
public function dockerImage(SetDockerImageRequest $request, Server $server): JsonResponse
|
public function dockerImage(SetDockerImageRequest $request, Server $server): JsonResponse
|
||||||
{
|
{
|
||||||
if (!in_array($server->image, array_values($server->egg->docker_images))) {
|
if (!in_array($server->image, $server->egg->docker_images)) {
|
||||||
throw new BadRequestHttpException('This server\'s Docker image has been manually set by an administrator and cannot be updated.');
|
throw new BadRequestHttpException('This server\'s Docker image has been manually set by an administrator and cannot be updated.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Api\Client\Servers\Settings;
|
||||||
|
|
||||||
|
use App\Contracts\Http\ClientPermissionsRequest;
|
||||||
|
use App\Http\Requests\Api\Client\ClientApiRequest;
|
||||||
|
use App\Models\Permission;
|
||||||
|
|
||||||
|
class DescriptionServerRequest extends ClientApiRequest implements ClientPermissionsRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the permissions string indicating which permission should be used to
|
||||||
|
* validate that the authenticated user has permission to perform this action against
|
||||||
|
* the given resource (server).
|
||||||
|
*/
|
||||||
|
public function permission(): string
|
||||||
|
{
|
||||||
|
return Permission::ACTION_SETTINGS_DESCRIPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rules to apply when validating this request.
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'description' => 'string|nullable',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,7 +26,6 @@ class RenameServerRequest extends ClientApiRequest implements ClientPermissionsR
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => Server::getRules()['name'],
|
'name' => Server::getRules()['name'],
|
||||||
'description' => 'string|nullable',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -333,26 +333,6 @@ class Node extends Model implements Validatable
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array<array-key, mixed>
|
|
||||||
*/
|
|
||||||
public function serverStatuses(): array
|
|
||||||
{
|
|
||||||
$statuses = [];
|
|
||||||
try {
|
|
||||||
$statuses = Http::daemon($this)->connectTimeout(1)->timeout(1)->get('/api/servers')->json() ?? [];
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
report($exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($statuses as $status) {
|
|
||||||
$uuid = fluent($status)->get('configuration.uuid');
|
|
||||||
cache()->remember("servers.$uuid.container.status", now()->addMinute(), fn () => fluent($status)->get('state'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $statuses;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return array{
|
/** @return array{
|
||||||
* memory_total: int, memory_used: int,
|
* memory_total: int, memory_used: int,
|
||||||
* swap_total: int, swap_used: int,
|
* swap_total: int, swap_used: int,
|
||||||
|
|||||||
@ -97,6 +97,8 @@ class Permission extends Model implements Validatable
|
|||||||
|
|
||||||
public const ACTION_SETTINGS_RENAME = 'settings.rename';
|
public const ACTION_SETTINGS_RENAME = 'settings.rename';
|
||||||
|
|
||||||
|
public const ACTION_SETTINGS_DESCRIPTION = 'settings.description';
|
||||||
|
|
||||||
public const ACTION_SETTINGS_REINSTALL = 'settings.reinstall';
|
public const ACTION_SETTINGS_REINSTALL = 'settings.reinstall';
|
||||||
|
|
||||||
public const ACTION_ACTIVITY_READ = 'activity.read';
|
public const ACTION_ACTIVITY_READ = 'activity.read';
|
||||||
@ -176,7 +178,7 @@ class Permission extends Model implements Validatable
|
|||||||
[
|
[
|
||||||
'name' => 'settings',
|
'name' => 'settings',
|
||||||
'icon' => 'tabler-settings',
|
'icon' => 'tabler-settings',
|
||||||
'permissions' => ['rename', 'reinstall'],
|
'permissions' => ['rename', 'description', 'reinstall'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'activity',
|
'name' => 'activity',
|
||||||
|
|||||||
@ -435,25 +435,24 @@ class Server extends Model implements Validatable
|
|||||||
|
|
||||||
public function retrieveStatus(): ContainerStatus
|
public function retrieveStatus(): ContainerStatus
|
||||||
{
|
{
|
||||||
$status = cache()->get("servers.$this->uuid.container.status");
|
return cache()->remember("servers.$this->uuid.status", now()->addSeconds(15), function () {
|
||||||
|
// @phpstan-ignore myCustomRules.forbiddenGlobalFunctions
|
||||||
|
$details = app(DaemonServerRepository::class)->setServer($this)->getDetails();
|
||||||
|
|
||||||
if ($status === null) {
|
return ContainerStatus::tryFrom(Arr::get($details, 'state')) ?? ContainerStatus::Missing;
|
||||||
$this->node->serverStatuses();
|
});
|
||||||
|
|
||||||
$status = cache()->get("servers.$this->uuid.container.status");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ContainerStatus::tryFrom($status) ?? ContainerStatus::Missing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<mixed>
|
* @return array<mixed>
|
||||||
*/
|
*/
|
||||||
public function resources(): array
|
public function retrieveResources(): array
|
||||||
{
|
{
|
||||||
return cache()->remember("resources:$this->uuid", now()->addSeconds(15), function () {
|
return cache()->remember("servers.$this->uuid.resources", now()->addSeconds(15), function () {
|
||||||
// @phpstan-ignore myCustomRules.forbiddenGlobalFunctions
|
// @phpstan-ignore myCustomRules.forbiddenGlobalFunctions
|
||||||
return Arr::get(app(DaemonServerRepository::class)->setServer($this)->getDetails(), 'utilization', []);
|
$details = app(DaemonServerRepository::class)->setServer($this)->getDetails();
|
||||||
|
|
||||||
|
return Arr::get($details, 'utilization', []);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,7 +460,7 @@ class Server extends Model implements Validatable
|
|||||||
{
|
{
|
||||||
$resourceAmount = $this->{$resourceKey} ?? 0;
|
$resourceAmount = $this->{$resourceKey} ?? 0;
|
||||||
if (!$limit) {
|
if (!$limit) {
|
||||||
$resourceAmount = $this->resources()[$resourceKey] ?? 0;
|
$resourceAmount = $this->retrieveResources()[$resourceKey] ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($type === ServerResourceType::Time) {
|
if ($type === ServerResourceType::Time) {
|
||||||
@ -494,7 +493,7 @@ class Server extends Model implements Validatable
|
|||||||
public function condition(): Attribute
|
public function condition(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
get: fn () => $this->isSuspended() ? ServerState::Suspended : $this->status ?? $this->retrieveStatus(),
|
get: fn () => $this->status ?? $this->retrieveStatus(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,7 +64,7 @@ class ServerPanelProvider extends PanelProvider
|
|||||||
->navigationItems([
|
->navigationItems([
|
||||||
NavigationItem::make('Open in Admin')
|
NavigationItem::make('Open in Admin')
|
||||||
->url(fn () => EditServer::getUrl(['record' => Filament::getTenant()], panel: 'admin'))
|
->url(fn () => EditServer::getUrl(['record' => Filament::getTenant()], panel: 'admin'))
|
||||||
->visible(fn () => auth()->user()->can('view server', Filament::getTenant()))
|
->visible(fn () => auth()->user()->canAccessPanel(Filament::getPanel('admin')) && auth()->user()->can('view server', Filament::getTenant()))
|
||||||
->icon('tabler-arrow-back')
|
->icon('tabler-arrow-back')
|
||||||
->sort(99),
|
->sort(99),
|
||||||
])
|
])
|
||||||
|
|||||||
@ -6,12 +6,11 @@ use App\Extensions\Filesystem\S3Filesystem;
|
|||||||
use Aws\S3\S3Client;
|
use Aws\S3\S3Client;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use App\Models\Backup;
|
use App\Models\Backup;
|
||||||
use GuzzleHttp\Exception\ClientException;
|
|
||||||
use Illuminate\Database\ConnectionInterface;
|
use Illuminate\Database\ConnectionInterface;
|
||||||
use App\Extensions\Backups\BackupManager;
|
use App\Extensions\Backups\BackupManager;
|
||||||
use App\Repositories\Daemon\DaemonBackupRepository;
|
use App\Repositories\Daemon\DaemonBackupRepository;
|
||||||
use App\Exceptions\Service\Backup\BackupLockedException;
|
use App\Exceptions\Service\Backup\BackupLockedException;
|
||||||
use Illuminate\Http\Client\ConnectionException;
|
use Exception;
|
||||||
|
|
||||||
class DeleteBackupService
|
class DeleteBackupService
|
||||||
{
|
{
|
||||||
@ -48,12 +47,10 @@ class DeleteBackupService
|
|||||||
$this->connection->transaction(function () use ($backup) {
|
$this->connection->transaction(function () use ($backup) {
|
||||||
try {
|
try {
|
||||||
$this->daemonBackupRepository->setServer($backup->server)->delete($backup);
|
$this->daemonBackupRepository->setServer($backup->server)->delete($backup);
|
||||||
} catch (ConnectionException $exception) {
|
} catch (Exception $exception) {
|
||||||
$previous = $exception->getPrevious();
|
|
||||||
|
|
||||||
// Don't fail the request if the Daemon responds with a 404, just assume the backup
|
// Don't fail the request if the Daemon responds with a 404, just assume the backup
|
||||||
// doesn't actually exist and remove its reference from the Panel as well.
|
// doesn't actually exist and remove its reference from the Panel as well.
|
||||||
if (!$previous instanceof ClientException || $previous->getResponse()->getStatusCode() !== Response::HTTP_NOT_FOUND) {
|
if ($exception->getCode() !== Response::HTTP_NOT_FOUND) {
|
||||||
throw $exception;
|
throw $exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,15 +10,14 @@
|
|||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"ext-zip": "*",
|
"ext-zip": "*",
|
||||||
"abdelhamiderrahmouni/filament-monaco-editor": "^0.2.5",
|
"abdelhamiderrahmouni/filament-monaco-editor": "^0.2.5",
|
||||||
"aws/aws-sdk-php": "^3.343",
|
"aws/aws-sdk-php": "^3.344",
|
||||||
"aymanalhattami/filament-context-menu": "^1.0",
|
|
||||||
"calebporzio/sushi": "^2.5",
|
"calebporzio/sushi": "^2.5",
|
||||||
"chillerlan/php-qrcode": "^5.0.2",
|
"chillerlan/php-qrcode": "^5.0.2",
|
||||||
"dedoc/scramble": "^0.12.10",
|
"dedoc/scramble": "^0.12.10",
|
||||||
"doctrine/dbal": "~3.6.0",
|
"doctrine/dbal": "~3.6.0",
|
||||||
"filament/filament": "^3.3",
|
"filament/filament": "^3.3",
|
||||||
"guzzlehttp/guzzle": "^7.9",
|
"guzzlehttp/guzzle": "^7.9",
|
||||||
"laravel/framework": "^12.17",
|
"laravel/framework": "^12.18",
|
||||||
"laravel/helpers": "^1.7",
|
"laravel/helpers": "^1.7",
|
||||||
"laravel/sanctum": "^4.1",
|
"laravel/sanctum": "^4.1",
|
||||||
"laravel/socialite": "^5.21",
|
"laravel/socialite": "^5.21",
|
||||||
@ -105,4 +104,4 @@
|
|||||||
},
|
},
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"prefer-stable": true
|
"prefer-stable": true
|
||||||
}
|
}
|
||||||
219
composer.lock
generated
219
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "9a250ae6162d7d877649172284b56c13",
|
"content-hash": "a006241b5687d547b51a60e6ac50ccae",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "abdelhamiderrahmouni/filament-monaco-editor",
|
"name": "abdelhamiderrahmouni/filament-monaco-editor",
|
||||||
@ -1020,16 +1020,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "aws/aws-sdk-php",
|
"name": "aws/aws-sdk-php",
|
||||||
"version": "3.343.23",
|
"version": "3.344.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||||
"reference": "010869992129557cfbf2740d94d82ef3b5228462"
|
"reference": "0cf789243c7de82be7d3f7641cab37b5bb5d937d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/010869992129557cfbf2740d94d82ef3b5228462",
|
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0cf789243c7de82be7d3f7641cab37b5bb5d937d",
|
||||||
"reference": "010869992129557cfbf2740d94d82ef3b5228462",
|
"reference": "0cf789243c7de82be7d3f7641cab37b5bb5d937d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1111,86 +1111,10 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
||||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.343.23"
|
"source": "https://github.com/aws/aws-sdk-php/tree/3.344.3"
|
||||||
},
|
},
|
||||||
"time": "2025-06-02T18:04:47+00:00"
|
"time": "2025-06-02T18:04:47+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "aymanalhattami/filament-context-menu",
|
|
||||||
"version": "1.0.3",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/aymanalhattami/filament-context-menu.git",
|
|
||||||
"reference": "5118d36303e86891d3037e6e26882d548b880b9c"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/aymanalhattami/filament-context-menu/zipball/5118d36303e86891d3037e6e26882d548b880b9c",
|
|
||||||
"reference": "5118d36303e86891d3037e6e26882d548b880b9c",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"filament/filament": "^3.0",
|
|
||||||
"php": "^8.2",
|
|
||||||
"spatie/laravel-package-tools": "^1.15.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"larastan/larastan": "^2.0",
|
|
||||||
"laravel/pint": "^1.0",
|
|
||||||
"nunomaduro/collision": "^8.0",
|
|
||||||
"orchestra/testbench": "^9.0",
|
|
||||||
"pestphp/pest": "^3.0",
|
|
||||||
"pestphp/pest-plugin-arch": "^3.0",
|
|
||||||
"pestphp/pest-plugin-laravel": "^3.0",
|
|
||||||
"phpstan/extension-installer": "^1.0",
|
|
||||||
"phpstan/phpstan-deprecation-rules": "^1.0",
|
|
||||||
"phpstan/phpstan-phpunit": "^1.0"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"laravel": {
|
|
||||||
"aliases": {
|
|
||||||
"Skeleton": "AymanAlhattami\\FilamentContextMenu\\Facades\\FilamentContextMenu"
|
|
||||||
},
|
|
||||||
"providers": [
|
|
||||||
"AymanAlhattami\\FilamentContextMenu\\FilamentContextMenuServiceProvider"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"AymanAlhattami\\FilamentContextMenu\\": "src/",
|
|
||||||
"AymanAlhattami\\FilamentContextMenu\\Database\\Factories\\": "database/factories/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Ayman Alhattami",
|
|
||||||
"email": "ayman.m.alhattami@gmail.com",
|
|
||||||
"role": "Developer"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "context menu (right click menu) for filament",
|
|
||||||
"homepage": "https://github.com/aymanalhattami/filament-context-menu",
|
|
||||||
"keywords": [
|
|
||||||
"ayman alhattami",
|
|
||||||
"context menu",
|
|
||||||
"filament",
|
|
||||||
"filament admin panel",
|
|
||||||
"filament context menu",
|
|
||||||
"filament_context_menu",
|
|
||||||
"laravel"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/aymanalhattami/filament-context-menu/issues",
|
|
||||||
"source": "https://github.com/aymanalhattami/filament-context-menu"
|
|
||||||
},
|
|
||||||
"time": "2024-09-22T10:47:31+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "blade-ui-kit/blade-heroicons",
|
"name": "blade-ui-kit/blade-heroicons",
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
@ -2634,7 +2558,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "filament/actions",
|
"name": "filament/actions",
|
||||||
"version": "v3.3.20",
|
"version": "v3.3.21",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/filamentphp/actions.git",
|
"url": "https://github.com/filamentphp/actions.git",
|
||||||
@ -2687,16 +2611,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "filament/filament",
|
"name": "filament/filament",
|
||||||
"version": "v3.3.20",
|
"version": "v3.3.21",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/filamentphp/panels.git",
|
"url": "https://github.com/filamentphp/panels.git",
|
||||||
"reference": "94ee92244d2a64666fb8c1ea50cb7315ebceb63b"
|
"reference": "8d915ef313835f46f49175396de82feb0166d8a8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/filamentphp/panels/zipball/94ee92244d2a64666fb8c1ea50cb7315ebceb63b",
|
"url": "https://api.github.com/repos/filamentphp/panels/zipball/8d915ef313835f46f49175396de82feb0166d8a8",
|
||||||
"reference": "94ee92244d2a64666fb8c1ea50cb7315ebceb63b",
|
"reference": "8d915ef313835f46f49175396de82feb0166d8a8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -2748,20 +2672,20 @@
|
|||||||
"issues": "https://github.com/filamentphp/filament/issues",
|
"issues": "https://github.com/filamentphp/filament/issues",
|
||||||
"source": "https://github.com/filamentphp/filament"
|
"source": "https://github.com/filamentphp/filament"
|
||||||
},
|
},
|
||||||
"time": "2025-05-27T18:46:23+00:00"
|
"time": "2025-06-10T16:10:42+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "filament/forms",
|
"name": "filament/forms",
|
||||||
"version": "v3.3.20",
|
"version": "v3.3.21",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/filamentphp/forms.git",
|
"url": "https://github.com/filamentphp/forms.git",
|
||||||
"reference": "d73cdda057a4f5bd409eab9573101e73edb404cc"
|
"reference": "014dd23a7691dc25bb037f26df852cfec5602d01"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/filamentphp/forms/zipball/d73cdda057a4f5bd409eab9573101e73edb404cc",
|
"url": "https://api.github.com/repos/filamentphp/forms/zipball/014dd23a7691dc25bb037f26df852cfec5602d01",
|
||||||
"reference": "d73cdda057a4f5bd409eab9573101e73edb404cc",
|
"reference": "014dd23a7691dc25bb037f26df852cfec5602d01",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -2804,11 +2728,11 @@
|
|||||||
"issues": "https://github.com/filamentphp/filament/issues",
|
"issues": "https://github.com/filamentphp/filament/issues",
|
||||||
"source": "https://github.com/filamentphp/filament"
|
"source": "https://github.com/filamentphp/filament"
|
||||||
},
|
},
|
||||||
"time": "2025-06-03T13:40:37+00:00"
|
"time": "2025-06-10T16:10:45+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "filament/infolists",
|
"name": "filament/infolists",
|
||||||
"version": "v3.3.20",
|
"version": "v3.3.21",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/filamentphp/infolists.git",
|
"url": "https://github.com/filamentphp/infolists.git",
|
||||||
@ -2859,7 +2783,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "filament/notifications",
|
"name": "filament/notifications",
|
||||||
"version": "v3.3.20",
|
"version": "v3.3.21",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/filamentphp/notifications.git",
|
"url": "https://github.com/filamentphp/notifications.git",
|
||||||
@ -2911,16 +2835,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "filament/support",
|
"name": "filament/support",
|
||||||
"version": "v3.3.20",
|
"version": "v3.3.21",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/filamentphp/support.git",
|
"url": "https://github.com/filamentphp/support.git",
|
||||||
"reference": "4f9793ad3339301ca53ea6f2c984734f7ac38ce7"
|
"reference": "5c140580d7feeabb4d2b0007c854676ae87be1b3"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/filamentphp/support/zipball/4f9793ad3339301ca53ea6f2c984734f7ac38ce7",
|
"url": "https://api.github.com/repos/filamentphp/support/zipball/5c140580d7feeabb4d2b0007c854676ae87be1b3",
|
||||||
"reference": "4f9793ad3339301ca53ea6f2c984734f7ac38ce7",
|
"reference": "5c140580d7feeabb4d2b0007c854676ae87be1b3",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -2966,20 +2890,20 @@
|
|||||||
"issues": "https://github.com/filamentphp/filament/issues",
|
"issues": "https://github.com/filamentphp/filament/issues",
|
||||||
"source": "https://github.com/filamentphp/filament"
|
"source": "https://github.com/filamentphp/filament"
|
||||||
},
|
},
|
||||||
"time": "2025-06-03T06:16:13+00:00"
|
"time": "2025-06-10T16:10:55+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "filament/tables",
|
"name": "filament/tables",
|
||||||
"version": "v3.3.20",
|
"version": "v3.3.21",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/filamentphp/tables.git",
|
"url": "https://github.com/filamentphp/tables.git",
|
||||||
"reference": "1a107a8411549297b97d1142b1f7a5fa7a65e32b"
|
"reference": "3d52c23443f6846774a6a2ce60f6e6173ce20943"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/filamentphp/tables/zipball/1a107a8411549297b97d1142b1f7a5fa7a65e32b",
|
"url": "https://api.github.com/repos/filamentphp/tables/zipball/3d52c23443f6846774a6a2ce60f6e6173ce20943",
|
||||||
"reference": "1a107a8411549297b97d1142b1f7a5fa7a65e32b",
|
"reference": "3d52c23443f6846774a6a2ce60f6e6173ce20943",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -3018,11 +2942,11 @@
|
|||||||
"issues": "https://github.com/filamentphp/filament/issues",
|
"issues": "https://github.com/filamentphp/filament/issues",
|
||||||
"source": "https://github.com/filamentphp/filament"
|
"source": "https://github.com/filamentphp/filament"
|
||||||
},
|
},
|
||||||
"time": "2025-06-02T09:43:47+00:00"
|
"time": "2025-06-10T16:10:40+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "filament/widgets",
|
"name": "filament/widgets",
|
||||||
"version": "v3.3.20",
|
"version": "v3.3.21",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/filamentphp/widgets.git",
|
"url": "https://github.com/filamentphp/widgets.git",
|
||||||
@ -3794,16 +3718,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/framework",
|
"name": "laravel/framework",
|
||||||
"version": "v12.17.0",
|
"version": "v12.18.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/framework.git",
|
"url": "https://github.com/laravel/framework.git",
|
||||||
"reference": "8729d084510480fdeec9b6ad198180147d4a7f06"
|
"reference": "7d264a0dad2bfc5c154240b38e8ce9b2c4cdd14d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/framework/zipball/8729d084510480fdeec9b6ad198180147d4a7f06",
|
"url": "https://api.github.com/repos/laravel/framework/zipball/7d264a0dad2bfc5c154240b38e8ce9b2c4cdd14d",
|
||||||
"reference": "8729d084510480fdeec9b6ad198180147d4a7f06",
|
"reference": "7d264a0dad2bfc5c154240b38e8ce9b2c4cdd14d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -4005,7 +3929,7 @@
|
|||||||
"issues": "https://github.com/laravel/framework/issues",
|
"issues": "https://github.com/laravel/framework/issues",
|
||||||
"source": "https://github.com/laravel/framework"
|
"source": "https://github.com/laravel/framework"
|
||||||
},
|
},
|
||||||
"time": "2025-06-03T14:04:18+00:00"
|
"time": "2025-06-10T14:48:34+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/helpers",
|
"name": "laravel/helpers",
|
||||||
@ -6461,16 +6385,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpdocumentor/reflection",
|
"name": "phpdocumentor/reflection",
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpDocumentor/Reflection.git",
|
"url": "https://github.com/phpDocumentor/Reflection.git",
|
||||||
"reference": "ab969af5e53c3bb400eea958b90b87ecc34f4dff"
|
"reference": "d91b3270832785602adcc24ae2d0974ba99a8ff8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpDocumentor/Reflection/zipball/ab969af5e53c3bb400eea958b90b87ecc34f4dff",
|
"url": "https://api.github.com/repos/phpDocumentor/Reflection/zipball/d91b3270832785602adcc24ae2d0974ba99a8ff8",
|
||||||
"reference": "ab969af5e53c3bb400eea958b90b87ecc34f4dff",
|
"reference": "d91b3270832785602adcc24ae2d0974ba99a8ff8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -6527,9 +6451,9 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpDocumentor/Reflection/issues",
|
"issues": "https://github.com/phpDocumentor/Reflection/issues",
|
||||||
"source": "https://github.com/phpDocumentor/Reflection/tree/6.2.1"
|
"source": "https://github.com/phpDocumentor/Reflection/tree/6.3.0"
|
||||||
},
|
},
|
||||||
"time": "2025-05-30T18:42:55+00:00"
|
"time": "2025-06-06T13:39:18+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpdocumentor/reflection-common",
|
"name": "phpdocumentor/reflection-common",
|
||||||
@ -7998,16 +7922,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "secondnetwork/blade-tabler-icons",
|
"name": "secondnetwork/blade-tabler-icons",
|
||||||
"version": "v3.33.0",
|
"version": "v3.34.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/secondnetwork/blade-tabler-icons.git",
|
"url": "https://github.com/secondnetwork/blade-tabler-icons.git",
|
||||||
"reference": "523b3ede493ce9f8cbe3a5bdce21769976a80b28"
|
"reference": "e48c0a5a53798d42c7beff760de8cbc7dbbccff4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/secondnetwork/blade-tabler-icons/zipball/523b3ede493ce9f8cbe3a5bdce21769976a80b28",
|
"url": "https://api.github.com/repos/secondnetwork/blade-tabler-icons/zipball/e48c0a5a53798d42c7beff760de8cbc7dbbccff4",
|
||||||
"reference": "523b3ede493ce9f8cbe3a5bdce21769976a80b28",
|
"reference": "e48c0a5a53798d42c7beff760de8cbc7dbbccff4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -8050,9 +7974,9 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/secondnetwork/blade-tabler-icons/issues",
|
"issues": "https://github.com/secondnetwork/blade-tabler-icons/issues",
|
||||||
"source": "https://github.com/secondnetwork/blade-tabler-icons/tree/v3.33.0"
|
"source": "https://github.com/secondnetwork/blade-tabler-icons/tree/v3.34.0"
|
||||||
},
|
},
|
||||||
"time": "2025-05-17T06:28:48+00:00"
|
"time": "2025-06-09T08:41:55+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "socialiteproviders/authentik",
|
"name": "socialiteproviders/authentik",
|
||||||
@ -8701,16 +8625,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "spatie/laravel-health",
|
"name": "spatie/laravel-health",
|
||||||
"version": "1.34.2",
|
"version": "1.34.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/spatie/laravel-health.git",
|
"url": "https://github.com/spatie/laravel-health.git",
|
||||||
"reference": "e7d9d6e0807a9de46f544c76d54badc19af36ddc"
|
"reference": "d421bc223c7a8c872ad944706d98a74b1056f761"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/spatie/laravel-health/zipball/e7d9d6e0807a9de46f544c76d54badc19af36ddc",
|
"url": "https://api.github.com/repos/spatie/laravel-health/zipball/d421bc223c7a8c872ad944706d98a74b1056f761",
|
||||||
"reference": "e7d9d6e0807a9de46f544c76d54badc19af36ddc",
|
"reference": "d421bc223c7a8c872ad944706d98a74b1056f761",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -8782,7 +8706,7 @@
|
|||||||
"spatie"
|
"spatie"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/spatie/laravel-health/tree/1.34.2"
|
"source": "https://github.com/spatie/laravel-health/tree/1.34.3"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -8790,7 +8714,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-05-20T08:31:02+00:00"
|
"time": "2025-06-04T22:04:19+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "spatie/laravel-package-tools",
|
"name": "spatie/laravel-package-tools",
|
||||||
@ -12744,16 +12668,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "filp/whoops",
|
"name": "filp/whoops",
|
||||||
"version": "2.18.0",
|
"version": "2.18.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/filp/whoops.git",
|
"url": "https://github.com/filp/whoops.git",
|
||||||
"reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e"
|
"reference": "8fcc6a862f2e7b94eb4221fd0819ddba3d30ab26"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/filp/whoops/zipball/a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
|
"url": "https://api.github.com/repos/filp/whoops/zipball/8fcc6a862f2e7b94eb4221fd0819ddba3d30ab26",
|
||||||
"reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
|
"reference": "8fcc6a862f2e7b94eb4221fd0819ddba3d30ab26",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -12803,7 +12727,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/filp/whoops/issues",
|
"issues": "https://github.com/filp/whoops/issues",
|
||||||
"source": "https://github.com/filp/whoops/tree/2.18.0"
|
"source": "https://github.com/filp/whoops/tree/2.18.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -12811,7 +12735,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-03-15T12:00:00+00:00"
|
"time": "2025-06-03T18:56:14+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "hamcrest/hamcrest-php",
|
"name": "hamcrest/hamcrest-php",
|
||||||
@ -12967,16 +12891,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "larastan/larastan",
|
"name": "larastan/larastan",
|
||||||
"version": "v3.4.0",
|
"version": "v3.4.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/larastan/larastan.git",
|
"url": "https://github.com/larastan/larastan.git",
|
||||||
"reference": "1042fa0c2ee490bb6da7381f3323f7292ad68222"
|
"reference": "dc20d24871d5a2138b292b0430d94d18da3dbc53"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/larastan/larastan/zipball/1042fa0c2ee490bb6da7381f3323f7292ad68222",
|
"url": "https://api.github.com/repos/larastan/larastan/zipball/dc20d24871d5a2138b292b0430d94d18da3dbc53",
|
||||||
"reference": "1042fa0c2ee490bb6da7381f3323f7292ad68222",
|
"reference": "dc20d24871d5a2138b292b0430d94d18da3dbc53",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -13044,7 +12968,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/larastan/larastan/issues",
|
"issues": "https://github.com/larastan/larastan/issues",
|
||||||
"source": "https://github.com/larastan/larastan/tree/v3.4.0"
|
"source": "https://github.com/larastan/larastan/tree/v3.4.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -13052,20 +12976,20 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-04-22T09:44:59+00:00"
|
"time": "2025-06-09T21:23:36+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/pail",
|
"name": "laravel/pail",
|
||||||
"version": "v1.2.2",
|
"version": "v1.2.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/pail.git",
|
"url": "https://github.com/laravel/pail.git",
|
||||||
"reference": "f31f4980f52be17c4667f3eafe034e6826787db2"
|
"reference": "8cc3d575c1f0e57eeb923f366a37528c50d2385a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/pail/zipball/f31f4980f52be17c4667f3eafe034e6826787db2",
|
"url": "https://api.github.com/repos/laravel/pail/zipball/8cc3d575c1f0e57eeb923f366a37528c50d2385a",
|
||||||
"reference": "f31f4980f52be17c4667f3eafe034e6826787db2",
|
"reference": "8cc3d575c1f0e57eeb923f366a37528c50d2385a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -13085,7 +13009,7 @@
|
|||||||
"orchestra/testbench-core": "^8.13|^9.0|^10.0",
|
"orchestra/testbench-core": "^8.13|^9.0|^10.0",
|
||||||
"pestphp/pest": "^2.20|^3.0",
|
"pestphp/pest": "^2.20|^3.0",
|
||||||
"pestphp/pest-plugin-type-coverage": "^2.3|^3.0",
|
"pestphp/pest-plugin-type-coverage": "^2.3|^3.0",
|
||||||
"phpstan/phpstan": "^1.10",
|
"phpstan/phpstan": "^1.12.27",
|
||||||
"symfony/var-dumper": "^6.3|^7.0"
|
"symfony/var-dumper": "^6.3|^7.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -13121,6 +13045,7 @@
|
|||||||
"description": "Easily delve into your Laravel application's log files directly from the command line.",
|
"description": "Easily delve into your Laravel application's log files directly from the command line.",
|
||||||
"homepage": "https://github.com/laravel/pail",
|
"homepage": "https://github.com/laravel/pail",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"dev",
|
||||||
"laravel",
|
"laravel",
|
||||||
"logs",
|
"logs",
|
||||||
"php",
|
"php",
|
||||||
@ -13130,7 +13055,7 @@
|
|||||||
"issues": "https://github.com/laravel/pail/issues",
|
"issues": "https://github.com/laravel/pail/issues",
|
||||||
"source": "https://github.com/laravel/pail"
|
"source": "https://github.com/laravel/pail"
|
||||||
},
|
},
|
||||||
"time": "2025-01-28T15:15:15+00:00"
|
"time": "2025-06-05T13:55:57+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/pint",
|
"name": "laravel/pint",
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"version": "PLCN_v1",
|
"version": "PLCN_v1",
|
||||||
"update_url": "https:\/\/github.com\/pelican-dev\/panel\/raw\/main\/database\/Seeders\/eggs\/rust\/egg-rust.json"
|
"update_url": "https:\/\/github.com\/pelican-dev\/panel\/raw\/main\/database\/Seeders\/eggs\/rust\/egg-rust.json"
|
||||||
},
|
},
|
||||||
"exported_at": "2025-03-18T12:36:48+00:00",
|
"exported_at": "2025-06-06T11:57:17+00:00",
|
||||||
"name": "Rust",
|
"name": "Rust",
|
||||||
"author": "panel@example.com",
|
"author": "panel@example.com",
|
||||||
"uuid": "bace2dfb-209c-452a-9459-7d6f340b07ae",
|
"uuid": "bace2dfb-209c-452a-9459-7d6f340b07ae",
|
||||||
@ -20,7 +20,7 @@
|
|||||||
"ghcr.io\/parkervcp\/games:rust": "ghcr.io\/parkervcp\/games:rust"
|
"ghcr.io\/parkervcp\/games:rust": "ghcr.io\/parkervcp\/games:rust"
|
||||||
},
|
},
|
||||||
"file_denylist": [],
|
"file_denylist": [],
|
||||||
"startup": ".\/RustDedicated -batchmode +server.port {{SERVER_PORT}} +server.queryport {{QUERY_PORT}} +server.identity \"rust\" +rcon.port {{RCON_PORT}} +rcon.web true +server.hostname \\\"{{HOSTNAME}}\\\" +server.level \\\"{{LEVEL}}\\\" +server.description \\\"{{DESCRIPTION}}\\\" +server.url \\\"{{SERVER_URL}}\\\" +server.headerimage \\\"{{SERVER_IMG}}\\\" +server.logoimage \\\"{{SERVER_LOGO}}\\\" +server.maxplayers {{MAX_PLAYERS}} +rcon.password \\\"{{RCON_PASS}}\\\" +server.saveinterval {{SAVEINTERVAL}} +app.port {{APP_PORT}} $( [ -z ${MAP_URL} ] && printf %s \"+server.worldsize \\\"{{WORLD_SIZE}}\\\" +server.seed \\\"{{WORLD_SEED}}\\\"\" || printf %s \"+server.levelurl {{MAP_URL}}\" ) {{ADDITIONAL_ARGS}}",
|
"startup": ".\/RustDedicated -batchmode +server.port {{SERVER_PORT}} +server.queryport {{QUERY_PORT}} +server.identity \"rust\" +rcon.port {{RCON_PORT}} +rcon.web true +server.hostname \\\"{{SERVER_HOSTNAME}}\\\" +server.level \\\"{{LEVEL}}\\\" +server.description \\\"{{DESCRIPTION}}\\\" +server.url \\\"{{SERVER_URL}}\\\" +server.headerimage \\\"{{SERVER_IMG}}\\\" +server.logoimage \\\"{{SERVER_LOGO}}\\\" +server.maxplayers {{MAX_PLAYERS}} +rcon.password \\\"{{RCON_PASS}}\\\" +server.saveinterval {{SAVEINTERVAL}} +app.port {{APP_PORT}} $( [ -z ${MAP_URL} ] && printf %s \"+server.worldsize \\\"{{WORLD_SIZE}}\\\" +server.seed \\\"{{WORLD_SEED}}\\\"\" || printf %s \"+server.levelurl {{MAP_URL}}\" ) {{ADDITIONAL_ARGS}}",
|
||||||
"config": {
|
"config": {
|
||||||
"files": "{}",
|
"files": "{}",
|
||||||
"startup": "{\r\n \"done\": \"Server startup complete\"\r\n}",
|
"startup": "{\r\n \"done\": \"Server startup complete\"\r\n}",
|
||||||
@ -38,7 +38,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Server Name",
|
"name": "Server Name",
|
||||||
"description": "The name of your server in the public server list.",
|
"description": "The name of your server in the public server list.",
|
||||||
"env_variable": "HOSTNAME",
|
"env_variable": "SERVER_HOSTNAME",
|
||||||
"default_value": "A Rust Server",
|
"default_value": "A Rust Server",
|
||||||
"user_viewable": true,
|
"user_viewable": true,
|
||||||
"user_editable": true,
|
"user_editable": true,
|
||||||
|
|||||||
@ -16,7 +16,8 @@ return [
|
|||||||
'startup_update' => 'Allows a user to modify the startup variables for the server.',
|
'startup_update' => 'Allows a user to modify the startup variables for the server.',
|
||||||
'startup_docker_image' => 'Allows a user to modify the Docker image used when running the server.',
|
'startup_docker_image' => 'Allows a user to modify the Docker image used when running the server.',
|
||||||
'settings_reinstall' => 'Allows a user to trigger a reinstall of this server.',
|
'settings_reinstall' => 'Allows a user to trigger a reinstall of this server.',
|
||||||
'settings_rename' => 'Allows a user to rename this server and change the description of it.',
|
'settings_rename' => 'Allows a user to rename this server.',
|
||||||
|
'settings_description' => 'Allows a user to change the description of this server.',
|
||||||
'activity_read' => 'Allows a user to view the activity logs for the server.',
|
'activity_read' => 'Allows a user to view the activity logs for the server.',
|
||||||
'websocket_*' => 'Allows a user access to the websocket for this server.',
|
'websocket_*' => 'Allows a user access to the websocket for this server.',
|
||||||
'control_console' => 'Allows a user to send data to the server console.',
|
'control_console' => 'Allows a user to send data to the server console.',
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -5,7 +5,7 @@
|
|||||||
$userFontSize = auth()->user()->getCustomization()['console_font_size'] ?? 14;
|
$userFontSize = auth()->user()->getCustomization()['console_font_size'] ?? 14;
|
||||||
$userRows = auth()->user()->getCustomization()['console_rows'] ?? 30;
|
$userRows = auth()->user()->getCustomization()['console_rows'] ?? 30;
|
||||||
@endphp
|
@endphp
|
||||||
@if($userFont)
|
@if($userFont !== "monospace")
|
||||||
<link rel="preload" href="{{ asset("storage/fonts/{$userFont}.ttf") }}" as="font" crossorigin>
|
<link rel="preload" href="{{ asset("storage/fonts/{$userFont}.ttf") }}" as="font" crossorigin>
|
||||||
<style>
|
<style>
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|||||||
@ -1,47 +1,55 @@
|
|||||||
<div class="relative">
|
<div wire:poll.15s class="relative">
|
||||||
<div
|
<a href="{{ \App\Filament\Server\Pages\Console::getUrl(panel: 'server', tenant: $server) }}" wire:navigate>
|
||||||
class="absolute left-0 top-1 bottom-0 w-1 rounded-lg"
|
<div
|
||||||
style="background-color: {{ $server->condition->getColor(true) }};">
|
class="absolute left-0 top-1 bottom-0 w-1 rounded-lg"
|
||||||
</div>
|
style="background-color: {{ $server->condition->getColor(true) }};">
|
||||||
|
|
||||||
<div class="flex-1 dark:bg-gray-800 dark:text-white rounded-lg overflow-hidden p-3">
|
|
||||||
<div class="flex items-center mb-5 gap-2">
|
|
||||||
<x-filament::icon-button
|
|
||||||
:icon="$server->condition->getIcon()"
|
|
||||||
:color="$server->condition->getColor()"
|
|
||||||
:tooltip="$server->condition->getLabel()"
|
|
||||||
size="xl"
|
|
||||||
/>
|
|
||||||
<h2 class="text-xl font-bold">
|
|
||||||
{{ $server->name }}
|
|
||||||
<span class="dark:text-gray-400">({{ $server->formatResource('uptime', type: \App\Enums\ServerResourceType::Time) }})</span>
|
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-between text-center">
|
<div class="flex-1 dark:bg-gray-800 dark:text-white rounded-lg overflow-hidden p-3">
|
||||||
<div>
|
<div class="flex items-center mb-5 gap-2">
|
||||||
<p class="text-sm dark:text-gray-400">CPU</p>
|
<x-filament::icon-button
|
||||||
<p class="text-md font-semibold">{{ $server->formatResource('cpu_absolute', type: \App\Enums\ServerResourceType::Percentage) }}</p>
|
:icon="$server->condition->getIcon()"
|
||||||
<hr class="p-0.5">
|
:color="$server->condition->getColor()"
|
||||||
<p class="text-xs dark:text-gray-400">{{ $server->formatResource('cpu', type: \App\Enums\ServerResourceType::Percentage, limit: true) }}</p>
|
:tooltip="$server->condition->getLabel()"
|
||||||
|
size="xl"
|
||||||
|
/>
|
||||||
|
<h2 class="text-xl font-bold">
|
||||||
|
{{ $server->name }}
|
||||||
|
<span class="dark:text-gray-400">({{ $server->formatResource('uptime', type: \App\Enums\ServerResourceType::Time) }})</span>
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<p class="text-sm dark:text-gray-400">Memory</p>
|
<div class="flex justify-between text-center">
|
||||||
<p class="text-md font-semibold">{{ $server->formatResource('memory_bytes') }}</p>
|
<div>
|
||||||
<hr class="p-0.5">
|
<p class="text-sm dark:text-gray-400">CPU</p>
|
||||||
<p class="text-xs dark:text-gray-400">{{ $server->formatResource('memory', limit: true) }}</p>
|
<p class="text-md font-semibold">{{ $server->formatResource('cpu_absolute', type: \App\Enums\ServerResourceType::Percentage) }}</p>
|
||||||
</div>
|
<hr class="p-0.5">
|
||||||
<div>
|
<p class="text-xs dark:text-gray-400">{{ $server->formatResource('cpu', type: \App\Enums\ServerResourceType::Percentage, limit: true) }}</p>
|
||||||
<p class="text-sm dark:text-gray-400">Disk</p>
|
</div>
|
||||||
<p class="text-md font-semibold">{{ $server->formatResource('disk_bytes') }}</p>
|
<div>
|
||||||
<hr class="p-0.5">
|
<p class="text-sm dark:text-gray-400">Memory</p>
|
||||||
<p class="text-xs dark:text-gray-400">{{ $server->formatResource('disk', limit: true) }}</p>
|
<p class="text-md font-semibold">{{ $server->formatResource('memory_bytes') }}</p>
|
||||||
</div>
|
<hr class="p-0.5">
|
||||||
<div class="hidden sm:block">
|
<p class="text-xs dark:text-gray-400">{{ $server->formatResource('memory', limit: true) }}</p>
|
||||||
<p class="text-sm dark:text-gray-400">Network</p>
|
</div>
|
||||||
<hr class="p-0.5">
|
<div>
|
||||||
<p class="text-md font-semibold">{{ $server->allocation->address }} </p>
|
<p class="text-sm dark:text-gray-400">Disk</p>
|
||||||
|
<p class="text-md font-semibold">{{ $server->formatResource('disk_bytes') }}</p>
|
||||||
|
<hr class="p-0.5">
|
||||||
|
<p class="text-xs dark:text-gray-400">{{ $server->formatResource('disk', limit: true) }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="hidden sm:block">
|
||||||
|
<p class="text-sm dark:text-gray-400">Network</p>
|
||||||
|
<hr class="p-0.5">
|
||||||
|
<p class="text-md font-semibold">{{ $server->allocation->address }} </p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
|
|
||||||
|
<x-filament-tables::actions
|
||||||
|
:actions="\App\Filament\App\Resources\ServerResource\Pages\ListServers::getPowerActions()"
|
||||||
|
:alignment="\Filament\Support\Enums\Alignment::Center"
|
||||||
|
:record="$server"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -129,6 +129,7 @@ Route::prefix('/servers/{server:uuid}')->middleware([ServerSubject::class, Authe
|
|||||||
|
|
||||||
Route::prefix('/settings')->group(function () {
|
Route::prefix('/settings')->group(function () {
|
||||||
Route::post('/rename', [Client\Servers\SettingsController::class, 'rename']);
|
Route::post('/rename', [Client\Servers\SettingsController::class, 'rename']);
|
||||||
|
Route::post('/description', [Client\Servers\SettingsController::class, 'description']);
|
||||||
Route::post('/reinstall', [Client\Servers\SettingsController::class, 'reinstall']);
|
Route::post('/reinstall', [Client\Servers\SettingsController::class, 'reinstall']);
|
||||||
Route::put('/docker-image', [Client\Servers\SettingsController::class, 'dockerImage']);
|
Route::put('/docker-image', [Client\Servers\SettingsController::class, 'dockerImage']);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -21,11 +21,9 @@ class SettingsControllerTest extends ClientApiIntegrationTestCase
|
|||||||
/** @var \App\Models\Server $server */
|
/** @var \App\Models\Server $server */
|
||||||
[$user, $server] = $this->generateTestAccount($permissions);
|
[$user, $server] = $this->generateTestAccount($permissions);
|
||||||
$originalName = $server->name;
|
$originalName = $server->name;
|
||||||
$originalDescription = $server->description;
|
|
||||||
|
|
||||||
$response = $this->actingAs($user)->postJson("/api/client/servers/$server->uuid/settings/rename", [
|
$response = $this->actingAs($user)->postJson("/api/client/servers/$server->uuid/settings/rename", [
|
||||||
'name' => '',
|
'name' => '',
|
||||||
'description' => '',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY);
|
$response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||||
@ -33,18 +31,15 @@ class SettingsControllerTest extends ClientApiIntegrationTestCase
|
|||||||
|
|
||||||
$server = $server->refresh();
|
$server = $server->refresh();
|
||||||
$this->assertSame($originalName, $server->name);
|
$this->assertSame($originalName, $server->name);
|
||||||
$this->assertSame($originalDescription, $server->description);
|
|
||||||
|
|
||||||
$this->actingAs($user)
|
$this->actingAs($user)
|
||||||
->postJson("/api/client/servers/$server->uuid/settings/rename", [
|
->postJson("/api/client/servers/$server->uuid/settings/rename", [
|
||||||
'name' => 'Test Server Name',
|
'name' => 'Test Server Name',
|
||||||
'description' => 'This is a test server.',
|
|
||||||
])
|
])
|
||||||
->assertStatus(Response::HTTP_NO_CONTENT);
|
->assertStatus(Response::HTTP_NO_CONTENT);
|
||||||
|
|
||||||
$server = $server->refresh();
|
$server = $server->refresh();
|
||||||
$this->assertSame('Test Server Name', $server->name);
|
$this->assertSame('Test Server Name', $server->name);
|
||||||
$this->assertSame('This is a test server.', $server->description);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -2,10 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Tests\Integration\Services\Backups;
|
namespace App\Tests\Integration\Services\Backups;
|
||||||
|
|
||||||
use GuzzleHttp\Psr7\Request;
|
|
||||||
use GuzzleHttp\Psr7\Response;
|
use GuzzleHttp\Psr7\Response;
|
||||||
use App\Models\Backup;
|
use App\Models\Backup;
|
||||||
use GuzzleHttp\Exception\ClientException;
|
|
||||||
use App\Extensions\Backups\BackupManager;
|
use App\Extensions\Backups\BackupManager;
|
||||||
use App\Extensions\Filesystem\S3Filesystem;
|
use App\Extensions\Filesystem\S3Filesystem;
|
||||||
use App\Services\Backups\DeleteBackupService;
|
use App\Services\Backups\DeleteBackupService;
|
||||||
@ -54,7 +52,7 @@ class DeleteBackupServiceTest extends IntegrationTestCase
|
|||||||
$backup = Backup::factory()->create(['server_id' => $server->id]);
|
$backup = Backup::factory()->create(['server_id' => $server->id]);
|
||||||
|
|
||||||
$mock = $this->mock(DaemonBackupRepository::class);
|
$mock = $this->mock(DaemonBackupRepository::class);
|
||||||
$mock->expects('setServer->delete')->with($backup)->andThrow(new ConnectionException(previous: new ClientException('', new Request('DELETE', '/'), new Response(404))));
|
$mock->expects('setServer->delete')->with($backup)->andThrow(new ConnectionException(code: 404));
|
||||||
|
|
||||||
$this->app->make(DeleteBackupService::class)->handle($backup);
|
$this->app->make(DeleteBackupService::class)->handle($backup);
|
||||||
|
|
||||||
@ -69,7 +67,7 @@ class DeleteBackupServiceTest extends IntegrationTestCase
|
|||||||
$backup = Backup::factory()->create(['server_id' => $server->id]);
|
$backup = Backup::factory()->create(['server_id' => $server->id]);
|
||||||
|
|
||||||
$mock = $this->mock(DaemonBackupRepository::class);
|
$mock = $this->mock(DaemonBackupRepository::class);
|
||||||
$mock->expects('setServer->delete')->with($backup)->andThrow(new ConnectionException(previous: new ClientException('', new Request('DELETE', '/'), new Response(500))));
|
$mock->expects('setServer->delete')->with($backup)->andThrow(new ConnectionException(code: 500));
|
||||||
|
|
||||||
$this->expectException(ConnectionException::class);
|
$this->expectException(ConnectionException::class);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user