Skip to content

Commit 85ba09a

Browse files
antfuclaude
andcommitted
feat(self-inspect): router-based tabs with richer component views
Use Nuxt file-based routing for separate tab pages with PanelSideNav, shared refresh composable, and enhanced views with grouping/badges. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 242afaf commit 85ba09a

File tree

12 files changed

+446
-265
lines changed

12 files changed

+446
-265
lines changed
Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,42 @@
11
<script setup lang="ts">
22
import { useHead } from '#app/composables/head'
3-
3+
import PanelSideNav from '@vitejs/devtools-ui/components/PanelSideNav.vue'
4+
import { useSideNav } from '@vitejs/devtools-ui/composables/nav'
5+
import { useRefresh } from './composables/refresh'
46
import { connect, connectionState } from './composables/rpc'
57
import './styles/global.css'
6-
import '@vitejs/devtools-ui/composables/dark'
8+
import './composables/dark'
79
810
useHead({
911
title: 'DevTools Self Inspect',
1012
})
1113
1214
connect()
15+
16+
useSideNav([
17+
{
18+
title: 'RPC Functions',
19+
to: '/rpc',
20+
icon: 'i-ph-plugs-connected-duotone',
21+
},
22+
{
23+
title: 'Docks',
24+
to: '/docks',
25+
icon: 'i-ph-layout-duotone',
26+
},
27+
{
28+
title: 'Client Scripts',
29+
to: '/scripts',
30+
icon: 'i-ph-code-duotone',
31+
},
32+
{
33+
title: 'DevTools Plugins',
34+
to: '/plugins',
35+
icon: 'i-ph-puzzle-piece-duotone',
36+
},
37+
])
38+
39+
const { refresh, loading } = useRefresh()
1340
</script>
1441

