Skip to content

Commit

Permalink
Support multiple filament panel (also tenant), and add new column for…
Browse files Browse the repository at this point in the history
… deteching filament panel path
  • Loading branch information
cklei-carly committed Aug 12, 2024
1 parent 287a6b1 commit 2d73fb2
Show file tree
Hide file tree
Showing 10 changed files with 220 additions and 42 deletions.
33 changes: 18 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,20 @@ This is an authentication plugin for Filament Admin with Laravel-permission
php artisan config:clear
```

4. Then execute the following commands:

4. Register the plugin in your Panel provider:
> **Important: Register the plugin in your Panel provider after version 2.x**
``` bash
use SolutionForest\FilamentAccessManagement\FilamentAccessManagementPanel;
public function panel(Panel $panel): Panel
{
return $panel
->plugin(FilamentAccessManagementPanel::make());
}
```

5. Then execute the following commands:
```bash
php artisan filament-access-management:install
```
Expand All @@ -48,23 +61,13 @@ This is an authentication plugin for Filament Admin with Laravel-permission
You can also create the super admin user with:
```bash
php artisan make:super-admin-user
```
5. Register the plugin in your Panel provider:
> **Important: Register the plugin in your Panel provider after version 2.x**
``` bash
use SolutionForest\FilamentAccessManagement\FilamentAccessManagementPanel;
public function panel(Panel $panel): Panel
{
return $panel
->plugin(FilamentAccessManagementPanel::make());
}
```
6. Call upgrade command to upgrade data after version **2.2.0**
```bash
php artisan filament-access-management:upgrade
```
## Publish Configs, Views, Translations and Migrations
Expand Down
33 changes: 33 additions & 0 deletions database/migrations/upgrade_menu_table.php.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use SolutionForest\FilamentAccessManagement\Support\Utils;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table(Utils::getMenuTableName(), function (Blueprint $table) {
$table->boolean('is_filament_panel')->after('uri')->default(false);
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
if (empty(Utils::getMenuTableName())) {
throw new \Exception('Error: config/filament-access-management.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
}

Schema::table(Utils::getMenuTableName(), function (Blueprint $table) {
$table->dropColumn('is_filament_panel');
});
}
};
40 changes: 35 additions & 5 deletions database/seeders/NavigationSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace SolutionForest\FilamentAccessManagement\Database\Seeders;

use Filament\Facades\Filament;
use Filament\Navigation\NavigationItem;
use Filament\Pages\Dashboard;
use Filament\Resources\Resource;
use Illuminate\Database\Seeder;
use SolutionForest\FilamentAccessManagement\Facades\FilamentAuthenticate;
use SolutionForest\FilamentAccessManagement\Support\Utils;
Expand All @@ -27,9 +27,37 @@ public function run(): void
/** @var \Illuminate\Support\Collection<array-key, \Illuminate\Support\Collection<array-key, \Filament\Navigation\NavigationItem>> */
$navigationGroup = collect(array_merge($pages, $resources))
->filter(fn ($item) => is_string($item) && method_exists($item, 'getNavigationItems'))
->map(fn ($item) => $item::getNavigationItems())
->flatten()
->filter(fn ($navItem) => is_a($navItem, NavigationItem::class))
->map(function ($itemFQCN) {
if (is_subclass_of($itemFQCN, \Filament\Resources\Pages\Page::class) ||
is_subclass_of($itemFQCN, \Filament\Pages\Page::class)) {

$path = $itemFQCN::getRoutePath();

} elseif (is_subclass_of($itemFQCN, \Filament\Resources\Resource::class)) {
try {

$path = (string)str($itemFQCN::getRoutePrefix())->prepend('/')->rtrim('/');

} catch (\Exception $e) {
return null;
}

} else {
return null;
}
return NavigationItem::make($itemFQCN::getNavigationLabel())
->group($itemFQCN::getNavigationGroup())
->parentItem($itemFQCN::getNavigationParentItem())
->icon($itemFQCN::getNavigationIcon())
->activeIcon($itemFQCN::getActiveNavigationIcon())
// ->isActiveWhen(fn (): bool => request()->routeIs($itemFQCN::getNavigationItemActiveRoutePattern()))
->sort($itemFQCN::getNavigationSort())
->badge($itemFQCN::getNavigationBadge(), color: $itemFQCN::getNavigationBadgeColor())
->badgeTooltip($itemFQCN::getNavigationBadgeTooltip())
->url($path);
// ->url($itemFQCN::getNavigationUrl());
})
->filter()
->groupBy(fn (NavigationItem $navItem) => $navItem->getGroup())
->sortKeys();

Expand All @@ -48,9 +76,11 @@ public function run(): void
parent: $parentId,
icon: $navItem->getIcon(),
activeIcon: $navItem->getActiveIcon(),
uri: admin_base_path($navItem->getUrl()),
// uri: admin_base_path($navItem->getUrl()),
uri: $navItem->getUrl(),
badge: $navItem->getBadge(),
badgeColor: $navItem->getBadgeColor(),
isFilamentPanel: true,
);
}
}
Expand Down
1 change: 1 addition & 0 deletions resources/lang/en/filament-access-management.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
'field.menu.icon' => 'ICON',
'field.menu.parent' => 'Parent',
'field.menu.uri' => 'URI',
'field.menu.is_filament_panel' => 'Filament Panel?',

'field.guard_name' => 'Guard Name',
'field.title' => 'Title',
Expand Down
60 changes: 60 additions & 0 deletions src/Commands/Upgrade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

namespace SolutionForest\FilamentAccessManagement\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Str;
use SolutionForest\FilamentAccessManagement\Support\Utils;

use function Laravel\Prompts\progress;

class Upgrade extends Command
{

protected $signature = 'filament-access-management:upgrade';

public $description = 'Upgrade FilamentAccessManagement';

public function handle(): int
{
$this->upgradeMenuUrl();

return static::SUCCESS;
}

private function upgradeMenuUrl()
{
$model = Utils::getMenuModel();

// Find the old uri on FilamentAccessManagement v1
$v1PathRecords = $model::where(function ($query) {
return $query
// ->orWhere('uri', '/') // Admin default page on filament v2
->orWhere('uri', '/admin') // Admin dashboard page on filament v2
->orWhere('uri', 'like', '/admin/%'); // The page(s) under admin on filament v2
})
->where('is_filament_panel', false) // default value
->get();

progress('Updating uri of menu as current version', count($v1PathRecords), function () use ($v1PathRecords) {

foreach ($v1PathRecords as $v1PathRecord) {

try {

$newUri = (string)str($v1PathRecord->uri)
->replace('/admin', '');

$v1PathRecord->update([
'uri' => $newUri,
'is_filament_panel' => true,
]);

} catch (\Exception $e) {
$this->error("Updating uri of menu failed (Detail: {$e->getMessage()})");
}
}
});

}
}
4 changes: 3 additions & 1 deletion src/FilamentAccessManagementServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,15 @@ protected function getCommands(): array
return [
Commands\MakeSuperAdminUser::class,
Commands\MakeMenu::class,
Commands\Upgrade::class,
];
}

protected function getMigrations(): array
{
return [
'create_filament_admin_tables',
'upgrade_menu_table',
];
}

Expand Down Expand Up @@ -93,7 +95,7 @@ public function bootingPackage(): void
public function packageBooted(): void
{
parent::packageBooted();

if ($this->app->runningInConsole()) {

$configFiles = [
Expand Down
26 changes: 22 additions & 4 deletions src/Models/Menu.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
use SolutionForest\FilamentAccessManagement\Facades\FilamentAuthenticate;
use SolutionForest\FilamentAccessManagement\Support\Utils;
use SolutionForest\FilamentTree\Concern\ModelTree;
use SolutionForest\FilamentTree\Support\Utils as FilamentTreeHelper;
use Spatie\EloquentSortable\SortableTrait;

class Menu extends Model
{
Expand All @@ -19,16 +17,37 @@ class Menu extends Model
'icon',
'active_icon',
'uri',
'is_filament_panel',
'badge',
'badge_color',
'parent_id',
'order',
];

public $casts = [
'is_filament_panel' => 'boolean',
];

public function getNavigationUrl(): ?string
{
$uriColumnName = $this->determineUriColumnName();
return empty($this->{$uriColumnName}) ? null : admin_url($this->{$uriColumnName});
if (empty($this->{$uriColumnName})) {
return null;
}
if ($this->is_filament_panel && $panel = (filament()->getCurrentPanel() ?? filament()->getDefaultPanel())) {

$pathInPanel = (string)str($panel->getPath())
->trim('/')
->append('/')
->when($panel->hasTenancy(),
fn ($str) => $str
->append(filament()->getTenant()?->getKey())
->append('/'))
->append(trim($this->{$uriColumnName}, '/'));

return url($pathInPanel);
}
return $this->{$uriColumnName};
}

public function determineTitleColumnName() : string
Expand Down Expand Up @@ -61,7 +80,6 @@ public function determineBadgeColorColumnName() : string
return 'badge_color';
}


protected static function boot()
{
parent::boot();
Expand Down
4 changes: 4 additions & 0 deletions src/Pages/Menu.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ protected function getFormSchema(): array
->label(__('filament-access-management::filament-access-management.field.menu.uri'))
->helperText('Relative path or external URL'),

Forms\Components\Toggle::make('is_filament_panel')
->label(__('filament-access-management::filament-access-management.field.menu.is_filament_panel'))
->inlineLabel(),

IconPicker::make('icon')
->label(__('filament-access-management::filament-access-management.field.menu.icon'))
->preload()
Expand Down
51 changes: 36 additions & 15 deletions src/Support/Menu.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,15 @@ public static function createNavigation(string $title,
?string $activeIcon= null,
?string $uri= null,
?string $badge= null,
?string $badgeColor= null): Model
?string $badgeColor= null,
bool $isFilamentPanel= false): Model
{
return Utils::getMenuModel()::firstOrCreate(
['title' => $title, 'parent_id' => $parent ?? -1],
[
'title' => $title,
'parent_id' => $parent ?? -1,
'is_filament_panel' => $isFilamentPanel,
],
[
'icon' => $icon,
'active_icon' => $activeIcon,
Expand Down Expand Up @@ -174,22 +179,38 @@ private static function buildNavigationGroupItems(array $treeItems = [], ?string
}

$model = app(Utils::getMenuModel());

$labelColumnName = method_exists($model, 'determineTitleColumnName') ? $model->determineTitleColumnName() : 'title';
$iconColumnName = method_exists($model, 'determineIconColumnName') ? $model->determineIconColumnName() : 'icon';
$activeIconColumnName = method_exists($model, 'determineActiveIconColumnName') ? $model->determineActiveIconColumnName() : 'active_icon';
$uriColumnName = method_exists($model, 'determineUriColumnName') ? $model->determineUriColumnName() : 'uri';
$badgeColumnName = method_exists($model, 'determineBadgeColumnName') ? $model->determineBadgeColumnName() : 'badge';
$badgeColorColumnName = method_exists($model, 'determineBadgeColorColumnName') ? $model->determineBadgeColorColumnName() : 'badge_color';
$orderColumnName = method_exists($model, 'determineOrderColumnName') ? $model->determineOrderColumnName() : FilamentTree\Support\Utils::orderColumnName();

return collect($treeItems)
->map(function (array $treeItem) {
static::handleTranslatable($treeItem);
return $treeItem;
})
->map(fn (array $treeItem) =>
NavigationItem::make()
->map(function (array $treeItem) use ($model) {

$labelColumnName = method_exists($model, 'determineTitleColumnName') ? $model->determineTitleColumnName() : 'title';
$iconColumnName = method_exists($model, 'determineIconColumnName') ? $model->determineIconColumnName() : 'icon';
$activeIconColumnName = method_exists($model, 'determineActiveIconColumnName') ? $model->determineActiveIconColumnName() : 'active_icon';
$uriColumnName = method_exists($model, 'determineUriColumnName') ? $model->determineUriColumnName() : 'uri';
$badgeColumnName = method_exists($model, 'determineBadgeColumnName') ? $model->determineBadgeColumnName() : 'badge';
$badgeColorColumnName = method_exists($model, 'determineBadgeColorColumnName') ? $model->determineBadgeColorColumnName() : 'badge_color';
$orderColumnName = method_exists($model, 'determineOrderColumnName') ? $model->determineOrderColumnName() : FilamentTree\Support\Utils::orderColumnName();

$url = trim(($treeItem[$uriColumnName] ?? "/"), '/');

if (($treeItem['is_filament_panel'] ?? false) == true && $panel = (filament()->getCurrentPanel() ?? filament()->getDefaultPanel())) {

$pathInPanel = (string)str($panel->getPath())
->trim('/')
->append('/')
->when($panel->hasTenancy(),
fn ($str) => $str
->append(filament()->getTenant()?->getKey())
->append('/'))
->append($url);

$url = url($pathInPanel);
}

return NavigationItem::make()
->label(static::ensureNavigationLabel($treeItem[$labelColumnName]) ?? "")
->group($groupLabel ?? "")
->groupIcon($groupIcon ?? "")
Expand All @@ -198,7 +219,7 @@ private static function buildNavigationGroupItems(array $treeItems = [], ?string
->isActiveWhen(fn (): bool => request()->is(trim(($treeItem[$uriColumnName] ?? "/"), '/')))
->sort(intval($treeItem[$orderColumnName] ?? 0))
->badge(($treeItem[$badgeColumnName] ?? null), color: ($treeItem[$badgeColorColumnName] ?? null))
->url(admin_url(trim(($treeItem[$uriColumnName] ?? "/"), '/')))
)->toArray();
->url($url);
})->toArray();
}
}
Loading

0 comments on commit 2d73fb2

Please sign in to comment.