Skip to content

Commit 3a6f337

Browse files
antfuclaude
andauthored
feat(self-inspect): add shared state viewer/editor (#240)
Co-authored-by: Claude Haiku 4.5 <[email protected]>
1 parent 76ab37c commit 3a6f337

File tree

8 files changed

+152
-0
lines changed

8 files changed

+152
-0
lines changed

packages/self-inspect/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
},
4141
"devDependencies": {
4242
"@unocss/nuxt": "catalog:build",
43+
"@visual-json/vue": "catalog:frontend",
4344
"@vueuse/core": "catalog:frontend",
4445
"@vueuse/nuxt": "catalog:build",
4546
"structured-clone-es": "catalog:deps",

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const navItems = [
1616
{ title: 'Docks', to: '/docks', icon: 'i-ph-layout-duotone' },
1717
{ title: 'Client Scripts', to: '/scripts', icon: 'i-ph-code-duotone' },
1818
{ title: 'Plugins', to: '/plugins', icon: 'i-ph-puzzle-piece-duotone' },
19+
{ title: 'Shared State', to: '/state', icon: 'i-ph-database-duotone' },
1920
{ title: 'Auth Tokens', to: '/auth', icon: 'i-ph-key-duotone' },
2021
]
2122
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<script setup lang="ts">
2+
import { JsonEditor } from '@visual-json/vue'
3+
import { nanoid } from '@vitejs/devtools-kit/utils/nanoid'
4+
import { computed, ref, shallowRef, watch } from 'vue'
5+
import { useRpc } from '../composables/rpc'
6+
7+
const props = defineProps<{
8+
keys: string[]
9+
}>()
10+
11+
const rpc = useRpc()
12+
const showInternal = ref(false)
13+
const selectedKey = ref<string>()
14+
15+
const filteredKeys = computed(() => {
16+
if (showInternal.value)
17+
return props.keys
18+
return props.keys.filter(key => !key.startsWith('devtoolskit:internal:') && !key.startsWith('__'))
19+
})
20+
const stateValue = shallowRef<any>()
21+
const loading = ref(false)
22+
23+
async function loadState(key: string) {
24+
loading.value = true
25+
try {
26+
stateValue.value = await rpc.value.call('devtoolskit:internal:rpc:server-state:get', key)
27+
}
28+
finally {
29+
loading.value = false
30+
}
31+
}
32+
33+
watch(selectedKey, (key) => {
34+
stateValue.value = undefined
35+
if (key)
36+
loadState(key)
37+
})
38+
39+
function selectKey(key: string) {
40+
selectedKey.value = key
41+
}
42+
43+
async function handleChange(value: any) {
44+
if (!selectedKey.value)
45+
return
46+
const syncId = nanoid()
47+
stateValue.value = value
48+
await rpc.value.call('devtoolskit:internal:rpc:server-state:set', selectedKey.value, value, syncId)
49+
}
50+
</script>
51+
52+
<template>
53+
<div flex="~" h-full of-hidden>
54+
<!-- Keys list -->
55+
<div w-60 shrink-0 border="r base" flex="~ col" of-hidden>
56+
<div px3 py2 text-xs op60 border="b base" flex="~ items-center justify-between">
57+
<span>{{ filteredKeys.length }} shared states</span>
58+
<label flex="~ items-center gap-1" cursor-pointer>
59+
<input v-model="showInternal" type="checkbox">
60+
<span>Internal</span>
61+
</label>
62+
</div>
63+
<div flex-1 of-auto>
64+
<button
65+
v-for="key in filteredKeys" :key="key"
66+
block w-full text-left
67+
px3 py2 text-sm font-mono
68+
border="b base"
69+
hover:bg-active transition-colors
70+
:class="selectedKey === key ? 'bg-active! text-primary' : 'op70'"
71+
@click="selectKey(key)"
72+
>
73+
{{ key }}
74+
</button>
75+
</div>
76+
</div>
77+
78+
<!-- State viewer/editor -->
79+
<div flex-1 of-auto>
80+
<div v-if="!selectedKey" flex="~ items-center justify-center" h-full op40 text-sm>
81+
Select a shared state to inspect
82+
</div>
83+
<VisualLoading v-else-if="loading" />
84+
<div v-else-if="stateValue !== undefined" h-full>
85+
<JsonEditor
86+
:value="stateValue"
87+
height="100%"
88+
@change="handleChange"
89+
/>
90+
</div>
91+
</div>
92+
</div>
93+
</template>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<script setup lang="ts">
2+
import { useRpc } from '#imports'
3+
import { onMounted, shallowRef } from 'vue'
4+
import { useRefreshProvider } from '../composables/refresh'
5+
6+
const rpc = useRpc()
7+
const keys = shallowRef<string[]>()
8+
9+
async function fetchData() {
10+
keys.value = await rpc.value.call('devtoolskit:self-inspect:get-shared-state-keys')
11+
}
12+
13+
useRefreshProvider(fetchData)
14+
onMounted(fetchData)
15+
</script>
16+
17+
<template>
18+
<VisualLoading v-if="!keys" />
19+
<SharedStateView v-else :keys="keys" />
20+
</template>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { defineRpcFunction } from '@vitejs/devtools-kit'
2+
3+
export const getSharedStateKeys = defineRpcFunction({
4+
name: 'devtoolskit:self-inspect:get-shared-state-keys',
5+
type: 'query',
6+
setup: (context) => {
7+
return {
8+
handler: async () => {
9+
return context.rpc.sharedState.keys()
10+
},
11+
}
12+
},
13+
})

packages/self-inspect/src/node/rpc/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { getClientScripts } from './functions/get-client-scripts'
44
import { getDevtoolsPlugins } from './functions/get-devtools-plugins'
55
import { getDocks } from './functions/get-docks'
66
import { getRpcFunctions } from './functions/get-rpc-functions'
7+
import { getSharedStateKeys } from './functions/get-shared-state-keys'
78
import { revokeAuthTokenRpc } from './functions/revoke-auth-token'
89
import '@vitejs/devtools-kit'
910

@@ -13,6 +14,7 @@ export const rpcFunctions = [
1314
getClientScripts,
1415
getDevtoolsPlugins,
1516
getAuthTokens,
17+
getSharedStateKeys,
1618
revokeAuthTokenRpc,
1719
] as const
1820

pnpm-lock.yaml

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ catalogs:
9090
'@floating-ui/dom': ^1.7.6
9191
'@json-render/core': 0.13.0
9292
'@json-render/vue': 0.13.0
93+
'@visual-json/vue': ^0.3.1
9394
'@vueuse/components': ^14.2.1
9495
'@vueuse/core': ^14.2.1
9596
'@vueuse/router': ^14.2.1

0 commit comments

Comments
 (0)