Skip to content

Commit a7b36c7

Browse files
committed
[segment explorer] capture defined boundaries
1 parent 81f0c76 commit a7b36c7

File tree

5 files changed

+114
-9
lines changed

5 files changed

+114
-9
lines changed

packages/next/src/client/components/layout-router.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,16 @@ export default function OuterLayoutRouter({
665665
.SegmentStateProvider as typeof import('../../next-devtools/userspace/app/segment-explorer-node').SegmentStateProvider as typeof import('../../next-devtools/userspace/app/segment-explorer-node').SegmentStateProvider
666666

667667
child = (
668-
<SegmentStateProvider key={stateKey}>{child}</SegmentStateProvider>
668+
<SegmentStateProvider
669+
key={stateKey}
670+
boundaries={{
671+
notFound: !!notFound,
672+
loading: !!loadingModuleData,
673+
error: !!error,
674+
}}
675+
>
676+
{child}
677+
</SegmentStateProvider>
669678
)
670679
}
671680

packages/next/src/next-devtools/dev-overlay/components/overview/segment-boundary-trigger.tsx

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import { Menu } from '@base-ui-components/react/menu'
33
import type { SegmentNodeState } from '../../../userspace/app/segment-explorer-node'
44

55
export function SegmentBoundaryTrigger({
6+
boundaries,
67
onSelectBoundary,
78
offset,
89
}: {
10+
boundaries: SegmentNodeState['boundaries']
911
onSelectBoundary: SegmentNodeState['setBoundaryType']
1012
offset: number
1113
}) {
@@ -16,10 +18,26 @@ export function SegmentBoundaryTrigger({
1618
})
1719
const shadowRootRef = useRef<ShadowRoot>(shadowRoot)
1820

21+
console.log('boundaries', boundaries)
1922
const triggerOptions = [
20-
{ label: 'Trigger Loading', value: 'loading', icon: <LoadingIcon /> },
21-
{ label: 'Trigger Error', value: 'error', icon: <ErrorIcon /> },
22-
{ label: 'Trigger Not Found', value: 'not-found', icon: <NotFoundIcon /> },
23+
{
24+
label: 'Loading',
25+
value: 'loading',
26+
icon: <LoadingIcon />,
27+
disabled: !boundaries.loading,
28+
},
29+
{
30+
label: 'Error',
31+
value: 'error',
32+
icon: <ErrorIcon />,
33+
disabled: !boundaries.error,
34+
},
35+
{
36+
label: 'Not Found',
37+
value: 'not-found',
38+
icon: <NotFoundIcon />,
39+
disabled: !boundaries.notFound,
40+
},
2341
]
2442

2543
const resetOption = {
@@ -74,6 +92,7 @@ export function SegmentBoundaryTrigger({
7492
key={option.value}
7593
className="segment-boundary-dropdown-item"
7694
onClick={() => handleSelect(option.value)}
95+
disabled={option.disabled}
7796
>
7897
{option.icon}
7998
{option.label}
@@ -86,6 +105,14 @@ export function SegmentBoundaryTrigger({
86105
key={resetOption.value}
87106
className="segment-boundary-dropdown-item"
88107
onClick={() => handleSelect(resetOption.value)}
108+
// disable reset if there is no boundary
109+
disabled={
110+
!(
111+
boundaries.loading ||
112+
boundaries.error ||
113+
boundaries.notFound
114+
)
115+
}
89116
>
90117
{resetOption.icon}
91118
{resetOption.label}
@@ -274,9 +301,14 @@ export const styles = `
274301
width: 100%;
275302
}
276303
304+
.segment-boundary-dropdown-item[data-disabled] {
305+
color: var(--color-gray-400);
306+
cursor: not-allowed;
307+
}
308+
277309
.segment-boundary-dropdown-item svg {
278310
margin-right: 12px;
279-
color: var(--color-gray-900);
311+
color: currentColor;
280312
}
281313
282314
.segment-boundary-dropdown-item:hover {

packages/next/src/next-devtools/dev-overlay/components/overview/segment-explorer.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ function PageSegmentTreeLayerPresentation({
208208
<SegmentBoundaryTrigger
209209
offset={6}
210210
onSelectBoundary={pageChild.value.setBoundaryType}
211+
boundaries={pageChild.value.boundaries}
211212
/>
212213
)}
213214
</div>

packages/next/src/next-devtools/dev-overlay/segment-explorer-trie.test.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const createSegmentNode = ({
1919
type,
2020
pagePath,
2121
boundaryType: null,
22+
boundaries: { notFound: false, loading: false, error: false },
2223
setBoundaryType: placeholder,
2324
}
2425
}
@@ -73,6 +74,11 @@ describe('Segment Explorer', () => {
7374
pagePath: '/a/layout.js',
7475
type: 'layout',
7576
boundaryType: null,
77+
boundaries: {
78+
notFound: false,
79+
loading: false,
80+
error: false,
81+
},
7682
setBoundaryType: expect.anything(),
7783
},
7884
},
@@ -82,6 +88,11 @@ describe('Segment Explorer', () => {
8288
pagePath: '/a/page.js',
8389
type: 'page',
8490
boundaryType: null,
91+
boundaries: {
92+
notFound: false,
93+
loading: false,
94+
error: false,
95+
},
8596
setBoundaryType: expect.anything(),
8697
},
8798
},
@@ -94,6 +105,7 @@ describe('Segment Explorer', () => {
94105
pagePath: '/layout.js',
95106
type: 'layout',
96107
boundaryType: null,
108+
boundaries: { notFound: false, loading: false, error: false },
97109
setBoundaryType: expect.anything(),
98110
},
99111
},
@@ -140,6 +152,11 @@ describe('Segment Explorer', () => {
140152
pagePath: '/a/b/@sidebar/page.js',
141153
type: 'page',
142154
boundaryType: null,
155+
boundaries: {
156+
notFound: false,
157+
loading: false,
158+
error: false,
159+
},
143160
setBoundaryType: expect.anything(),
144161
},
145162
},
@@ -152,6 +169,11 @@ describe('Segment Explorer', () => {
152169
pagePath: '/a/b/layout.js',
153170
type: 'layout',
154171
boundaryType: null,
172+
boundaries: {
173+
notFound: false,
174+
loading: false,
175+
error: false,
176+
},
155177
setBoundaryType: expect.anything(),
156178
},
157179
},
@@ -161,6 +183,11 @@ describe('Segment Explorer', () => {
161183
pagePath: '/a/b/page.js',
162184
type: 'page',
163185
boundaryType: null,
186+
boundaries: {
187+
notFound: false,
188+
loading: false,
189+
error: false,
190+
},
164191
setBoundaryType: expect.anything(),
165192
},
166193
},
@@ -173,6 +200,11 @@ describe('Segment Explorer', () => {
173200
pagePath: '/a/layout.js',
174201
type: 'layout',
175202
boundaryType: null,
203+
boundaries: {
204+
notFound: false,
205+
loading: false,
206+
error: false,
207+
},
176208
setBoundaryType: expect.anything(),
177209
},
178210
},
@@ -185,6 +217,7 @@ describe('Segment Explorer', () => {
185217
pagePath: '/layout.js',
186218
type: 'layout',
187219
boundaryType: null,
220+
boundaries: { notFound: false, loading: false, error: false },
188221
setBoundaryType: expect.anything(),
189222
},
190223
},
@@ -215,6 +248,11 @@ describe('Segment Explorer', () => {
215248
pagePath: '/a/b/@sidebar/page.js',
216249
type: 'page',
217250
boundaryType: null,
251+
boundaries: {
252+
notFound: false,
253+
loading: false,
254+
error: false,
255+
},
218256
setBoundaryType: expect.anything(),
219257
},
220258
},
@@ -227,6 +265,11 @@ describe('Segment Explorer', () => {
227265
pagePath: '/a/b/page.js',
228266
type: 'page',
229267
boundaryType: null,
268+
boundaries: {
269+
notFound: false,
270+
loading: false,
271+
error: false,
272+
},
230273
setBoundaryType: expect.anything(),
231274
},
232275
},
@@ -239,6 +282,11 @@ describe('Segment Explorer', () => {
239282
pagePath: '/a/layout.js',
240283
type: 'layout',
241284
boundaryType: null,
285+
boundaries: {
286+
notFound: false,
287+
loading: false,
288+
error: false,
289+
},
242290
setBoundaryType: expect.anything(),
243291
},
244292
},
@@ -251,6 +299,7 @@ describe('Segment Explorer', () => {
251299
pagePath: '/layout.js',
252300
type: 'layout',
253301
boundaryType: null,
302+
boundaries: { notFound: false, loading: false, error: false },
254303
setBoundaryType: expect.anything(),
255304
},
256305
},

packages/next/src/next-devtools/userspace/app/segment-explorer-node.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const SEGMENT_EXPLORER_SIMULATED_ERROR_MESSAGE =
1919
export type SegmentNodeState = {
2020
type: string
2121
pagePath: string
22+
boundaries: { notFound: boolean; loading: boolean; error: boolean }
2223
boundaryType: string | null
2324
setBoundaryType: (type: 'error' | 'not-found' | 'loading' | null) => void
2425
}
@@ -30,15 +31,16 @@ function SegmentTrieNode({
3031
type: string
3132
pagePath: string
3233
}): React.ReactNode {
33-
const { boundaryType, setBoundaryType } = useSegmentState()
34+
const { boundaryType, setBoundaryType, boundaries } = useSegmentState()
3435
const nodeState: SegmentNodeState = useMemo(
3536
() => ({
3637
type,
3738
pagePath,
39+
boundaries,
3840
boundaryType,
3941
setBoundaryType,
4042
}),
41-
[type, pagePath, boundaryType, setBoundaryType]
43+
[type, pagePath, boundaryType, setBoundaryType, boundaries]
4244
)
4345

4446
// Use `useLayoutEffect` to ensure the state is updated during suspense.
@@ -112,14 +114,22 @@ export function SegmentViewNode({
112114
}
113115

114116
const SegmentStateContext = createContext<{
117+
boundaries: { notFound: boolean; loading: boolean; error: boolean }
115118
boundaryType: 'not-found' | 'error' | 'loading' | null
116119
setBoundaryType: (type: 'not-found' | 'error' | 'loading' | null) => void
117120
}>({
121+
boundaries: { notFound: false, loading: false, error: false },
118122
boundaryType: null,
119123
setBoundaryType: () => {},
120124
})
121125

122-
export function SegmentStateProvider({ children }: { children: ReactNode }) {
126+
export function SegmentStateProvider({
127+
children,
128+
boundaries,
129+
}: {
130+
children: ReactNode
131+
boundaries: { notFound: boolean; loading: boolean; error: boolean }
132+
}) {
123133
const [boundaryType, setBoundaryType] = useState<
124134
'not-found' | 'error' | 'loading' | null
125135
>(null)
@@ -143,7 +153,11 @@ export function SegmentStateProvider({ children }: { children: ReactNode }) {
143153
return (
144154
<SegmentStateContext.Provider
145155
key={errorBoundaryKey}
146-
value={{ boundaryType, setBoundaryType: setBoundaryTypeAndReload }}
156+
value={{
157+
boundaryType,
158+
setBoundaryType: setBoundaryTypeAndReload,
159+
boundaries,
160+
}}
147161
>
148162
{children}
149163
</SegmentStateContext.Provider>

0 commit comments

Comments
 (0)