1542
<template>
@@ -20,7 +47,25 @@ connect()
2047
v-else-if="!connectionState.connected"
2148
text="Connecting..."
2249
/>
23-
<div v-else h-vh>
24-
<NuxtPage />
50+
<div v-else grid="~ cols-[max-content_1fr]" h-vh>
51+
<PanelSideNav :show-dark-mode-toggle="false" />
52+
<div flex="~ col" of-hidden>
53+
<div flex="~ items-center justify-end" border="b base" px2 h8 shrink-0>
54+
<button
55+
p1.5 rounded
56+
hover:bg-active
57+
op50 hover:op100
58+
transition-colors
59+
title="Refresh"
60+
:disabled="loading"
61+
@click="refresh"
62+
>
63+
<span i-ph-arrow-clockwise text-sm :class="loading ? 'animate-spin' : ''" />
64+
</button>
65+
</div>
66+
<div flex-1 of-auto>
67+
<NuxtPage />
68+
</div>
69+
</div>
2570
</div>
2671
</template>
Lines changed: 67 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,78 @@
11
<script setup lang="ts">
2-
import type { ClientScriptInfo } from '../../types'
2+
import type { ClientScriptInfo } from '~~/types'
3+
import { computed } from 'vue'
34
4-
defineProps<{
5+
const props = defineProps<{
56
scripts: ClientScriptInfo[]
67
}>()
8+
9+
const grouped = computed(() => {
10+
const groups = new Map<string, ClientScriptInfo[]>()
11+
for (const script of props.scripts) {
12+
const type = script.dockType
13+
if (!groups.has(type))
14+
groups.set(type, [])
15+
groups.get(type)!.push(script)
16+
}
17+
return Array.from(groups.entries()).sort(([a], [b]) => a.localeCompare(b))
18+
})
19+
20+
function shortPath(path: string): string {
21+
const parts = path.split('/')
22+
if (parts.length <= 3)
23+
return path
24+
return `.../${parts.slice(-3).join('/')}`
25+
}
726
</script>
827

928
<template>
1029
<div v-if="scripts.length === 0" flex="~ items-center justify-center" py8 op50>
1130
No client scripts registered.
1231
</div>
13-
<table v-else w-full text-sm>
14-
<thead>
15-
<tr border="b base" text-left>
16-
<th px2 py1.5 font-medium op60>
17-
Dock ID
18-
</th>
19-
<th px2 py1.5 font-medium op60>
20-
Dock Title
21-
</th>
22-
<th px2 py1.5 font-medium op60>
23-
Dock Type
24-
</th>
25-
<th px2 py1.5 font-medium op60>
26-
Import From
27-
</th>
28-
<th px2 py1.5 font-medium op60>
29-
Import Name
30-
</th>
31-
</tr>
32-
</thead>
33-
<tbody>
34-
<tr v-for="script in scripts" :key="script.dockId" border="b base" hover:bg-active>
35-
<td px2 py1.5 font-mono text-xs>
36-
{{ script.dockId }}
37-
</td>
38-
<td px2 py1.5>
39-
{{ script.dockTitle }}
40-
</td>
41-
<td px2 py1.5>
42-
<DisplayBadge :text="script.dockType" />
43-
</td>
44-
<td px2 py1.5 font-mono text-xs max-w-60 truncate>
45-
{{ script.script.importFrom }}
46-
</td>
47-
<td px2 py1.5 font-mono text-xs>
48-
{{ script.script.importName ?? 'default' }}
49-
</td>
50-
</tr>
51-
</tbody>
52-
</table>
32+
<div v-else flex="~ col gap-3" p4>
33+
<div text-xs op60>
34+
{{ scripts.length }} client scripts registered
35+
</div>
36+
37+
<div v-for="[type, typeScripts] in grouped" :key="type">
38+
<div flex="~ items-center gap-2" mb1 mt2>
39+
<DisplayBadge :text="type" />
40+
<DisplayNumberBadge :value="typeScripts.length" />
41+
</div>
42+
<table w-full text-sm>
43+
<thead>
44+
<tr border="b base" text-left>
45+
<th px2 py1 font-medium op60 text-xs>
46+
Dock ID
47+
</th>
48+
<th px2 py1 font-medium op60 text-xs>
49+
Dock Title
50+
</th>
51+
<th px2 py1 font-medium op60 text-xs>
52+
Import From
53+
</th>
54+
<th px2 py1 font-medium op60 text-xs>
55+
Import Name
56+
</th>
57+
</tr>
58+
</thead>
59+
<tbody>
60+
<tr v-for="script in typeScripts" :key="script.dockId" border="b base" hover:bg-active>
61+
<td px2 py1.5 font-mono text-xs>
62+
{{ script.dockId }}
63+
</td>
64+
<td px2 py1.5>
65+
{{ script.dockTitle }}
66+
</td>
67+
<td px2 py1.5 font-mono text-xs max-w-60 truncate :title="script.script.importFrom">
68+
{{ shortPath(script.script.importFrom) }}
69+
</td>
70+
<td px2 py1.5 font-mono text-xs>
71+
{{ script.script.importName ?? 'default' }}
72+
</td>
73+
</tr>
74+
</tbody>
75+
</table>
76+
</div>
77+
</div>
5378
</template>

packages/self-inspect/src/app/components/DevtoolsPluginsList.vue

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import type { DevtoolsPluginInfo } from '../../types'
2+
import type { DevtoolsPluginInfo } from '~~/types'
33
import { computed, ref } from 'vue'
44
55
const props = defineProps<{
@@ -8,6 +8,8 @@ const props = defineProps<{
88
99
const showAll = ref(false)
1010
11+
const devtoolsCount = computed(() => props.plugins.filter(p => p.hasDevtools).length)
12+
1113
const filtered = computed(() => {
1214
if (showAll.value)
1315
return props.plugins
@@ -16,32 +18,40 @@ const filtered = computed(() => {
1618
</script>
1719

1820
<template>
19-
<div flex="~ col gap-3">
20-
<div flex="~ items-center gap-2">
21-
<label flex="~ items-center gap-1.5" text-sm op60 cursor-pointer select-none>
21+
<div flex="~ col gap-3" p4>
22+
<div flex="~ items-center gap-3" text-xs>
23+
<span op60>
24+
{{ devtoolsCount }} devtools plugins / {{ plugins.length }} total
25+
</span>
26+
<label flex="~ items-center gap-1.5" op60 cursor-pointer select-none>
2227
<input v-model="showAll" type="checkbox">
23-
Show all Vite plugins ({{ plugins.length }} total)
28+
Show all
2429
</label>
2530
</div>
31+
2632
<table w-full text-sm>
2733
<thead>
2834
<tr border="b base" text-left>
29-
<th px2 py1.5 font-medium op60>
35+
<th px2 py1 font-medium op60 text-xs>
3036
Plugin Name
3137
</th>
32-
<th px2 py1.5 font-medium op60 text-center>
38+
<th px2 py1 font-medium op60 text-xs text-center>
3339
DevTools
3440
</th>
35-
<th px2 py1.5 font-medium op60 text-center>
41+
<th px2 py1 font-medium op60 text-xs text-center>
3642
Setup
3743
</th>
38-
<th px2 py1.5 font-medium op60>
44+
<th px2 py1 font-medium op60 text-xs>
3945
Capabilities
4046
</th>
4147
</tr>
4248
</thead>
4349
<tbody>
44-
<tr v-for="plugin in filtered" :key="plugin.name" border="b base" hover:bg-active>
50+
<tr
51+
v-for="plugin in filtered" :key="plugin.name"
52+
border="b base" hover:bg-active
53+
:class="!plugin.hasDevtools ? 'op40' : ''"
54+
>
4555
<td px2 py1.5 font-mono text-xs>
4656
{{ plugin.name }}
4757
</td>
@@ -53,10 +63,11 @@ const filtered = computed(() => {
5363
<span v-if="plugin.hasSetup" i-ph-check text-green />
5464
<span v-else op20>-</span>
5565
</td>
56-
<td px2 py1.5 text-xs>
57-
<span v-if="plugin.capabilities" font-mono op60>
58-
{{ JSON.stringify(plugin.capabilities) }}
59-
</span>
66+
<td px2 py1.5 flex="~ items-center gap-1">
67+
<template v-if="plugin.capabilities">
68+
<DisplayBadge v-if="plugin.capabilities.dev" text="dev" />
69+
<DisplayBadge v-if="plugin.capabilities.build" text="build" />
70+
</template>
6071
<span v-else op20>-</span>
6172
</td>
6273
</tr>

0 commit comments

Comments
 (0)