Skip to content

Commit ea1db04

Browse files
committed
feat(plugin): on.setPluginSettings
1 parent f6dee0a commit ea1db04

File tree

8 files changed

+76
-7
lines changed

8 files changed

+76
-7
lines changed

docs/plugin/api-reference.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ It has the following properties:
2626
- `logo` (optional): URL to a logo of your Vue plugin.
2727
- `componentStateTypes` (optional): an array of custom component state section names you are going to add to the Component inspector. If you add new state to the component inspector, you should declare their sections here so the devtools can display the plugin icon.
2828
- `disableAppScope` (optional): if set to `true`, the hooks registered with this plugin will not be scoped to the associated app. In that case, you might need to use the `app` payload property to check what the current app is inside each hook.
29+
- `disablePluginScope` (optional): if set to `true`, the hooks registered with this plugin will not be scoped to the current plugin. In that case, you might need to use the `pluginId` payload property (depending on the hook) to check what the related plugin is inside each hook.
2930
- `enableEarlyProxy` (optional): if set to `true`, the plugin will run even if the Vue devtools are not connected yet using a proxy of the Plugin API and a buffer queue. This is useful if you need to add timeline events before the user opens the devtools.
3031
- `settings` (optional): an object describing the plugin settings. Learn more about plugin settings [here](./plugins-guide.md#plugin-settings).
3132

@@ -595,18 +596,42 @@ api.on.timelineCleared(() => {
595596
})
596597
```
597598

598-
## Utilities
599+
## Settings
600+
601+
Plugin settings allow the user to customize the plugin behavior. Learn more about plugin settings [here](./plugins-guide.md#plugin-settings).
599602

600603
### getSettings
601604

602-
Get the current plugin settings. Learn more about plugin settings [here](./plugins-guide.md#plugin-settings).
605+
Get the current plugin settings.
603606

604607
Example:
605608

606609
```js
607610
api.getSettings()
608611
```
609612

613+
### on.setPluginSettings
614+
615+
Hook called when the user changes the plugin settings.
616+
617+
Payload properties:
618+
619+
- `key`: settings item
620+
- `newValue`: new value for the changed settings
621+
- `oldValue`: its old value (deep clone)
622+
- `settings`: the whole current settings state object
623+
624+
```js
625+
// Plugin settings change
626+
api.on.setPluginSettings(payload => {
627+
console.log('plugin settings changed', payload.settings,
628+
// Info about the change
629+
payload.key, payload.newValue, payload.oldValue)
630+
})
631+
```
632+
633+
## Utilities
634+
610635
### getComponentInstances
611636

612637
Component instances on the Vue app.

docs/plugin/plugins-guide.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,14 @@ setupDevtoolsPlugin({
836836

837837
![screenshot of the plugin settings](../assets/plugin-settings.png)
838838

839+
You can listen for changes made to the settings by the user with the [`api.on.setPluginSettings`](./api-reference.md#on-setpluginsettings) hook:
840+
841+
```js
842+
api.on.setPluginSettings(payload => {
843+
// Do something...
844+
})
845+
```
846+
839847
### Tree-shaking for production
840848

841849
As we are going to write code only for integrating for the Vue Devtools, it would be a good idea to strip it for the production versions of our package - thus improving size and performance.

packages/api/src/api/hooks.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ export const enum Hooks {
2323
TIMELINE_CLEARED = 'timelineCleared',
2424
GET_INSPECTOR_TREE = 'getInspectorTree',
2525
GET_INSPECTOR_STATE = 'getInspectorState',
26-
EDIT_INSPECTOR_STATE = 'editInspectorState'
26+
EDIT_INSPECTOR_STATE = 'editInspectorState',
27+
SET_PLUGIN_SETTINGS = 'setPluginSettings',
2728
}
2829

2930
export interface ComponentBounds {
@@ -136,6 +137,14 @@ export type HookPayloads = {
136137
state: EditStatePayload
137138
set: (object: any, path: string | (string[]), value: any, cb?: (object: any, field: string, value: any) => void) => void
138139
}
140+
[Hooks.SET_PLUGIN_SETTINGS]: {
141+
app: App
142+
pluginId: string
143+
key: string
144+
newValue: any
145+
oldValue: any
146+
settings: any
147+
}
139148
}
140149

141150
export type EditStatePayload = {
@@ -172,4 +181,5 @@ export interface Hookable<TContext> {
172181
getInspectorTree (handler: HookHandler<HookPayloads[Hooks.GET_INSPECTOR_TREE], TContext>)
173182
getInspectorState (handler: HookHandler<HookPayloads[Hooks.GET_INSPECTOR_STATE], TContext>)
174183
editInspectorState (handler: HookHandler<HookPayloads[Hooks.EDIT_INSPECTOR_STATE], TContext>)
184+
setPluginSettings (handler: HookHandler<HookPayloads[Hooks.SET_PLUGIN_SETTINGS], TContext>)
175185
}

packages/api/src/plugin.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export interface PluginDescriptor {
99
componentStateTypes?: string[]
1010
logo?: string
1111
disableAppScope?: boolean
12+
disablePluginScope?: boolean
1213
/**
1314
* Run the plugin setup and expose the api even if the devtools is not opened yet.
1415
* Useful to record timeline events early.

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ export class DevtoolsHookable implements Hookable<BackendContext> {
3434
// App scope
3535
if (!this.plugin.descriptor.disableAppScope &&
3636
this.ctx.currentAppRecord.options.app !== this.plugin.descriptor.app) return
37+
38+
// Plugin scope
39+
if (!this.plugin.descriptor.disablePluginScope &&
40+
(args[0] as any).pluginId != null && (args[0] as any).pluginId !== this.plugin.descriptor.id) return
41+
3742
return originalHandler(...args)
3843
}
3944
}
@@ -143,4 +148,8 @@ export class DevtoolsHookable implements Hookable<BackendContext> {
143148
editInspectorState (handler: Handler<HookPayloads[Hooks.EDIT_INSPECTOR_STATE]>) {
144149
this.hook(Hooks.EDIT_INSPECTOR_STATE, handler, PluginPermission.CUSTOM_INSPECTOR)
145150
}
151+
152+
setPluginSettings (handler: Handler<HookPayloads[Hooks.SET_PLUGIN_SETTINGS]>) {
153+
this.hook(Hooks.SET_PLUGIN_SETTINGS, handler)
154+
}
146155
}

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
getComponentInstance
3333
} from './component'
3434
import { addQueuedPlugins, addPlugin, sendPluginList, addPreviouslyRegisteredPlugins } from './plugin'
35-
import { PluginDescriptor, SetupFunction, TimelineLayerOptions, TimelineEventOptions, CustomInspectorOptions } from '@vue/devtools-api'
35+
import { PluginDescriptor, SetupFunction, TimelineLayerOptions, TimelineEventOptions, CustomInspectorOptions, Hooks } from '@vue/devtools-api'
3636
import { registerApp, selectApp, waitForAppsRegistration, sendApps, _legacy_getAndRegisterApps, getAppRecord, removeApp } from './app'
3737
import { sendInspectorTree, getInspector, getInspectorWithAppId, sendInspectorState, editInspectorState, sendCustomInspectors, selectInspectorNode } from './inspector'
3838
import { showScreenshot } from './timeline-screenshot'
@@ -560,7 +560,16 @@ function connectBridge () {
560560
await sendPluginList(ctx)
561561
})
562562

563-
ctx.bridge.on(BridgeEvents.TO_BACK_DEVTOOLS_PLUGIN_SETTING_UPDATED, ({ pluginId }) => {
564-
ctx.hook.emit(HookEvents.PLUGIN_SETTINGS_SET, pluginId, getPluginSettings(pluginId))
563+
ctx.bridge.on(BridgeEvents.TO_BACK_DEVTOOLS_PLUGIN_SETTING_UPDATED, ({ pluginId, key, newValue, oldValue }) => {
564+
const settings = getPluginSettings(pluginId)
565+
ctx.hook.emit(HookEvents.PLUGIN_SETTINGS_SET, pluginId, settings)
566+
ctx.api.callHook(Hooks.SET_PLUGIN_SETTINGS, {
567+
app: ctx.currentAppRecord.options.app,
568+
pluginId,
569+
key,
570+
newValue,
571+
oldValue,
572+
settings
573+
})
565574
})
566575
}

packages/app-frontend/src/features/plugin/PluginSettings.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import PluginSettingsItem from './PluginSettingsItem.vue'
44
55
import { defineComponent, computed, PropType } from '@vue/composition-api'
66
import { getPluginSettings, setPluginSettings, getPluginDefaultSettings } from '@vue-devtools/shared-utils'
7+
import cloneDeep from 'lodash/cloneDeep'
78
import { Plugin } from '.'
89
import { getBridge } from '../bridge'
910
import { BridgeEvents } from '@vue-devtools/shared-utils/src'
@@ -27,11 +28,12 @@ export default defineComponent({
2728
const currentValues = computed(() => getPluginSettings(props.plugin.id, defaultValues.value))
2829
2930
function updateValue (id: string, value: any) {
31+
const oldValue = cloneDeep(currentValues.value[id])
3032
setPluginSettings(props.plugin.id, {
3133
...currentValues.value,
3234
[id]: value
3335
})
34-
getBridge().send(BridgeEvents.TO_BACK_DEVTOOLS_PLUGIN_SETTING_UPDATED, { pluginId: props.plugin.id })
36+
getBridge().send(BridgeEvents.TO_BACK_DEVTOOLS_PLUGIN_SETTING_UPDATED, { pluginId: props.plugin.id, key: id, newValue: value, oldValue })
3537
}
3638
3739
return {

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,11 @@ export default {
297297
}
298298
}
299299
})
300+
301+
// Plugin settings change
302+
api.on.setPluginSettings(payload => {
303+
console.log('plugin settings changed', payload)
304+
})
300305
})
301306

302307
// Outside of setupDevtoolsPlugin

0 commit comments

Comments
 (0)