Skip to content

Commit a932972

Browse files
committed
[devtools] panel ui issues tab sidebar
1 parent 5b2f9e6 commit a932972

File tree

3 files changed

+170
-4
lines changed

3 files changed

+170
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import type { ReadyRuntimeError } from '../../../../utils/get-error-by-type'
2+
3+
import { Suspense, useMemo } from 'react'
4+
5+
import { css } from '../../../../utils/css'
6+
import { getFrameSource } from '../../../../../shared/stack-frame'
7+
import { useFrames } from '../../../../utils/get-error-by-type'
8+
import { getErrorTypeLabel } from '../../../../container/errors'
9+
10+
export function IssuesTabSidebar({
11+
runtimeErrors,
12+
activeIdx,
13+
setActiveIndex,
14+
}: {
15+
runtimeErrors: ReadyRuntimeError[]
16+
errorType: string | null
17+
activeIdx: number
18+
setActiveIndex: (idx: number) => void
19+
}) {
20+
return (
21+
<aside data-nextjs-devtools-panel-tab-issues-sidebar>
22+
{runtimeErrors.map((runtimeError, idx) => {
23+
// TODO: Loading state
24+
return (
25+
<Suspense fallback={<div>Loading...</div>}>
26+
<IssuesTabSidebarFrame
27+
key={idx}
28+
runtimeError={runtimeError}
29+
idx={idx}
30+
activeIdx={activeIdx}
31+
setActiveIndex={setActiveIndex}
32+
/>
33+
</Suspense>
34+
)
35+
})}
36+
</aside>
37+
)
38+
}
39+
40+
function IssuesTabSidebarFrame({
41+
runtimeError,
42+
idx,
43+
activeIdx,
44+
setActiveIndex,
45+
}: {
46+
runtimeError: ReadyRuntimeError
47+
idx: number
48+
activeIdx: number
49+
setActiveIndex: (idx: number) => void
50+
}) {
51+
const frames = useFrames(runtimeError)
52+
53+
const firstFrame = useMemo(() => {
54+
const firstFirstPartyFrameIndex = frames.findIndex(
55+
(entry) =>
56+
!entry.ignored &&
57+
Boolean(entry.originalCodeFrame) &&
58+
Boolean(entry.originalStackFrame)
59+
)
60+
61+
return frames[firstFirstPartyFrameIndex] ?? null
62+
}, [frames])
63+
64+
if (!firstFrame?.originalStackFrame) {
65+
// TODO: Better handling
66+
return <div>No frame</div>
67+
}
68+
69+
const frameSource = getFrameSource(firstFrame.originalStackFrame)
70+
const errorType = getErrorTypeLabel(runtimeError.error, runtimeError.type)
71+
72+
return (
73+
<button
74+
data-nextjs-devtools-panel-tab-issues-sidebar-frame
75+
data-nextjs-devtools-panel-tab-issues-sidebar-frame-active={
76+
idx === activeIdx
77+
}
78+
onClick={() => setActiveIndex(idx)}
79+
>
80+
<span data-nextjs-devtools-panel-tab-issues-sidebar-frame-error-type>
81+
{errorType}
82+
</span>
83+
<span data-nextjs-devtools-panel-tab-issues-sidebar-frame-source>
84+
{frameSource}
85+
</span>
86+
</button>
87+
)
88+
}
89+
90+
export const DEVTOOLS_PANEL_TAB_ISSUES_SIDEBAR_STYLES = css`
91+
[data-nextjs-devtools-panel-tab-issues-sidebar] {
92+
display: flex;
93+
flex-direction: column;
94+
gap: 4px;
95+
padding: 8px;
96+
border-right: 1px solid var(--color-gray-400);
97+
98+
min-width: 128px;
99+
100+
@media (min-width: 576px) {
101+
max-width: 138px;
102+
width: 100%;
103+
}
104+
105+
@media (min-width: 768px) {
106+
max-width: 172.5px;
107+
width: 100%;
108+
}
109+
110+
@media (min-width: 992px) {
111+
max-width: 230px;
112+
width: 100%;
113+
}
114+
}
115+
116+
[data-nextjs-devtools-panel-tab-issues-sidebar-frame] {
117+
display: flex;
118+
flex-direction: column;
119+
padding: 10px 8px;
120+
border-radius: var(--rounded-lg);
121+
transition: background-color 0.2s ease-in-out;
122+
123+
&:hover {
124+
background-color: var(--color-gray-200);
125+
}
126+
127+
&:active {
128+
background-color: var(--color-gray-300);
129+
}
130+
}
131+
132+
[data-nextjs-devtools-panel-tab-issues-sidebar-frame-active='true'] {
133+
background-color: var(--color-gray-100);
134+
}
135+
136+
[data-nextjs-devtools-panel-tab-issues-sidebar-frame-error-type] {
137+
display: inline-block;
138+
align-self: flex-start;
139+
color: var(--color-gray-1000);
140+
font-size: var(--size-14);
141+
font-weight: 500;
142+
line-height: var(--size-20);
143+
}
144+
145+
[data-nextjs-devtools-panel-tab-issues-sidebar-frame-source] {
146+
display: inline-block;
147+
align-self: flex-start;
148+
color: var(--color-gray-900);
149+
font-size: var(--size-13);
150+
line-height: var(--size-18);
151+
}
152+
`

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { DebugInfo } from '../../../../../shared/types'
22
import type { ReadyRuntimeError } from '../../../../utils/get-error-by-type'
33
import type { HydrationErrorState } from '../../../../../shared/hydration-error'
44

