diff --git a/packages/next/src/next-devtools/dev-overlay/components/overview/segment-explorer.tsx b/packages/next/src/next-devtools/dev-overlay/components/overview/segment-explorer.tsx
index 01c803cde24a..ada99aa0bd7b 100644
--- a/packages/next/src/next-devtools/dev-overlay/components/overview/segment-explorer.tsx
+++ b/packages/next/src/next-devtools/dev-overlay/components/overview/segment-explorer.tsx
@@ -80,6 +80,8 @@ function PageSegmentTreeLayerPresentation({
{folderName && (
{folderName}
+ {/* hidden slashes for testing snapshots */}
+ {'/'}
)}
@@ -151,6 +153,9 @@ export const DEV_TOOLS_INFO_RENDER_FILES_STYLES = css`
.segment-explorer-filename--path {
margin-right: 8px;
}
+ .segment-explorer-filename--path small {
+ width: 0;
+ }
.segment-explorer-filename--name {
color: var(--color-gray-800);
}
diff --git a/packages/next/src/next-devtools/dev-overlay/segment-explorer.test.tsx b/packages/next/src/next-devtools/dev-overlay/segment-explorer.test.tsx
index 752e501ce37f..0d19bff0f55d 100644
--- a/packages/next/src/next-devtools/dev-overlay/segment-explorer.test.tsx
+++ b/packages/next/src/next-devtools/dev-overlay/segment-explorer.test.tsx
@@ -75,7 +75,7 @@ describe('Segment Explorer', () => {
})
})
- test.failing('remove node in the middle', () => {
+ test('remove node in the middle', () => {
insertSegmentNode({ pagePath: '/a/b/@sidebar/page.js', type: 'page' })
insertSegmentNode({ pagePath: '/a/b/page.js', type: 'page' })
insertSegmentNode({ pagePath: '/a/b/layout.js', type: 'layout' })
diff --git a/packages/next/src/next-devtools/dev-overlay/segment-explorer.ts b/packages/next/src/next-devtools/dev-overlay/segment-explorer.ts
index 826149b923c8..a78866eee646 100644
--- a/packages/next/src/next-devtools/dev-overlay/segment-explorer.ts
+++ b/packages/next/src/next-devtools/dev-overlay/segment-explorer.ts
@@ -55,9 +55,11 @@ const createSegmentTreeStore = (): {
const { subscribe, getSnapshot, getServerSnapshot } = createSegmentTreeStore()
function createTrie({
- getKey = (k) => k as unknown as string,
+ getCharacters = (item: Value) => [item] as string[],
+ compare = (a: Value | undefined, b: Value | undefined) => a === b,
}: {
- getKey: (k: Value) => string
+ getCharacters?: (item: Value) => string[]
+ compare?: (a: Value | undefined, b: Value | undefined) => boolean
}): Trie {
const root: TrieNode = {
value: undefined,
@@ -72,8 +74,7 @@ function createTrie({
function insert(value: Value) {
let currentNode = root
- const key = getKey(value)
- const segments = key.split('/')
+ const segments = getCharacters(value)
for (const segment of segments) {
if (!currentNode.children[segment]) {
@@ -91,8 +92,31 @@ function createTrie({
markUpdated()
}
- function remove(_: Value) {
- // TODO Implement remove functionality
+ function remove(value: Value) {
+ let currentNode = root
+ const segments = getCharacters(value)
+ const stack: TrieNode[] = []
+ let found = true
+ for (const segment of segments) {
+ if (!currentNode.children[segment]) {
+ found = false
+ break
+ }
+ stack.push(currentNode)
+ currentNode = currentNode.children[segment]!
+ }
+ // If the value is not found, skip removal
+ if (!found || !compare(currentNode.value, value)) {
+ return
+ }
+ currentNode.value = undefined
+ for (let i = stack.length - 1; i >= 0; i--) {
+ const parentNode = stack[i]
+ const segment = segments[i]
+ if (Object.keys(parentNode.children[segment]!.children).length === 0) {
+ delete parentNode.children[segment]
+ }
+ }
markUpdated()
}
@@ -113,7 +137,11 @@ export type SegmentTrie = Trie
export type SegmentTrieNode = TrieNode
const trie: SegmentTrie = createTrie({
- getKey: (item) => item.pagePath,
+ compare: (a, b) => {
+ if (!a || !b) return false
+ return a.pagePath === b.pagePath && a.type === b.type
+ },
+ getCharacters: (item) => item.pagePath.split('/'),
})
export const insertSegmentNode = trie.insert
export const removeSegmentNode = trie.remove
diff --git a/test/development/app-dir/segment-explorer/segment-explorer.test.ts b/test/development/app-dir/segment-explorer/segment-explorer.test.ts
index 81b29df78768..83e5180ada9a 100644
--- a/test/development/app-dir/segment-explorer/segment-explorer.test.ts
+++ b/test/development/app-dir/segment-explorer/segment-explorer.test.ts
@@ -26,32 +26,32 @@ describe('segment-explorer', () => {
it('should render the segment explorer for parallel routes', async () => {
const browser = await next.browser('/parallel-routes')
expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
- "applayout.tsx
- parallel-routeslayout.tsx
- parallel-routespage.tsx
- @barlayout.tsx
- @barpage.tsx
- @foolayout.tsx
- @foopage.tsx"
+ "app/layout.tsx
+ parallel-routes/layout.tsx
+ parallel-routes/page.tsx
+ @bar/layout.tsx
+ @bar/page.tsx
+ @foo/layout.tsx
+ @foo/page.tsx"
`)
})
it('should render the segment explorer for nested routes', async () => {
const browser = await next.browser('/blog/~/grid')
expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
- "applayout.tsx
- (v2)layout.tsx
- (team)layout.tsx
- (overview)layout.tsx
- gridpage.tsx"
+ "app/layout.tsx
+ (v2)/layout.tsx
+ (team)/layout.tsx
+ (overview)/layout.tsx
+ grid/page.tsx"
`)
})
it('should cleanup on soft navigation', async () => {
const browser = await next.browser('/soft-navigation/a')
expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
- "applayout.tsx
- apage.tsx"
+ "app/layout.tsx
+ a/page.tsx"
`)
await browser.elementByCss('[href="/soft-navigation/b"]').click()
@@ -59,11 +59,9 @@ describe('segment-explorer', () => {
expect(await browser.elementByCss('body').text()).toContain('Page B')
})
- // FIXME: Should no longer contain /soft-navigation/a/page.js
expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
- "applayout.tsx
- apage.tsx
- bpage.tsx"
+ "app/layout.tsx
+ b/page.tsx"
`)
})
})