Summary
In a Filament v5 panel that uses topNavigation(), all three resources registered by MailsPlugin (MailResource, EventResource, SuppressionResource) share the same URL prefix (admin/mails/, admin/mails/events, admin/mails/suppressions). Combined with Filament's default getNavigationItemActiveRoutePattern(), the parent MailResource ends up matching its child resources' route names, so two navigation entries are shown as active simultaneously.
Repro
- Install
backstage/mails ^3.0 on a Filament v5 panel using ->topNavigation().
- Register the plugin:
->plugin(MailsPlugin::make()).
- Visit
/admin/mails/events (or /admin/mails/suppressions).
- Open the "Emails" navigation dropdown.
Both the parent Emails group's "Emails" item and the Events (or Suppressions) child item are rendered with the active/green styling.
Expected
Only the item corresponding to the current page should be highlighted.
Cause
Filament's default in Resource\Concerns\HasNavigation::getNavigationItemActiveRoutePattern():
public static function getNavigationItemActiveRoutePattern(): string | array
{
return static::getRouteBaseName() . '.*';
}
For MailResource this becomes filament.<panel>.resources.mails.* — which greedily matches filament.<panel>.resources.mails.events.index and filament.<panel>.resources.mails.suppressions.index. Both belong to sibling resources that happen to live under the same URL/base-name prefix.
Proposed fix
Override getNavigationItemActiveRoutePattern() on MailResource to enumerate only the route names that genuinely belong to that resource, so the wildcard doesn't bleed into siblings:
public static function getNavigationItemActiveRoutePattern(): string | array
{
return [
static::getRouteBaseName() . '.index',
static::getRouteBaseName() . '.create',
static::getRouteBaseName() . '.edit',
static::getRouteBaseName() . '.view',
];
}
(Adjust the list to whichever pages are actually defined in getPages().)
A symmetric override on EventResource / SuppressionResource is unnecessary because their base names already include the parent's prefix; only the parent is greedy.
Environment
backstage/mails: v3.0.14
filament/filament: v5.2.1
- Laravel: v12
- PHP: 8.4
Happy to send a PR if helpful.
Summary
In a Filament v5 panel that uses
topNavigation(), all three resources registered byMailsPlugin(MailResource,EventResource,SuppressionResource) share the same URL prefix (admin/mails/,admin/mails/events,admin/mails/suppressions). Combined with Filament's defaultgetNavigationItemActiveRoutePattern(), the parentMailResourceends up matching its child resources' route names, so two navigation entries are shown as active simultaneously.Repro
backstage/mails ^3.0on a Filament v5 panel using->topNavigation().->plugin(MailsPlugin::make())./admin/mails/events(or/admin/mails/suppressions).Both the parent Emails group's "Emails" item and the Events (or Suppressions) child item are rendered with the active/green styling.
Expected
Only the item corresponding to the current page should be highlighted.
Cause
Filament's default in
Resource\Concerns\HasNavigation::getNavigationItemActiveRoutePattern():For
MailResourcethis becomesfilament.<panel>.resources.mails.*— which greedily matchesfilament.<panel>.resources.mails.events.indexandfilament.<panel>.resources.mails.suppressions.index. Both belong to sibling resources that happen to live under the same URL/base-name prefix.Proposed fix
Override
getNavigationItemActiveRoutePattern()onMailResourceto enumerate only the route names that genuinely belong to that resource, so the wildcard doesn't bleed into siblings:(Adjust the list to whichever pages are actually defined in
getPages().)A symmetric override on
EventResource/SuppressionResourceis unnecessary because their base names already include the parent's prefix; only the parent is greedy.Environment
backstage/mails: v3.0.14filament/filament: v5.2.1Happy to send a PR if helpful.