5+
import { IssuesTabSidebar } from './issues-tab-sidebar'
56
import {
67
GenericErrorDescription,
78
HydrationErrorDescription,
@@ -22,8 +23,15 @@ export function IssuesTab({
2223
runtimeErrors: ReadyRuntimeError[]
2324
getSquashedHydrationErrorDetails: (error: Error) => HydrationErrorState | null
2425
}) {
25-
const { isLoading, errorCode, errorType, hydrationWarning, activeError } =
26-
useActiveRuntimeError({ runtimeErrors, getSquashedHydrationErrorDetails })
26+
const {
27+
isLoading,
28+
errorCode,
29+
errorType,
30+
hydrationWarning,
31+
activeError,
32+
activeIdx,
33+
setActiveIndex,
34+
} = useActiveRuntimeError({ runtimeErrors, getSquashedHydrationErrorDetails })
2735

2836
if (isLoading) {
2937
// TODO: better loading state
@@ -42,8 +50,12 @@ export function IssuesTab({
4250

4351
return (
4452
<div data-nextjs-devtools-panel-tab-issues>
45-
{/* TODO: Sidebar */}
46-
<aside>Sidebar</aside>
53+
<IssuesTabSidebar
54+
runtimeErrors={runtimeErrors}
55+
errorType={errorType}
56+
activeIdx={activeIdx}
57+
setActiveIndex={setActiveIndex}
58+
/>
4759
<div data-nextjs-devtools-panel-tab-issues-content>
4860
<div className="nextjs-container-errors-header">
4961
<div

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { DEVTOOLS_PANEL_VERSION_INFO_STYLES } from '../components/devtools-panel
3030
import { DEVTOOLS_PANEL_TAB_SETTINGS_STYLES } from '../components/devtools-panel/devtools-panel-tab/settings-tab'
3131
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'
33+
import { DEVTOOLS_PANEL_TAB_ISSUES_SIDEBAR_STYLES } from '../components/devtools-panel/devtools-panel-tab/issues-tab/issues-tab-sidebar'
3334

3435
export function ComponentStyles() {
3536
return (
@@ -66,6 +67,7 @@ export function ComponentStyles() {
6667
${DEVTOOLS_PANEL_VERSION_INFO_STYLES}
6768
${DEVTOOLS_PANEL_TAB_SETTINGS_STYLES}
6869
${DEVTOOLS_PANEL_TAB_ISSUES_STYLES}
70+
${DEVTOOLS_PANEL_TAB_ISSUES_SIDEBAR_STYLES}
6971
`}
7072
</style>
7173
)

0 commit comments

Comments
 (0)