Skip to content

Commit effa8e6

Browse files
committed
[devtools] panel ui issues tab content
1 parent b617792 commit effa8e6

File tree

5 files changed

+146
-4
lines changed

5 files changed

+146
-4
lines changed

packages/next/src/next-devtools/dev-overlay/components/devtools-panel/devtools-panel-tab/devtools-panel-tab.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { DevToolsPanelTabType } from '../devtools-panel'
2-
import type { Corners } from '../../../shared'
2+
import type { Corners, OverlayState } from '../../../shared'
33
import type { DebugInfo } from '../../../../shared/types'
44
import type { ReadyRuntimeError } from '../../../utils/get-error-by-type'
55
import type { HydrationErrorState } from '../../../../shared/hydration-error'
@@ -16,6 +16,7 @@ export function DevToolsPanelTab({
1616
debugInfo,
1717
runtimeErrors,
1818
getSquashedHydrationErrorDetails,
19+
buildError,
1920
}: {
2021
activeTab: DevToolsPanelTabType
2122
devToolsPosition: Corners
@@ -25,6 +26,7 @@ export function DevToolsPanelTab({
2526
debugInfo: DebugInfo
2627
runtimeErrors: ReadyRuntimeError[]
2728
getSquashedHydrationErrorDetails: (error: Error) => HydrationErrorState | null
29+
buildError: OverlayState['buildError']
2830
}) {
2931
switch (activeTab) {
3032
case 'settings':
@@ -44,6 +46,7 @@ export function DevToolsPanelTab({
4446
debugInfo={debugInfo}
4547
runtimeErrors={runtimeErrors}
4648
getSquashedHydrationErrorDetails={getSquashedHydrationErrorDetails}
49+
buildError={buildError}
4750
/>
4851
)
4952
default:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import type { ReadyRuntimeError } from '../../../../utils/get-error-by-type'
2+
import type { OverlayState } from '../../../../shared'
3+
4+
import { Suspense, useMemo, useState } from 'react'
5+
6+
import { Terminal } from '../../../terminal'
7+
import { HotlinkedText } from '../../../hot-linked-text'
8+
import { PseudoHtmlDiff } from '../../../../container/runtime-error/component-stack-pseudo-html'
9+
import { useFrames } from '../../../../utils/get-error-by-type'
10+
import { CodeFrame } from '../../../code-frame/code-frame'
11+
import { CallStack } from '../../../call-stack/call-stack'
12+
import { NEXTJS_HYDRATION_ERROR_LINK } from '../../../../../shared/react-19-hydration-error'
13+
import { css } from '../../../../utils/css'
14+
15+
export function IssuesTabContent({
16+
notes,
17+
buildError,
18+
hydrationWarning,
19+
errorDetails,
20+
activeError,
21+
}: {
22+
notes: string | null
23+
buildError: OverlayState['buildError']
24+
hydrationWarning: string | null
25+
errorDetails: {
26+
hydrationWarning: string | null
27+
notes: string | null
28+
reactOutputComponentDiff: string | null
29+
}
30+
activeError: ReadyRuntimeError
31+
}) {
32+
if (buildError) {
33+
return <Terminal content={buildError} />
34+
}
35+
36+
return (
37+
<>
38+
<div className="error-overlay-notes-container">
39+
{notes ? (
40+
<>
41+
<p
42+
id="nextjs__container_errors__notes"
43+
className="nextjs__container_errors__notes"
44+
>
45+
{notes}
46+
</p>
47+
</>
48+
) : null}
49+
{hydrationWarning ? (
50+
<p
51+
id="nextjs__container_errors__link"
52+
className="nextjs__container_errors__link"
53+
>
54+
<HotlinkedText
55+
text={`See more info here: ${NEXTJS_HYDRATION_ERROR_LINK}`}
56+
/>
57+
</p>
58+
) : null}
59+
</div>
60+
{errorDetails.reactOutputComponentDiff ? (
61+
<PseudoHtmlDiff
62+
reactOutputComponentDiff={errorDetails.reactOutputComponentDiff || ''}
63+
/>
64+
) : null}
65+
{/* TODO: Loading state */}
66+
<Suspense fallback={<div data-nextjs-error-suspended />}>
67+
<RuntimeError key={activeError.id.toString()} error={activeError} />
68+
</Suspense>
69+
</>
70+
)
71+
}
72+
73+
/* Ported the content from container/runtime-error/index.tsx */
74+
function RuntimeError({ error }: { error: ReadyRuntimeError }) {
75+
const [isIgnoreListOpen, setIsIgnoreListOpen] = useState(false)
76+
const frames = useFrames(error)
77+
78+
const ignoredFramesTally = useMemo(() => {
79+
return frames.reduce((tally, frame) => tally + (frame.ignored ? 1 : 0), 0)
80+
}, [frames])
81+
82+
const firstFrame = useMemo(() => {
83+
const firstFirstPartyFrameIndex = frames.findIndex(
84+
(entry) =>
85+
!entry.ignored &&
86+
Boolean(entry.originalCodeFrame) &&
87+
Boolean(entry.originalStackFrame)
88+
)
89+
90+
return frames[firstFirstPartyFrameIndex] ?? null
91+
}, [frames])
92+
93+
if (!firstFrame?.originalStackFrame || !firstFrame?.originalCodeFrame) {
94+
// TODO: Better handling
95+
return null
96+
}
97+
98+
return (
99+
<>
100+
{firstFrame && (
101+
<CodeFrame
102+
stackFrame={firstFrame.originalStackFrame}
103+
codeFrame={firstFrame.originalCodeFrame}
104+
/>
105+
)}
106+
107+
{frames.length > 0 && (
108+
<CallStack
109+
frames={frames}
110+
isIgnoreListOpen={isIgnoreListOpen}
111+
onToggleIgnoreList={() => setIsIgnoreListOpen(!isIgnoreListOpen)}
112+
ignoredFramesTally={ignoredFramesTally}
113+
/>
114+
)}
115+
</>
116+
)
117+
}
118+
119+
/* Shares the style with container/errors.tsx and errors/dialog/header.tsx */
120+
export const DEVTOOLS_PANEL_TAB_ISSUES_CONTENT_STYLES = css`
121+
[data-nextjs-devtools-panel-tab-issues-content] {
122+
width: 100%;
123+
padding: 14px;
124+
}
125+
`

packages/next/src/next-devtools/dev-overlay/components/devtools-panel/devtools-panel-tab/issues-tab/issues-tab.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import type { OverlayState } from '../../../../shared'
12
import type { DebugInfo } from '../../../../../shared/types'
23
import type { ReadyRuntimeError } from '../../../../utils/get-error-by-type'
34
import type { HydrationErrorState } from '../../../../../shared/hydration-error'
45

56
import { IssuesTabSidebar } from './issues-tab-sidebar'
7+
import { IssuesTabContent } from './issues-tab-content'
68
import {
79
GenericErrorDescription,
810
HydrationErrorDescription,
@@ -18,10 +20,12 @@ export function IssuesTab({
1820
debugInfo,
1921
runtimeErrors,
2022
getSquashedHydrationErrorDetails,
23+
buildError,
2124
}: {
2225
debugInfo: DebugInfo
2326
runtimeErrors: ReadyRuntimeError[]
2427
getSquashedHydrationErrorDetails: (error: Error) => HydrationErrorState | null
28+
buildError: OverlayState['buildError']
2529
}) {
2630
const {
2731
isLoading,
@@ -31,6 +35,8 @@ export function IssuesTab({
3135
activeError,
3236
activeIdx,
3337
setActiveIndex,
38+
notes,
39+
errorDetails,
3440
} = useActiveRuntimeError({ runtimeErrors, getSquashedHydrationErrorDetails })
3541

3642
if (isLoading) {
@@ -78,9 +84,13 @@ export function IssuesTab({
7884
</div>
7985
<ErrorMessage errorMessage={errorMessage} />
8086
</div>
81-
82-
{/* TODO: Content */}
83-
<div>Content</div>
87+
<IssuesTabContent
88+
buildError={buildError}
89+
notes={notes}
90+
hydrationWarning={hydrationWarning}
91+
errorDetails={errorDetails}
92+
activeError={activeError}
93+
/>
8494
</div>
8595
</div>
8696
)

packages/next/src/next-devtools/dev-overlay/components/devtools-panel/devtools-panel.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ export function DevToolsPanel({
155155
getSquashedHydrationErrorDetails={
156156
getSquashedHydrationErrorDetails
157157
}
158+
buildError={state.buildError}
158159
/>
159160
</DialogBody>
160161
</DialogContent>

packages/next/src/next-devtools/dev-overlay/styles/component-styles.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { CALL_STACK_STYLES } from '../components/call-stack/call-stack'
3232
import { DEVTOOLS_PANEL_TAB_ISSUES_STYLES } from '../components/devtools-panel/devtools-panel-tab/issues-tab/issues-tab'
3333
import { DEVTOOLS_PANEL_TAB_ISSUES_SIDEBAR_STYLES } from '../components/devtools-panel/devtools-panel-tab/issues-tab/issues-tab-sidebar'
3434
import { DEVTOOLS_PANEL_TAB_ISSUES_SIDEBAR_FRAME_SKELETON_STYLES } from '../components/devtools-panel/devtools-panel-tab/issues-tab/issues-tab-sidebar-frame-skeleton'
35+
import { DEVTOOLS_PANEL_TAB_ISSUES_CONTENT_STYLES } from '../components/devtools-panel/devtools-panel-tab/issues-tab/issues-tab-content'
3536

3637
export function ComponentStyles() {
3738
return (
@@ -70,6 +71,8 @@ export function ComponentStyles() {
7071
${DEVTOOLS_PANEL_TAB_ISSUES_STYLES}
7172
${DEVTOOLS_PANEL_TAB_ISSUES_SIDEBAR_STYLES}
7273
${DEVTOOLS_PANEL_TAB_ISSUES_SIDEBAR_FRAME_SKELETON_STYLES}
74+
${DEVTOOLS_PANEL_TAB_ISSUES_SIDEBAR_FRAME_SKELETON_STYLES}
75+
${DEVTOOLS_PANEL_TAB_ISSUES_CONTENT_STYLES}
7376
`}
7477
</style>
7578
)

0 commit comments

Comments
 (0)