Merge remote-tracking branch 'upstream/main' into boy132/lazy-load-server-entries

This commit is contained in:
Boy132 2025-05-28 09:35:05 +02:00
commit d9af7b1b29
20 changed files with 177 additions and 220 deletions

View File

@ -79,7 +79,7 @@ class ApiKeyResource extends Resource
TextColumn::make('user.username')
->label(trans('admin/apikey.table.created_by'))
->icon('tabler-user')
->url(fn (ApiKey $apiKey) => auth()->user()->can('update user', $apiKey->user) ? EditUser::getUrl(['record' => $apiKey->user]) : null),
->url(fn (ApiKey $apiKey) => auth()->user()->can('update', $apiKey->user) ? EditUser::getUrl(['record' => $apiKey->user]) : null),
])
->actions([
DeleteAction::make(),

View File

@ -71,10 +71,10 @@ class DatabasesRelationManager extends RelationManager
])
->actions([
DeleteAction::make()
->authorize(fn (Database $database) => auth()->user()->can('delete database', $database)),
->authorize(fn (Database $database) => auth()->user()->can('delete', $database)),
ViewAction::make()
->color('primary')
->hidden(fn () => !auth()->user()->can('viewList database')),
->hidden(fn () => !auth()->user()->can('viewAny', Database::class)),
]);
}
}

View File

@ -97,7 +97,7 @@ class AllocationsRelationManager extends RelationManager
])
->groupedBulkActions([
DeleteBulkAction::make()
->authorize(fn () => auth()->user()->can('update node')),
->authorize(fn () => auth()->user()->can('update', $this->getOwnerRecord())),
]);
}
}

View File

@ -79,8 +79,6 @@ class ServerResource extends Resource
{
$query = parent::getEloquentQuery();
return $query->whereHas('node', function (Builder $query) {
$query->whereIn('id', auth()->user()->accessibleNodes()->pluck('id'));
});
return $query->whereIn('node_id', auth()->user()->accessibleNodes()->pluck('id'));
}
}

View File

@ -144,6 +144,7 @@ class CreateServer extends CreateRecord
->relationship('user', 'username')
->searchable(['username', 'email'])
->getOptionLabelFromRecordUsing(fn (User $user) => "$user->username ($user->email)")
->createOptionAction(fn (Action $action) => $action->authorize(fn () => auth()->user()->can('create', User::class)))
->createOptionForm([
TextInput::make('username')
->label(trans('admin/user.username'))
@ -205,6 +206,7 @@ class CreateServer extends CreateRecord
->where('node_id', $get('node_id'))
->whereNull('server_id'),
)
->createOptionAction(fn (Action $action) => $action->authorize(fn (Get $get) => auth()->user()->can('create', Node::find($get('node_id')))))
->createOptionForm(function (Get $get) {
$getPage = $get;

View File

@ -686,7 +686,7 @@ class EditServer extends EditRecord
ServerResource::getMountCheckboxList($get),
]),
Tab::make(trans('admin/server.databases'))
->hidden(fn () => !auth()->user()->can('viewList database'))
->hidden(fn () => !auth()->user()->can('viewAny', Database::class))
->icon('tabler-database')
->columns(4)
->schema([
@ -710,7 +710,7 @@ class EditServer extends EditRecord
->hintAction(
Action::make('Delete')
->label(trans('filament-actions::delete.single.modal.actions.delete.label'))
->authorize(fn (Database $database) => auth()->user()->can('delete database', $database))
->authorize(fn (Database $database) => auth()->user()->can('delete', $database))
->color('danger')
->icon('tabler-trash')
->requiresConfirmation()
@ -763,7 +763,7 @@ class EditServer extends EditRecord
->columnSpan(4),
FormActions::make([
Action::make('createDatabase')
->authorize(fn () => auth()->user()->can('create database'))
->authorize(fn () => auth()->user()->can('create', Database::class))
->disabled(fn () => DatabaseHost::query()->count() < 1)
->label(fn () => DatabaseHost::query()->count() < 1 ? trans('admin/server.no_db_hosts') : trans('admin/server.create_database'))
->color(fn () => DatabaseHost::query()->count() < 1 ? 'danger' : 'primary')
@ -1065,7 +1065,7 @@ class EditServer extends EditRecord
}
})
->hidden(fn () => $canForceDelete)
->authorize(fn (Server $server) => auth()->user()->can('delete server', $server)),
->authorize(fn (Server $server) => auth()->user()->can('delete', $server)),
Actions\Action::make('ForceDelete')
->color('danger')
->label(trans('filament-actions::force-delete.single.label'))
@ -1082,7 +1082,7 @@ class EditServer extends EditRecord
}
})
->visible(fn () => $canForceDelete)
->authorize(fn (Server $server) => auth()->user()->can('delete server', $server)),
->authorize(fn (Server $server) => auth()->user()->can('delete', $server)),
Actions\Action::make('console')
->label(trans('admin/server.console'))
->icon('tabler-terminal')

