feat: refine NavbarManager to restrict navigation modifications in admin context, enhance route handling, and improve icon validation, ensuring better separation of frontend and admin functionalities
This commit is contained in:
@@ -20,11 +20,11 @@ class NavbarLinkResource extends Resource
|
||||
{
|
||||
protected static ?string $model = NavbarLink::class;
|
||||
|
||||
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-bars-3';
|
||||
protected static ?string $navigationIcon = 'heroicon-o-bars-3';
|
||||
|
||||
protected static ?string $navigationLabel = 'Navbar Manager';
|
||||
|
||||
protected static string|\UnitEnum|null $navigationGroup = 'Content';
|
||||
protected static ?string $navigationGroup = 'Content';
|
||||
|
||||
public static function getAvailableRoutes(): array
|
||||
{
|
||||
|
||||
@@ -50,26 +50,79 @@ class NavbarManager extends Extension
|
||||
|
||||
public function boot()
|
||||
{
|
||||
// Register view service provider
|
||||
// Don't run any navigation modifications in admin or console
|
||||
if ($this->isAdminContext()) {
|
||||
// Only register Filament resource in admin
|
||||
$this->registerFilamentResource();
|
||||
return;
|
||||
}
|
||||
|
||||
// Register view service provider (frontend only)
|
||||
app()->register(\Paymenter\Extensions\Others\NavbarManager\Providers\ViewServiceProvider::class);
|
||||
|
||||
// Register custom routes for navbar links
|
||||
require __DIR__ . '/routes/web.php';
|
||||
|
||||
// Register event listeners for navigation - dodaće naše linkove uz postojeće
|
||||
// Register event listeners for navigation - only for frontend
|
||||
Event::listen('navigation', function () {
|
||||
return $this->getNavigationLinks('primary');
|
||||
if (!$this->isAdminContext()) {
|
||||
return $this->getNavigationLinks('primary');
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
Event::listen('navigation.account-dropdown', function () {
|
||||
return $this->getNavigationLinks('account');
|
||||
if (!$this->isAdminContext()) {
|
||||
return $this->getNavigationLinks('account');
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
Event::listen('navigation.dashboard', function () {
|
||||
return $this->getNavigationLinks('dashboard');
|
||||
if (!$this->isAdminContext()) {
|
||||
return $this->getNavigationLinks('dashboard');
|
||||
}
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
// Register the Filament resource
|
||||
/**
|
||||
* Check if we're in admin context
|
||||
*/
|
||||
private function isAdminContext(): bool
|
||||
{
|
||||
if (app()->runningInConsole()) {
|
||||
return false; // Allow in console for migrations, etc.
|
||||
}
|
||||
|
||||
try {
|
||||
$currentPath = request()->path();
|
||||
|
||||
// Check for admin routes
|
||||
if (str_starts_with($currentPath, 'admin') ||
|
||||
str_contains($currentPath, '/admin/') ||
|
||||
request()->is('admin') ||
|
||||
request()->is('admin/*')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for Filament routes
|
||||
if (str_starts_with($currentPath, 'filament') ||
|
||||
request()->is('filament/*')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Filament resource
|
||||
*/
|
||||
private function registerFilamentResource(): void
|
||||
{
|
||||
try {
|
||||
\Filament\Facades\Filament::serving(function () {
|
||||
\Filament\Facades\Filament::getCurrentPanel()
|
||||
@@ -78,7 +131,9 @@ class NavbarManager extends Extension
|
||||
]);
|
||||
});
|
||||
} catch (\Exception $e) {
|
||||
// Resource not yet available
|
||||
\Log::error('NavbarManager: Failed to register Filament resource', [
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,6 +303,61 @@ class NavbarManager extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
private function isValidIcon($icon)
|
||||
{
|
||||
// Basic validation for RemixIcon format
|
||||
if (!preg_match('/^ri-[\w-]+$/', $icon)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// List of common valid RemixIcon names to avoid errors (without -line/-fill suffix)
|
||||
$commonIcons = [
|
||||
'ri-home', 'ri-user', 'ri-settings', 'ri-dashboard',
|
||||
'ri-menu', 'ri-link', 'ri-external-link', 'ri-folder',
|
||||
'ri-file', 'ri-edit', 'ri-delete-bin', 'ri-add',
|
||||
'ri-navigation', 'ri-admin', 'ri-function', 'ri-archive-stack',
|
||||
'ri-receipt', 'ri-customer-service', 'ri-settings-3', 'ri-megaphone',
|
||||
'ri-shopping-bag', 'ri-check', 'ri-close', 'ri-arrow-down-s'
|
||||
];
|
||||
|
||||
// Remove -line or -fill suffix if present to get base icon name
|
||||
$baseIcon = preg_replace('/-(?:line|fill)$/', '', $icon);
|
||||
|
||||
// If it's in our common list, it's definitely valid
|
||||
if (in_array($baseIcon, $commonIcons)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For other icons, just check the format (basic validation)
|
||||
// In a production environment, you might want to check if the SVG file actually exists
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$children = [];
|
||||
foreach ($link->children->where('is_active', true) as $child) {
|
||||
if ($this->shouldShowLink($child)) {
|
||||
$childFormatted = $this->formatLink($child);
|
||||
if ($childFormatted) {
|
||||
$children[] = $childFormatted;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($children)) {
|
||||
$formatted['children'] = $children;
|
||||
}
|
||||
}
|
||||
|
||||
return $formatted;
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('NavbarManager: Error formatting link', [
|
||||
'link_id' => $link->id ?? 'unknown',
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private function isValidIcon($icon)
|
||||
{
|
||||
// Basic validation for RemixIcon format
|
||||
|
||||
@@ -10,17 +10,44 @@ class ViewServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot()
|
||||
{
|
||||
// Register view namespace
|
||||
$this->loadViewsFrom(__DIR__ . '/../resources/views', 'navbar-manager');
|
||||
// Load migrations from the extension so they run when the extension is enabled
|
||||
// Always load migrations regardless of context
|
||||
$this->loadMigrationsFrom(__DIR__ . '/../Database/migrations');
|
||||
|
||||
// Register Blade components
|
||||
Blade::componentNamespace('Paymenter\\Extensions\\Others\\NavbarManager\\View\\Components', 'navbar-manager');
|
||||
// Only register views and components if not in admin context
|
||||
if (!$this->isAdminContext()) {
|
||||
// Register view namespace
|
||||
$this->loadViewsFrom(__DIR__ . '/../resources/views', 'navbar-manager');
|
||||
|
||||
// Register global Blade directive for easy navbar usage
|
||||
Blade::directive('navbarManagerLinks', function ($expression) {
|
||||
return "<?php echo \Paymenter\Extensions\Others\NavbarManager\Helpers\NavbarHelper::render($expression); ?>";
|
||||
});
|
||||
// Register Blade components
|
||||
Blade::componentNamespace('Paymenter\\Extensions\\Others\\NavbarManager\\View\\Components', 'navbar-manager');
|
||||
|
||||
// Register global Blade directive for easy navbar usage
|
||||
Blade::directive('navbarManagerLinks', function ($expression) {
|
||||
return "<?php echo \Paymenter\Extensions\Others\NavbarManager\Helpers\NavbarHelper::render($expression); ?>";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we're in admin context
|
||||
*/
|
||||
private function isAdminContext(): bool
|
||||
{
|
||||
if (app()->runningInConsole()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$currentPath = request()->path();
|
||||
|
||||
return str_starts_with($currentPath, 'admin') ||
|
||||
str_contains($currentPath, '/admin/') ||
|
||||
str_starts_with($currentPath, 'filament') ||
|
||||
request()->is('admin') ||
|
||||
request()->is('admin/*') ||
|
||||
request()->is('filament/*');
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Paymenter\Extensions\Others\NavbarManager\Models\NavbarLink;
|
||||
|
||||
Route::group(['prefix' => 'navbar'], function () {
|
||||
// Only register frontend routes, not in admin
|
||||
Route::group(['prefix' => 'navbar', 'middleware' => ['web']], function () {
|
||||
Route::get('/redirect/{linkId}', function($linkId) {
|
||||
try {
|
||||
$link = NavbarLink::findOrFail($linkId);
|
||||
@@ -19,6 +20,10 @@ Route::group(['prefix' => 'navbar'], function () {
|
||||
|
||||
abort(404);
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('NavbarManager: Redirect failed', [
|
||||
'link_id' => $linkId,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
abort(404);
|
||||
}
|
||||
})->name('navbar.redirect');
|
||||
|
||||
Reference in New Issue
Block a user