Skip to content

Commit d409810

Browse files
feat(devtools-ui): jsonTree collapsible path (#196)
* feat(devtools-ui): jsonTree collapsible path * chore: changeset * chore: fix knip test * fix: merge error * fix: incorrect merge
1 parent 779f5fd commit d409810

File tree

3 files changed

+72
-4
lines changed

3 files changed

+72
-4
lines changed

.changeset/chubby-clowns-walk.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/devtools-ui': minor
3+
---
4+
5+
Adds collapsible path prop to devtools-ui, allowing an array of object paths to collapse by default.

packages/devtools-ui/src/components/tree.tsx

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import { For, Match, Show, Switch, createSignal } from 'solid-js'
22
import clsx from 'clsx'
33
import { css, useStyles } from '../styles/use-styles'
44
import { CopiedCopier, Copier, ErrorCopier } from './icons'
5+
import type { CollapsiblePaths } from '../utils/deep-keys'
56

6-
export function JsonTree(props: {
7-
value: any
7+
export function JsonTree<TData, TName extends CollapsiblePaths<TData>>(props: {
8+
value: TData
89
copyable?: boolean
910
defaultExpansionDepth?: number
11+
collapsePaths?: Array<TName>
1012
}) {
1113
return (
1214
<JsonValue
@@ -15,6 +17,8 @@ export function JsonTree(props: {
1517
copyable={props.copyable}
1618
depth={0}
1719
defaultExpansionDepth={props.defaultExpansionDepth ?? 1}
20+
path=""
21+
collapsePaths={props.collapsePaths}
1822
/>
1923
)
2024
}
@@ -25,8 +29,12 @@ function JsonValue(props: {
2529
isRoot?: boolean
2630
isLastKey?: boolean
2731
copyable?: boolean
32+
2833
defaultExpansionDepth: number
2934
depth: number
35+
36+
collapsePaths?: Array<string>
37+
path: string
3038
}) {
3139
const {
3240
value,
@@ -36,6 +44,8 @@ function JsonValue(props: {
3644
copyable,
3745
defaultExpansionDepth,
3846
depth,
47+
collapsePaths,
48+
path,
3949
} = props
4050
const styles = useStyles()
4151

@@ -75,6 +85,8 @@ function JsonValue(props: {
7585
copyable={copyable}
7686
keyName={keyName}
7787
value={value}
88+
collapsePaths={collapsePaths}
89+
path={path}
7890
/>
7991
)
8092
}
@@ -86,6 +98,8 @@ function JsonValue(props: {
8698
copyable={copyable}
8799
keyName={keyName}
88100
value={value}
101+
collapsePaths={collapsePaths}
102+
path={path}
89103
/>
90104
)
91105
}
@@ -107,15 +121,22 @@ const ArrayValue = ({
107121
copyable,
108122
defaultExpansionDepth,
109123
depth,
124+
collapsePaths,
125+
path,
110126
}: {
111127
value: Array<any>
112128
copyable?: boolean
113129
keyName?: string
114130
defaultExpansionDepth: number
115131
depth: number
132+
collapsePaths?: Array<string>
133+
path: string
116134
}) => {
117135
const styles = useStyles()
118-
const [expanded, setExpanded] = createSignal(depth <= defaultExpansionDepth)
136+
137+
const [expanded, setExpanded] = createSignal(
138+
depth <= defaultExpansionDepth && !collapsePaths?.includes(path),
139+
)
119140

120141
if (value.length === 0) {
121142
return (
@@ -125,6 +146,7 @@ const ArrayValue = ({
125146
&quot;{keyName}&quot;:{' '}
126147
</span>
127148
)}
149+
128150
<span class={styles().tree.valueBraces}>[]</span>
129151
</span>
130152
)
@@ -135,6 +157,7 @@ const ArrayValue = ({
135157
onClick={() => setExpanded(!expanded())}
136158
expanded={expanded()}
137159
/>
160+
138161
{keyName && (
139162
<span
140163
onclick={(e) => {
@@ -148,7 +171,9 @@ const ArrayValue = ({
148171
<span class={styles().tree.info}>{value.length} items</span>
149172
</span>
150173
)}
174+
151175
<span class={styles().tree.valueBraces}>[</span>
176+
152177
<Show when={expanded()}>
153178
<span class={styles().tree.expandedLine(Boolean(keyName))}>
154179
<For each={value}>
@@ -161,12 +186,15 @@ const ArrayValue = ({
161186
isLastKey={isLastKey}
162187
defaultExpansionDepth={defaultExpansionDepth}
163188
depth={depth + 1}
189+
collapsePaths={collapsePaths}
190+
path={path ? `${path}[${i()}]` : `[${i()}]`}
164191
/>
165192
)
166193
}}
167194
</For>
168195
</span>
169196
</Show>
197+
170198
<Show when={!expanded()}>
171199
<span
172200
onClick={(e) => {
@@ -190,15 +218,23 @@ const ObjectValue = ({
190218
copyable,
191219
defaultExpansionDepth,
192220
depth,
221+
collapsePaths,
222+
path,
193223
}: {
194224
value: Record<string, any>
195225
keyName?: string
196226
copyable?: boolean
197227
defaultExpansionDepth: number
198228
depth: number
229+
collapsePaths?: Array<string>
230+
path: string
199231
}) => {
200232
const styles = useStyles()
201-
const [expanded, setExpanded] = createSignal(depth <= defaultExpansionDepth)
233+
234+
const [expanded, setExpanded] = createSignal(
235+
depth <= defaultExpansionDepth && !collapsePaths?.includes(path),
236+
)
237+
202238
const keys = Object.keys(value)
203239
const lastKeyName = keys[keys.length - 1]
204240

@@ -210,10 +246,12 @@ const ObjectValue = ({
210246
&quot;{keyName}&quot;:{' '}
211247
</span>
212248
)}
249+
213250
<span class={styles().tree.valueBraces}>{'{}'}</span>
214251
</span>
215252
)
216253
}
254+
217255
return (
218256
<span class={styles().tree.expanderContainer}>
219257
{keyName && (
@@ -222,6 +260,7 @@ const ObjectValue = ({
222260
expanded={expanded()}
223261
/>
224262
)}
263+
225264
{keyName && (
226265
<span
227266
onClick={(e) => {
@@ -235,7 +274,9 @@ const ObjectValue = ({
235274
<span class={styles().tree.info}>{keys.length} items</span>
236275
</span>
237276
)}
277+
238278
<span class={styles().tree.valueBraces}>{'{'}</span>
279+
239280
<Show when={expanded()}>
240281
<span class={styles().tree.expandedLine(Boolean(keyName))}>
241282
<For each={keys}>
@@ -248,12 +289,15 @@ const ObjectValue = ({
248289
copyable={copyable}
249290
defaultExpansionDepth={defaultExpansionDepth}
250291
depth={depth + 1}
292+
collapsePaths={collapsePaths}
293+
path={`${path}${path ? '.' : ''}${k}`}
251294
/>
252295
</>
253296
)}
254297
</For>
255298
</span>
256299
</Show>
300+
257301
<Show when={!expanded()}>
258302
<span
259303
onClick={(e) => {
@@ -266,6 +310,7 @@ const ObjectValue = ({
266310
{`...`}
267311
</span>
268312
</Show>
313+
269314
<span class={styles().tree.valueBraces}>{'}'}</span>
270315
</span>
271316
)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
type CollapsibleKeys<T, TPrefix extends string = ''> =
2+
T extends ReadonlyArray<infer U>
3+
?
4+
| (TPrefix extends '' ? '' : TPrefix)
5+
| CollapsibleKeys<U, `${TPrefix}[${number}]`>
6+
: T extends object
7+
?
8+
| (TPrefix extends '' ? '' : TPrefix)
9+
| {
10+
[K in Extract<keyof T, string>]: CollapsibleKeys<
11+
T[K],
12+
TPrefix extends '' ? `${K}` : `${TPrefix}.${K}`
13+
>
14+
}[Extract<keyof T, string>]
15+
: never
16+
17+
export type CollapsiblePaths<T> =
18+
CollapsibleKeys<T> extends string ? CollapsibleKeys<T> : never

0 commit comments

Comments
 (0)