From 549f53e35fecd642f94bf0a98d27ac860eb86188 Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Thu, 11 Sep 2025 10:00:11 +0545 Subject: [PATCH 1/7] feat: adding brand tenant switcher menu --- .../brand-with-tenant-switcher.blade.php | 101 ++++++++++++++++++ .../Resources/UserResource/Pages/EditUser.php | 7 -- .../Resources/UserResource/Pages/ViewUser.php | 7 -- src/Providers/AdminPanelProvider.php | 19 +--- .../Filament/BrandWithTenantSwitcherTest.php | 25 +++++ .../Providers/WorkbenchServiceProvider.php | 10 ++ 6 files changed, 141 insertions(+), 28 deletions(-) create mode 100644 resources/views/filament/components/brand-with-tenant-switcher.blade.php create mode 100644 tests/Feature/Filament/BrandWithTenantSwitcherTest.php diff --git a/resources/views/filament/components/brand-with-tenant-switcher.blade.php b/resources/views/filament/components/brand-with-tenant-switcher.blade.php new file mode 100644 index 0000000..859b374 --- /dev/null +++ b/resources/views/filament/components/brand-with-tenant-switcher.blade.php @@ -0,0 +1,101 @@ +@php + use Eclipse\Core\Services\Registry; + use Filament\Facades\Filament; + use Illuminate\Database\Eloquent\Model; + use Eclipse\Core\Filament\Pages\Dashboard; + + $appName = Registry::getSite()->name ?? config('app.name'); + $hasSpaMode = Filament::getCurrentPanel()->hasSpaMode(); + $dashboardUrl = '/' . trim(Filament::getCurrentPanel()->getPath(), '/'); + + $currentTenant = filament()->getTenant(); + $currentTenantName = $currentTenant ? filament()->getTenantName($currentTenant) : null; + + $tenants = []; + $canSwitchTenants = false; + + if (config('eclipse.multi_site', false) && filament()->auth()->check()) { + $tenants = array_filter( + filament()->getUserTenants(filament()->auth()->user()), + fn(Model $tenant): bool => !$tenant->is($currentTenant), + ); + $canSwitchTenants = count($tenants) > 0; + } + + $hasFrontend = collect(filament()->getPanels())->has('frontend'); + $frontendUrl = config('app.url'); + + if ($hasFrontend) { + try { + if ($currentTenant && $currentTenant->domain) { + $frontendUrl = "https://{$currentTenant->domain}"; + } else { + $frontendUrl = Dashboard::getUrl(); + } + } catch (Exception $e) { + $frontendUrl = config('app.url'); + } + } +@endphp + +@if ($canSwitchTenants || $hasFrontend) +
+ + + + + + + + + + + @if ($canSwitchTenants) + @foreach ($tenants as $tenant) + + {{ filament()->getTenantName($tenant) }} + + @endforeach + @endif + + @if ($hasFrontend) + @if ($canSwitchTenants) + + @endif + + +
+ + Frontend + +
+
+ @endif +
+
+
+@else + +@endif diff --git a/src/Filament/Resources/UserResource/Pages/EditUser.php b/src/Filament/Resources/UserResource/Pages/EditUser.php index 25b356d..0219e66 100644 --- a/src/Filament/Resources/UserResource/Pages/EditUser.php +++ b/src/Filament/Resources/UserResource/Pages/EditUser.php @@ -5,14 +5,9 @@ use Eclipse\Core\Filament\Resources\UserResource; use Filament\Actions; use Filament\Resources\Pages\EditRecord; -use Nben\FilamentRecordNav\Actions\NextRecordAction; -use Nben\FilamentRecordNav\Actions\PreviousRecordAction; -use Nben\FilamentRecordNav\Concerns\WithRecordNavigation; class EditUser extends EditRecord { - use WithRecordNavigation; - protected static string $resource = UserResource::class; public function hasCombinedRelationManagerTabsWithContent(): bool @@ -28,8 +23,6 @@ public function getContentTabLabel(): ?string protected function getHeaderActions(): array { return [ - PreviousRecordAction::make(), - NextRecordAction::make(), Actions\ViewAction::make(), Actions\DeleteAction::make(), ]; diff --git a/src/Filament/Resources/UserResource/Pages/ViewUser.php b/src/Filament/Resources/UserResource/Pages/ViewUser.php index 2b25d9c..ae24f6d 100644 --- a/src/Filament/Resources/UserResource/Pages/ViewUser.php +++ b/src/Filament/Resources/UserResource/Pages/ViewUser.php @@ -6,15 +6,10 @@ use Eclipse\Core\Filament\Resources\UserResource; use Filament\Actions; use Filament\Resources\Pages\ViewRecord; -use Nben\FilamentRecordNav\Actions\NextRecordAction; -use Nben\FilamentRecordNav\Actions\PreviousRecordAction; -use Nben\FilamentRecordNav\Concerns\WithRecordNavigation; use STS\FilamentImpersonate\Pages\Actions\Impersonate; class ViewUser extends ViewRecord { - use WithRecordNavigation; - protected static string $resource = UserResource::class; public function hasCombinedRelationManagerTabsWithContent(): bool @@ -30,8 +25,6 @@ public function getContentTabLabel(): ?string protected function getHeaderActions(): array { return [ - PreviousRecordAction::make(), - NextRecordAction::make(), Actions\EditAction::make(), SendEmailAction::make(), Impersonate::make() diff --git a/src/Providers/AdminPanelProvider.php b/src/Providers/AdminPanelProvider.php index 3d67986..04b02c2 100644 --- a/src/Providers/AdminPanelProvider.php +++ b/src/Providers/AdminPanelProvider.php @@ -5,7 +5,7 @@ use BezhanSalleh\FilamentShield\Facades\FilamentShield; use BezhanSalleh\FilamentShield\FilamentShieldPlugin; use BezhanSalleh\FilamentShield\Middleware\SyncShieldTenant; -use BezhanSalleh\PanelSwitch\PanelSwitch; +use BezhanSalleh\PanelSwitch\Facades\PanelSwitch; use DutchCodingCompany\FilamentDeveloperLogins\FilamentDeveloperLoginsPlugin; use Eclipse\Common\CommonPlugin; use Eclipse\Common\Providers\GlobalSearchProvider; @@ -77,7 +77,7 @@ public function panel(Panel $panel): Panel ]) ->topNavigation() ->brandLogo( - fn (): View => view('eclipse::filament.components.brand') + fn (): View => view('eclipse::filament.components.brand-with-tenant-switcher') ) ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') ->discoverResources(in: $package_src.'Filament/Resources', for: 'Eclipse\\Core\\Filament\\Resources') @@ -171,13 +171,6 @@ public function panel(Panel $panel): Panel fn () => view('eclipse::filament.components.my-settings') ); - if ($hasTenantMenu) { - $panel->renderHook( - PanelsRenderHook::GLOBAL_SEARCH_END, - fn () => view('eclipse::filament.components.tenant-menu') - ); - } - // If the Pro version of the Spotlight plugin is installed, use that, otherwise use the free version if (class_exists(\pxlrbt\FilamentSpotlightPro\SpotlightPlugin::class)) { /** @noinspection PhpFullyQualifiedNameUsageInspection */ @@ -243,10 +236,8 @@ public function boot(): void // Load customized translations for Filament Shield $this->loadTranslationsFrom(__DIR__.'/../../resources/lang/vendor/filament-shield', 'filament-shield'); - // Configure Panel Switch - PanelSwitch::configureUsing(function (PanelSwitch $panelSwitch) { - $panelSwitch - ->simple() + if (class_exists(PanelSwitch::class)) { + PanelSwitch::simple() ->icons([ 'admin' => 'heroicon-s-cog-6-tooth', 'frontend' => 'heroicon-s-globe-alt', @@ -256,6 +247,6 @@ public function boot(): void 'frontend' => 'Frontend', ]) ->visible(fn (): bool => auth()->check()); - }); + } } } diff --git a/tests/Feature/Filament/BrandWithTenantSwitcherTest.php b/tests/Feature/Filament/BrandWithTenantSwitcherTest.php new file mode 100644 index 0000000..0d639a0 --- /dev/null +++ b/tests/Feature/Filament/BrandWithTenantSwitcherTest.php @@ -0,0 +1,25 @@ +get('/admin/login'); + + $response->assertStatus(200); + $response->assertSee(config('app.name')); +}); + +test('brand component renders with multi-site enabled', function () { + config(['eclipse.multi_site' => true]); + + $response = $this->get('/admin/login'); + $response->assertStatus(200); + $response->assertSee(config('app.name')); +}); + +test('brand component shows app name consistently', function () { + config(['eclipse.multi_site' => true]); + + $response = $this->get('/admin/login'); + + $response->assertStatus(200); + $response->assertSee(config('app.name')); +}); diff --git a/workbench/app/Providers/WorkbenchServiceProvider.php b/workbench/app/Providers/WorkbenchServiceProvider.php index 5e009da..d21b7cc 100644 --- a/workbench/app/Providers/WorkbenchServiceProvider.php +++ b/workbench/app/Providers/WorkbenchServiceProvider.php @@ -11,6 +11,16 @@ class WorkbenchServiceProvider extends ServiceProvider */ public function register(): void { + // Register Common package service provider + if (class_exists(\Eclipse\Common\CommonServiceProvider::class)) { + $this->app->register(\Eclipse\Common\CommonServiceProvider::class); + } + + // Register PanelSwitch service provider + if (class_exists(\BezhanSalleh\PanelSwitch\PanelSwitchServiceProvider::class)) { + $this->app->register(\BezhanSalleh\PanelSwitch\PanelSwitchServiceProvider::class); + } + $this->app->register(\Eclipse\Core\Providers\AdminPanelProvider::class); } From 19392df09df4fdb9bfbd5682ff2c2807f5d9cc4a Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Thu, 11 Sep 2025 10:39:38 +0545 Subject: [PATCH 2/7] fix: reverting some of the changes --- .../Resources/UserResource/Pages/EditUser.php | 7 ++++++ .../Resources/UserResource/Pages/ViewUser.php | 7 ++++++ src/Providers/AdminPanelProvider.php | 24 +++++++++---------- .../Providers/WorkbenchServiceProvider.php | 10 -------- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/Filament/Resources/UserResource/Pages/EditUser.php b/src/Filament/Resources/UserResource/Pages/EditUser.php index 0219e66..25b356d 100644 --- a/src/Filament/Resources/UserResource/Pages/EditUser.php +++ b/src/Filament/Resources/UserResource/Pages/EditUser.php @@ -5,9 +5,14 @@ use Eclipse\Core\Filament\Resources\UserResource; use Filament\Actions; use Filament\Resources\Pages\EditRecord; +use Nben\FilamentRecordNav\Actions\NextRecordAction; +use Nben\FilamentRecordNav\Actions\PreviousRecordAction; +use Nben\FilamentRecordNav\Concerns\WithRecordNavigation; class EditUser extends EditRecord { + use WithRecordNavigation; + protected static string $resource = UserResource::class; public function hasCombinedRelationManagerTabsWithContent(): bool @@ -23,6 +28,8 @@ public function getContentTabLabel(): ?string protected function getHeaderActions(): array { return [ + PreviousRecordAction::make(), + NextRecordAction::make(), Actions\ViewAction::make(), Actions\DeleteAction::make(), ]; diff --git a/src/Filament/Resources/UserResource/Pages/ViewUser.php b/src/Filament/Resources/UserResource/Pages/ViewUser.php index ae24f6d..2b25d9c 100644 --- a/src/Filament/Resources/UserResource/Pages/ViewUser.php +++ b/src/Filament/Resources/UserResource/Pages/ViewUser.php @@ -6,10 +6,15 @@ use Eclipse\Core\Filament\Resources\UserResource; use Filament\Actions; use Filament\Resources\Pages\ViewRecord; +use Nben\FilamentRecordNav\Actions\NextRecordAction; +use Nben\FilamentRecordNav\Actions\PreviousRecordAction; +use Nben\FilamentRecordNav\Concerns\WithRecordNavigation; use STS\FilamentImpersonate\Pages\Actions\Impersonate; class ViewUser extends ViewRecord { + use WithRecordNavigation; + protected static string $resource = UserResource::class; public function hasCombinedRelationManagerTabsWithContent(): bool @@ -25,6 +30,8 @@ public function getContentTabLabel(): ?string protected function getHeaderActions(): array { return [ + PreviousRecordAction::make(), + NextRecordAction::make(), Actions\EditAction::make(), SendEmailAction::make(), Impersonate::make() diff --git a/src/Providers/AdminPanelProvider.php b/src/Providers/AdminPanelProvider.php index 04b02c2..62d85d4 100644 --- a/src/Providers/AdminPanelProvider.php +++ b/src/Providers/AdminPanelProvider.php @@ -5,7 +5,7 @@ use BezhanSalleh\FilamentShield\Facades\FilamentShield; use BezhanSalleh\FilamentShield\FilamentShieldPlugin; use BezhanSalleh\FilamentShield\Middleware\SyncShieldTenant; -use BezhanSalleh\PanelSwitch\Facades\PanelSwitch; +use BezhanSalleh\PanelSwitch\PanelSwitch; use DutchCodingCompany\FilamentDeveloperLogins\FilamentDeveloperLoginsPlugin; use Eclipse\Common\CommonPlugin; use Eclipse\Common\Providers\GlobalSearchProvider; @@ -236,17 +236,15 @@ public function boot(): void // Load customized translations for Filament Shield $this->loadTranslationsFrom(__DIR__.'/../../resources/lang/vendor/filament-shield', 'filament-shield'); - if (class_exists(PanelSwitch::class)) { - PanelSwitch::simple() - ->icons([ - 'admin' => 'heroicon-s-cog-6-tooth', - 'frontend' => 'heroicon-s-globe-alt', - ]) - ->labels([ - 'admin' => 'Admin Panel', - 'frontend' => 'Frontend', - ]) - ->visible(fn (): bool => auth()->check()); - } + PanelSwitch::simple() + ->icons([ + 'admin' => 'heroicon-s-cog-6-tooth', + 'frontend' => 'heroicon-s-globe-alt', + ]) + ->labels([ + 'admin' => 'Admin Panel', + 'frontend' => 'Frontend', + ]) + ->visible(fn (): bool => auth()->check()); } } diff --git a/workbench/app/Providers/WorkbenchServiceProvider.php b/workbench/app/Providers/WorkbenchServiceProvider.php index d21b7cc..5e009da 100644 --- a/workbench/app/Providers/WorkbenchServiceProvider.php +++ b/workbench/app/Providers/WorkbenchServiceProvider.php @@ -11,16 +11,6 @@ class WorkbenchServiceProvider extends ServiceProvider */ public function register(): void { - // Register Common package service provider - if (class_exists(\Eclipse\Common\CommonServiceProvider::class)) { - $this->app->register(\Eclipse\Common\CommonServiceProvider::class); - } - - // Register PanelSwitch service provider - if (class_exists(\BezhanSalleh\PanelSwitch\PanelSwitchServiceProvider::class)) { - $this->app->register(\BezhanSalleh\PanelSwitch\PanelSwitchServiceProvider::class); - } - $this->app->register(\Eclipse\Core\Providers\AdminPanelProvider::class); } From db7ba6ff0738dbc9f6a91741ad6fc68afa42ef50 Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Thu, 11 Sep 2025 10:56:39 +0545 Subject: [PATCH 3/7] fix: failing tests --- package-lock.json | 2 +- src/Providers/AdminPanelProvider.php | 2 +- .../app/Providers/WorkbenchServiceProvider.php | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ee19468..f2b4cd4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "app", + "name": "core", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/src/Providers/AdminPanelProvider.php b/src/Providers/AdminPanelProvider.php index 62d85d4..9075d6d 100644 --- a/src/Providers/AdminPanelProvider.php +++ b/src/Providers/AdminPanelProvider.php @@ -5,7 +5,7 @@ use BezhanSalleh\FilamentShield\Facades\FilamentShield; use BezhanSalleh\FilamentShield\FilamentShieldPlugin; use BezhanSalleh\FilamentShield\Middleware\SyncShieldTenant; -use BezhanSalleh\PanelSwitch\PanelSwitch; +use BezhanSalleh\PanelSwitch\Facades\PanelSwitch; use DutchCodingCompany\FilamentDeveloperLogins\FilamentDeveloperLoginsPlugin; use Eclipse\Common\CommonPlugin; use Eclipse\Common\Providers\GlobalSearchProvider; diff --git a/workbench/app/Providers/WorkbenchServiceProvider.php b/workbench/app/Providers/WorkbenchServiceProvider.php index 5e009da..9c3fa07 100644 --- a/workbench/app/Providers/WorkbenchServiceProvider.php +++ b/workbench/app/Providers/WorkbenchServiceProvider.php @@ -2,7 +2,10 @@ namespace Workbench\App\Providers; +use BezhanSalleh\PanelSwitch\PanelSwitchServiceProvider; +use Eclipse\Common\CommonServiceProvider; use Illuminate\Support\ServiceProvider; +use Nben\FilamentRecordNav\FilamentRecordNavServiceProvider; class WorkbenchServiceProvider extends ServiceProvider { @@ -11,6 +14,18 @@ class WorkbenchServiceProvider extends ServiceProvider */ public function register(): void { + if (class_exists(CommonServiceProvider::class)) { + $this->app->register(CommonServiceProvider::class); + } + + if (class_exists(PanelSwitchServiceProvider::class)) { + $this->app->register(PanelSwitchServiceProvider::class); + } + + if (class_exists(FilamentRecordNavServiceProvider::class)) { + $this->app->register(FilamentRecordNavServiceProvider::class); + } + $this->app->register(\Eclipse\Core\Providers\AdminPanelProvider::class); } From 4e485988ce246a837e3ca9c54bbee9769629b04d Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Fri, 12 Sep 2025 01:53:49 +0545 Subject: [PATCH 4/7] fix: refactor tenant switcher component and fix frontend panel detection --- composer.json | 1 - package-lock.json | 2 +- .../brand-with-tenant-switcher.blade.php | 61 ++-------- src/Providers/AdminPanelProvider.php | 15 +-- .../Components/BrandWithTenantSwitcher.php | 107 ++++++++++++++++++ .../Filament/BrandWithTenantSwitcherTest.php | 45 +++++++- .../Providers/WorkbenchServiceProvider.php | 13 ++- 7 files changed, 169 insertions(+), 75 deletions(-) create mode 100644 src/View/Components/BrandWithTenantSwitcher.php diff --git a/composer.json b/composer.json index 95cc046..937f941 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,6 @@ "require": { "php": "^8.3", "bezhansalleh/filament-language-switch": "^3.1", - "bezhansalleh/filament-panel-switch": "^1.1", "bezhansalleh/filament-shield": "^3.3", "datalinx/php-utils": "^2.5", "dutchcodingcompany/filament-developer-logins": "^1.6", diff --git a/package-lock.json b/package-lock.json index f2b4cd4..ee19468 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "core", + "name": "app", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/resources/views/filament/components/brand-with-tenant-switcher.blade.php b/resources/views/filament/components/brand-with-tenant-switcher.blade.php index 859b374..8563e00 100644 --- a/resources/views/filament/components/brand-with-tenant-switcher.blade.php +++ b/resources/views/filament/components/brand-with-tenant-switcher.blade.php @@ -1,51 +1,11 @@ -@php - use Eclipse\Core\Services\Registry; - use Filament\Facades\Filament; - use Illuminate\Database\Eloquent\Model; - use Eclipse\Core\Filament\Pages\Dashboard; - - $appName = Registry::getSite()->name ?? config('app.name'); - $hasSpaMode = Filament::getCurrentPanel()->hasSpaMode(); - $dashboardUrl = '/' . trim(Filament::getCurrentPanel()->getPath(), '/'); - - $currentTenant = filament()->getTenant(); - $currentTenantName = $currentTenant ? filament()->getTenantName($currentTenant) : null; - - $tenants = []; - $canSwitchTenants = false; - - if (config('eclipse.multi_site', false) && filament()->auth()->check()) { - $tenants = array_filter( - filament()->getUserTenants(filament()->auth()->user()), - fn(Model $tenant): bool => !$tenant->is($currentTenant), - ); - $canSwitchTenants = count($tenants) > 0; - } - - $hasFrontend = collect(filament()->getPanels())->has('frontend'); - $frontendUrl = config('app.url'); - - if ($hasFrontend) { - try { - if ($currentTenant && $currentTenant->domain) { - $frontendUrl = "https://{$currentTenant->domain}"; - } else { - $frontendUrl = Dashboard::getUrl(); - } - } catch (Exception $e) { - $frontendUrl = config('app.url'); - } - } -@endphp - -@if ($canSwitchTenants || $hasFrontend) +@if ($shouldShowDropdown)
- + @@ -62,20 +22,21 @@ class="h-4 w-4 text-gray-400 transition duration-75 group-hover:text-gray-500 gr @if ($canSwitchTenants) - @foreach ($tenants as $tenant) + @foreach ($getTenants as $tenant) {{ filament()->getTenantName($tenant) }} @endforeach @endif + @if ($hasFrontend) @if ($canSwitchTenants) @endif -
@else diff --git a/src/Providers/AdminPanelProvider.php b/src/Providers/AdminPanelProvider.php index 9075d6d..346954d 100644 --- a/src/Providers/AdminPanelProvider.php +++ b/src/Providers/AdminPanelProvider.php @@ -5,7 +5,6 @@ use BezhanSalleh\FilamentShield\Facades\FilamentShield; use BezhanSalleh\FilamentShield\FilamentShieldPlugin; use BezhanSalleh\FilamentShield\Middleware\SyncShieldTenant; -use BezhanSalleh\PanelSwitch\Facades\PanelSwitch; use DutchCodingCompany\FilamentDeveloperLogins\FilamentDeveloperLoginsPlugin; use Eclipse\Common\CommonPlugin; use Eclipse\Common\Providers\GlobalSearchProvider; @@ -16,6 +15,7 @@ use Eclipse\Core\Models\Site; use Eclipse\Core\Models\User; use Eclipse\Core\Services\Registry; +use Eclipse\Core\View\Components\BrandWithTenantSwitcher; use Eclipse\World\EclipseWorld; use Filament\Http\Middleware\Authenticate; use Filament\Http\Middleware\DisableBladeIconComponents; @@ -77,7 +77,7 @@ public function panel(Panel $panel): Panel ]) ->topNavigation() ->brandLogo( - fn (): View => view('eclipse::filament.components.brand-with-tenant-switcher') + fn (): View => app(BrandWithTenantSwitcher::class)->render() ) ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') ->discoverResources(in: $package_src.'Filament/Resources', for: 'Eclipse\\Core\\Filament\\Resources') @@ -235,16 +235,5 @@ public function boot(): void // Load customized translations for Filament Shield $this->loadTranslationsFrom(__DIR__.'/../../resources/lang/vendor/filament-shield', 'filament-shield'); - - PanelSwitch::simple() - ->icons([ - 'admin' => 'heroicon-s-cog-6-tooth', - 'frontend' => 'heroicon-s-globe-alt', - ]) - ->labels([ - 'admin' => 'Admin Panel', - 'frontend' => 'Frontend', - ]) - ->visible(fn (): bool => auth()->check()); } } diff --git a/src/View/Components/BrandWithTenantSwitcher.php b/src/View/Components/BrandWithTenantSwitcher.php new file mode 100644 index 0000000..978cc17 --- /dev/null +++ b/src/View/Components/BrandWithTenantSwitcher.php @@ -0,0 +1,107 @@ + $this->shouldShowDropdown(), + 'getAppName' => $this->getAppName(), + 'hasSpaMode' => $this->hasSpaMode(), + 'getDashboardUrl' => $this->getDashboardUrl(), + 'getCurrentTenant' => $this->getCurrentTenant(), + 'getCurrentTenantName' => $this->getCurrentTenantName(), + 'canSwitchTenants' => $this->canSwitchTenants(), + 'getTenants' => $this->getTenants(), + 'hasFrontend' => $this->hasFrontend(), + 'getFrontendUrl' => $this->getFrontendUrl(), + ]); + } + + public function getAppName(): string + { + return Registry::getSite()->name ?? config('app.name'); + } + + public function hasSpaMode(): bool + { + return Filament::getCurrentPanel()->hasSpaMode(); + } + + public function getDashboardUrl(): string + { + return '/'.trim(Filament::getCurrentPanel()->getPath(), '/'); + } + + public function getCurrentTenant(): ?Model + { + return filament()->getTenant(); + } + + public function getCurrentTenantName(): ?string + { + $currentTenant = $this->getCurrentTenant(); + + return $currentTenant ? filament()->getTenantName($currentTenant) : null; + } + + public function getTenants(): array + { + if (! $this->isMultiSiteEnabled() || ! filament()->auth()->check()) { + return []; + } + + $currentTenant = $this->getCurrentTenant(); + + return array_filter( + filament()->getUserTenants(filament()->auth()->user()), + fn (Model $tenant): bool => ! $tenant->is($currentTenant), + ); + } + + public function canSwitchTenants(): bool + { + return count($this->getTenants()) > 0; + } + + public function hasFrontend(): bool + { + return collect(Filament::getPanels())->has('frontend'); + } + + public function getFrontendUrl(): string + { + if (! $this->hasFrontend()) { + return config('app.url'); + } + + try { + $currentTenant = $this->getCurrentTenant(); + if ($currentTenant?->domain) { + return "https://{$currentTenant->domain}"; + } else { + return config('app.url'); + } + } catch (Exception $e) { + return config('app.url'); + } + } + + public function shouldShowDropdown(): bool + { + return $this->canSwitchTenants() || $this->hasFrontend(); + } + + private function isMultiSiteEnabled(): bool + { + return config('eclipse.multi_site', false); + } +} diff --git a/tests/Feature/Filament/BrandWithTenantSwitcherTest.php b/tests/Feature/Filament/BrandWithTenantSwitcherTest.php index 0d639a0..c60a346 100644 --- a/tests/Feature/Filament/BrandWithTenantSwitcherTest.php +++ b/tests/Feature/Filament/BrandWithTenantSwitcherTest.php @@ -1,5 +1,9 @@ get('/admin/login'); @@ -15,11 +19,44 @@ $response->assertSee(config('app.name')); }); -test('brand component shows app name consistently', function () { +test('brand component dropdown behavior depends on frontend and tenant availability', function () { + $component = new BrandWithTenantSwitcher; + + $hasFrontend = $component->hasFrontend(); + $canSwitchTenants = $component->canSwitchTenants(); + $shouldShowDropdown = $component->shouldShowDropdown(); + + expect($shouldShowDropdown)->toBe($hasFrontend || $canSwitchTenants); + + expect($hasFrontend)->toBeBool(); + expect($canSwitchTenants)->toBeBool(); + expect($shouldShowDropdown)->toBeBool(); +}); + +test('tenant switcher logic handles multiple and single tenant scenarios', function () { config(['eclipse.multi_site' => true]); - $response = $this->get('/admin/login'); + $user = User::factory()->create(); + $site1 = Site::factory()->create(['name' => 'Primary Site']); + $site2 = Site::factory()->create(['name' => 'Secondary Site']); - $response->assertStatus(200); - $response->assertSee(config('app.name')); + $user->sites()->attach([$site1->id, $site2->id]); + + expect($user->sites)->toHaveCount(2); + expect($user->sites->pluck('name'))->toContain('Primary Site', 'Secondary Site'); + + $singleSiteUser = User::factory()->create(); + $singleSite = Site::factory()->create(['name' => 'Only Site']); + $singleSiteUser->sites()->attach($singleSite->id); + + expect($singleSiteUser->sites)->toHaveCount(1); + expect($singleSiteUser->sites->first()->name)->toBe('Only Site'); +}); + +test('brand component renders app name correctly', function () { + $component = new BrandWithTenantSwitcher; + + $appName = $component->getAppName(); + + expect($appName)->toBe(config('app.name')); }); diff --git a/workbench/app/Providers/WorkbenchServiceProvider.php b/workbench/app/Providers/WorkbenchServiceProvider.php index 9c3fa07..a8c3f83 100644 --- a/workbench/app/Providers/WorkbenchServiceProvider.php +++ b/workbench/app/Providers/WorkbenchServiceProvider.php @@ -2,8 +2,9 @@ namespace Workbench\App\Providers; -use BezhanSalleh\PanelSwitch\PanelSwitchServiceProvider; use Eclipse\Common\CommonServiceProvider; +use Eclipse\Core\Providers\AdminPanelProvider; +use Eclipse\Frontend\Providers\FrontendPanelProvider; use Illuminate\Support\ServiceProvider; use Nben\FilamentRecordNav\FilamentRecordNavServiceProvider; @@ -18,15 +19,15 @@ public function register(): void $this->app->register(CommonServiceProvider::class); } - if (class_exists(PanelSwitchServiceProvider::class)) { - $this->app->register(PanelSwitchServiceProvider::class); - } - if (class_exists(FilamentRecordNavServiceProvider::class)) { $this->app->register(FilamentRecordNavServiceProvider::class); } - $this->app->register(\Eclipse\Core\Providers\AdminPanelProvider::class); + $this->app->register(AdminPanelProvider::class); + + if (class_exists(FrontendPanelProvider::class)) { + $this->app->register(FrontendPanelProvider::class); + } } /** From 39ddca9750e29db5791302144289ae0cba6c4db2 Mon Sep 17 00:00:00 2001 From: ankitcodes4u Date: Mon, 22 Sep 2025 02:14:58 +0545 Subject: [PATCH 5/7] fix: fixing the issue of frontend link not showing --- src/EclipseServiceProvider.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/EclipseServiceProvider.php b/src/EclipseServiceProvider.php index 2fd2e29..e0111be 100644 --- a/src/EclipseServiceProvider.php +++ b/src/EclipseServiceProvider.php @@ -22,6 +22,7 @@ use Eclipse\Core\Providers\HorizonServiceProvider; use Eclipse\Core\Providers\TelescopeServiceProvider; use Eclipse\Core\Services\Registry; +use Eclipse\Frontend\Providers\FrontendPanelProvider; use Filament\Facades\Filament; use Filament\Resources\Resource; use Filament\Support\Facades\FilamentAsset; @@ -99,6 +100,10 @@ public function register(): self $this->app->register(AdminPanelProvider::class); } + if (class_exists(FrontendPanelProvider::class)) { + $this->app->register(FrontendPanelProvider::class); + } + if ($this->app->environment('local')) { $this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class); $this->app->register(TelescopeServiceProvider::class); From 00a0a43ee4b9df6ea27b3b3ced1359ff9dd42e0e Mon Sep 17 00:00:00 2001 From: thapacodes4u Date: Sun, 12 Oct 2025 13:06:49 +0545 Subject: [PATCH 6/7] fix: resolving conflict --- .github/workflows/test-runner.yml | 8 +- composer.json | 29 ++-- config/filament-shield.php | 100 +++++------ config/themes.php | 36 ---- ...139_add_themes_settings_to_users_table.php | 23 --- database/seeders/CoreSeeder.php | 34 +++- database/seeders/RoleSeeder.php | 6 +- .../filament/components/my-settings.blade.php | 5 +- .../filament/components/tenant-menu.blade.php | 14 +- src/Console/Commands/PostComposerUpdate.php | 1 - src/EclipseServiceProvider.php | 61 ++++++- src/Filament/Actions/SendEmailAction.php | 13 +- src/Filament/Actions/SendEmailTableAction.php | 2 +- src/Filament/Pages/EditProfile.php | 11 +- src/Filament/Pages/ManageEclipse.php | 16 +- src/Filament/Pages/ManageUserSettings.php | 23 +-- src/Filament/Resources/LocaleResource.php | 74 ++++----- .../LocaleResource/Pages/EditLocale.php | 4 +- .../LocaleResource/Pages/ListLocales.php | 8 +- src/Filament/Resources/MailLogResource.php | 113 ++++++------- .../MailLogResource/Pages/ListMailLogs.php | 4 +- src/Filament/Resources/SiteResource.php | 66 ++++---- .../Resources/SiteResource/Pages/EditSite.php | 4 +- .../SiteResource/Pages/ListSites.php | 8 +- src/Filament/Resources/UserResource.php | 156 +++++++++--------- .../Resources/UserResource/Pages/EditUser.php | 7 +- .../UserResource/Pages/ListUsers.php | 8 +- .../Resources/UserResource/Pages/ViewUser.php | 6 +- .../AddressesRelationManager.php | 98 ++++++----- src/Http/Middleware/SetupSite.php | 2 +- src/Listeners/LogEmailToDatabase.php | 13 +- src/Mail/SendEmailToUser.php | 3 +- src/Models/Locale.php | 2 +- src/Models/Scopes/ActiveScope.php | 18 -- src/Models/User.php | 7 +- src/Policies/LocalePolicy.php | 24 +-- src/Policies/MailLogPolicy.php | 12 +- src/Policies/SitePolicy.php | 24 +-- src/Policies/User/RolePolicy.php | 28 ++-- src/Policies/UserPolicy.php | 52 +++--- src/Providers/AdminPanelProvider.php | 20 +-- .../Filament/Resources/LocaleResourceTest.php | 24 ++- .../Resources/MailLogResourceTest.php | 3 +- .../Filament/Resources/UserResourceTest.php | 8 +- tests/Feature/UserEmailTest.php | 8 +- tests/Feature/UserImpersonationTest.php | 11 +- tests/Pest.php | 3 +- tests/TestCase.php | 2 +- tests/Unit/Models/Scopes/ActiveScopeTest.php | 16 -- workbench/database/factories/UserFactory.php | 2 +- 50 files changed, 633 insertions(+), 587 deletions(-) delete mode 100644 config/themes.php delete mode 100644 database/migrations/2025_05_27_071139_add_themes_settings_to_users_table.php delete mode 100644 src/Models/Scopes/ActiveScope.php delete mode 100644 tests/Unit/Models/Scopes/ActiveScopeTest.php diff --git a/.github/workflows/test-runner.yml b/.github/workflows/test-runner.yml index b78f75f..fd9ce47 100644 --- a/.github/workflows/test-runner.yml +++ b/.github/workflows/test-runner.yml @@ -1,15 +1,13 @@ name: Tests on: - # Run testing on all push and pull requests for the main branch that have committed changes in PHP files + # Run testing on all push and pull requests that have committed changes in PHP files push: - branches: [ "main" ] paths: - - '**.php' + - '**/*.php' pull_request: - branches: [ "main" ] paths: - - '**.php' + - '**/*.php' # Make it possible to run the workflow manually workflow_dispatch: diff --git a/composer.json b/composer.json index 937f941..752bbbe 100644 --- a/composer.json +++ b/composer.json @@ -42,34 +42,33 @@ }, "require": { "php": "^8.3", - "bezhansalleh/filament-language-switch": "^3.1", - "bezhansalleh/filament-shield": "^3.3", + "bezhansalleh/filament-language-switch": "^4.0", + "bezhansalleh/filament-panel-switch": "^2.0", + "bezhansalleh/filament-shield": "^4.0", "datalinx/php-utils": "^2.5", - "dutchcodingcompany/filament-developer-logins": "^1.6", + "dutchcodingcompany/filament-developer-logins": "^2.0", "eclipsephp/common": "dev-main", "eclipsephp/world-plugin": "dev-main", - "filament/filament": "^3.3", - "filament/spatie-laravel-media-library-plugin": "^3.2", - "filament/spatie-laravel-translatable-plugin": "^3.2", - "hasnayeen/themes": "^3.0", + "filament/filament": "^4.0", + "filament/spatie-laravel-media-library-plugin": "^4.0", + "lara-zeus/spatie-translatable": "^1.0", "laravel/framework": "^12.0", "laravel/horizon": "^5.31", "laravel/telescope": "^5.5", "laravel/tinker": "^2.10", + "nben/filament-record-nav": "^1.0", "opcodesio/log-viewer": "^3.17", - "pxlrbt/filament-environment-indicator": "^2.1", - "pxlrbt/filament-excel": "^2.4", - "pxlrbt/filament-spotlight": "^1.3", - "shuvroroy/filament-spatie-laravel-health": "^2.3", + "pxlrbt/filament-environment-indicator": "^3.0", + "pxlrbt/filament-excel": "^3.0", + "pxlrbt/filament-spotlight": "^2.0", + "shuvroroy/filament-spatie-laravel-health": "^3.0", "spatie/laravel-package-tools": "^1.18", "spatie/laravel-translatable": "^6.11", "spatie/security-advisories-health-check": "^1.2", - "stechstudio/filament-impersonate": "^3.16", + "stechstudio/filament-impersonate": "^4.0", "symfony/http-client": "^7.3", "symfony/mailgun-mailer": "^7.3", - "tangodev-it/filament-emoji-picker": "^1.0", - "typesense/typesense-php": "^5.0", - "nben/filament-record-nav": "^1.0" + "typesense/typesense-php": "^5.0" }, "require-dev": { "laravel/pint": "^1.21", diff --git a/config/filament-shield.php b/config/filament-shield.php index 65c1230..2d8bbb8 100644 --- a/config/filament-shield.php +++ b/config/filament-shield.php @@ -1,29 +1,31 @@ [ - 'should_register_navigation' => true, 'slug' => 'shield/roles', - 'navigation_sort' => -1, - 'navigation_badge' => true, - 'navigation_group' => true, - 'is_globally_searchable' => false, 'show_model_path' => true, - 'is_scoped_to_tenant' => false, 'cluster' => null, + 'tabs' => [ + 'pages' => true, + 'widgets' => true, + 'resources' => true, + 'custom_permissions' => true, + ], ], 'tenant_model' => \Eclipse\Core\Models\Site::class, - 'auth_provider_model' => [ - 'fqcn' => \Eclipse\Core\Models\User::class, - ], + 'auth_provider_model' => \Eclipse\Core\Models\User::class, 'super_admin' => [ 'enabled' => true, 'name' => 'super_admin', 'define_via_gate' => false, - 'intercept_gate' => 'before', // after + 'intercept_gate' => 'before', ], 'panel_user' => [ @@ -31,51 +33,56 @@ 'name' => 'panel_user', ], - 'permission_prefixes' => [ - 'resource' => [ - 'view_any', - 'view', - 'create', - 'update', - 'restore', - 'restore_any', - 'replicate', - 'reorder', - 'delete', - 'delete_any', - 'force_delete', - 'force_delete_any', - ], - - 'page' => 'page', - 'widget' => 'widget', + 'permissions' => [ + 'separator' => '_', + 'case' => 'lower_snake', + 'generate' => true, ], - 'entities' => [ - 'pages' => true, - 'widgets' => true, - 'resources' => true, - 'custom_permissions' => false, + 'policies' => [ + 'path' => app_path('Policies'), + 'merge' => false, + 'generate' => true, + 'methods' => [ + 'viewAny', 'view', 'create', 'update', 'restore', 'restoreAny', + 'replicate', 'reorder', 'delete', 'deleteAny', 'forceDelete', 'forceDeleteAny', + ], + 'single_parameter_methods' => [ + 'viewAny', 'create', 'deleteAny', 'forceDeleteAny', 'restoreAny', 'reorder', + ], ], - 'generator' => [ - 'option' => 'policies_and_permissions', - 'policy_directory' => 'Policies', - 'policy_namespace' => 'Policies', + 'localization' => [ + 'enabled' => false, + 'key' => 'filament-shield::filament-shield', ], - 'exclude' => [ - 'enabled' => true, + 'resources' => [ + 'subject' => 'model', + 'manage' => [], + 'exclude' => [], + ], - 'pages' => [ - 'Dashboard', + 'pages' => [ + 'subject' => 'class', + 'prefix' => 'view', + 'exclude' => [ + Dashboard::class, ], + ], - 'widgets' => [ - 'AccountWidget', 'FilamentInfoWidget', + 'widgets' => [ + 'subject' => 'class', + 'prefix' => 'view', + 'exclude' => [ + AccountWidget::class, + FilamentInfoWidget::class, ], + ], - 'resources' => [], + 'custom_permissions' => [ + 'impersonate_user', + 'send_email_user', ], 'discovery' => [ @@ -84,8 +91,5 @@ 'discover_all_pages' => false, ], - 'register_role_policy' => [ - 'enabled' => true, - ], - + 'register_role_policy' => true, ]; diff --git a/config/themes.php b/config/themes.php deleted file mode 100644 index 03fae51..0000000 --- a/config/themes.php +++ /dev/null @@ -1,36 +0,0 @@ - 'user', - - /* - |-------------------------------------------------------------------------- - | Theme Icon - |-------------------------------------------------------------------------- - */ - - 'icon' => 'heroicon-o-swatch', - - /* - |-------------------------------------------------------------------------- - | Default Theme - |-------------------------------------------------------------------------- - */ - - 'default' => [ - 'theme' => 'default', - 'theme_color' => 'blue', - ], -]; diff --git a/database/migrations/2025_05_27_071139_add_themes_settings_to_users_table.php b/database/migrations/2025_05_27_071139_add_themes_settings_to_users_table.php deleted file mode 100644 index 310d8cb..0000000 --- a/database/migrations/2025_05_27_071139_add_themes_settings_to_users_table.php +++ /dev/null @@ -1,23 +0,0 @@ -string('theme')->nullable()->default('default'); - $table->string('theme_color')->nullable(); - }); - } - - public function down() - { - Schema::table('users', function (Blueprint $table) { - $table->dropColumn(['theme', 'theme_color']); - }); - } -}; diff --git a/database/seeders/CoreSeeder.php b/database/seeders/CoreSeeder.php index ec37038..6644ddb 100644 --- a/database/seeders/CoreSeeder.php +++ b/database/seeders/CoreSeeder.php @@ -2,6 +2,9 @@ namespace Eclipse\Core\Database\Seeders; +use Eclipse\Core\Models\Site; +use Eclipse\Core\Models\User\Permission; +use Eclipse\Core\Models\User\Role; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\Artisan; @@ -16,7 +19,6 @@ public function run(): void '--all' => null, '--panel' => 'admin', '--option' => 'permissions', - '--minimal' => null, ]); // Seed additional roles @@ -25,7 +27,37 @@ public function run(): void // Sites $this->call(SiteSeeder::class); + // Assign permissions to roles + $this->assignPermissionsToRoles(); + // Users $this->call(UserSeeder::class); } + + private function assignPermissionsToRoles(): void + { + $allPermissions = Permission::all(); + + foreach (Site::all() as $site) { + foreach (['super_admin', 'admin'] as $roleName) { + $role = Role::firstOrCreate([ + 'name' => $roleName, + 'guard_name' => 'web', + 'site_id' => $site->id, + ]); + + $role->syncPermissions($allPermissions); + } + } + + $this->assignCustomPermissionsToRoles(); + } + + private function assignCustomPermissionsToRoles(): void + { + app(\Spatie\Permission\PermissionRegistrar::class)->forgetCachedPermissions(); + $guard = config('auth.defaults.guard', 'web'); + Permission::findOrCreate('impersonate_user', $guard); + Permission::findOrCreate('send_email_user', $guard); + } } diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php index 2d82fde..5cbd981 100644 --- a/database/seeders/RoleSeeder.php +++ b/database/seeders/RoleSeeder.php @@ -14,7 +14,11 @@ public function run(): void { if (is_array(config('eclipse.seed.roles.presets'))) { foreach (config('eclipse.seed.roles.presets') as $preset) { - Role::create($preset['data']); + $data = $preset['data']; + Role::firstOrCreate([ + 'name' => $data['name'], + 'guard_name' => $data['guard_name'] ?? 'web', + ], $data); } } diff --git a/resources/views/filament/components/my-settings.blade.php b/resources/views/filament/components/my-settings.blade.php index 7805951..3537def 100644 --- a/resources/views/filament/components/my-settings.blade.php +++ b/resources/views/filament/components/my-settings.blade.php @@ -9,8 +9,9 @@ @endphp
- + {{ __($navigationLabel) }} diff --git a/resources/views/filament/components/tenant-menu.blade.php b/resources/views/filament/components/tenant-menu.blade.php index 2df3b0f..f029ee0 100644 --- a/resources/views/filament/components/tenant-menu.blade.php +++ b/resources/views/filament/components/tenant-menu.blade.php @@ -1,14 +1,17 @@ @php + use Illuminate\Database\Eloquent\Model; + $currentTenant = filament()->getTenant(); - $currentTenantName = filament()->getTenantName($currentTenant); + $currentTenantName = $currentTenant ? filament()->getTenantName($currentTenant) : null; - $canSwitchTenants = count( + $canSwitchTenants = $currentTenant ? count( $tenants = array_filter( filament()->getUserTenants(filament()->auth()->user()), - fn(\Illuminate\Database\Eloquent\Model $tenant): bool => !$tenant->is($currentTenant), + fn(Model $tenant): bool => $tenant && !$tenant->is($currentTenant), ), - ); + ) : 0; @endphp +@if($currentTenant)