cluster improvements & docs

This commit is contained in:
Dan Harrin
2024-01-14 10:44:47 +00:00
parent 3dceadc839
commit e15960c743
27 changed files with 376 additions and 38 deletions
+1 -1
View File
@@ -146,7 +146,7 @@ This will create several files in the `app/Filament/Resources` directory:
| | +-- ListPatients.php
```
Visit `/admin/patients` in your browser and observe a new link called "Patients" in the sidebar. Clicking the link will display an empty table. Let's add a form to create new patients.
Visit `/admin/patients` in your browser and observe a new link called "Patients" in the navigation. Clicking the link will display an empty table. Let's add a form to create new patients.
### Setting up the resource form
@@ -364,6 +364,8 @@ public static function getNavigationParentItem(): ?string
}
```
> If you're reaching for a third level of navigation like this, you should consider using [clusters](clusters) instead, which are a logical grouping of resources and [custom pages](../pages), which can share their own separate navigation.
## Generating URLs to resource pages
Filament provides `getUrl()` static method on resource classes to generate URLs to resources and specific pages within them. Traditionally, you would need to construct the URL by hand or by using Laravel's `route()` helper, but these methods depend on knowledge of the resource's slug or route naming conventions.
@@ -506,6 +508,8 @@ public static function getRecordSubNavigation(Page $page): array
Each item in the sub-navigation can be customized using the [same navigation methods as normal pages](../navigation).
> If you're looking to add sub-navigation to switch *between* entire resources and [custom pages](../pages), you might be looking for [clusters](../clusters), which are used to group these together. The `getRecordSubNavigation()` method is intended to construct a navigation between pages that relate to a particular record *inside* a resource.
### Sub-navigation position
The sub-navigation is rendered at the start of the page by default. You may change the position by setting the `$subNavigationPosition` property on the resource. The value may be `SubNavigationPosition::Start`, `SubNavigationPosition::End`, or `SubNavigationPosition::Top` to render the sub-navigation as tabs:
@@ -311,6 +311,8 @@ public function form(Form $form): Form
}
```
## Adding edit pages to resource sub-navigation
If you're using [resource sub-navigation](getting-started#resource-sub-navigation), you can register this page as normal in `getRecordSubNavigation()` of the resource:
```php
@@ -147,6 +147,8 @@ public function infolist(Infolist $infolist): Infolist
}
```
## Adding view pages to resource sub-navigation
If you're using [resource sub-navigation](getting-started#resource-sub-navigation), you can register this page as normal in `getRecordSubNavigation()` of the resource:
```php
@@ -859,6 +859,8 @@ public static function getPages(): array
Now, you can customize the page in exactly the same way as a relation manager, with the same `table()` and `form()`.
### Adding relation pages to resource sub-navigation
If you're using [resource sub-navigation](getting-started#resource-sub-navigation), you can register this page as normal in `getRecordSubNavigation()` of the resource:
```php
+7 -12
View File
@@ -18,26 +18,17 @@ This command will create two files - a page class in the `/Pages` directory of t
Page classes are all full-page [Livewire](https://livewire.laravel.com) components with a few extra utilities you can use with the panel.
## Conditionally hiding pages in navigation
## Authorization
You can prevent pages from appearing in the menu by overriding the `shouldRegisterNavigation()` method in your Page class. This is useful if you want to control which users can see the page in the sidebar.
You can prevent pages from appearing in the menu by overriding the `canAccess()` method in your Page class. This is useful if you want to control which users can see the page in the navigation, and also which users can visit the page directly:
```php
public static function shouldRegisterNavigation(): bool
public static function canAccess(): bool
{
return auth()->user()->canManageSettings();
}
```
Please be aware that all users will still be able to visit this page through its direct URL, so to fully limit access, you must also check in the `mount()` method of the page:
```php
public function mount(): void
{
abort_unless(auth()->user()->canManageSettings(), 403);
}
```
## Adding actions to pages
Actions are buttons that can perform tasks on the page, or visit a URL. You can read more about their capabilities [here](../actions).
@@ -336,3 +327,7 @@ use App\Filament\Pages\Settings;
Settings::getUrl(panel: 'marketing');
```
## Adding sub-navigation between pages
You may want to add a common sub-navigation to multiple pages, to allow users to quickly navigate between them. You can do this by defining a [cluster](clusters). Clusters can also contain [resources](resources), and you can switch between multiple pages or resources within a cluster.
+1 -1
View File
@@ -274,7 +274,7 @@ You may also customize the title of the dashboard by overriding the `$title` pro
protected static ?string $title = 'Finance dashboard';
```
The primary dashboard shown to a user is the first one they have access to (controlled by `canAccess()` method), according to the defined navigation sort order.
The primary dashboard shown to a user is the first one they have access to (controlled by [`canAccess()` method](pages#authorization)), according to the defined navigation sort order.
The default sort order for dashboards is `-2`. You can control the sort order of custom dashboards with `$navigationSort`:
+28 -4
View File
@@ -4,7 +4,9 @@ title: Navigation
## Overview
By default, Filament will register navigation items for each of your [resources](resources/getting-started) and [custom pages](pages). These classes contain static properties and methods that you can override, to configure that navigation item.
By default, Filament will register navigation items for each of your [resources](resources/getting-started), [custom pages](pages), and [clusters](clusters). These classes contain static properties and methods that you can override, to configure that navigation item.
If you're looking to add a second layer of navigation to your app, you can use [clusters](clusters). These are useful for grouping resources and pages together.
## Customizing a navigation item's label
@@ -79,9 +81,9 @@ You may group navigation items by specifying a `$navigationGroup` property on a
protected static ?string $navigationGroup = 'Settings';
```
All items in the same navigation group will be displayed together under the same group label, "Settings" in this case. Ungrouped items will remain at the top of the sidebar.
All items in the same navigation group will be displayed together under the same group label, "Settings" in this case. Ungrouped items will remain at the start of the navigation.
#### Grouping navigation items under other items
### Grouping navigation items under other items
You may group navigation items as children of other items, by passing the label of the parent item as the `$navigationParentItem`:
@@ -91,8 +93,19 @@ protected static ?string $navigationParentItem = 'Notifications';
protected static ?string $navigationGroup = 'Settings';
```
You may also use the `getNavigationParentItem()` method to set a dynamic parent item label:
```php
public static function getNavigationParentItem(): ?string
{
return __('filament/navigation.groups.settings.items.notifications');
}
```
As seen above, if the parent item has a navigation group, that navigation group must also be defined, so the correct parent item can be identified.
> If you're reaching for a third level of navigation like this, you should consider using [clusters](clusters) instead, which are a logical grouping of resources and custom pages, which can share their own separate navigation.
### Customizing navigation groups
You may customize navigation groups by calling `navigationGroups()` in the [configuration](configuration), and passing `NavigationGroup` objects in order:
@@ -124,7 +137,7 @@ In this example, we pass in a custom `icon()` for the groups, and make one `coll
#### Ordering navigation groups
By using `navigationGroups()`, you are defining a new order for the navigation groups in the sidebar. If you just want to reorder the groups and not define an entire `NavigationGroup` object, you may just pass the labels of the groups in the new order:
By using `navigationGroups()`, you are defining a new order for the navigation groups. If you just want to reorder the groups and not define an entire `NavigationGroup` object, you may just pass the labels of the groups in the new order:
```php
$panel
@@ -238,6 +251,17 @@ To prevent resources or pages from showing up in navigation, you may use:
protected static bool $shouldRegisterNavigation = false;
```
Or, you may override the `shouldRegisterNavigation()` method:
```php
public static function shouldRegisterNavigation(): bool
{
return false;
}
```
Please note that these methods do not control direct access to the resource or page. They only control whether the resource or page will show up in the navigation. If you want to also control access, then you should use [resource authorization](resources/getting-started#authorization) or [page authorization](pages#authorization).
## Using top navigation
By default, Filament will use a sidebar navigation. You may use a top navigation instead by using the [configuration](configuration):
+1 -1
View File
@@ -8,7 +8,7 @@ By default, the configuration file is located at `app/Providers/Filament/AdminPa
## Introducing panels
By default, when you install the package, there is one panel that has been set up for you - and it lives on `/admin`. All the [resources](resources/getting-started), [pages](pages), and [dashboard widgets](dashboard) you create get registered to this panel.
By default, when you install the package, there is one panel that has been set up for you - and it lives on `/admin`. All the [resources](resources/getting-started), [custom pages](pages), and [dashboard widgets](dashboard) you create get registered to this panel.
However, you can create as many panels as you want, and each can have its own set of resources, pages and widgets.
+88
View File
@@ -0,0 +1,88 @@
---
title: Clusters
---
## Overview
Clusters are a hierarchical structure in panels that allow you to group [resources](resources) and [custom pages](pages) together. They are useful for organizing your panel into logical sections, and can help reduce the size of your panel's sidebar.
When using a cluster, a few things happen:
- A new navigation item is added to the navigation, which is a link to the first resource or page in the cluster.
- The individual navigation items for the resources or pages are no longer visible in the main navigation.
- A new sub-navigation UI is added to each resource or page in the cluster, which contains the navigation items for the resources or pages in the cluster.
- Resources and pages in the cluster get a new URL, prefixed with the name of the cluster. If you are generating URLs to [resources](resources/getting-started#generating-urls-to-resource-pages) and [pages](pages#generating-urls-to-pages) correctly, then this change should be handled for you automatically.
- The cluster's name is in the breadcrumbs of all resources and pages in the cluster. When clicking it, you are taken to the first resource or page in the cluster.
## Creating a cluster
Before creating your first cluster, you must tell the panel where cluster classes should be located. Alongside methods like `discoverResources()` and `discoverPages()` in the [configuration](configuration), you can use `discoverClusters()`:
```php
public function panel(Panel $panel): Panel
{
return $panel
// ...
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
->discoverClusters(in: app_path('Filament/Clusters'), for: 'App\\Filament\\Clusters');
}
```
Now, you can create a cluster with the `php artisan make:filament:cluster` command:
```bash
php artisan make:filament:cluster Settings
```
This will create a new cluster class in the `app/Filament/Clusters` directory:
```php
<?php
namespace App\Filament\Clusters;
use Filament\Clusters\Cluster;
class Settings extends Cluster
{
protected static ?string $navigationIcon = 'heroicon-o-squares-2x2';
}
```
The [`$navigationIcon`](navigation#customizing-a-navigation-items-icon) property is defined by default since you will most likely want to customize this immediately. All other [navigation properties and methods](navigation) are also available to use, including [`$navigationLabel`](navigation#customizing-a-navigation-items-label), [`$navigationSort`](navigation#sorting-navigation-items) and [`$navigationGroup`](navigation#grouping-navigation-items). These are used to customize the cluster's main navigation item, in the same way you would customize the item for a resource or page.
## Adding resources and pages to a cluster
To add resources and pages to a cluster, you just need to define the `$cluster` property on the resource or page class, and set it to the cluster class [you created](#creating-a-cluster):
```php
use App\Filament\Clusters\Settings;
protected static ?string $cluster = Settings::class;
```
## Code structure recommendations for panels using clusters
When using clusters, it is recommended that you move all of your resources and pages into a directory with the same name as the cluster. For example, here is an directory structure for a panel that uses a cluster called `Settings`, containing a `ColorResource` and two custom pages:
```
.
+-- Clusters
| +-- Settings.php
| +-- Settings
| | +-- Pages
| | | +-- ManageBranding.php
| | | +-- ManageNotifications.php
| | +-- Resources
| | | +-- ColorResource.php
| | | +-- ColorResource
| | | | +-- Pages
| | | | | +-- CreateColor.php
| | | | | +-- EditColor.php
| | | | | +-- ListColors.php
```
This is a recommendation, not a requirement. You can structure your panel however you like, as long as the resources and pages in your cluster use the [`$cluster`](#adding-resources-and-pages-to-a-cluster) property. This is just a suggestion to help you keep your panel organized.
When a cluster exists in your panel, and you generate new resources or pages with the `make:filament-resource` or `make:filament-page` commands, you will be asked if you want to create them inside a cluster directory, according to these guidelines. If you choose to, then Filament will also assign the correct `$cluster` property to the resource or page class for you. If you do not, you will need to [define the `$cluster` property](#adding-resources-and-pages-to-a-cluster) yourself.
@@ -282,7 +282,7 @@ Now, users will be redirected to the billing page if they don't have an active s
#### Requiring a subscription for specific resources and pages
Sometimes, you may wish to only require a subscription for certain [resources](resources/getting-started) and [pages](pages) in your app. You can do this by returning `true` from the `isTenantSubscriptionRequired()` method on the resource or page class:
Sometimes, you may wish to only require a subscription for certain [resources](resources/getting-started) and [custom pages](pages) in your app. You can do this by returning `true` from the `isTenantSubscriptionRequired()` method on the resource or page class:
```php
public static function isTenantSubscriptionRequired(Panel $panel): bool
@@ -341,7 +341,7 @@ public function panel(Panel $panel): Panel
## Customizing the tenant menu
The tenant-switching menu is featured in the sidebar of the admin layout. It's fully customizable.
The tenant-switching menu is featured in the admin layout. It's fully customizable.
To register new items to the tenant menu, you can use the [configuration](configuration):
@@ -569,7 +569,7 @@ The `getFilamentName()` method is used to retrieve the name of the current user.
## Setting the current tenant label
Inside the tenant switcher on the sidebar, you may wish to add a small label like "Active team" above the name of the current team. You can do this by implementing the `HasCurrentTenantLabel` method on the tenant model:
Inside the tenant switcher, you may wish to add a small label like "Active team" above the name of the current team. You can do this by implementing the `HasCurrentTenantLabel` method on the tenant model:
```php
<?php
@@ -25,7 +25,7 @@ Filament plugins build on top of the concepts of Laravel packages and allow you
A plugin class is used to allow your package to interact with a panel [configuration](configuration) file. It's a simple PHP class that implements the `Plugin` interface. 3 methods are required:
- The `getId()` method returns the unique identifier of the plugin amongst other plugins. Please ensure that it is specific enough to not clash with other plugins that might be used in the same project.
- The `register()` method allows you to use any [configuration](configuration) option that is available to the panel. This includes registering [resources](resources/getting-started), [pages](pages), [themes](themes), [render hooks](configuration#render-hooks) and more.
- The `register()` method allows you to use any [configuration](configuration) option that is available to the panel. This includes registering [resources](resources/getting-started), [custom pages](pages), [themes](themes), [render hooks](configuration#render-hooks) and more.
- The `boot()` method is run only when the panel that the plugin is being registered to is actually in-use. It is executed by a middleware class.
```php
@@ -66,6 +66,17 @@
{{ \Filament\Support\Facades\FilamentView::renderHook('panels::styles.after') }}
<script>
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
const activeSidebarItem = document.querySelector('.fi-sidebar-item-active')
const sidebarWrapper = document.querySelector('.fi-sidebar-nav')
sidebarWrapper.scrollTo(0, activeSidebarItem.offsetTop - (window.innerHeight / 2))
}, 0)
})
</script>
@if (! filament()->hasDarkMode())
<script>
localStorage.setItem('theme', 'light')
@@ -0,0 +1,12 @@
<?php
namespace Filament\Commands\Aliases;
use Filament\Commands;
class MakeClusterCommand extends Commands\MakeClusterCommand
{
protected $hidden = true;
protected $signature = 'filament:cluster {name?} {--panel=} {--F|force}';
}
@@ -0,0 +1,102 @@
<?php
namespace Filament\Commands;
use Filament\Facades\Filament;
use Filament\Panel;
use Filament\Support\Commands\Concerns\CanIndentStrings;
use Filament\Support\Commands\Concerns\CanManipulateFiles;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use function Laravel\Prompts\select;
use function Laravel\Prompts\text;
class MakeClusterCommand extends Command
{
use CanIndentStrings;
use CanManipulateFiles;
protected $description = 'Create a new Filament cluster class';
protected $signature = 'make:filament-cluster {name?} {--panel=} {--F|force}';
public function handle(): int
{
$cluster = (string) str(
$this->argument('name') ??
text(
label: 'What is the cluster name?',
placeholder: 'Settings',
required: true,
),
)
->trim('/')
->trim('\\')
->trim(' ')
->replace('/', '\\');
$clusterClass = (string) str($cluster)->afterLast('\\');
$clusterNamespace = str($cluster)->contains('\\') ?
(string) str($cluster)->beforeLast('\\') :
'';
$panel = $this->option('panel');
if ($panel) {
$panel = Filament::getPanel($panel);
}
if (! $panel) {
$panels = Filament::getPanels();
/** @var Panel $panel */
$panel = (count($panels) > 1) ? $panels[select(
label: 'Which panel would you like to create this in?',
options: array_map(
fn (Panel $panel): string => $panel->getId(),
$panels,
),
default: Filament::getDefaultPanel()->getId()
)] : Arr::first($panels);
}
$clusterDirectories = $panel->getClusterDirectories();
$clusterNamespaces = $panel->getClusterNamespaces();
$namespace = (count($clusterNamespaces) > 1) ?
select(
label: 'Which namespace would you like to create this in?',
options: $clusterNamespaces
) :
(Arr::first($clusterNamespaces) ?? 'App\\Filament\\Clusters');
$path = (count($clusterDirectories) > 1) ?
$clusterDirectories[array_search($namespace, $clusterNamespaces)] :
(Arr::first($clusterDirectories) ?? app_path('Filament/Clusters/'));
$path = (string) str($cluster)
->prepend('/')
->prepend($path)
->replace('\\', '/')
->replace('//', '/')
->append('.php');
$files = [$path];
if (! $this->option('force') && $this->checkForCollision($files)) {
return static::INVALID;
}
$this->copyStubToApp('Cluster', $path, [
'class' => $clusterClass,
'namespace' => $namespace . ($clusterNamespace !== '' ? "\\{$clusterNamespace}" : ''),
]);
$this->components->info("Filament cluster [{$path}] created successfully.");
if (empty($clusterNamespaces)) {
$this->components->info('Make sure to register the cluster with `discoverClusters()` in the panel service provider.');
}
return static::SUCCESS;
}
}
@@ -2,6 +2,7 @@
namespace Filament\Commands;
use Filament\Clusters\Cluster;
use Filament\Facades\Filament;
use Filament\Panel;
use Filament\Support\Commands\Concerns\CanIndentStrings;
@@ -240,9 +241,24 @@ class MakePageCommand extends Command
return static::INVALID;
}
$potentialCluster = empty($resource) ? ((string) str($namespace)->beforeLast('\Pages')) : null;
$clusterAssignment = null;
$clusterImport = null;
if (
filled($potentialCluster) &&
class_exists($potentialCluster) &&
is_subclass_of($potentialCluster, Cluster::class)
) {
$clusterAssignment = $this->indentString(PHP_EOL . PHP_EOL . 'protected static ?string $cluster = ' . class_basename($potentialCluster) . '::class;');
$clusterImport = "use {$potentialCluster};" . PHP_EOL;
}
if (empty($resource)) {
$this->copyStubToApp('Page', $path, [
'class' => $pageClass,
'clusterAssignment' => $clusterAssignment,
'clusterImport' => $clusterImport,
'namespace' => $namespace . ($pageNamespace !== '' ? "\\{$pageNamespace}" : ''),
'view' => $view,
]);
@@ -2,6 +2,7 @@
namespace Filament\Commands;
use Filament\Clusters\Cluster;
use Filament\Facades\Filament;
use Filament\Forms\Commands\Concerns\CanGenerateForms;
use Filament\Panel;
@@ -185,7 +186,21 @@ class MakeResourceCommand extends Command
$tableBulkActions = implode(PHP_EOL, $tableBulkActions);
$potentialCluster = (string) str($namespace)->beforeLast('\Resources');
$clusterAssignment = null;
$clusterImport = null;
if (
class_exists($potentialCluster) &&
is_subclass_of($potentialCluster, Cluster::class)
) {
$clusterAssignment = $this->indentString(PHP_EOL . PHP_EOL . 'protected static ?string $cluster = ' . class_basename($potentialCluster) . '::class;');
$clusterImport = "use {$potentialCluster};" . PHP_EOL;
}
$this->copyStubToApp('Resource', $resourcePath, [
'clusterAssignment' => $clusterAssignment,
'clusterImport' => $clusterImport,
'eloquentQuery' => $this->indentString($eloquentQuery, 1),
'formSchema' => $this->indentString($this->option('generate') ? $this->getResourceFormSchema(
$modelNamespace . ($modelSubNamespace !== '' ? "\\{$modelSubNamespace}" : '') . '\\' . $modelClass,
@@ -96,6 +96,7 @@ class FilamentServiceProvider extends PackageServiceProvider
protected function getCommands(): array
{
$commands = [
Commands\MakeClusterCommand::class,
Commands\MakePageCommand::class,
Commands\MakePanelCommand::class,
Commands\MakeRelationManagerCommand::class,
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace {{ namespace }};
use Filament\Clusters\Cluster;
class {{ class }} extends Cluster
{
protected static ?string $navigationIcon = 'heroicon-o-squares-2x2';
}
+2 -2
View File
@@ -2,11 +2,11 @@
namespace {{ namespace }};
use Filament\Pages\Page;
{{ clusterImport }}use Filament\Pages\Page;
class {{ class }} extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = '{{ view }}';
protected static string $view = '{{ view }}';{{ clusterAssignment }}
}
+2 -2
View File
@@ -2,7 +2,7 @@
namespace {{ namespace }};
use {{ resource }}\Pages;
{{ clusterImport }}use {{ resource }}\Pages;
use {{ resource }}\RelationManagers;
use {{ model }};
use Filament\Forms;
@@ -17,7 +17,7 @@ class {{ resourceClass }} extends Resource
{
protected static ?string $model = {{ modelClass }}::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';{{ clusterAssignment }}
public static function form(Form $form): Form
{
@@ -8,5 +8,5 @@ class MakeSettingsPageCommand extends Commands\MakeSettingsPageCommand
{
protected $hidden = true;
protected $signature = 'filament:settings-page {name?} {settingsClass?}';
protected $signature = 'filament:settings-page {name?} {settingsClass?} {--panel=} {--F|force}';
}
@@ -2,18 +2,25 @@
namespace Filament\Commands;
use Filament\Clusters\Cluster;
use Filament\Facades\Filament;
use Filament\Panel;
use Filament\Support\Commands\Concerns\CanIndentStrings;
use Filament\Support\Commands\Concerns\CanManipulateFiles;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use function Laravel\Prompts\select;
use function Laravel\Prompts\text;
class MakeSettingsPageCommand extends Command
{
use CanIndentStrings;
use CanManipulateFiles;
protected $description = 'Create a new Filament settings page class';
protected $signature = 'make:filament-settings-page {name?} {settingsClass?}';
protected $signature = 'make:filament-settings-page {name?} {settingsClass?} {--panel=} {--F|force}';
public function handle(): int
{
@@ -40,20 +47,67 @@ class MakeSettingsPageCommand extends Command
->trim('\\')
->trim(' ');
$path = app_path(
(string) str($page)
->prepend('Filament\\Pages\\')
->replace('\\', '/')
->append('.php'),
);
$panel = $this->option('panel');
if ($panel) {
$panel = Filament::getPanel($panel);
}
if (! $panel) {
$panels = Filament::getPanels();
/** @var Panel $panel */
$panel = (count($panels) > 1) ? $panels[select(
label: 'Which panel would you like to create this in?',
options: array_map(
fn (Panel $panel): string => $panel->getId(),
$panels,
),
default: Filament::getDefaultPanel()->getId()
)] : Arr::first($panels);
}
$pageDirectories = $panel->getPageDirectories();
$pageNamespaces = $panel->getPageNamespaces();
$namespace = (count($pageNamespaces) > 1) ?
select(
label: 'Which namespace would you like to create this in?',
options: $pageNamespaces
) :
(Arr::first($pageNamespaces) ?? 'App\\Filament\\Pages');
$path = (count($pageDirectories) > 1) ?
$pageDirectories[array_search($namespace, $pageNamespaces)] :
(Arr::first($pageDirectories) ?? app_path('Filament/Pages/'));
$path = (string) str($page)
->prepend('/')
->prepend($path)
->replace('\\', '/')
->replace('//', '/')
->append('.php');
if ($this->checkForCollision([$path])) {
return static::INVALID;
}
$potentialCluster = (string) str($namespace)->beforeLast('\Pages');
$clusterAssignment = null;
$clusterImport = null;
if (
class_exists($potentialCluster) &&
is_subclass_of($potentialCluster, Cluster::class)
) {
$clusterAssignment = $this->indentString(PHP_EOL . PHP_EOL . 'protected static ?string $cluster = ' . class_basename($potentialCluster) . '::class;');
$clusterImport = "use {$potentialCluster};" . PHP_EOL;
}
$this->copyStubToApp('SettingsPage', $path, [
'class' => $pageClass,
'namespace' => 'App\\Filament\\Pages' . ($pageNamespace !== '' ? "\\{$pageNamespace}" : ''),
'clusterAssignment' => $clusterAssignment,
'clusterImport' => $clusterImport,
'namespace' => $namespace . ($pageNamespace !== '' ? "\\{$pageNamespace}" : ''),
'settingsClass' => $settingsClass,
]);
@@ -2,7 +2,7 @@
namespace {{ namespace }};
use App\Settings\{{ settingsClass }};
{{ clusterImport }}use App\Settings\{{ settingsClass }};
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\SettingsPage;
@@ -11,7 +11,7 @@ class {{ class }} extends SettingsPage
{
protected static ?string $navigationIcon = 'heroicon-o-cog-6-tooth';
protected static string $settings = {{ settingsClass }}::class;
protected static string $settings = {{ settingsClass }}::class;{{ clusterAssignment }}
public function form(Form $form): Form
{