Skip to content

Commit 45110b8

Browse files
committed
Merge branch 'next' of github.com:vuejs/vue-devtools into next
2 parents 5d1afaa + 445dcdf commit 45110b8

File tree

14 files changed

+177
-7
lines changed

14 files changed

+177
-7
lines changed

docs/plugin/api-reference.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,31 @@ api.on.inspectTimelineEvent(payload => {
471471

472472
## Utilities
473473

474+
### getComponentInstances
475+
476+
Component instances on the Vue app.
477+
- `app`: the target Vue app instance
478+
479+
Example:
480+
481+
```js
482+
let componentInstances = []
483+
484+
api.on.getInspectorTree(async (payload) => {
485+
if (payload.inspectorId === 'test-inspector') { // e.g. custom inspector
486+
componentInstances = await api.getComponentInstances(app)
487+
for (const instance of instances) {
488+
payload.rootNodes.push({
489+
id: instance.uid.toString(),
490+
label: `Component ${instance.uid}`
491+
})
492+
}
493+
494+
// something todo ...
495+
}
496+
})
497+
```
498+
474499
### getComponentBounds
475500

476501
Computes the component bounds on the page.
@@ -513,3 +538,51 @@ api.on.inspectComponent(async payload => {
513538
}
514539
})
515540
```
541+
542+
### highlightElement
543+
544+
Highlight the element of the component.
545+
- `instance`: the target component instance
546+
547+
Example:
548+
549+
```js
550+
let componentInstances = [] // keeped component instance of the Vue app (e.g. `getComponentInstances`)
551+
552+
api.on.getInspectorState(payload => {
553+
if (payload.inspectorId === 'test-inspector') { // e.g. custom inspector
554+
// find component instance from custom inspector node
555+
const instance = componentInstances.find(instance => instance.uid.toString() === payload.nodeId)
556+
557+
if (instance) {
558+
api.highlightElement(instance)
559+
}
560+
561+
// something todo ...
562+
}
563+
})
564+
```
565+
566+
### unhighlightElement
567+
568+
Unhighlight the element.
569+
- `instance`: the target component instance
570+
571+
Example:
572+
573+
```js
574+
let componentInstances = [] // keeped component instance of the Vue app (e.g. `getComponentInstances`)
575+
576+
api.on.getInspectorState(payload => {
577+
if (payload.inspectorId === 'test-inspector') { // e.g. custom inspector
578+
// find component instance from custom inspector node
579+
const instance = componentInstances.find(instance => instance.uid.toString() === payload.nodeId)
580+
581+
if (instance) {
582+
api.unhighlightElement(instance)
583+
}
584+
585+
// something todo ...
586+
}
587+
})
588+
```

packages/api/src/api/api.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ComponentBounds, Hookable } from './hooks'
22
import { Context } from './context'
33
import { ComponentInstance, ComponentState, StateBase } from './component'
4+
import { App } from './app'
45
import { ID } from './util'
56

67
export interface DevtoolsPluginApi {
@@ -13,6 +14,9 @@ export interface DevtoolsPluginApi {
1314
sendInspectorState (inspectorId: string)
1415
getComponentBounds (instance: ComponentInstance): Promise<ComponentBounds>
1516
getComponentName (instance: ComponentInstance): Promise<string>
17+
getComponentInstances (app: App): Promise<ComponentInstance[]>
18+
highlightElement (instance: ComponentInstance)
19+
unhighlightElement ()
1620
}
1721

1822
export interface AppRecord {

packages/api/src/api/hooks.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const enum Hooks {
1313
INSPECT_COMPONENT = 'inspectComponent',
1414
GET_COMPONENT_BOUNDS = 'getComponentBounds',
1515
GET_COMPONENT_NAME = 'getComponentName',
16+
GET_COMPONENT_INSTANCES = 'getComponentInstances',
1617
GET_ELEMENT_COMPONENT = 'getElementComponent',
1718
GET_COMPONENT_ROOT_ELEMENTS = 'getComponentRootElements',
1819
EDIT_COMPONENT_STATE = 'editComponentState',
@@ -73,6 +74,10 @@ export type HookPayloads = {
7374
componentInstance: ComponentInstance
7475
name: string
7576
}
77+
[Hooks.GET_COMPONENT_INSTANCES]: {
78+
app: App
79+
componentInstances: ComponentInstance[]
80+
}
7681
[Hooks.GET_ELEMENT_COMPONENT]: {
7782
element: HTMLElement | any
7883
componentInstance: ComponentInstance
@@ -138,6 +143,7 @@ export interface Hookable<TContext> {
138143
inspectComponent (handler: HookHandler<HookPayloads[Hooks.INSPECT_COMPONENT], TContext>)
139144
getComponentBounds (handler: HookHandler<HookPayloads[Hooks.GET_COMPONENT_BOUNDS], TContext>)
140145
getComponentName (handler: HookHandler<HookPayloads[Hooks.GET_COMPONENT_NAME], TContext>)
146+
getComponentInstances (handler: HookHandler<HookPayloads[Hooks.GET_COMPONENT_INSTANCES], TContext>)
141147
getElementComponent (handler: HookHandler<HookPayloads[Hooks.GET_ELEMENT_COMPONENT], TContext>)
142148
getComponentRootElements (handler: HookHandler<HookPayloads[Hooks.GET_COMPONENT_ROOT_ELEMENTS], TContext>)
143149
editComponentState (handler: HookHandler<HookPayloads[Hooks.EDIT_COMPONENT_STATE], TContext>)

packages/app-backend-api/src/api.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@ export class DevtoolsApi {
126126
return payload.name
127127
}
128128

129+
async getComponentInstances (app: App) {
130+
const payload = await this.callHook(Hooks.GET_COMPONENT_INSTANCES, {
131+
app,
132+
componentInstances: []
133+
})
134+
return payload.componentInstances
135+
}
136+
129137
async getElementComponent (element: HTMLElement | any) {
130138
const payload = await this.callHook(Hooks.GET_ELEMENT_COMPONENT, {
131139
element,
@@ -259,4 +267,16 @@ export class DevtoolsPluginApiInstance implements DevtoolsPluginApi {
259267
getComponentName (instance: ComponentInstance) {
260268
return this.ctx.api.getComponentName(instance)
261269
}
270+
271+
getComponentInstances (app: App) {
272+
return this.ctx.api.getComponentInstances(app)
273+
}
274+
275+
highlightElement (instance: ComponentInstance) {
276+
this.ctx.hook.emit(HookEvents.COMPONENT_HIGHLIGHT, instance.__VUE_DEVTOOLS_UID__, this.plugin)
277+
}
278+
279+
unhighlightElement () {
280+
this.ctx.hook.emit(HookEvents.COMPONENT_UNHIGHLIGHT, this.plugin)
281+
}
262282
}

packages/app-backend-api/src/hooks.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ export class DevtoolsHookable implements Hookable<BackendContext> {
8181
this.hook(Hooks.GET_COMPONENT_NAME, handler)
8282
}
8383

84+
getComponentInstances (handler: Handler<HookPayloads[Hooks.GET_COMPONENT_INSTANCES]>) {
85+
this.hook(Hooks.GET_COMPONENT_INSTANCES, handler)
86+
}
87+
8488
getElementComponent (handler: Handler<HookPayloads[Hooks.GET_ELEMENT_COMPONENT]>) {
8589
this.hook(Hooks.GET_ELEMENT_COMPONENT, handler)
8690
}

packages/app-backend-core/src/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,14 @@ async function connect () {
200200
unHighlight()
201201
})
202202

203+
hook.on(HookEvents.COMPONENT_HIGHLIGHT, instanceId => {
204+
highlight(ctx.currentAppRecord.instanceMap.get(instanceId), ctx)
205+
})
206+
207+
hook.on(HookEvents.COMPONENT_UNHIGHLIGHT, () => {
208+
unHighlight()
209+
})
210+
203211
// Component picker
204212

205213
const componentPicker = new ComponentPicker(ctx)

packages/app-backend-vue3/src/components/util.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { classify } from '@vue-devtools/shared-utils'
22
import { basename } from '../util'
3+
import { ComponentInstance, App } from '@vue/devtools-api'
34
import { BackendContext } from '@vue-devtools/app-backend-api'
45

56
export function isBeingDestroyed (instance) {
@@ -66,3 +67,11 @@ export function getRenderKey (value): string {
6667
return 'Object'
6768
}
6869
}
70+
71+
export function getComponentInstances (app: App): ComponentInstance[] {
72+
const appRecord = app.__VUE_DEVTOOLS_APP_RECORD__
73+
const appId = appRecord.id.toString()
74+
return [...appRecord.instanceMap]
75+
.filter(([key]) => key.split(':')[0] === appId)
76+
.map(([,instance]) => instance) // eslint-disable-line comma-spacing
77+
}

packages/app-backend-vue3/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { DevtoolsBackend, BuiltinBackendFeature } from '@vue-devtools/app-backend-api'
22
import { ComponentWalker } from './components/tree'
33
import { editState, getInstanceDetails } from './components/data'
4-
import { getInstanceName } from './components/util'
4+
import { getInstanceName, getComponentInstances } from './components/util'
55
import { getComponentInstanceFromElement, getInstanceOrVnodeRect, getRootElementsFromComponentInstance } from './components/el'
66
import { HookEvents } from '@vue-devtools/shared-utils'
77

@@ -51,6 +51,10 @@ export const backend: DevtoolsBackend = {
5151
payload.componentInstance = getComponentInstanceFromElement(payload.element)
5252
})
5353

54+
api.on.getComponentInstances(payload => {
55+
payload.componentInstances = getComponentInstances(payload.app)
56+
})
57+
5458
api.on.getComponentRootElements(payload => {
5559
payload.rootElements = getRootElementsFromComponentInstance(payload.componentInstance)
5660
})

packages/app-frontend-legacy/src/components/DataField.vue

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,16 @@
136136
>
137137
<VueDropdownButton
138138
icon-left="flip_to_front"
139-
@click="copyToClipboard"
139+
@click="copyValue"
140140
>
141141
{{ $t('DataField.contextMenu.copyValue') }}
142142
</VueDropdownButton>
143+
<VueDropdownButton
144+
icon-left="flip_to_front"
145+
@click="copyPath"
146+
>
147+
{{ $t('DataField.contextMenu.copyPath') }}
148+
</VueDropdownButton>
143149
</div>
144150
</VueDropdown>
145151
</span>
@@ -420,10 +426,14 @@ export default {
420426
},
421427
422428
methods: {
423-
copyToClipboard () {
429+
copyValue () {
424430
copyToClipboard(this.field.value)
425431
},
426432
433+
copyPath () {
434+
copyToClipboard(this.path)
435+
},
436+
427437
onClick (event) {
428438
// Cancel if target is interactive
429439
if (event.target.tagName === 'INPUT' || event.target.className.includes('button')) {

packages/app-frontend-legacy/src/locales/en.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ export default {
3737
}
3838
},
3939
contextMenu: {
40-
copyValue: 'Copy Value'
40+
copyValue: 'Copy Value',
41+
copyPath: 'Copy Path'
4142
},
4243
quickEdit: {
4344
number: {

packages/app-frontend/src/features/inspector/DataField.vue

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,16 @@
148148
>
149149
<VueDropdownButton
150150
icon-left="flip_to_front"
151-
@click="copyToClipboard"
151+
@click="copyValue"
152152
>
153153
{{ $t('DataField.contextMenu.copyValue') }}
154154
</VueDropdownButton>
155+
<VueDropdownButton
156+
icon-left="flip_to_front"
157+
@click="copyPath"
158+
>
159+
{{ $t('DataField.contextMenu.copyPath') }}
160+
</VueDropdownButton>
155161
</div>
156162
</VueDropdown>
157163
</span>
@@ -437,10 +443,14 @@ export default {
437443
},
438444
439445
methods: {
440-
copyToClipboard () {
446+
copyValue () {
441447
copyToClipboard(this.field.value)
442448
},
443449
450+
copyPath () {
451+
copyToClipboard(this.path)
452+
},
453+
444454
onClick (event) {
445455
// Cancel if target is interactive
446456
if (event.target.tagName === 'INPUT' || event.target.className.includes('button')) {

packages/app-frontend/src/locales/en.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ export default {
3737
}
3838
},
3939
contextMenu: {
40-
copyValue: 'Copy Value'
40+
copyValue: 'Copy Value',
41+
copyPath: 'Copy Path'
4142
},
4243
quickEdit: {
4344
number: {

packages/shared-utils/src/consts.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ export enum HookEvents {
8888
COMPONENT_ADDED = 'component:added',
8989
COMPONENT_REMOVED = 'component:removed',
9090
COMPONENT_EMIT = 'component:emit',
91+
COMPONENT_HIGHLIGHT = 'component:highlight',
92+
COMPONENT_UNHIGHLIGHT = 'component:unhighlight',
9193
SETUP_DEVTOOLS_PLUGIN = 'devtools-plugin:setup',
9294
TIMELINE_LAYER_ADDED = 'timeline:layer-added',
9395
TIMELINE_EVENT_ADDED = 'timeline:event-added',

packages/shell-dev-vue3/src/devtools-plugin/index.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ export default {
129129
label: 'Test inspector 2'
130130
})
131131

132+
let componentInstances = []
133+
132134
api.on.getInspectorTree(payload => {
133135
if (payload.app === app && payload.inspectorId === 'test-inspector') {
134136
payload.rootNodes = [
@@ -155,6 +157,16 @@ export default {
155157
]
156158
}
157159
]
160+
} else if (payload.app === app && payload.inspectorId === 'test-inspector2') {
161+
api.getComponentInstances(app).then((instances) => {
162+
componentInstances = instances
163+
for (const instance of instances) {
164+
payload.rootNodes.push({
165+
id: instance.uid.toString(),
166+
label: `Component ${instance.uid}`
167+
})
168+
}
169+
})
158170
}
159171
})
160172

@@ -194,6 +206,12 @@ export default {
194206
]
195207
}
196208
}
209+
} else if (payload.app === app && payload.inspectorId === 'test-inspector2') {
210+
const instance = componentInstances.find(instance => instance.uid.toString() === payload.nodeId)
211+
if (instance) {
212+
api.unhighlightElement()
213+
api.highlightElement(instance)
214+
}
197215
}
198216
})
199217

0 commit comments

Comments
 (0)