View File

@ -68,13 +68,13 @@ class ListServers extends ListRecords
->searchable(),
SelectColumn::make('allocation_id')
->label(trans('admin/server.primary_allocation'))
->hidden(!auth()->user()->can('update server'))
->hidden(!auth()->user()->can('update server')) // TODO: update to policy check (fn (Server $server) --> $server is empty)
->options(fn (Server $server) => $server->allocations->mapWithKeys(fn ($allocation) => [$allocation->id => $allocation->address]))
->selectablePlaceholder(false)
->sortable(),
TextColumn::make('allocation_id_readonly')
->label(trans('admin/server.primary_allocation'))
->hidden(auth()->user()->can('update server'))
->hidden(auth()->user()->can('update server')) // TODO: update to policy check (fn (Server $server) --> $server is empty)
->state(fn (Server $server) => $server->allocation->address),
TextColumn::make('image')->hidden(),
TextColumn::make('backups_count')

View File

@ -26,7 +26,7 @@ class RotateDatabasePasswordAction extends Action
$this->icon('tabler-refresh');
$this->authorize(fn (Database $database) => auth()->user()->can('update database', $database));
$this->authorize(fn (Database $database) => auth()->user()->can('update', $database));
$this->modalHeading(trans('admin/databasehost.rotate_password'));

View File

@ -2,43 +2,27 @@
namespace App\Filament\Server\Components;
use Closure;
use Filament\Support\Concerns\EvaluatesClosures;
use Filament\Widgets\StatsOverviewWidget\Stat;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Contracts\View\View;
class SmallStatBlock extends Stat
{
protected string|Htmlable $label;
use EvaluatesClosures;
protected $value;
protected bool|Closure $copyOnClick = false;
public function label(string|Htmlable $label): static
public function copyOnClick(bool|Closure $copyOnClick = true): static
{
$this->label = $label;
$this->copyOnClick = $copyOnClick;
return $this;
}
public function value($value): static
public function shouldCopyOnClick(): bool
{
$this->value = $value;
return $this;
}
public function getLabel(): string|Htmlable
{
return $this->label;
}
public function getValue()
{
return value($this->value);
}
public function toHtml(): string
{
return $this->render()->render();
return $this->evaluate($this->copyOnClick);
}
public function render(): View

View File

@ -1,48 +0,0 @@
<?php
namespace App\Filament\Server\Components;
use Filament\Widgets\StatsOverviewWidget\Stat;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Contracts\View\View;
class StatBlock extends Stat
{
protected string|Htmlable $label;
protected $value;
public function label(string|Htmlable $label): static
{
$this->label = $label;
return $this;
}
public function value($value): static
{
$this->value = $value;
return $this;
}
public function getLabel(): string|Htmlable
{
return $this->label;
}
public function getValue()
{
return value($this->value);
}
public function toHtml(): string
{
return $this->render()->render();
}
public function render(): View
{
return view('filament.components.server-data-block', $this->data());
}
}

View File

@ -68,7 +68,7 @@ class ActivityResource extends Resource
return $user;
})
->tooltip(fn (ActivityLog $activityLog) => auth()->user()->can('seeIps activityLog') ? $activityLog->ip : '')
->url(fn (ActivityLog $activityLog) => $activityLog->actor instanceof User && auth()->user()->can('update user') ? EditUser::getUrl(['record' => $activityLog->actor], panel: 'admin') : '')
->url(fn (ActivityLog $activityLog) => $activityLog->actor instanceof User && auth()->user()->can('update', $activityLog->actor) ? EditUser::getUrl(['record' => $activityLog->actor], panel: 'admin') : '')
->grow(false),
DateTimeColumn::make('timestamp')
->since()
@ -105,7 +105,7 @@ class ActivityResource extends Resource
Action::make('edit')
->label(trans('filament-actions::edit.single.label'))
->icon('tabler-edit')
->visible(fn (ActivityLog $activityLog) => $activityLog->actor instanceof User && auth()->user()->can('update user'))
->visible(fn (ActivityLog $activityLog) => $activityLog->actor instanceof User && auth()->user()->can('update', $activityLog->actor))
->url(fn (ActivityLog $activityLog) => EditUser::getUrl(['record' => $activityLog->actor], panel: 'admin'))
),
DateTimePicker::make('timestamp'),

