Skip to content

Commit d69723f

Browse files
committedJun 5, 2024·
feat: further compatibility with v6 pluign API
1 parent a696b1c commit d69723f

File tree

20 files changed

+323
-48
lines changed

20 files changed

+323
-48
lines changed
 

‎packages/applet/src/components/state/ChildStateViewer.vue

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ withDefaults(defineProps<{
66
data: CustomInspectorState[]
77
depth: number
88
index: string
9+
expandedStateId?: string
910
}>(), {
1011
depth: 0,
12+
expandedStateId: '',
1113
})
1214
</script>
1315

@@ -17,7 +19,7 @@ withDefaults(defineProps<{
1719
v-for="(item, i) in data"
1820
:key="i"
1921
>
20-
<StateFieldViewer :data="item" :depth="depth + 1" :index="`${index}-${i}`" />
22+
<StateFieldViewer :data="item" :depth="depth + 1" :index="`${index}-${i}`" :expanded-state-id="expandedStateId" />
2123
</div>
2224
</div>
2325
</template>

‎packages/applet/src/components/state/RootStateViewer.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const { expanded, toggleExpanded } = useToggleExpanded(props.expandedStateId)
5757
<div
5858
v-if="item?.length && expanded.includes(`${index}`)"
5959
>
60-
<ChildStateViewer :data="item" :index="`${index}`" />
60+
<ChildStateViewer :data="item" :index="`${index}`" :expanded-state-id="expandedStateId" />
6161
</div>
6262
</div>
6363
</div>

‎packages/applet/src/components/state/StateFieldEditor.vue

+3-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ const buttonClass = computed(() => ({
4444
'opacity-0': !props.hovering,
4545
}))
4646
47-
function quickEdit(v: unknown, remove: boolean = false) {
48-
rpc.value.editInspectorState({
47+
async function quickEdit(v: unknown, remove: boolean = false) {
48+
await rpc.value.editInspectorState({
4949
path: props.data.path || [props.data.key],
5050
inspectorId: state.value.inspectorId,
5151
type: props.data.stateType!,
@@ -57,6 +57,7 @@ function quickEdit(v: unknown, remove: boolean = false) {
5757
remove,
5858
},
5959
} as unknown as DevToolsV6PluginAPIHookPayloads[DevToolsV6PluginAPIHookKeys.EDIT_COMPONENT_STATE])
60+
await rpc.value.sendInspectorState(state.value.inspectorId)
6061
}
6162
6263
function quickEditNum(v: number | string, offset: 1 | -1) {

‎packages/applet/src/components/state/StateFieldViewer.vue

+8-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const props = defineProps<{
1818
data: CustomInspectorState
1919
depth: number
2020
index: string
21+
expandedStateId?: string
2122
}>()
2223
2324
const STATE_FIELDS_LIMIT_SIZE = 30
@@ -30,7 +31,7 @@ const displayedValue = computed(() => formatInspectorStateValue(props.data.value
3031
}))
3132
const type = computed(() => getInspectorStateValueType(props.data.value))
3233
const raw = computed(() => getRaw(props.data.value))
33-
const { expanded, toggleExpanded } = useToggleExpanded()
34+
const { expanded, toggleExpanded } = useToggleExpanded(props.expandedStateId ?? '')
3435
3536
// custom state format class
3637
const stateFormatClass = computed(() => {
@@ -135,9 +136,9 @@ watch(() => editing.value, (v) => {
135136
}
136137
})
137138
138-
function submit() {
139+
async async function submit() {
139140
const data = props.data
140-
rpc.value.editInspectorState({
141+
await rpc.value.editInspectorState({
141142
path: normalizedPath.value,
142143
inspectorId: state.value.inspectorId,
143144
type: data.stateType!,
@@ -148,6 +149,7 @@ function submit() {
148149
value: toSubmit(editingText.value, raw.value.customType),
149150
},
150151
} as unknown as DevToolsV6PluginAPIHookPayloads[DevToolsV6PluginAPIHookKeys.EDIT_COMPONENT_STATE])
152+
await rpc.value.sendInspectorState(state.value.inspectorId)
151153
toggleEditing()
152154
}
153155
@@ -162,9 +164,9 @@ function addNewProp(type: EditorAddNewPropType) {
162164
addNewPropApi(type, raw.value.value)
163165
}
164166
165-
function submitDrafting() {
167+
async function submitDrafting() {
166168
const data = props.data
167-
rpc.value.editInspectorState({
169+
await rpc.value.editInspectorState({
168170
path: [...normalizedPath.value, draftingNewProp.value.key],
169171
inspectorId: state.value.inspectorId,
170172
type: data.stateType!,
@@ -175,6 +177,7 @@ function submitDrafting() {
175177
value: toSubmit(draftingNewProp.value.value),
176178
},
177179
} as unknown as DevToolsV6PluginAPIHookPayloads[DevToolsV6PluginAPIHookKeys.EDIT_COMPONENT_STATE])
180+
await rpc.value.sendInspectorState(state.value.inspectorId)
178181
resetDrafting()
179182
}
180183

‎packages/applet/src/composables/custom-inspector.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export interface CustomInspectorType {
55
id: string
66
label: string
77
logo: string
8+
icon: string
89
packageName: string | undefined
910
homepage: string | undefined
1011
}

‎packages/applet/src/modules/custom-inspector/components/state/Index.vue

+42-14
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,55 @@
11
<script setup lang="ts">
22
import { computed, onUnmounted, ref, watch } from 'vue'
33
import { Pane, Splitpanes } from 'splitpanes'
4-
import { DevToolsMessagingEvents, rpc } from '@vue/devtools-core'
4+
import { DevToolsMessagingEvents, onRpcConnected, rpc } from '@vue/devtools-core'
55
import { parse } from '@vue/devtools-kit'
66
import type { CustomInspectorNode, CustomInspectorOptions, CustomInspectorState } from '@vue/devtools-kit'
77
import { vTooltip } from '@vue/devtools-ui'
88
import Navbar from '~/components/basic/Navbar.vue'
9-
import SelectiveList from '~/components/basic/SelectiveList.vue'
109
import DevToolsHeader from '~/components/basic/DevToolsHeader.vue'
1110
import Empty from '~/components/basic/Empty.vue'
1211
import RootStateViewer from '~/components/state/RootStateViewer.vue'
1312
import { createExpandedContext } from '~/composables/toggle-expanded'
1413
import { useCustomInspectorState } from '~/composables/custom-inspector-state'
14+
import ComponentTree from '~/components/tree/TreeViewer.vue'
1515
16-
const { expanded: expandedStateNodes } = createExpandedContext('vue-query-state')
16+
const { expanded: expandedTreeNodes } = createExpandedContext()
17+
const { expanded: expandedStateNodes } = createExpandedContext('custom-inspector-state')
1718
1819
const customInspectState = useCustomInspectorState()
1920
2021
const inspectorId = computed(() => customInspectState.value.id!)
2122
const nodeActions = ref<CustomInspectorOptions['nodeActions']>([])
2223
const actions = ref<CustomInspectorOptions['nodeActions']>([])
2324
24-
const selected = ref('')
2525
const tree = ref<CustomInspectorNode[]>([])
26+
const treeNodeLinkedList = computed(() => tree.value?.length ? dfs(tree.value?.[0]) : [])
27+
const selected = ref('')
28+
2629
const state = ref<Record<string, CustomInspectorState[]>>({})
2730
const emptyState = computed(() => !Object.keys(state.value).length)
2831
32+
// tree
33+
function dfs(node: { id: string, children?: { id: string }[] }, path: string[] = [], linkedList: string[][] = []) {
34+
path.push(node.id)
35+
if (node.children?.length === 0)
36+
linkedList.push([...path])
37+
38+
node.children?.forEach((child) => {
39+
dfs(child, path, linkedList)
40+
})
41+
path.pop()
42+
return linkedList
43+
}
44+
45+
function getNodesByDepth(list: string[][], depth: number) {
46+
const nodes: string[] = []
47+
list.forEach((item) => {
48+
nodes.push(...item.slice(0, depth + 1))
49+
})
50+
return [...new Set(nodes)]
51+
}
52+
2953
function getNodeActions() {
3054
rpc.value.getInspectorNodeActions(inspectorId.value).then((actions) => {
3155
nodeActions.value = actions
@@ -80,6 +104,7 @@ const getInspectorTree = () => {
80104
tree.value = data
81105
if (!selected.value && data.length) {
82106
selected.value = data[0].id
107+
expandedTreeNodes.value = getNodesByDepth(treeNodeLinkedList.value, 1)
83108
getInspectorState(data[0].id)
84109
}
85110
})
@@ -94,10 +119,11 @@ function onInspectorTreeUpdated(_data: string) {
94119
if (!data.rootNodes.length || data.inspectorId !== inspectorId.value)
95120
return
96121
tree.value = data.rootNodes
97-
if ((!selected.value && data.rootNodes.length) || (selected.value && !data.rootNodes.find(node => node.id === selected.value))) {
98-
selected.value = data.rootNodes[0].id
99-
getInspectorState(data.rootNodes[0].id)
100-
}
122+
expandedTreeNodes.value = getNodesByDepth(treeNodeLinkedList.value, 1)
123+
// if ((!selected.value && data.rootNodes.length) || (selected.value && !data.rootNodes.find(node => node.id === selected.value))) {
124+
// selected.value = data.rootNodes[0].id
125+
// getInspectorState(data.rootNodes[0].id)
126+
// }
101127
}
102128
103129
function onInspectorStateUpdated(_data: string) {
@@ -106,17 +132,19 @@ function onInspectorStateUpdated(_data: string) {
106132
state: CustomInspectorState
107133
nodeId: string
108134
}
109-
if (data.inspectorId !== inspectorId.value || !data.state)
135+
if (data.inspectorId !== inspectorId.value || !data.state || data.nodeId !== selected.value)
110136
return
111137
112138
const { inspectorId: _inspectorId, ...filtered } = data.state
113139
114140
state.value = filterEmptyState(filtered as any)
115-
expandedStateNodes.value = Array.from({ length: Object.keys(state.value).length }, (_, i) => `${i}`)
141+
// expandedStateNodes.value = Array.from({ length: Object.keys(state.value).length }, (_, i) => `${i}`)
116142
}
117143
118-
rpc.functions.on(DevToolsMessagingEvents.INSPECTOR_TREE_UPDATED, onInspectorTreeUpdated)
119-
rpc.functions.on(DevToolsMessagingEvents.INSPECTOR_STATE_UPDATED, onInspectorStateUpdated)
144+
onRpcConnected(() => {
145+
rpc.functions.on(DevToolsMessagingEvents.INSPECTOR_TREE_UPDATED, onInspectorTreeUpdated)
146+
rpc.functions.on(DevToolsMessagingEvents.INSPECTOR_STATE_UPDATED, onInspectorStateUpdated)
147+
})
120148
121149
onUnmounted(() => {
122150
rpc.functions.off(DevToolsMessagingEvents.INSPECTOR_TREE_UPDATED, onInspectorTreeUpdated)
@@ -140,7 +168,7 @@ onUnmounted(() => {
140168
</div>
141169
</div>
142170
</div>
143-
<SelectiveList v-model="selected" :data="tree" />
171+
<ComponentTree v-model="selected" :data="tree" />
144172
</div>
145173
</Pane>
146174
<Pane size="60">
@@ -152,7 +180,7 @@ onUnmounted(() => {
152180
</div>
153181
</div>
154182
</div>
155-
<RootStateViewer v-if="selected && !emptyState" :data="state" :node-id="selected" :inspector-id="inspectorId" expanded-state-id="vue-query-state" class="no-scrollbar flex-1 select-none overflow-scroll" />
183+
<RootStateViewer v-if="selected && !emptyState" :data="state" :node-id="selected" :inspector-id="inspectorId" expanded-state-id="custom-inspector-state" class="no-scrollbar flex-1 select-none overflow-scroll" />
156184
<Empty v-else>
157185
No Data
158186
</Empty>

‎packages/client/src/components/common/SideNavItem.vue

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ function onClick() {
5454
<TabIcon
5555
text-xl
5656
:icon="tab.icon"
57+
:fallback="tab.fallbackIcon"
5758
title="Settings"
5859
:show-title="false"
5960
/>
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,31 @@
11
<script setup lang="ts">
2-
withDefaults(defineProps<{
2+
const props = withDefaults(defineProps<{
33
icon?: string
44
title?: string
55
showTitle?: boolean
6+
fallback?: string
67
}>(), {
78
showTitle: true,
89
})
10+
11+
const _icon = ref<string | undefined>(props.icon)
12+
13+
function onLoadError() {
14+
_icon.value = props.fallback
15+
}
916
</script>
1017

1118
<template>
1219
<img
13-
v-if="icon && (icon.startsWith('/') || icon.match(/^https?:/))"
20+
v-if="_icon && (_icon.startsWith('/') || _icon.match(/^https?:/))"
1421
:style="{
1522
width: '1em',
1623
height: '1em',
1724
}"
1825
v-bind="$attrs"
19-
:src="icon"
26+
:src="_icon"
2027
:alt="title"
28+
@error="onLoadError"
2129
>
2230
<div
2331
v-else
@@ -26,7 +34,7 @@ withDefaults(defineProps<{
2634
height: '1em',
2735
}"
2836
v-bind="$attrs"
29-
:class="icon || 'i-carbon-bring-forward'"
37+
:class="_icon || 'i-carbon-bring-forward'"
3038
:title="showTitle ? title : undefined"
3139
/>
3240
</template>

‎packages/client/src/composables/custom-inspector-tabs.ts

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export function useCustomInspectorTabs() {
1313
order: index,
1414
name: inspector.id,
1515
icon: inspector.logo,
16+
fallbackIcon: inspector.icon,
1617
title: inspector.label,
1718
path: `${CUSTOM_INSPECTOR_TAB_VIEW}/${inspector.id}`,
1819
category: 'modules',

‎packages/client/src/types/tab.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { MaybeRefOrGetter } from 'vue'
22
import type { CustomTab } from '@vue/devtools-kit'
33

44
export interface ModuleBuiltinTab extends Pick<CustomTab, 'name' | 'icon' | 'title' | 'category'> {
5+
fallbackIcon?: string
56
order?: number
67
path: string
78
show?: () => MaybeRefOrGetter<any>

‎packages/core/src/rpc/global.ts

+3
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ export const functions = {
6969
async editInspectorState(payload: DevToolsV6PluginAPIHookPayloads[DevToolsV6PluginAPIHookKeys.EDIT_INSPECTOR_STATE]) {
7070
return await devtools.ctx.api.editInspectorState(payload)
7171
},
72+
sendInspectorState(id: string) {
73+
return devtools.ctx.api.sendInspectorState(id)
74+
},
7275
inspectComponentInspector() {
7376
return devtools.ctx.api.inspectComponentInspector()
7477
},

‎packages/devtools-kit/src/api/v6/index.ts

+18-12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { DevToolsContextHookKeys, DevToolsV6PluginAPIHookKeys, DevToolsV6PluginA
44
import { devtoolsPluginBuffer } from '../../ctx/plugin'
55
import { devtoolsHooks } from '../../hook'
66
import { DevToolsHooks } from '../../types'
7+
import { getActiveInspectors } from '../../ctx/inspector'
78

89
export class DevToolsV6PluginAPI {
910
private plugin: DevToolsPlugin
@@ -54,18 +55,23 @@ export class DevToolsV6PluginAPI {
5455

5556
// component inspector
5657
notifyComponentUpdate(instance?: ComponentInstance) {
57-
if (instance) {
58-
const args = [
59-
instance.appContext.app,
60-
instance.uid,
61-
instance.parent?.uid,
62-
instance,
63-
] as const
64-
devtoolsHooks.callHook(DevToolsHooks.COMPONENT_UPDATED, ...args)
65-
}
66-
else {
67-
// @ts-expect-error skip type check
68-
devtoolsHooks.callHook(DevToolsHooks.COMPONENT_UPDATED)
58+
const inspector = getActiveInspectors().find(i => i.packageName === this.plugin.descriptor.packageName)
59+
if (inspector?.id) {
60+
// @TODO: handler
61+
if (instance) {
62+
const args = [
63+
instance.appContext.app,
64+
instance.uid,
65+
instance.parent?.uid,
66+
instance,
67+
] as const
68+
devtoolsHooks.callHook(DevToolsHooks.COMPONENT_UPDATED, ...args)
69+
}
70+
else {
71+
// @ts-expect-error skip type check
72+
devtoolsHooks.callHook(DevToolsHooks.COMPONENT_UPDATED)
73+
}
74+
this.hooks.callHook(DevToolsContextHookKeys.SEND_INSPECTOR_STATE, { inspectorId: inspector.id, plugin: this.plugin })
6975
}
7076
}
7177

‎packages/devtools-kit/src/ctx/api.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import { openInEditor } from '../core/open-in-editor'
77
import { normalizeRouterInfo } from '../core/router'
88
import { getComponentInspector } from '../core/component-inspector'
99
import type { DevToolsContextHooks, DevToolsMessagingHooks, DevToolsV6PluginAPIHookPayloads } from './hook'
10-
import { DevToolsV6PluginAPIHookKeys } from './hook'
10+
import { DevToolsContextHookKeys, DevToolsV6PluginAPIHookKeys } from './hook'
1111
import { activeAppRecord, devtoolsAppRecords, setActiveAppRecord, setActiveAppRecordId } from './state'
12-
import { callInspectorUpdatedHook } from './inspector'
12+
import { callInspectorUpdatedHook, getInspector } from './inspector'
1313

1414
export function createDevToolsApi(hooks: Hookable<DevToolsContextHooks & DevToolsMessagingHooks, HookKeys<DevToolsContextHooks & DevToolsMessagingHooks>>) {
1515
return {
@@ -60,11 +60,20 @@ export function createDevToolsApi(hooks: Hookable<DevToolsContextHooks & DevTool
6060
stateEditor.set(obj, path, value, cb || stateEditor.createDefaultSetCallback(payload.state))
6161
},
6262
}
63+
6364
// @ts-expect-error hookable
6465
hooks.callHookWith((callbacks) => {
6566
callbacks.forEach(cb => cb(_payload))
6667
}, DevToolsV6PluginAPIHookKeys.EDIT_INSPECTOR_STATE)
6768
},
69+
// send inspector state
70+
sendInspectorState(inspectorId: string) {
71+
const inspector = getInspector(inspectorId)
72+
hooks.callHook(DevToolsContextHookKeys.SEND_INSPECTOR_STATE, { inspectorId, plugin: {
73+
descriptor: inspector!.descriptor,
74+
setupFn: () => ({}),
75+
} })
76+
},
6877
// inspect component inspector
6978
inspectComponentInspector() {
7079
return inspectComponentHighLighter()

0 commit comments

Comments
 (0)
Please sign in to comment.