diff --git a/packages/panels/src/Panel/Concerns/HasComponents.php b/packages/panels/src/Panel/Concerns/HasComponents.php index 77ea374589..b931366fa9 100644 --- a/packages/panels/src/Panel/Concerns/HasComponents.php +++ b/packages/panels/src/Panel/Concerns/HasComponents.php @@ -122,9 +122,7 @@ trait HasComponents */ public function pages(array $pages): static { - if ($this->hasCachedComponents()) { - return $this; - } + $hasCachedComponents = $this->hasCachedComponents(); foreach ($pages as $page) { if ($page instanceof PageConfiguration) { @@ -142,15 +140,16 @@ trait HasComponents $this->pageConfigurations[$page->page][$page->getKey()] = $page; - $pageClass = $page->page; - } else { + if (! $hasCachedComponents) { + $this->queueLivewireComponentForRegistration($page->page); + $this->registerToCluster($page->page); + } + } elseif (! $hasCachedComponents) { $this->pages[] = $page; - $pageClass = $page; + $this->queueLivewireComponentForRegistration($page); + $this->registerToCluster($page); } - - $this->queueLivewireComponentForRegistration($pageClass); - $this->registerToCluster($pageClass); } return $this; @@ -161,9 +160,7 @@ trait HasComponents */ public function resources(array $resources): static { - if ($this->hasCachedComponents()) { - return $this; - } + $hasCachedComponents = $this->hasCachedComponents(); foreach ($resources as $resource) { if ($resource instanceof ResourceConfiguration) { @@ -181,14 +178,14 @@ trait HasComponents $this->resourceConfigurations[$resource->resource][$resource->getKey()] = $resource; - $resourceClass = $resource->resource; - } else { + if (! $hasCachedComponents) { + $this->registerToCluster($resource->resource); + } + } elseif (! $hasCachedComponents) { $this->resources[] = $resource; - $resourceClass = $resource; + $this->registerToCluster($resource); } - - $this->registerToCluster($resourceClass); } return $this; @@ -731,29 +728,11 @@ trait HasComponents 'clusterDirectories' => $this->clusterDirectories, 'clusterNamespaces' => $this->clusterNamespaces, 'pages' => $this->pages, - 'pageConfigurations' => array_map( - static fn (array $configurations): array => array_map( - static fn (PageConfiguration $configuration): array => [ - 'page' => $configuration->page, - 'key' => $configuration->getKey(), - ], - $configurations, - ), - $this->pageConfigurations, - ), + 'pageConfigurations' => [], 'pageDirectories' => $this->pageDirectories, 'pageNamespaces' => $this->pageNamespaces, 'resources' => $this->resources, - 'resourceConfigurations' => array_map( - static fn (array $configurations): array => array_map( - static fn (ResourceConfiguration $configuration): array => [ - 'resource' => $configuration->resource, - 'key' => $configuration->getKey(), - ], - $configurations, - ), - $this->resourceConfigurations, - ), + 'resourceConfigurations' => [], 'resourceDirectories' => $this->resourceDirectories, 'resourceNamespaces' => $this->resourceNamespaces, 'widgets' => $this->widgets, @@ -779,24 +758,9 @@ trait HasComponents $this->clusterDirectories = $cache['clusterDirectories'] ?? []; $this->clusterNamespaces = $cache['clusterNamespaces'] ?? []; $this->pages = $cache['pages'] ?? []; - $this->pageConfigurations = []; - - foreach ($cache['pageConfigurations'] ?? [] as $pageClass => $configurations) { - foreach ($configurations as $configuration) { - $this->pageConfigurations[$pageClass][$configuration['key']] = $configuration['page']::make($configuration['key']); - } - } - $this->pageDirectories = $cache['pageDirectories'] ?? []; $this->pageNamespaces = $cache['pageNamespaces'] ?? []; $this->resources = $cache['resources'] ?? []; - $this->resourceConfigurations = []; - - foreach ($cache['resourceConfigurations'] ?? [] as $resourceClass => $configurations) { - foreach ($configurations as $configuration) { - $this->resourceConfigurations[$resourceClass][$configuration['key']] = $configuration['resource']::make($configuration['key']); - } - } $this->resourceDirectories = $cache['resourceDirectories'] ?? []; $this->resourceNamespaces = $cache['resourceNamespaces'] ?? []; $this->widgets = $cache['widgets'] ?? []; diff --git a/tests/src/Panels/ComponentCachingTest.php b/tests/src/Panels/ComponentCachingTest.php new file mode 100644 index 0000000000..1b8187d60e --- /dev/null +++ b/tests/src/Panels/ComponentCachingTest.php @@ -0,0 +1,161 @@ +actingAs(User::factory()->create()); +}); + +afterEach(function (): void { + Filament::getPanel('admin')->clearCachedComponents(); + Filament::getPanel('configuration')->clearCachedComponents(); +}); + +it('can cache and restore resources', function (): void { + $panel = Filament::getPanel('admin'); + + $resourcesBefore = $panel->getResources(); + + $panel->cacheComponents(); + $panel->restoreCachedComponents(); + + $resourcesAfter = $panel->getResources(); + + expect($resourcesAfter)->toEqual($resourcesBefore); + expect($resourcesAfter)->toContain(PostResource::class); + expect($resourcesAfter)->toContain(UserResource::class); +}); + +it('can cache and restore pages', function (): void { + $panel = Filament::getPanel('admin'); + + $pagesBefore = $panel->getPages(); + + $panel->cacheComponents(); + $panel->restoreCachedComponents(); + + $pagesAfter = $panel->getPages(); + + expect($pagesAfter)->toEqual($pagesBefore); + expect($pagesAfter)->toContain(Settings::class); +}); + +it('can cache and restore widgets', function (): void { + $panel = Filament::getPanel('admin'); + + $widgetsBefore = $panel->getWidgets(); + + $panel->cacheComponents(); + $panel->restoreCachedComponents(); + + $widgetsAfter = $panel->getWidgets(); + + expect($widgetsAfter)->toEqual($widgetsBefore); +}); + +it('skips duplicate resource class strings when cached', function (): void { + $panel = Filament::getPanel('admin'); + + $panel->cacheComponents(); + $panel->restoreCachedComponents(); + + // Calling `resources()` again with cached components should not add duplicates + $countBefore = count($panel->getResources()); + $panel->resources([PostResource::class]); + $countAfter = count($panel->getResources()); + + expect($countAfter)->toBe($countBefore); +}); + +it('skips duplicate page class strings when cached', function (): void { + $panel = Filament::getPanel('admin'); + + $panel->cacheComponents(); + $panel->restoreCachedComponents(); + + // Calling `pages()` again with cached components should not add duplicates + $countBefore = count($panel->getPages()); + $panel->pages([Settings::class]); + $countAfter = count($panel->getPages()); + + expect($countAfter)->toBe($countBefore); +}); + +it('can clear cached components', function (): void { + $panel = Filament::getPanel('admin'); + + $panel->cacheComponents(); + + expect(file_exists($panel->getComponentCachePath()))->toBeTrue(); + + $panel->clearCachedComponents(); + + expect(file_exists($panel->getComponentCachePath()))->toBeFalse(); +}); + +it('preserves resource configurations after caching and restoring components', function (): void { + $panel = Filament::getPanel('configuration'); + + $panel->cacheComponents(); + $panel->restoreCachedComponents(); + + // Verify configurations still exist + $configurations = $panel->getResourceConfigurations(); + expect($configurations)->toHaveCount(2); + + // Verify configuration properties are preserved (not just class and key) + $featuredConfig = $panel->getResourceConfiguration(ConfigurablePostResource::class, 'featured'); + expect($featuredConfig)->not->toBeNull(); + expect($featuredConfig->getSlug())->toBe('featured-posts'); + expect($featuredConfig->getNavigationLabel())->toBe('Featured Posts'); + expect($featuredConfig->getNavigationGroup())->toBe('Featured Content'); + expect($featuredConfig->getNavigationSort())->toBe(1); + expect($featuredConfig->isFeatured())->toBeTrue(); + expect($featuredConfig->isArchived())->toBeFalse(); + + $archivedConfig = $panel->getResourceConfiguration(ConfigurablePostResource::class, 'archived'); + expect($archivedConfig)->not->toBeNull(); + expect($archivedConfig->getSlug())->toBe('archived-posts'); + expect($archivedConfig->getNavigationLabel())->toBe('Archived Posts'); + expect($archivedConfig->getNavigationGroup())->toBe('Archive'); + expect($archivedConfig->getNavigationSort())->toBe(100); + expect($archivedConfig->isFeatured())->toBeFalse(); + expect($archivedConfig->isArchived())->toBeTrue(); +}); + +it('preserves page configurations after caching and restoring components', function (): void { + $panel = Filament::getPanel('configuration'); + + $panel->cacheComponents(); + $panel->restoreCachedComponents(); + + // Verify configurations still exist + $configurations = $panel->getPageConfigurations(); + expect($configurations)->toHaveCount(2); + + // Verify configuration properties are preserved (not just class and key) + $generalConfig = $panel->getPageConfiguration(ConfigurableSettings::class, 'general'); + expect($generalConfig)->not->toBeNull(); + expect($generalConfig->getSlug())->toBe('general-settings'); + expect($generalConfig->getNavigationLabel())->toBe('General Settings'); + expect($generalConfig->getNavigationGroup())->toBe('Settings'); + expect($generalConfig->getNavigationSort())->toBe(1); + expect($generalConfig->getSettingsCategory())->toBe('general'); + + $advancedConfig = $panel->getPageConfiguration(ConfigurableSettings::class, 'advanced'); + expect($advancedConfig)->not->toBeNull(); + expect($advancedConfig->getSlug())->toBe('advanced-settings'); + expect($advancedConfig->getNavigationLabel())->toBe('Advanced Settings'); + expect($advancedConfig->getNavigationGroup())->toBe('Settings'); + expect($advancedConfig->getNavigationSort())->toBe(2); + expect($advancedConfig->getSettingsCategory())->toBe('advanced'); +});