View File

@ -6,8 +6,10 @@ use App\Enums\ContainerStatus;
use App\Filament\Server\Components\SmallStatBlock;
use App\Models\Server;
use Carbon\CarbonInterface;
use Filament\Notifications\Notification;
use Filament\Widgets\StatsOverviewWidget;
use Illuminate\Support\Number;
use Livewire\Attributes\On;
class ServerOverview extends StatsOverviewWidget
{
@ -19,14 +21,10 @@ class ServerOverview extends StatsOverviewWidget
{
return [
SmallStatBlock::make('Name', $this->server->name)
->extraAttributes([
'class' => 'overflow-x-auto',
]),
->copyOnClick(fn () => request()->isSecure()),
SmallStatBlock::make('Status', $this->status()),
SmallStatBlock::make('Address', $this->server->allocation->address)
->extraAttributes([
'class' => 'overflow-x-auto',
]),
->copyOnClick(fn () => request()->isSecure()),
SmallStatBlock::make('CPU', $this->cpuUsage()),
SmallStatBlock::make('Memory', $this->memoryUsage()),
SmallStatBlock::make('Disk', $this->diskUsage()),
@ -93,4 +91,16 @@ class ServerOverview extends StatsOverviewWidget
return $used . ($this->server->disk > 0 ? ' / ' . $total : ' / ∞');
}
#[On('copyClick')]
public function copyClick(string $value): void
{
$this->js("window.navigator.clipboard.writeText('{$value}');");
Notification::make()
->title('Copied to clipboard')
->body($value)
->success()
->send();
}
}

View File

@ -58,7 +58,7 @@ abstract class SubuserRequest extends ClientApiRequest
$server = $this->route()->parameter('server');
// If we are an admin or the server owner, no need to perform these checks.
if ($user->can('update server', $server) || $user->id === $server->owner_id) {
if ($user->can('update', $server) || $user->id === $server->owner_id) {
return;
}

View File

@ -265,8 +265,13 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
*/
public function accessibleServers(): Builder
{
if ($this->canned('viewList server')) {
return Server::query();
if ($this->canned('viewAny', Server::class)) {
return Server::select('servers.*')
->leftJoin('subusers', 'subusers.server_id', '=', 'servers.id')
->where(function (Builder $builder) {
$builder->where('servers.owner_id', $this->id)->orWhere('subusers.user_id', $this->id)->orWhereIn('servers.node_id', $this->accessibleNodes()->pluck('id'));
})
->distinct('servers.id');
}
return $this->directAccessibleServers();
@ -278,8 +283,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
*/
public function directAccessibleServers(): Builder
{
return Server::query()
->select('servers.*')
return Server::select('servers.*')
->leftJoin('subusers', 'subusers.server_id', '=', 'servers.id')
->where(function (Builder $builder) {
$builder->where('servers.owner_id', $this->id)->orWhere('subusers.user_id', $this->id);
@ -314,12 +318,12 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
protected function checkPermission(Server $server, string $permission = ''): bool
{
if ($this->canned('update server', $server) || $server->owner_id === $this->id) {
if ($this->canned('update', $server) || $server->owner_id === $this->id) {
return true;
}
// If the user only has "view" permissions allow viewing the console
if ($permission === Permission::ACTION_WEBSOCKET_CONNECT && $this->canned('view server', $server)) {
if ($permission === Permission::ACTION_WEBSOCKET_CONNECT && $this->canned('view', $server)) {
return true;
}
@ -434,7 +438,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
public function canAccessTenant(Model $tenant): bool
{
if ($tenant instanceof Server) {
if ($this->canned('view server', $tenant) || $tenant->owner_id === $this->id) {
if ($this->canned('view', $tenant) || $tenant->owner_id === $this->id) {
return true;
}

View File

@ -21,11 +21,6 @@ class ServerPolicy
return null;
}
// Make sure user can target node of the server
if (!$user->canTarget($server->node)) {
return false;
}
// Owner has full server permissions
if ($server->owner_id === $user->id) {
return true;
@ -37,6 +32,11 @@ class ServerPolicy
return true;
}
// Make sure user can target node of the server
if (!$user->canTarget($server->node)) {
return false;
}
// Return null to let default policies take over
return null;
}

View File

@ -16,8 +16,8 @@ class GetUserPermissionsService
*/
public function handle(Server $server, User $user): array
{
if ($user->isAdmin() && ($user->can('view server', $server) || $user->can('update server', $server))) {
$permissions = $user->can('update server', $server) ? ['*'] : ['websocket.connect', 'backup.read'];
if ($user->isAdmin() && ($user->can('view', $server) || $user->can('update', $server))) {
$permissions = $user->can('update', $server) ? ['*'] : ['websocket.connect', 'backup.read'];
$permissions[] = 'admin.websocket.errors';
$permissions[] = 'admin.websocket.install';

View File

@ -18,7 +18,7 @@
"doctrine/dbal": "~3.6.0",
"filament/filament": "^3.3",
"guzzlehttp/guzzle": "^7.9",
"laravel/framework": "^12.15",
"laravel/framework": "^12.16",
"laravel/helpers": "^1.7",
"laravel/sanctum": "^4.1",
"laravel/socialite": "^5.20",
@ -38,7 +38,7 @@
"spatie/laravel-data": "^4.15",
"spatie/laravel-fractal": "^6.3",
"spatie/laravel-health": "^1.34",
"spatie/laravel-permission": "^6.17",
"spatie/laravel-permission": "^6.18",
"spatie/laravel-query-builder": "^6.3",
"spatie/temporary-directory": "^2.3",
"symfony/http-client": "^7.2",

202
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0779ca7c1d1cbeeb09f80ec120490078",
"content-hash": "6ae0adb5b2985ecea907ceb281a08926",
"packages": [
{
"name": "abdelhamiderrahmouni/filament-monaco-editor",
@ -1020,16 +1020,16 @@
},
{
"name": "aws/aws-sdk-php",
"version": "3.343.14",
"version": "3.343.18",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "8bb5b542b28c4538b44de4335396e77bf9fbedf6"
"reference": "ae98d503173740cce23b30d2ba2737c49b0d9876"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/8bb5b542b28c4538b44de4335396e77bf9fbedf6",
"reference": "8bb5b542b28c4538b44de4335396e77bf9fbedf6",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/ae98d503173740cce23b30d2ba2737c49b0d9876",
"reference": "ae98d503173740cce23b30d2ba2737c49b0d9876",
"shasum": ""
},
"require": {
@ -1111,9 +1111,9 @@
"support": {
"forum": "https://github.com/aws/aws-sdk-php/discussions",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.343.14"
"source": "https://github.com/aws/aws-sdk-php/tree/3.343.18"
},
"time": "2025-05-19T18:02:45+00:00"
"time": "2025-05-23T18:08:18+00:00"
},
{
"name": "aymanalhattami/filament-context-menu",
@ -2630,7 +2630,7 @@
},
{
"name": "filament/actions",
"version": "v3.3.15",
"version": "v3.3.16",
"source": {
"type": "git",
"url": "https://github.com/filamentphp/actions.git",
@ -2683,16 +2683,16 @@
},
{
"name": "filament/filament",
"version": "v3.3.15",
"version": "v3.3.16",
"source": {
"type": "git",
"url": "https://github.com/filamentphp/panels.git",
"reference": "bc83f6ca48340cc4127994687be121462fed9b7a"
"reference": "ed0a0109e6b2663247fcd73076c95c918bc5b412"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filamentphp/panels/zipball/bc83f6ca48340cc4127994687be121462fed9b7a",
"reference": "bc83f6ca48340cc4127994687be121462fed9b7a",
"url": "https://api.github.com/repos/filamentphp/panels/zipball/ed0a0109e6b2663247fcd73076c95c918bc5b412",
"reference": "ed0a0109e6b2663247fcd73076c95c918bc5b412",
"shasum": ""
},
"require": {
@ -2744,20 +2744,20 @@
"issues": "https://github.com/filamentphp/filament/issues",
"source": "https://github.com/filamentphp/filament"
},
"time": "2025-05-19T07:26:37+00:00"
"time": "2025-05-21T08:45:13+00:00"
},
{
"name": "filament/forms",
"version": "v3.3.15",
"version": "v3.3.16",
"source": {
"type": "git",
"url": "https://github.com/filamentphp/forms.git",
"reference": "0e46d1d14e6f30a57dd85103d2b07aff52a75a5a"
"reference": "eeb18e482b1addc5fe88d57f59d6b91cb71957ff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filamentphp/forms/zipball/0e46d1d14e6f30a57dd85103d2b07aff52a75a5a",
"reference": "0e46d1d14e6f30a57dd85103d2b07aff52a75a5a",
"url": "https://api.github.com/repos/filamentphp/forms/zipball/eeb18e482b1addc5fe88d57f59d6b91cb71957ff",
"reference": "eeb18e482b1addc5fe88d57f59d6b91cb71957ff",
"shasum": ""
},
"require": {
@ -2800,11 +2800,11 @@
"issues": "https://github.com/filamentphp/filament/issues",
"source": "https://github.com/filamentphp/filament"
},
"time": "2025-05-19T07:26:45+00:00"
"time": "2025-05-21T08:45:29+00:00"
},
{
"name": "filament/infolists",
"version": "v3.3.15",
"version": "v3.3.16",
"source": {
"type": "git",
"url": "https://github.com/filamentphp/infolists.git",
@ -2855,16 +2855,16 @@
},
{
"name": "filament/notifications",
"version": "v3.3.15",
"version": "v3.3.16",
"source": {
"type": "git",
"url": "https://github.com/filamentphp/notifications.git",
"reference": "edf7960621b2181b4c2fc040b0712fbd5dd036ef"
"reference": "356f50e24798a6f06522bfa5123c6ffd054171d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filamentphp/notifications/zipball/edf7960621b2181b4c2fc040b0712fbd5dd036ef",
"reference": "edf7960621b2181b4c2fc040b0712fbd5dd036ef",
"url": "https://api.github.com/repos/filamentphp/notifications/zipball/356f50e24798a6f06522bfa5123c6ffd054171d3",
"reference": "356f50e24798a6f06522bfa5123c6ffd054171d3",
"shasum": ""
},
"require": {
@ -2903,20 +2903,20 @@
"issues": "https://github.com/filamentphp/filament/issues",
"source": "https://github.com/filamentphp/filament"
},
"time": "2025-04-23T06:39:49+00:00"
"time": "2025-05-21T08:44:14+00:00"
},
{
"name": "filament/support",
"version": "v3.3.15",
"version": "v3.3.16",
"source": {
"type": "git",
"url": "https://github.com/filamentphp/support.git",
"reference": "0ab49fdb2bc937257d6f8e1f7b97a03216a43656"
"reference": "537663fa2c5057aa236a189255b623b5124d32d8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filamentphp/support/zipball/0ab49fdb2bc937257d6f8e1f7b97a03216a43656",
"reference": "0ab49fdb2bc937257d6f8e1f7b97a03216a43656",
"url": "https://api.github.com/repos/filamentphp/support/zipball/537663fa2c5057aa236a189255b623b5124d32d8",
"reference": "537663fa2c5057aa236a189255b623b5124d32d8",
"shasum": ""
},
"require": {
@ -2962,11 +2962,11 @@
"issues": "https://github.com/filamentphp/filament/issues",
"source": "https://github.com/filamentphp/filament"
},
"time": "2025-04-30T09:16:34+00:00"
"time": "2025-05-21T08:45:20+00:00"
},
{
"name": "filament/tables",
"version": "v3.3.15",
"version": "v3.3.16",
"source": {
"type": "git",
"url": "https://github.com/filamentphp/tables.git",
@ -3018,7 +3018,7 @@
},
{
"name": "filament/widgets",
"version": "v3.3.15",
"version": "v3.3.16",
"source": {
"type": "git",
"url": "https://github.com/filamentphp/widgets.git",
@ -3790,16 +3790,16 @@
},
{
"name": "laravel/framework",
"version": "v12.15.0",
"version": "v12.16.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "2ef7fb183f18e547af4eb9f5a55b2ac1011f0b77"
"reference": "293bb1c70224faebfd3d4328e201c37115da055f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/2ef7fb183f18e547af4eb9f5a55b2ac1011f0b77",
"reference": "2ef7fb183f18e547af4eb9f5a55b2ac1011f0b77",
"url": "https://api.github.com/repos/laravel/framework/zipball/293bb1c70224faebfd3d4328e201c37115da055f",
"reference": "293bb1c70224faebfd3d4328e201c37115da055f",
"shasum": ""
},
"require": {
@ -4001,7 +4001,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-05-20T15:10:44+00:00"
"time": "2025-05-27T15:49:44+00:00"
},
{
"name": "laravel/helpers",
@ -4246,16 +4246,16 @@
},
{
"name": "laravel/socialite",
"version": "v5.20.0",
"version": "v5.21.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/socialite.git",
"reference": "30972c12a41f71abeb418bc9ff157da8d9231519"
"reference": "d83639499ad14985c9a6a9713b70073300ce998d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/socialite/zipball/30972c12a41f71abeb418bc9ff157da8d9231519",
"reference": "30972c12a41f71abeb418bc9ff157da8d9231519",
"url": "https://api.github.com/repos/laravel/socialite/zipball/d83639499ad14985c9a6a9713b70073300ce998d",
"reference": "d83639499ad14985c9a6a9713b70073300ce998d",
"shasum": ""
},
"require": {
@ -4314,7 +4314,7 @@
"issues": "https://github.com/laravel/socialite/issues",
"source": "https://github.com/laravel/socialite"
},
"time": "2025-04-21T14:21:34+00:00"
"time": "2025-05-19T12:56:37+00:00"
},
{
"name": "laravel/tinker",
@ -9450,16 +9450,16 @@
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.5.1",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
@ -9472,7 +9472,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.5-dev"
"dev-main": "3.6-dev"
}
},
"autoload": {
@ -9497,7 +9497,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
},
"funding": [
{
@ -9513,7 +9513,7 @@
"type": "tidelift"
}
],
"time": "2024-09-25T14:20:29+00:00"
"time": "2024-09-25T14:21:43+00:00"
},
{
"name": "symfony/error-handler",
@ -9672,16 +9672,16 @@
},
{
"name": "symfony/event-dispatcher-contracts",
"version": "v3.5.1",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
"reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f"
"reference": "59eb412e93815df44f05f342958efa9f46b1e586"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f",
"reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586",
"reference": "59eb412e93815df44f05f342958efa9f46b1e586",
"shasum": ""
},
"require": {
@ -9695,7 +9695,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.5-dev"
"dev-main": "3.6-dev"
}
},
"autoload": {
@ -9728,7 +9728,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1"
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0"
},
"funding": [
{
@ -9744,7 +9744,7 @@
"type": "tidelift"
}
],
"time": "2024-09-25T14:20:29+00:00"
"time": "2024-09-25T14:21:43+00:00"
},
{
"name": "symfony/finder",
@ -9976,16 +9976,16 @@
},
{
"name": "symfony/http-client-contracts",
"version": "v3.5.2",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client-contracts.git",
"reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645"
"reference": "75d7043853a42837e68111812f4d964b01e5101c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645",
"reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645",
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c",
"reference": "75d7043853a42837e68111812f4d964b01e5101c",
"shasum": ""
},
"require": {
@ -9998,7 +9998,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.5-dev"
"dev-main": "3.6-dev"
}
},
"autoload": {
@ -10034,7 +10034,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2"
"source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0"
},
"funding": [
{
@ -10050,7 +10050,7 @@
"type": "tidelift"
}
],
"time": "2024-12-07T08:49:48+00:00"
"time": "2025-04-29T11:18:49+00:00"
},
{
"name": "symfony/http-foundation",
@ -11328,16 +11328,16 @@
},
{
"name": "symfony/service-contracts",
"version": "v3.5.1",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0"
"reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
"reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
"reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
"shasum": ""
},
"require": {
@ -11355,7 +11355,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.5-dev"
"dev-main": "3.6-dev"
}
},
"autoload": {
@ -11391,7 +11391,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.5.1"
"source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
},
"funding": [
{
@ -11407,7 +11407,7 @@
"type": "tidelift"
}
],
"time": "2024-09-25T14:20:29+00:00"
"time": "2025-04-25T09:37:31+00:00"
},
{
"name": "symfony/string",
@ -11593,16 +11593,16 @@
},
{
"name": "symfony/translation-contracts",
"version": "v3.5.1",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
"reference": "4667ff3bd513750603a09c8dedbea942487fb07c"
"reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c",
"reference": "4667ff3bd513750603a09c8dedbea942487fb07c",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
"reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
"shasum": ""
},
"require": {
@ -11615,7 +11615,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.5-dev"
"dev-main": "3.6-dev"
}
},
"autoload": {
@ -11651,7 +11651,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/translation-contracts/tree/v3.5.1"
"source": "https://github.com/symfony/translation-contracts/tree/v3.6.0"
},
"funding": [
{
@ -11667,7 +11667,7 @@
"type": "tidelift"
}
],
"time": "2024-09-25T14:20:29+00:00"
"time": "2024-09-27T08:32:26+00:00"
},
{
"name": "symfony/uid",
@ -13198,16 +13198,16 @@
},
{
"name": "laravel/sail",
"version": "v1.43.0",
"version": "v1.43.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/sail.git",
"reference": "71a509b14b2621ce58574274a74290f933c687f7"
"reference": "3e7d899232a8c5e3ea4fc6dee7525ad583887e72"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sail/zipball/71a509b14b2621ce58574274a74290f933c687f7",
"reference": "71a509b14b2621ce58574274a74290f933c687f7",
"url": "https://api.github.com/repos/laravel/sail/zipball/3e7d899232a8c5e3ea4fc6dee7525ad583887e72",
"reference": "3e7d899232a8c5e3ea4fc6dee7525ad583887e72",
"shasum": ""
},
"require": {
@ -13257,7 +13257,7 @@
"issues": "https://github.com/laravel/sail/issues",
"source": "https://github.com/laravel/sail"
},
"time": "2025-05-13T13:34:34+00:00"
"time": "2025-05-19T13:19:21+00:00"
},
{
"name": "mockery/mockery",
@ -14016,16 +14016,16 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.16",
"version": "2.1.17",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9"
"reference": "89b5ef665716fa2a52ecd2633f21007a6a349053"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9",
"reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053",
"reference": "89b5ef665716fa2a52ecd2633f21007a6a349053",
"shasum": ""
},
"require": {
@ -14070,7 +14070,7 @@
"type": "github"
}
],
"time": "2025-05-16T09:40:10+00:00"
"time": "2025-05-21T20:55:28+00:00"
},
{
"name": "phpunit/php-code-coverage",
@ -14873,23 +14873,23 @@
},
{
"name": "sebastian/environment",
"version": "7.2.0",
"version": "7.2.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5"
"reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5",
"reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4",
"reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4",
"shasum": ""
},
"require": {
"php": ">=8.2"
},
"require-dev": {
"phpunit/phpunit": "^11.0"
"phpunit/phpunit": "^11.3"
},
"suggest": {
"ext-posix": "*"
@ -14925,15 +14925,27 @@
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"security": "https://github.com/sebastianbergmann/environment/security/policy",
"source": "https://github.com/sebastianbergmann/environment/tree/7.2.0"
"source": "https://github.com/sebastianbergmann/environment/tree/7.2.1"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/environment",
"type": "tidelift"
}
],
"time": "2024-07-03T04:54:44+00:00"
"time": "2025-05-21T11:55:47+00:00"
},
{
"name": "sebastian/exporter",
@ -15966,7 +15978,7 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {},
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
@ -15977,7 +15989,7 @@
"ext-pdo": "*",
"ext-zip": "*"
},
"platform-dev": [],
"platform-dev": {},
"platform-overrides": {
"php": "8.2"
},

View File

@ -1,10 +0,0 @@
<div class="fi-wi-stats-overview-stat relative rounded-lg bg-white p-4 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
<div class="grid grid-flow-row">
<span class="text-sm font-medium text-gray-500 dark:text-gray-400">
{{ $getLabel() }}
</span>
<div class="text-xl font-semibold text-gray-950 dark:text-white">
{{ $getValue() }}
</div>
</div>
</div>

View File

@ -1,9 +1,14 @@
<div
class="grid grid-flow-row w-full p-3 rounded-lg bg-white shadow-sm overflow-hidden ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
<div class="fi-small-stat-block grid grid-flow-row w-full p-3 rounded-lg bg-white shadow-sm overflow-hidden overflow-x-auto ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
@if ($shouldCopyOnClick())
<span class="cursor-pointer" wire:click="copyClick('{{ $getValue() }}')">
@else
<span>
@endif
<span class="text-md font-medium text-gray-500 dark:text-gray-400">
{{ $getLabel() }}
</span>
<span class="text-md font-semibold">{{ $getValue() }}</span>
<span class="text-md font-semibold">
{{ $getValue() }}
</span>
</span>
</div>