fix(next): incorrect active state for partial matches of collection names in sidebar (#11511)
Previously, collections with similar names (e.g., `uploads` and `uploads-poly`) both appeared active when viewing either collection. This was due to `pathname.startsWith(href)`, which caused partial matches. This update refines the `isActive` logic to prevent partial matches.
This commit is contained in:
@@ -44,7 +44,8 @@ export const DefaultNavClient: React.FC<{
|
||||
id = `nav-global-${slug}`
|
||||
}
|
||||
|
||||
const isActive = pathname.startsWith(href)
|
||||
const isActive =
|
||||
pathname.startsWith(href) && ['/', undefined].includes(pathname[href.length])
|
||||
|
||||
const Label = (
|
||||
<>
|
||||
|
||||
14
test/admin/collections/UploadTwo.ts
Normal file
14
test/admin/collections/UploadTwo.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { uploadTwoCollectionSlug } from '../slugs.js'
|
||||
|
||||
export const UploadTwoCollection: CollectionConfig = {
|
||||
slug: uploadTwoCollectionSlug,
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
upload: true,
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import { CollectionNoApiView } from './collections/NoApiView.js'
|
||||
import { CollectionNotInView } from './collections/NotInView.js'
|
||||
import { Posts } from './collections/Posts.js'
|
||||
import { UploadCollection } from './collections/Upload.js'
|
||||
import { UploadTwoCollection } from './collections/UploadTwo.js'
|
||||
import { Users } from './collections/Users.js'
|
||||
import { with300Documents } from './collections/With300Documents.js'
|
||||
import { CustomGlobalViews1 } from './globals/CustomViews1.js'
|
||||
@@ -40,6 +41,7 @@ import {
|
||||
protectedCustomNestedViewPath,
|
||||
publicCustomViewPath,
|
||||
} from './shared.js'
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
admin: {
|
||||
importMap: {
|
||||
@@ -141,6 +143,7 @@ export default buildConfigWithDefaults({
|
||||
},
|
||||
collections: [
|
||||
UploadCollection,
|
||||
UploadTwoCollection,
|
||||
Posts,
|
||||
Users,
|
||||
CollectionHidden,
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
notInViewCollectionSlug,
|
||||
postsCollectionSlug,
|
||||
settingsGlobalSlug,
|
||||
uploadTwoCollectionSlug,
|
||||
} from '../../slugs.js'
|
||||
|
||||
const { beforeAll, beforeEach, describe } = test
|
||||
@@ -73,6 +74,7 @@ describe('General', () => {
|
||||
let disableDuplicateURL: AdminUrlUtil
|
||||
let serverURL: string
|
||||
let adminRoutes: ReturnType<typeof getRoutes>
|
||||
let uploadsTwo: AdminUrlUtil
|
||||
|
||||
beforeAll(async ({ browser }, testInfo) => {
|
||||
const prebuild = false // Boolean(process.env.CI)
|
||||
@@ -90,6 +92,7 @@ describe('General', () => {
|
||||
globalURL = new AdminUrlUtil(serverURL, globalSlug)
|
||||
customViewsURL = new AdminUrlUtil(serverURL, customViews2CollectionSlug)
|
||||
disableDuplicateURL = new AdminUrlUtil(serverURL, disableDuplicateSlug)
|
||||
uploadsTwo = new AdminUrlUtil(serverURL, uploadTwoCollectionSlug)
|
||||
|
||||
context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
@@ -424,6 +427,27 @@ describe('General', () => {
|
||||
expect(tagName).toBe('a')
|
||||
})
|
||||
|
||||
test('should only have one nav item active at a time', async () => {
|
||||
await page.goto(uploadsTwo.list)
|
||||
await openNav(page)
|
||||
|
||||
// Locate "uploads" and "uploads-two" nav items
|
||||
const uploadsNavItem = page.locator('.nav-group__content #nav-uploads')
|
||||
const uploadsTwoNavItem = page.locator('.nav-group__content #nav-uploads-two')
|
||||
|
||||
// Ensure both exist before continuing
|
||||
await expect(uploadsNavItem).toBeVisible()
|
||||
await expect(uploadsTwoNavItem).toBeVisible()
|
||||
|
||||
// Locate all nav items containing the nav__link-indicator
|
||||
const activeNavItems = page.locator(
|
||||
'.nav-group__content .nav__link:has(.nav__link-indicator), .nav-group__content div.nav__link:has(.nav__link-indicator)',
|
||||
)
|
||||
|
||||
// Expect exactly one nav item to have the indicator
|
||||
await expect(activeNavItems).toHaveCount(1)
|
||||
})
|
||||
|
||||
test('breadcrumbs — should navigate from list to dashboard', async () => {
|
||||
await page.goto(postsUrl.list)
|
||||
await page.locator(`.step-nav a[href="${adminRoutes.routes.admin}"]`).click()
|
||||
|
||||
@@ -66,6 +66,7 @@ export interface Config {
|
||||
};
|
||||
collections: {
|
||||
uploads: Upload;
|
||||
'uploads-two': UploadsTwo;
|
||||
posts: Post;
|
||||
users: User;
|
||||
'hidden-collection': HiddenCollection;
|
||||
@@ -90,6 +91,7 @@ export interface Config {
|
||||
collectionsJoins: {};
|
||||
collectionsSelect: {
|
||||
uploads: UploadsSelect<false> | UploadsSelect<true>;
|
||||
'uploads-two': UploadsTwoSelect<false> | UploadsTwoSelect<true>;
|
||||
posts: PostsSelect<false> | PostsSelect<true>;
|
||||
users: UsersSelect<false> | UsersSelect<true>;
|
||||
'hidden-collection': HiddenCollectionSelect<false> | HiddenCollectionSelect<true>;
|
||||
@@ -192,6 +194,25 @@ export interface Upload {
|
||||
};
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "uploads-two".
|
||||
*/
|
||||
export interface UploadsTwo {
|
||||
id: string;
|
||||
title?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string | null;
|
||||
thumbnailURL?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
focalX?: number | null;
|
||||
focalY?: number | null;
|
||||
}
|
||||
/**
|
||||
* This is a custom collection description.
|
||||
*
|
||||
@@ -469,6 +490,10 @@ export interface PayloadLockedDocument {
|
||||
relationTo: 'uploads';
|
||||
value: string | Upload;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'uploads-two';
|
||||
value: string | UploadsTwo;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'posts';
|
||||
value: string | Post;
|
||||
@@ -611,6 +636,24 @@ export interface UploadsSelect<T extends boolean = true> {
|
||||
};
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "uploads-two_select".
|
||||
*/
|
||||
export interface UploadsTwoSelect<T extends boolean = true> {
|
||||
title?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
url?: T;
|
||||
thumbnailURL?: T;
|
||||
filename?: T;
|
||||
mimeType?: T;
|
||||
filesize?: T;
|
||||
width?: T;
|
||||
height?: T;
|
||||
focalX?: T;
|
||||
focalY?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "posts_select".
|
||||
|
||||
@@ -12,6 +12,8 @@ export const notInViewCollectionSlug = 'not-in-view-collection'
|
||||
export const noApiViewCollectionSlug = 'collection-no-api-view'
|
||||
export const disableDuplicateSlug = 'disable-duplicate'
|
||||
export const uploadCollectionSlug = 'uploads'
|
||||
|
||||
export const uploadTwoCollectionSlug = 'uploads-two'
|
||||
export const customFieldsSlug = 'custom-fields'
|
||||
|
||||
export const listDrawerSlug = 'with-list-drawer'
|
||||
|
||||
Reference in New Issue
Block a user