From 8e4d4c2ff6e7cc98ad99837007e56cafcea66d1a Mon Sep 17 00:00:00 2001 From: Codex Agent Date: Wed, 31 Dec 2025 10:06:21 +0100 Subject: [PATCH] Neuordnung des SuperAdminBackends --- .../Blog/Resources/CategoryResource.php | 36 +++--- app/Filament/Blog/Resources/PostResource.php | 31 +++-- .../Clusters/DailyOps/DailyOpsCluster.php | 22 ++++ .../Clusters/RareAdmin/RareAdminCluster.php | 22 ++++ .../Clusters/WeeklyOps/WeeklyOpsCluster.php | 22 ++++ .../Resources/Coupons/CouponResource.php | 5 +- app/Filament/Resources/EmotionResource.php | 20 ++-- .../Resources/EventPurchaseResource.php | 29 +++-- app/Filament/Resources/EventResource.php | 5 +- app/Filament/Resources/EventTypeResource.php | 18 ++- .../Resources/GiftVoucherResource.php | 9 +- .../InfrastructureActionLogResource.php | 10 +- app/Filament/Resources/LegalPageResource.php | 24 ++-- .../Resources/MediaStorageTargetResource.php | 7 +- .../Resources/PackageAddonResource.php | 5 +- app/Filament/Resources/PackageResource.php | 7 +- app/Filament/Resources/PhotoResource.php | 6 +- .../PhotoboothSettingResource.php | 5 +- .../Tables/PhotoboothSettingsTable.php | 3 +- .../Resources/PurchaseHistoryResource.php | 5 +- app/Filament/Resources/PurchaseResource.php | 11 +- app/Filament/Resources/TaskResource.php | 25 ++-- .../Resources/TenantFeedbackResource.php | 5 +- .../Tables/TenantFeedbackTable.php | 3 +- .../Resources/TenantPackageResource.php | 9 +- app/Filament/Resources/TenantResource.php | 6 +- app/Filament/Resources/UserResource.php | 10 +- .../SuperAdmin/Pages/DokployDeployments.php | 10 ++ .../Pages/WatermarkSettingsPage.php | 10 +- .../Filament/SuperAdminPanelProvider.php | 46 +++++--- resources/lang/de/admin.php | 14 +++ resources/lang/en/admin.php | 14 +++ tests/Feature/FilamentPanelNavigationTest.php | 110 ++++++++++++++++++ tests/Unit/SuperAdminNavigationGroupsTest.php | 93 +++++++++++++++ 34 files changed, 526 insertions(+), 131 deletions(-) create mode 100644 app/Filament/Clusters/DailyOps/DailyOpsCluster.php create mode 100644 app/Filament/Clusters/RareAdmin/RareAdminCluster.php create mode 100644 app/Filament/Clusters/WeeklyOps/WeeklyOpsCluster.php create mode 100644 tests/Feature/FilamentPanelNavigationTest.php create mode 100644 tests/Unit/SuperAdminNavigationGroupsTest.php diff --git a/app/Filament/Blog/Resources/CategoryResource.php b/app/Filament/Blog/Resources/CategoryResource.php index 7696687..32ccc9a 100644 --- a/app/Filament/Blog/Resources/CategoryResource.php +++ b/app/Filament/Blog/Resources/CategoryResource.php @@ -2,33 +2,30 @@ namespace App\Filament\Blog\Resources; -use Illuminate\Support\Facades\Log; - use App\Filament\Blog\Resources\CategoryResource\Pages; use App\Filament\Blog\Traits\HasContentEditor; +use App\Filament\Clusters\RareAdmin\RareAdminCluster; use App\Models\BlogCategory; -use Filament\Forms; -use Filament\Forms\Components\MarkdownEditor; -use Filament\Schemas\Components\Section; -use Filament\Forms\Components\TextInput; -use Filament\Forms\Components\Textarea; -use Filament\Forms\Components\Toggle; -use Filament\Schemas\Components\Utilities\Get; -use Filament\Schemas\Components\Utilities\Set; -use Filament\Infolists\Components\TextEntry; -use Filament\Resources\Resource; -use Filament\Schemas\Schema; use Filament\Actions\BulkActionGroup; use Filament\Actions\DeleteBulkAction; use Filament\Actions\EditAction; +use Filament\Forms\Components\MarkdownEditor; +use Filament\Forms\Components\TextInput; +use Filament\Forms\Components\Toggle; +use Filament\Infolists\Components\TextEntry; +use Filament\Resources\Resource; +use Filament\Schemas\Components\Section; +use Filament\Schemas\Components\Tabs as SchemaTabs; +use Filament\Schemas\Components\Tabs\Tab as SchemaTab; +use Filament\Schemas\Components\Utilities\Get; +use Filament\Schemas\Components\Utilities\Set; +use Filament\Schemas\Schema; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; use Illuminate\Support\Str; -use Filament\Schemas\Components\Tabs as SchemaTabs; -use Filament\Schemas\Components\Tabs\Tab as SchemaTab; class CategoryResource extends Resource { @@ -36,7 +33,9 @@ class CategoryResource extends Resource protected static ?string $model = BlogCategory::class; - protected static string | \BackedEnum | null $navigationIcon = 'heroicon-o-list-bullet'; + protected static ?string $cluster = RareAdminCluster::class; + + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-list-bullet'; protected static ?string $navigationLabel = 'Kategorien'; @@ -46,7 +45,7 @@ class CategoryResource extends Resource public static function getNavigationGroup(): string { - return 'Content & Bibliothek'; + return __('admin.nav.content'); } public static function form(Schema $schema): Schema @@ -159,7 +158,6 @@ class CategoryResource extends Resource return $transformed; } - public static function table(Table $table): Table { return $table @@ -219,4 +217,4 @@ class CategoryResource extends Resource SoftDeletingScope::class, ]); } -} \ No newline at end of file +} diff --git a/app/Filament/Blog/Resources/PostResource.php b/app/Filament/Blog/Resources/PostResource.php index 8da428c..02c0004 100644 --- a/app/Filament/Blog/Resources/PostResource.php +++ b/app/Filament/Blog/Resources/PostResource.php @@ -4,46 +4,43 @@ namespace App\Filament\Blog\Resources; use App\Filament\Blog\Resources\PostResource\Pages; use App\Filament\Blog\Traits\HasContentEditor; -use App\Models\BlogPost; +use App\Filament\Clusters\RareAdmin\RareAdminCluster; use App\Models\BlogCategory; -use Filament\Forms; +use App\Models\BlogPost; +use Filament\Actions\BulkActionGroup; +use Filament\Actions\DeleteAction; +use Filament\Actions\DeleteBulkAction; use Filament\Forms\Components\DateTimePicker; use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\MarkdownEditor; -use Filament\Schemas\Components\Section; use Filament\Forms\Components\Select; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; +use Filament\Resources\Resource; +use Filament\Schemas\Components\Section; +use Filament\Schemas\Components\Tabs as SchemaTabs; +use Filament\Schemas\Components\Tabs\Tab as SchemaTab; use Filament\Schemas\Components\Utilities\Get; use Filament\Schemas\Components\Utilities\Set; -use Filament\Infolists\Components\TextEntry; -use Filament\Resources\Resource; use Filament\Schemas\Schema; -use Filament\Tables; -use Filament\Actions\BulkActionGroup; -use Filament\Actions\CreateAction; -use Filament\Actions\DeleteAction; -use Filament\Actions\DeleteBulkAction; -use Filament\Actions\EditAction; -use Filament\Actions\ViewAction; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\TernaryFilter; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; -use Illuminate\Support\Arr; use Illuminate\Support\Str; -use Filament\Schemas\Components\Tabs as SchemaTabs; -use Filament\Schemas\Components\Tabs\Tab as SchemaTab; + class PostResource extends Resource { use HasContentEditor; protected static ?string $model = BlogPost::class; - protected static string | \BackedEnum | null $navigationIcon = 'heroicon-o-document-text'; + protected static ?string $cluster = RareAdminCluster::class; + + protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-document-text'; protected static ?string $navigationLabel = 'Beiträge'; @@ -53,7 +50,7 @@ class PostResource extends Resource public static function getNavigationGroup(): string { - return 'Content & Bibliothek'; + return __('admin.nav.content'); } public static function form(Schema $schema): Schema diff --git a/app/Filament/Clusters/DailyOps/DailyOpsCluster.php b/app/Filament/Clusters/DailyOps/DailyOpsCluster.php new file mode 100644 index 0000000..b4be45d --- /dev/null +++ b/app/Filament/Clusters/DailyOps/DailyOpsCluster.php @@ -0,0 +1,22 @@ +name; if (is_array($value)) { $loc = app()->getLocale(); + return $value[$loc] ?? ($value['de'] ?? ($value['en'] ?? '')); } + return (string) $value; }) ->searchable(['name->de', 'name->en']) diff --git a/app/Filament/Resources/EventPurchaseResource.php b/app/Filament/Resources/EventPurchaseResource.php index e421cd2..a63b013 100644 --- a/app/Filament/Resources/EventPurchaseResource.php +++ b/app/Filament/Resources/EventPurchaseResource.php @@ -2,36 +2,35 @@ namespace App\Filament\Resources; +use App\Exports\EventPurchaseExporter; +use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster; use App\Filament\Resources\EventPurchaseResource\Pages; use App\Models\EventPurchase; -use App\Exports\EventPurchaseExporter; -use Filament\Forms\Components\DatePicker; -use Filament\Forms\Components\Select; -use Filament\Forms\Components\TextInput; -use Filament\Forms\Components\Textarea; -use Filament\Schemas\Schema; -use Filament\Resources\Resource; -use Filament\Tables; use Filament\Actions\Action; use Filament\Actions\BulkActionGroup; use Filament\Actions\DeleteBulkAction; use Filament\Actions\ExportBulkAction; use Filament\Actions\ViewAction; +use Filament\Forms\Components\DatePicker; +use Filament\Forms\Components\Select; +use Filament\Forms\Components\Textarea; +use Filament\Forms\Components\TextInput; +use Filament\Resources\Resource; +use Filament\Schemas\Schema; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\Filter; use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Filters\TernaryFilter; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\SoftDeletingScope; use Illuminate\Support\Facades\Log; -use BackedEnum; -use UnitEnum; class EventPurchaseResource extends Resource { protected static ?string $model = EventPurchase::class; + protected static ?string $cluster = WeeklyOpsCluster::class; + public static function shouldRegisterNavigation(): bool { return false; @@ -39,7 +38,7 @@ class EventPurchaseResource extends Resource public static function getNavigationGroup(): string { - return 'Billing & Finanzen'; + return __('admin.nav.commercial'); } public static function form(Schema $schema): Schema @@ -99,7 +98,7 @@ class EventPurchaseResource extends Resource TextColumn::make('package_id') ->label('Paket') ->badge() - ->color(fn (string $state): string => match($state) { + ->color(fn (string $state): string => match ($state) { 'starter_pack' => 'info', 'pro_pack' => 'success', 'lifetime_unlimited' => 'danger', @@ -112,7 +111,7 @@ class EventPurchaseResource extends Resource ->sortable(), TextColumn::make('platform') ->badge() - ->color(fn (string $state): string => match($state) { + ->color(fn (string $state): string => match ($state) { 'ios' => 'info', 'android' => 'success', 'web' => 'warning', @@ -174,7 +173,7 @@ class EventPurchaseResource extends Resource ->visible(fn (EventPurchase $record): bool => $record->transaction_id && is_null($record->refunded_at)) ->action(function (EventPurchase $record) { $record->update(['refunded_at' => now()]); - Log::info('Refund processed for purchase ID: ' . $record->id); + Log::info('Refund processed for purchase ID: '.$record->id); }), ]) ->bulkActions([ diff --git a/app/Filament/Resources/EventResource.php b/app/Filament/Resources/EventResource.php index 1a50549..c1ce6a0 100644 --- a/app/Filament/Resources/EventResource.php +++ b/app/Filament/Resources/EventResource.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\DailyOps\DailyOpsCluster; use App\Filament\Resources\EventResource\Pages; use App\Filament\Resources\EventResource\RelationManagers\EventPackagesRelationManager; use App\Models\Event; @@ -27,6 +28,8 @@ class EventResource extends Resource { protected static ?string $model = Event::class; + protected static ?string $cluster = DailyOpsCluster::class; + protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-calendar'; protected static UnitEnum|string|null $navigationGroup = null; @@ -35,7 +38,7 @@ class EventResource extends Resource public static function getNavigationGroup(): UnitEnum|string|null { - return __('admin.nav.event_management'); + return __('admin.nav.events'); } public static function form(Schema $form): Schema diff --git a/app/Filament/Resources/EventTypeResource.php b/app/Filament/Resources/EventTypeResource.php index 1deadee..ffa9968 100644 --- a/app/Filament/Resources/EventTypeResource.php +++ b/app/Filament/Resources/EventTypeResource.php @@ -2,31 +2,37 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster; use App\Filament\Resources\EventTypeResource\Pages; use App\Models\EventType; +use BackedEnum; +use Filament\Actions; use Filament\Forms\Components\KeyValue; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; -use Filament\Schemas\Schema; +use Filament\Resources\Resource; use Filament\Schemas\Components\Tabs as SchemaTabs; use Filament\Schemas\Components\Tabs\Tab as SchemaTab; -use Filament\Resources\Resource; +use Filament\Schemas\Schema; use Filament\Tables; -use Filament\Actions; use Filament\Tables\Table; use UnitEnum; -use BackedEnum; class EventTypeResource extends Resource { protected static ?string $model = EventType::class; + + protected static ?string $cluster = WeeklyOpsCluster::class; + protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-swatch'; + protected static UnitEnum|string|null $navigationGroup = null; public static function getNavigationGroup(): UnitEnum|string|null { - return __('admin.nav.event_management'); + return __('admin.nav.events'); } + protected static ?int $navigationSort = 20; public static function form(Schema $form): Schema @@ -76,8 +82,10 @@ class EventTypeResource extends Resource $value = $record->name; if (is_array($value)) { $loc = app()->getLocale(); + return $value[$loc] ?? ($value['de'] ?? ($value['en'] ?? '')); } + return (string) $value; }) ->searchable(['name->de', 'name->en']) diff --git a/app/Filament/Resources/GiftVoucherResource.php b/app/Filament/Resources/GiftVoucherResource.php index 7b86c35..cd973ee 100644 --- a/app/Filament/Resources/GiftVoucherResource.php +++ b/app/Filament/Resources/GiftVoucherResource.php @@ -2,34 +2,37 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster; use App\Filament\Resources\GiftVoucherResource\Pages; use App\Models\GiftVoucher; use App\Services\GiftVouchers\GiftVoucherService; use BackedEnum; use Carbon\Carbon; -use Filament\Forms\Components\Textarea; use Filament\Actions\Action; +use Filament\Actions\ExportAction; use Filament\Forms\Components\DateTimePicker; +use Filament\Forms\Components\Textarea; use Filament\Resources\Resource; use Filament\Schemas\Schema; use Filament\Tables\Columns\BadgeColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Table; -use Filament\Tables\Actions\ExportAction; use UnitEnum; class GiftVoucherResource extends Resource { protected static ?string $model = GiftVoucher::class; + protected static ?string $cluster = WeeklyOpsCluster::class; + protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-gift'; protected static ?int $navigationSort = 12; public static function getNavigationGroup(): UnitEnum|string|null { - return __('admin.nav.billing'); + return __('admin.nav.commercial'); } public static function table(Table $table): Table diff --git a/app/Filament/Resources/InfrastructureActionLogs/InfrastructureActionLogResource.php b/app/Filament/Resources/InfrastructureActionLogs/InfrastructureActionLogResource.php index 9c2e8d9..989bfb0 100644 --- a/app/Filament/Resources/InfrastructureActionLogs/InfrastructureActionLogResource.php +++ b/app/Filament/Resources/InfrastructureActionLogs/InfrastructureActionLogResource.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources\InfrastructureActionLogs; +use App\Filament\Clusters\RareAdmin\RareAdminCluster; use App\Filament\Resources\InfrastructureActionLogs\Pages\ManageInfrastructureActionLogs; use App\Models\InfrastructureActionLog; use BackedEnum; @@ -16,12 +17,19 @@ class InfrastructureActionLogResource extends Resource { protected static ?string $model = InfrastructureActionLog::class; + protected static ?string $cluster = RareAdminCluster::class; + protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack; - protected static string|UnitEnum|null $navigationGroup = 'Platform'; + protected static string|UnitEnum|null $navigationGroup = null; protected static ?int $navigationSort = 90; + public static function getNavigationGroup(): UnitEnum|string|null + { + return __('admin.nav.infrastructure'); + } + public static function table(Table $table): Table { return $table diff --git a/app/Filament/Resources/LegalPageResource.php b/app/Filament/Resources/LegalPageResource.php index d3ad897..aa184f4 100644 --- a/app/Filament/Resources/LegalPageResource.php +++ b/app/Filament/Resources/LegalPageResource.php @@ -2,33 +2,39 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\RareAdmin\RareAdminCluster; use App\Filament\Resources\LegalPageResource\Pages; use App\Models\LegalPage; -use Filament\Resources\Resource; -use Filament\Tables; -use Filament\Tables\Table; +use BackedEnum; use Filament\Actions; -use Filament\Schemas\Schema; +use Filament\Forms\Components\DatePicker; +use Filament\Forms\Components\KeyValue; +use Filament\Forms\Components\MarkdownEditor; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; -use Filament\Forms\Components\KeyValue; -use Filament\Forms\Components\DatePicker; -use Filament\Forms\Components\MarkdownEditor; +use Filament\Resources\Resource; use Filament\Schemas\Components\Tabs as SchemaTabs; use Filament\Schemas\Components\Tabs\Tab as SchemaTab; +use Filament\Schemas\Schema; +use Filament\Tables; +use Filament\Tables\Table; use UnitEnum; -use BackedEnum; class LegalPageResource extends Resource { protected static ?string $model = LegalPage::class; + + protected static ?string $cluster = RareAdminCluster::class; + protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-scale'; + protected static UnitEnum|string|null $navigationGroup = null; public static function getNavigationGroup(): UnitEnum|string|null { - return __('admin.nav.content_library'); + return __('admin.nav.content'); } + protected static ?int $navigationSort = 40; public static function form(Schema $form): Schema diff --git a/app/Filament/Resources/MediaStorageTargetResource.php b/app/Filament/Resources/MediaStorageTargetResource.php index cf76414..50b52bb 100644 --- a/app/Filament/Resources/MediaStorageTargetResource.php +++ b/app/Filament/Resources/MediaStorageTargetResource.php @@ -2,8 +2,10 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\RareAdmin\RareAdminCluster; use App\Filament\Resources\MediaStorageTargetResource\Pages; use App\Models\MediaStorageTarget; +use BackedEnum; use Filament\Actions; use Filament\Forms\Components\KeyValue; use Filament\Forms\Components\Select; @@ -14,19 +16,20 @@ use Filament\Schemas\Schema; use Filament\Tables; use Filament\Tables\Table; use UnitEnum; -use BackedEnum; class MediaStorageTargetResource extends Resource { protected static ?string $model = MediaStorageTarget::class; + protected static ?string $cluster = RareAdminCluster::class; + protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-server'; protected static string|UnitEnum|null $navigationGroup = null; public static function getNavigationGroup(): UnitEnum|string|null { - return __('admin.nav.platform_management'); + return __('admin.nav.storage'); } protected static ?int $navigationSort = 60; diff --git a/app/Filament/Resources/PackageAddonResource.php b/app/Filament/Resources/PackageAddonResource.php index 55f895b..e82bcb1 100644 --- a/app/Filament/Resources/PackageAddonResource.php +++ b/app/Filament/Resources/PackageAddonResource.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster; use App\Filament\Resources\PackageAddonResource\Pages; use App\Jobs\SyncPackageAddonToPaddle; use App\Models\PackageAddon; @@ -21,13 +22,15 @@ class PackageAddonResource extends Resource { protected static ?string $model = PackageAddon::class; + protected static ?string $cluster = WeeklyOpsCluster::class; + protected static \BackedEnum|string|null $navigationIcon = 'heroicon-o-plus-circle'; protected static ?int $navigationSort = 6; public static function getNavigationGroup(): \BackedEnum|string|null { - return __('admin.nav.platform_management'); + return __('admin.nav.commercial'); } public static function form(Schema $schema): Schema diff --git a/app/Filament/Resources/PackageResource.php b/app/Filament/Resources/PackageResource.php index 56fda11..1e0fe6d 100644 --- a/app/Filament/Resources/PackageResource.php +++ b/app/Filament/Resources/PackageResource.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster; use App\Filament\Resources\PackageResource\Pages; use App\Jobs\PullPackageFromPaddle; use App\Jobs\SyncPackageToPaddle; @@ -11,9 +12,9 @@ use Filament\Actions; use Filament\Actions\BulkActionGroup; use Filament\Actions\DeleteAction; use Filament\Actions\DeleteBulkAction; +use Filament\Actions\EditAction; use Filament\Actions\ForceDeleteAction; use Filament\Actions\ForceDeleteBulkAction; -use Filament\Actions\EditAction; use Filament\Actions\RestoreAction; use Filament\Actions\RestoreBulkAction; use Filament\Actions\ViewAction; @@ -45,13 +46,15 @@ class PackageResource extends Resource { protected static ?string $model = Package::class; + protected static ?string $cluster = WeeklyOpsCluster::class; + protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-cube'; protected static string|UnitEnum|null $navigationGroup = null; public static function getNavigationGroup(): UnitEnum|string|null { - return __('admin.nav.platform_management'); + return __('admin.nav.commercial'); } protected static ?int $navigationSort = 5; diff --git a/app/Filament/Resources/PhotoResource.php b/app/Filament/Resources/PhotoResource.php index a4e8165..acd5c1f 100644 --- a/app/Filament/Resources/PhotoResource.php +++ b/app/Filament/Resources/PhotoResource.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\DailyOps\DailyOpsCluster; use App\Filament\Resources\PhotoResource\Pages; use App\Models\Event; use App\Models\Photo; @@ -11,7 +12,6 @@ use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\KeyValue; use Filament\Forms\Components\Select; use Filament\Forms\Components\Toggle; -use Filament\Forms\Form; use Filament\Resources\Resource; use Filament\Schemas\Schema; use Filament\Tables; @@ -22,6 +22,8 @@ class PhotoResource extends Resource { protected static ?string $model = Photo::class; + protected static ?string $cluster = DailyOpsCluster::class; + protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-photo'; protected static UnitEnum|string|null $navigationGroup = null; @@ -30,7 +32,7 @@ class PhotoResource extends Resource public static function getNavigationGroup(): UnitEnum|string|null { - return __('admin.nav.event_management'); + return __('admin.nav.events'); } public static function form(Schema $form): Schema diff --git a/app/Filament/Resources/PhotoboothSettings/PhotoboothSettingResource.php b/app/Filament/Resources/PhotoboothSettings/PhotoboothSettingResource.php index 2a905c8..27399c8 100644 --- a/app/Filament/Resources/PhotoboothSettings/PhotoboothSettingResource.php +++ b/app/Filament/Resources/PhotoboothSettings/PhotoboothSettingResource.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources\PhotoboothSettings; +use App\Filament\Clusters\RareAdmin\RareAdminCluster; use App\Filament\Resources\PhotoboothSettings\Pages\EditPhotoboothSetting; use App\Filament\Resources\PhotoboothSettings\Pages\ListPhotoboothSettings; use App\Filament\Resources\PhotoboothSettings\Schemas\PhotoboothSettingForm; @@ -20,6 +21,8 @@ class PhotoboothSettingResource extends Resource { protected static ?string $model = PhotoboothSetting::class; + protected static ?string $cluster = RareAdminCluster::class; + protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack; protected static UnitEnum|string|null $navigationGroup = null; @@ -28,7 +31,7 @@ class PhotoboothSettingResource extends Resource public static function getNavigationGroup(): UnitEnum|string|null { - return __('admin.nav.platform_management'); + return __('admin.nav.storage'); } public static function form(Schema $schema): Schema diff --git a/app/Filament/Resources/PhotoboothSettings/Tables/PhotoboothSettingsTable.php b/app/Filament/Resources/PhotoboothSettings/Tables/PhotoboothSettingsTable.php index b57c036..f41d476 100644 --- a/app/Filament/Resources/PhotoboothSettings/Tables/PhotoboothSettingsTable.php +++ b/app/Filament/Resources/PhotoboothSettings/Tables/PhotoboothSettingsTable.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources\PhotoboothSettings\Tables; +use Filament\Actions\EditAction; use Filament\Tables; use Filament\Tables\Table; @@ -28,7 +29,7 @@ class PhotoboothSettingsTable ->label(__('Aktualisiert')), ]) ->recordActions([ - Tables\Actions\EditAction::make(), + EditAction::make(), ]) ->headerActions([]) ->bulkActions([]); diff --git a/app/Filament/Resources/PurchaseHistoryResource.php b/app/Filament/Resources/PurchaseHistoryResource.php index c9f2926..e1fa659 100644 --- a/app/Filament/Resources/PurchaseHistoryResource.php +++ b/app/Filament/Resources/PurchaseHistoryResource.php @@ -3,6 +3,7 @@ namespace App\Filament\Resources; use App\Exports\PurchaseHistoryExporter; +use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster; use App\Filament\Resources\PurchaseHistoryResource\Pages; use App\Models\PurchaseHistory; use BackedEnum; @@ -21,13 +22,15 @@ class PurchaseHistoryResource extends Resource { protected static ?string $model = PurchaseHistory::class; + protected static ?string $cluster = WeeklyOpsCluster::class; + protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-receipt-refund'; protected static ?int $navigationSort = 20; public static function getNavigationGroup(): string { - return __('admin.nav.billing'); + return __('admin.nav.commercial'); } public static function form(Schema $form): Schema diff --git a/app/Filament/Resources/PurchaseResource.php b/app/Filament/Resources/PurchaseResource.php index 72617bf..6a74e3b 100644 --- a/app/Filament/Resources/PurchaseResource.php +++ b/app/Filament/Resources/PurchaseResource.php @@ -2,8 +2,12 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\DailyOps\DailyOpsCluster; use App\Filament\Resources\PurchaseResource\Pages; use App\Models\PackagePurchase; +use App\Notifications\Customer\RefundReceipt; +use App\Notifications\Ops\RefundProcessed; +use App\Services\Paddle\PaddleTransactionService; use BackedEnum; use Filament\Actions\Action; use Filament\Actions\BulkActionGroup; @@ -26,19 +30,18 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Notification; -use App\Notifications\Ops\RefundProcessed; -use App\Notifications\Customer\RefundReceipt; -use App\Services\Paddle\PaddleTransactionService; class PurchaseResource extends Resource { protected static ?string $model = PackagePurchase::class; + protected static ?string $cluster = DailyOpsCluster::class; + protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-shopping-cart'; public static function getNavigationGroup(): string { - return 'Billing & Finanzen'; + return __('admin.nav.billing'); } protected static ?int $navigationSort = 10; diff --git a/app/Filament/Resources/TaskResource.php b/app/Filament/Resources/TaskResource.php index 98e0eea..fb40005 100644 --- a/app/Filament/Resources/TaskResource.php +++ b/app/Filament/Resources/TaskResource.php @@ -2,33 +2,38 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster; use App\Filament\Resources\TaskResource\Pages; use App\Models\Task; -use Filament\Forms\Components\KeyValue; +use BackedEnum; +use Filament\Actions; +use Filament\Forms\Components\MarkdownEditor; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; -use Filament\Forms\Components\MarkdownEditor; -use Filament\Schemas\Schema; +use Filament\Resources\Resource; use Filament\Schemas\Components\Tabs as SchemaTabs; use Filament\Schemas\Components\Tabs\Tab as SchemaTab; -use Filament\Resources\Resource; +use Filament\Schemas\Schema; use Filament\Tables; use Filament\Tables\Table; -use Filament\Actions; use UnitEnum; -use BackedEnum; class TaskResource extends Resource { protected static ?string $model = Task::class; + + protected static ?string $cluster = WeeklyOpsCluster::class; + protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-clipboard-document-check'; + protected static UnitEnum|string|null $navigationGroup = null; + protected static ?int $navigationSort = 30; public static function getNavigationGroup(): UnitEnum|string|null { - return __('admin.nav.tasks_emotions'); + return __('admin.nav.curation'); } public static function getNavigationLabel(): string @@ -106,8 +111,10 @@ class TaskResource extends Resource $value = $record->title; if (is_array($value)) { $loc = app()->getLocale(); + return $value[$loc] ?? ($value['de'] ?? ($value['en'] ?? '')); } + return (string) $value; }) ->limit(60) @@ -119,8 +126,10 @@ class TaskResource extends Resource $value = optional($record->emotion)->name; if (is_array($value)) { $loc = app()->getLocale(); + return $value[$loc] ?? ($value['de'] ?? ($value['en'] ?? '')); } + return (string) ($value ?? ''); }) ->sortable() @@ -132,8 +141,10 @@ class TaskResource extends Resource $value = optional($record->eventType)->name; if (is_array($value)) { $loc = app()->getLocale(); + return $value[$loc] ?? ($value['de'] ?? ($value['en'] ?? '')); } + return (string) ($value ?? ''); }) ->toggleable(), diff --git a/app/Filament/Resources/TenantFeedbackResource.php b/app/Filament/Resources/TenantFeedbackResource.php index 050da82..7174224 100644 --- a/app/Filament/Resources/TenantFeedbackResource.php +++ b/app/Filament/Resources/TenantFeedbackResource.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\DailyOps\DailyOpsCluster; use App\Filament\Resources\TenantFeedbackResource\Pages\ListTenantFeedback; use App\Filament\Resources\TenantFeedbackResource\Pages\ViewTenantFeedback; use App\Filament\Resources\TenantFeedbackResource\Schemas\TenantFeedbackForm; @@ -19,6 +20,8 @@ class TenantFeedbackResource extends Resource { protected static ?string $model = TenantFeedback::class; + protected static ?string $cluster = DailyOpsCluster::class; + protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedChatBubbleBottomCenterText; protected static UnitEnum|string|null $navigationGroup = null; @@ -47,7 +50,7 @@ class TenantFeedbackResource extends Resource public static function getNavigationGroup(): UnitEnum|string|null { - return __('Feedback & Support'); + return __('admin.nav.feedback_support'); } public static function getRelations(): array diff --git a/app/Filament/Resources/TenantFeedbackResource/Tables/TenantFeedbackTable.php b/app/Filament/Resources/TenantFeedbackResource/Tables/TenantFeedbackTable.php index a08feb0..07d383a 100644 --- a/app/Filament/Resources/TenantFeedbackResource/Tables/TenantFeedbackTable.php +++ b/app/Filament/Resources/TenantFeedbackResource/Tables/TenantFeedbackTable.php @@ -3,6 +3,7 @@ namespace App\Filament\Resources\TenantFeedbackResource\Tables; use App\Models\TenantFeedback; +use Filament\Actions\ViewAction; use Filament\Tables; use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Table; @@ -69,7 +70,7 @@ class TenantFeedbackTable ->toArray()), ]) ->recordActions([ - Tables\Actions\ViewAction::make(), + ViewAction::make(), ]) ->bulkActions([]); } diff --git a/app/Filament/Resources/TenantPackageResource.php b/app/Filament/Resources/TenantPackageResource.php index 1ca6721..e90a166 100644 --- a/app/Filament/Resources/TenantPackageResource.php +++ b/app/Filament/Resources/TenantPackageResource.php @@ -2,12 +2,12 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster; use App\Filament\Resources\TenantPackageResource\Pages; use App\Models\TenantPackage; use BackedEnum; use Filament\Actions\ActionGroup; use Filament\Actions\BulkActionGroup; -use Filament\Actions\CreateAction; use Filament\Actions\DeleteAction; use Filament\Actions\DeleteBulkAction; use Filament\Actions\EditAction; @@ -15,26 +15,25 @@ use Filament\Actions\ViewAction; use Filament\Forms\Components\DateTimePicker; use Filament\Forms\Components\Select; use Filament\Forms\Components\Toggle; -use Filament\Forms\Form; use Filament\Resources\Resource; use Filament\Schemas\Schema; -use Filament\Tables; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; -use UnitEnum; class TenantPackageResource extends Resource { protected static ?string $model = TenantPackage::class; + protected static ?string $cluster = WeeklyOpsCluster::class; + protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-shopping-bag'; protected static ?string $slug = 'tenant-packages'; public static function getNavigationGroup(): string { - return 'Billing & Finanzen'; + return __('admin.nav.commercial'); } public static function form(Schema $form): Schema diff --git a/app/Filament/Resources/TenantResource.php b/app/Filament/Resources/TenantResource.php index 4d35a61..55164b9 100644 --- a/app/Filament/Resources/TenantResource.php +++ b/app/Filament/Resources/TenantResource.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\DailyOps\DailyOpsCluster; use App\Filament\Resources\TenantResource\Pages; use App\Filament\Resources\TenantResource\RelationManagers\PackagePurchasesRelationManager; use App\Filament\Resources\TenantResource\RelationManagers\TenantPackagesRelationManager; @@ -13,7 +14,6 @@ use Filament\Forms\Components\KeyValue; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; -use Filament\Notifications\Notification; use Filament\Resources\Resource; use Filament\Schemas\Schema; use Filament\Tables; @@ -25,13 +25,15 @@ class TenantResource extends Resource { protected static ?string $model = Tenant::class; + protected static ?string $cluster = DailyOpsCluster::class; + protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-building-office'; protected static UnitEnum|string|null $navigationGroup = null; public static function getNavigationGroup(): UnitEnum|string|null { - return __('admin.nav.platform_management'); + return __('admin.nav.tenants'); } protected static ?int $navigationSort = 10; diff --git a/app/Filament/Resources/UserResource.php b/app/Filament/Resources/UserResource.php index 04e3c54..b613af0 100644 --- a/app/Filament/Resources/UserResource.php +++ b/app/Filament/Resources/UserResource.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources; +use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster; use App\Filament\Resources\UserResource\Pages; use App\Models\User; use BackedEnum; @@ -10,29 +11,28 @@ use Filament\Actions\BulkActionGroup; use Filament\Actions\DeleteBulkAction; use Filament\Actions\EditAction; use Filament\Actions\ViewAction; -use Filament\Schemas\Components\Section; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; -use Filament\Forms\Form; use Filament\Resources\Resource; +use Filament\Schemas\Components\Section; use Filament\Schemas\Schema; -use Filament\Tables; use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; -use UnitEnum; class UserResource extends Resource { protected static ?string $model = User::class; + protected static ?string $cluster = WeeklyOpsCluster::class; + protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-user-circle'; protected static ?string $slug = 'users'; public static function getNavigationGroup(): string { - return 'Plattform-Verwaltung'; + return __('admin.nav.platform'); } public static function form(Schema $form): Schema diff --git a/app/Filament/SuperAdmin/Pages/DokployDeployments.php b/app/Filament/SuperAdmin/Pages/DokployDeployments.php index 4abdc3d..eccf8e9 100644 --- a/app/Filament/SuperAdmin/Pages/DokployDeployments.php +++ b/app/Filament/SuperAdmin/Pages/DokployDeployments.php @@ -2,6 +2,7 @@ namespace App\Filament\SuperAdmin\Pages; +use App\Filament\Clusters\RareAdmin\RareAdminCluster; use App\Models\InfrastructureActionLog; use App\Services\Dokploy\DokployClient; use BackedEnum; @@ -17,6 +18,10 @@ class DokployDeployments extends Page protected static ?string $title = 'Infrastructure Controls'; + protected static null|string|\UnitEnum $navigationGroup = null; + + protected static ?string $cluster = RareAdminCluster::class; + protected string $view = 'filament.super-admin.pages.dokploy-deployments'; public array $composes = []; @@ -25,6 +30,11 @@ class DokployDeployments extends Page public ?string $dokployWebUrl = null; + public static function getNavigationGroup(): \UnitEnum|string|null + { + return __('admin.nav.infrastructure'); + } + public function mount(DokployClient $client): void { $this->dokployWebUrl = config('dokploy.web_url'); diff --git a/app/Filament/SuperAdmin/Pages/WatermarkSettingsPage.php b/app/Filament/SuperAdmin/Pages/WatermarkSettingsPage.php index 4f55c63..680b408 100644 --- a/app/Filament/SuperAdmin/Pages/WatermarkSettingsPage.php +++ b/app/Filament/SuperAdmin/Pages/WatermarkSettingsPage.php @@ -2,6 +2,7 @@ namespace App\Filament\SuperAdmin\Pages; +use App\Filament\Clusters\RareAdmin\RareAdminCluster; use App\Models\WatermarkSetting; use Filament\Forms; use Filament\Forms\Form; @@ -12,12 +13,19 @@ class WatermarkSettingsPage extends Page { protected static null|string|\BackedEnum $navigationIcon = 'heroicon-o-sparkles'; + protected static ?string $cluster = RareAdminCluster::class; + protected string $view = 'filament.super-admin.pages.watermark-settings-page'; - protected static null|string|\UnitEnum $navigationGroup = 'Branding'; + protected static null|string|\UnitEnum $navigationGroup = null; protected static ?int $navigationSort = 20; + public static function getNavigationGroup(): \UnitEnum|string|null + { + return __('admin.nav.branding'); + } + public ?string $asset = null; public string $position = 'bottom-right'; diff --git a/app/Providers/Filament/SuperAdminPanelProvider.php b/app/Providers/Filament/SuperAdminPanelProvider.php index 5517de5..7180ab9 100644 --- a/app/Providers/Filament/SuperAdminPanelProvider.php +++ b/app/Providers/Filament/SuperAdminPanelProvider.php @@ -2,10 +2,6 @@ namespace App\Providers\Filament; -use App\Filament\Blog\Resources\CategoryResource; -use App\Filament\Blog\Resources\PostResource; -use App\Filament\Resources\InfrastructureActionLogs\InfrastructureActionLogResource; -use App\Filament\Resources\LegalPageResource; use App\Filament\Widgets\DokployPlatformHealth; use App\Filament\Widgets\PlatformStatsWidget; use App\Filament\Widgets\RevenueTrendWidget; @@ -15,6 +11,7 @@ use Boquizo\FilamentLogViewer\FilamentLogViewerPlugin; use Filament\Http\Middleware\Authenticate; use Filament\Http\Middleware\DisableBladeIconComponents; use Filament\Http\Middleware\DispatchServingFilamentEvent; +use Filament\Navigation\NavigationGroup; use Filament\Pages; use Filament\Panel; use Filament\PanelProvider; @@ -38,18 +35,45 @@ class SuperAdminPanelProvider extends PanelProvider ->default() ->id('superadmin') ->path('super-admin') + ->topNavigation() ->colors([ 'primary' => Color::Pink, ]) ->plugins([ FilamentLogViewerPlugin::make() - ->navigationGroup('Platform') + ->navigationGroup(__('admin.nav.infrastructure')) ->navigationLabel('Log Viewer') ->navigationIcon(Heroicon::OutlinedDocumentText) ->navigationSort(20), ]) + ->navigationGroups([ + NavigationGroup::make() + ->label(__('admin.nav.curation')), + NavigationGroup::make() + ->label(__('admin.nav.events')), + NavigationGroup::make() + ->label(__('admin.nav.tenants')), + NavigationGroup::make() + ->label(__('admin.nav.billing')), + NavigationGroup::make() + ->label(__('admin.nav.feedback_support')), + NavigationGroup::make() + ->label(__('admin.nav.platform')), + NavigationGroup::make() + ->label(__('admin.nav.commercial')), + NavigationGroup::make() + ->label(__('admin.nav.infrastructure')), + NavigationGroup::make() + ->label(__('admin.nav.storage')), + NavigationGroup::make() + ->label(__('admin.nav.content')), + NavigationGroup::make() + ->label(__('admin.nav.branding')), + ]) ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') + ->discoverResources(in: app_path('Filament/Blog/Resources'), for: 'App\\Filament\\Blog\\Resources') ->discoverPages(in: app_path('Filament/SuperAdmin/Pages'), for: 'App\\Filament\\SuperAdmin\\Pages') + ->discoverClusters(in: app_path('Filament/Clusters'), for: 'App\\Filament\\Clusters') ->pages([ Pages\Dashboard::class, ]) @@ -84,18 +108,6 @@ class SuperAdminPanelProvider extends PanelProvider ->authMiddleware([ Authenticate::class, ]) - ->resources([ - \App\Filament\Resources\EventResource::class, - \App\Filament\Resources\PhotoResource::class, - \App\Filament\Resources\UserResource::class, - \App\Filament\Resources\TenantPackageResource::class, - \App\Filament\Resources\TaskResource::class, - \App\Filament\Resources\MediaStorageTargetResource::class, - PostResource::class, - CategoryResource::class, - LegalPageResource::class, - InfrastructureActionLogResource::class, - ]) ->pages([ Pages\Dashboard::class, \App\Filament\SuperAdmin\Pages\WatermarkSettingsPage::class, diff --git a/resources/lang/de/admin.php b/resources/lang/de/admin.php index 6f3f0dd..1cce77c 100644 --- a/resources/lang/de/admin.php +++ b/resources/lang/de/admin.php @@ -5,8 +5,22 @@ return [ 'platform' => 'Plattform', 'library' => 'Bibliothek', 'content' => 'Inhalte', + 'daily_ops' => 'Täglicher Betrieb', + 'weekly_ops' => 'Wöchentliche Aufgaben', + 'rare_admin' => 'Selten / Admin', 'platform_management' => 'Plattformverwaltung', + 'events' => 'Events', + 'tenants' => 'Mandanten', + 'curation' => 'Kuration', + 'event_management' => 'Event-Management', + 'tasks_emotions' => 'Aufgaben & Emotionen', + 'content_library' => 'Content & Bibliothek', 'billing' => 'Billing & Finanzen', + 'commercial' => 'Kommerziell', + 'infrastructure' => 'Infrastruktur', + 'storage' => 'Speicher', + 'feedback_support' => 'Feedback & Support', + 'branding' => 'Branding', 'security' => 'Sicherheit', ], diff --git a/resources/lang/en/admin.php b/resources/lang/en/admin.php index 4904fcd..3a4dd00 100644 --- a/resources/lang/en/admin.php +++ b/resources/lang/en/admin.php @@ -5,8 +5,22 @@ return [ 'platform' => 'Platform', 'library' => 'Library', 'content' => 'Content', + 'daily_ops' => 'Daily Ops', + 'weekly_ops' => 'Weekly Ops', + 'rare_admin' => 'Rare / Admin', 'platform_management' => 'Platform Management', + 'events' => 'Events', + 'tenants' => 'Tenants', + 'curation' => 'Curation', + 'event_management' => 'Event Management', + 'tasks_emotions' => 'Tasks & Emotions', + 'content_library' => 'Content & Library', 'billing' => 'Billing & Finance', + 'commercial' => 'Commercial', + 'infrastructure' => 'Infrastructure', + 'storage' => 'Storage', + 'feedback_support' => 'Feedback & Support', + 'branding' => 'Branding', 'security' => 'Security', ], diff --git a/tests/Feature/FilamentPanelNavigationTest.php b/tests/Feature/FilamentPanelNavigationTest.php new file mode 100644 index 0000000..ebdc112 --- /dev/null +++ b/tests/Feature/FilamentPanelNavigationTest.php @@ -0,0 +1,110 @@ +assertNotEmpty($panels); + + foreach ($panels as $panel) { + Filament::setCurrentPanel($panel); + Filament::bootCurrentPanel(); + + if ($panel->hasTenancy()) { + $tenantModel = $panel->getTenantModel(); + $this->assertNotNull($tenantModel, $panel->getId()); + + $userModel = \App\Models\User::class; + $user = $userModel::factory()->create(); + Filament::auth()->login($user); + + $tenant = $tenantModel::factory()->create(); + Filament::setTenant($tenant); + } + + foreach ($panel->getResources() as $resource) { + $this->assertTrue(is_subclass_of($resource, Resource::class), $resource); + $this->assertIsArray($resource::getPages(), $resource); + $this->assertIsArray($resource::getNavigationItems(), $resource); + } + + foreach ($panel->getPages() as $page) { + if (! is_subclass_of($page, FilamentPage::class)) { + continue; + } + + if (! $page::shouldRegisterNavigation()) { + continue; + } + + if (str_contains($page::getRoutePath($panel), '{')) { + continue; + } + + $this->assertIsArray($page::getNavigationItems(), $page); + } + + foreach ($panel->getClusters() as $cluster) { + $this->assertTrue(is_subclass_of($cluster, Cluster::class), $cluster); + $this->assertIsArray($cluster::getNavigationItems(), $cluster); + } + + Filament::setTenant(null, true); + } + } + + public function test_all_resource_index_pages_render_without_errors(): void + { + $panels = Filament::getPanels(); + + $this->assertNotEmpty($panels); + + foreach ($panels as $panel) { + Filament::setCurrentPanel($panel); + Filament::bootCurrentPanel(); + + $userModel = \App\Models\User::class; + $user = $userModel::factory()->create(); + Filament::auth()->login($user); + + if ($panel->hasTenancy()) { + $tenantModel = $panel->getTenantModel(); + $this->assertNotNull($tenantModel, $panel->getId()); + + $tenant = $tenantModel::factory()->create(); + Filament::setTenant($tenant); + } + + foreach ($panel->getResources() as $resource) { + $resource::skipAuthorization(); + + $pages = $resource::getPages(); + $this->assertNotEmpty($pages, $resource); + + $registration = $pages['index'] ?? reset($pages); + $pageClass = $registration instanceof PageRegistration ? $registration->getPage() : $registration; + + Livewire::test($pageClass) + ->assertStatus(200); + } + + Filament::auth()->logout(); + Filament::setTenant(null, true); + } + } +} diff --git a/tests/Unit/SuperAdminNavigationGroupsTest.php b/tests/Unit/SuperAdminNavigationGroupsTest.php new file mode 100644 index 0000000..1ee4f29 --- /dev/null +++ b/tests/Unit/SuperAdminNavigationGroupsTest.php @@ -0,0 +1,93 @@ +setLocale('en'); + + $expectations = [ + \App\Filament\Resources\EventResource::class => 'admin.nav.events', + \App\Filament\Resources\EventTypeResource::class => 'admin.nav.events', + \App\Filament\Resources\PhotoResource::class => 'admin.nav.events', + \App\Filament\Resources\TaskResource::class => 'admin.nav.curation', + \App\Filament\Resources\EmotionResource::class => 'admin.nav.curation', + \App\Filament\Resources\LegalPageResource::class => 'admin.nav.content', + \App\Filament\Blog\Resources\PostResource::class => 'admin.nav.content', + \App\Filament\Blog\Resources\CategoryResource::class => 'admin.nav.content', + \App\Filament\Resources\UserResource::class => 'admin.nav.platform', + \App\Filament\Resources\TenantResource::class => 'admin.nav.tenants', + \App\Filament\Resources\MediaStorageTargetResource::class => 'admin.nav.storage', + \App\Filament\Resources\PackageAddonResource::class => 'admin.nav.commercial', + \App\Filament\Resources\PackageResource::class => 'admin.nav.commercial', + \App\Filament\Resources\PhotoboothSettings\PhotoboothSettingResource::class => 'admin.nav.storage', + \App\Filament\Resources\PurchaseResource::class => 'admin.nav.billing', + \App\Filament\Resources\PurchaseHistoryResource::class => 'admin.nav.commercial', + \App\Filament\Resources\EventPurchaseResource::class => 'admin.nav.commercial', + \App\Filament\Resources\TenantPackageResource::class => 'admin.nav.commercial', + \App\Filament\Resources\Coupons\CouponResource::class => 'admin.nav.commercial', + \App\Filament\Resources\GiftVoucherResource::class => 'admin.nav.commercial', + \App\Filament\Resources\TenantFeedbackResource::class => 'admin.nav.feedback_support', + \App\Filament\Resources\InfrastructureActionLogs\InfrastructureActionLogResource::class => 'admin.nav.infrastructure', + \App\Filament\SuperAdmin\Pages\WatermarkSettingsPage::class => 'admin.nav.branding', + \App\Filament\SuperAdmin\Pages\DokployDeployments::class => 'admin.nav.infrastructure', + ]; + + foreach ($expectations as $resourceClass => $key) { + $this->assertSame(__($key), $resourceClass::getNavigationGroup(), $resourceClass); + } + + $clusterExpectations = [ + \App\Filament\Resources\EventResource::class => DailyOpsCluster::class, + \App\Filament\Resources\PhotoResource::class => DailyOpsCluster::class, + \App\Filament\Resources\TenantResource::class => DailyOpsCluster::class, + \App\Filament\Resources\PurchaseResource::class => DailyOpsCluster::class, + \App\Filament\Resources\TenantFeedbackResource::class => DailyOpsCluster::class, + \App\Filament\Resources\TaskResource::class => WeeklyOpsCluster::class, + \App\Filament\Resources\EmotionResource::class => WeeklyOpsCluster::class, + \App\Filament\Resources\EventTypeResource::class => WeeklyOpsCluster::class, + \App\Filament\Resources\UserResource::class => WeeklyOpsCluster::class, + \App\Filament\Resources\PackageResource::class => WeeklyOpsCluster::class, + \App\Filament\Resources\PackageAddonResource::class => WeeklyOpsCluster::class, + \App\Filament\Resources\TenantPackageResource::class => WeeklyOpsCluster::class, + \App\Filament\Resources\Coupons\CouponResource::class => WeeklyOpsCluster::class, + \App\Filament\Resources\GiftVoucherResource::class => WeeklyOpsCluster::class, + \App\Filament\Resources\PurchaseHistoryResource::class => WeeklyOpsCluster::class, + \App\Filament\Resources\EventPurchaseResource::class => WeeklyOpsCluster::class, + \App\Filament\Resources\InfrastructureActionLogs\InfrastructureActionLogResource::class => RareAdminCluster::class, + \App\Filament\Resources\MediaStorageTargetResource::class => RareAdminCluster::class, + \App\Filament\Resources\PhotoboothSettings\PhotoboothSettingResource::class => RareAdminCluster::class, + \App\Filament\Resources\LegalPageResource::class => RareAdminCluster::class, + \App\Filament\Blog\Resources\PostResource::class => RareAdminCluster::class, + \App\Filament\Blog\Resources\CategoryResource::class => RareAdminCluster::class, + \App\Filament\SuperAdmin\Pages\WatermarkSettingsPage::class => RareAdminCluster::class, + \App\Filament\SuperAdmin\Pages\DokployDeployments::class => RareAdminCluster::class, + ]; + + foreach ($clusterExpectations as $resourceClass => $clusterClass) { + $this->assertSame($clusterClass, $resourceClass::getCluster(), $resourceClass); + } + + $this->assertSame(SubNavigationPosition::Top, DailyOpsCluster::getSubNavigationPosition()); + $this->assertSame(SubNavigationPosition::Top, WeeklyOpsCluster::getSubNavigationPosition()); + $this->assertSame(SubNavigationPosition::Top, RareAdminCluster::getSubNavigationPosition()); + } + + public function test_super_admin_panel_uses_top_navigation(): void + { + $provider = new SuperAdminPanelProvider(app()); + $panel = $provider->panel(Panel::make()); + + $this->assertTrue($panel->hasTopNavigation()); + } +}