diff --git a/packages/applet/src/components/settings/Settings.vue b/packages/applet/src/components/settings/Settings.vue new file mode 100644 index 000000000..6b7b24a8c --- /dev/null +++ b/packages/applet/src/components/settings/Settings.vue @@ -0,0 +1,59 @@ + + + + + + + + {{ item.label }} + + + + toggleOption(index, v)" + > + + {{ name }} + + + + + + toggleOption(index, v)" + /> + + + + toggleOption(index, v)" /> + + + + + + diff --git a/packages/applet/src/modules/custom-inspector/components/Settings.vue b/packages/applet/src/modules/custom-inspector/components/Settings.vue new file mode 100644 index 000000000..90c5c8f03 --- /dev/null +++ b/packages/applet/src/modules/custom-inspector/components/Settings.vue @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/packages/applet/src/modules/custom-inspector/index.vue b/packages/applet/src/modules/custom-inspector/index.vue index 4f3fe4c9e..4a307ffe1 100644 --- a/packages/applet/src/modules/custom-inspector/index.vue +++ b/packages/applet/src/modules/custom-inspector/index.vue @@ -3,6 +3,7 @@ import { computed, onUnmounted, ref, watch } from 'vue' import { onRpcConnected, rpc } from '@vue/devtools-core' import About from './components/About.vue' +import Settings from './components/Settings.vue' import State from './components/state/Index.vue' import Timeline from './components/timeline/Index.vue' import AppConnecting from '~/components/basic/AppConnecting.vue' @@ -17,6 +18,9 @@ const emit = defineEmits(['loadError']) const inspectorState = createCustomInspectorStateContext() const loading = ref(false) +const pluginSettings = ref(null) +provide('pluginSettings', pluginSettings) + const routes = computed(() => { return [ { @@ -36,6 +40,12 @@ const routes = computed(() => { name: 'About', component: About, }, + pluginSettings.value && ({ + path: '/settings', + name: 'Settings', + component: Settings, + icon: 'i-mdi:cog-outline', + }), ].filter(Boolean) as VirtualRoute[] }) @@ -62,6 +72,14 @@ function getInspectorInfo() { restoreRouter() loading.value = false }) + rpc.value.getPluginSettings(props.id).then((settings) => { + if (settings.options) { + pluginSettings.value = settings + } + else { + pluginSettings.value = null + } + }) }) } diff --git a/packages/applet/src/modules/pinia/components/Settings.vue b/packages/applet/src/modules/pinia/components/Settings.vue new file mode 100644 index 000000000..058506946 --- /dev/null +++ b/packages/applet/src/modules/pinia/components/Settings.vue @@ -0,0 +1,23 @@ + + + + + + + + + + diff --git a/packages/applet/src/modules/pinia/index.vue b/packages/applet/src/modules/pinia/index.vue index 595bd6d68..6d3452cdd 100644 --- a/packages/applet/src/modules/pinia/index.vue +++ b/packages/applet/src/modules/pinia/index.vue @@ -1,31 +1,57 @@ diff --git a/packages/core/src/rpc/global.ts b/packages/core/src/rpc/global.ts index f363e7baa..b898fe2d4 100644 --- a/packages/core/src/rpc/global.ts +++ b/packages/core/src/rpc/global.ts @@ -121,6 +121,12 @@ export const functions = { async toggleApp(id: string) { return devtools.ctx.api.toggleApp(id) }, + updatePluginSettings(pluginId: string, key: string, value: string) { + return devtools.ctx.api.updatePluginSettings(pluginId, key, value) + }, + getPluginSettings(pluginId: string) { + return devtools.ctx.api.getPluginSettings(pluginId) + }, getRouterInfo() { return devtoolsRouterInfo }, diff --git a/packages/devtools-kit/src/api/v6/index.ts b/packages/devtools-kit/src/api/v6/index.ts index 28dc9ffe9..ffdf9b1bc 100644 --- a/packages/devtools-kit/src/api/v6/index.ts +++ b/packages/devtools-kit/src/api/v6/index.ts @@ -1,10 +1,10 @@ import type { DevtoolsContext } from '../../ctx' import type { App, ComponentBounds, ComponentInstance, CustomInspectorOptions, DevToolsPlugin, TimelineEventOptions, TimelineLayerOptions } from '../../types' import { DevToolsContextHookKeys, DevToolsV6PluginAPIHookKeys, DevToolsV6PluginAPIHooks } from '../../ctx/hook' -import { devtoolsPluginBuffer } from '../../ctx/plugin' import { devtoolsHooks } from '../../hook' import { DevToolsHooks } from '../../types' import { getActiveInspectors } from '../../ctx/inspector' +import { getPluginSettings, initPluginSettings } from '../../core/plugin/plugin-settings' export class DevToolsV6PluginAPI { private plugin: DevToolsPlugin @@ -78,6 +78,9 @@ export class DevToolsV6PluginAPI { // custom inspector addInspector(options: CustomInspectorOptions) { this.hooks.callHook(DevToolsContextHookKeys.ADD_INSPECTOR, { inspector: options, plugin: this.plugin }) + if (this.plugin.descriptor.settings) { + initPluginSettings(options.id, this.plugin.descriptor.settings) + } } sendInspectorTree(inspectorId: string) { @@ -107,21 +110,9 @@ export class DevToolsV6PluginAPI { // settings getSettings(pluginId?: string) { - function _getSettings(settings) { - const _settings = {} - Object.keys(settings!).forEach((key) => { - _settings[key] = settings![key].defaultValue - }) + const inspector = getActiveInspectors().find(i => i.packageName === this.plugin.descriptor.packageName) - return _settings - } - if (pluginId) { - const item = devtoolsPluginBuffer.find(item => item[0].id === pluginId)?.[0] ?? null - return _getSettings(item?.settings) ?? _getSettings(this.plugin.descriptor.settings) - } - else { - return _getSettings(this.plugin.descriptor.settings) - } + return getPluginSettings((pluginId ?? inspector?.id)!, this.plugin.descriptor.settings) } // utilities diff --git a/packages/devtools-kit/src/core/plugin/index.ts b/packages/devtools-kit/src/core/plugin/index.ts index 3c1d51772..8789a519a 100644 --- a/packages/devtools-kit/src/core/plugin/index.ts +++ b/packages/devtools-kit/src/core/plugin/index.ts @@ -1,8 +1,9 @@ import { target } from '@vue/devtools-shared' import { App, PluginDescriptor, PluginSetupFunction } from '../../types' import { hook } from '../../hook' -import { devtoolsContext, devtoolsPluginBuffer } from '../../ctx' +import { devtoolsContext, devtoolsInspector, devtoolsPluginBuffer } from '../../ctx' import { DevToolsPluginAPI } from '../../api' +import { initPluginSettings } from '../../core/plugin/plugin-settings' export * from './components' @@ -33,6 +34,13 @@ export function callDevToolsPluginSetupFn(plugin: [PluginDescriptor, PluginSetup } setupFn(api) + if (pluginDescriptor.settings) { + const inspector = devtoolsInspector.find(inspector => inspector.descriptor.id === pluginDescriptor.id) + if (inspector) { + inspector.descriptor.settings = pluginDescriptor.settings + initPluginSettings(inspector.options.id, pluginDescriptor.settings) + } + } } export function removeRegisteredPluginApp(app: App) { diff --git a/packages/devtools-kit/src/core/plugin/plugin-settings.ts b/packages/devtools-kit/src/core/plugin/plugin-settings.ts new file mode 100644 index 000000000..fdff2212e --- /dev/null +++ b/packages/devtools-kit/src/core/plugin/plugin-settings.ts @@ -0,0 +1,68 @@ +import { devtoolsPluginBuffer } from '../../ctx/plugin' +import { PluginDescriptor } from '../../types' +import { DevToolsV6PluginAPIHookKeys, devtoolsContext, getInspector } from '../../ctx' + +function _getSettings(settings: PluginDescriptor['settings']) { + const _settings = {} + Object.keys(settings!).forEach((key) => { + _settings[key] = settings![key].defaultValue + }) + + return _settings +} + +function getPluginLocalKey(pluginId: string) { + return `__VUE_DEVTOOLS_NEXT_PLUGIN_SETTINGS__${pluginId}__` +} + +export function getPluginSettingsOptions(pluginId: string) { + const descriptor = getInspector(pluginId)?.descriptor + const item = devtoolsPluginBuffer.find(item => item[0].id === descriptor?.id)?.[0] ?? null + return item?.settings ?? null +} + +export function getPluginSettings(pluginId: string, fallbackValue?: PluginDescriptor['settings']) { + const localKey = getPluginLocalKey(pluginId) + if (localKey) { + const localSettings = localStorage.getItem(localKey) + if (localSettings) { + return JSON.parse(localSettings) + } + } + + if (pluginId) { + const item = devtoolsPluginBuffer.find(item => item[0].id === pluginId)?.[0] ?? null + return _getSettings(item?.settings ?? {}) + } + return _getSettings(fallbackValue) +} + +export function initPluginSettings(pluginId: string, settings: PluginDescriptor['settings']) { + const localKey = getPluginLocalKey(pluginId) + const localSettings = localStorage.getItem(localKey) + if (!localSettings) { + localStorage.setItem(localKey, JSON.stringify(_getSettings(settings))) + } +} + +export function setPluginSettings(pluginId: string, key: string, value: string) { + const localKey = getPluginLocalKey(pluginId) + const localSettings = localStorage.getItem(localKey)! + const parsedLocalSettings = JSON.parse(localSettings || '{}') + const updated = { + ...parsedLocalSettings, + [key]: value, + } + localStorage.setItem(localKey, JSON.stringify(updated)) + + // @ts-expect-error hookable + devtoolsContext.hooks.callHookWith((callbacks) => { + callbacks.forEach(cb => cb({ + pluginId, + key, + oldValue: parsedLocalSettings[key], + newValue: value, + settings: updated, + })) + }, DevToolsV6PluginAPIHookKeys.SET_PLUGIN_SETTINGS) +} diff --git a/packages/devtools-kit/src/ctx/api.ts b/packages/devtools-kit/src/ctx/api.ts index da9276e77..8c0c60590 100644 --- a/packages/devtools-kit/src/ctx/api.ts +++ b/packages/devtools-kit/src/ctx/api.ts @@ -9,6 +9,7 @@ import { openInEditor } from '../core/open-in-editor' import { normalizeRouterInfo } from '../core/router' import { getComponentInspector } from '../core/component-inspector' import { registerDevToolsPlugin } from '../core/plugin' +import { getPluginSettings, getPluginSettingsOptions, setPluginSettings } from '../core/plugin/plugin-settings' import type { DevToolsContextHooks, DevToolsMessagingHooks, DevToolsV6PluginAPIHookPayloads } from './hook' import { DevToolsContextHookKeys, DevToolsV6PluginAPIHookKeys } from './hook' import { activeAppRecord, devtoolsAppRecords, setActiveAppRecord, setActiveAppRecordId } from './state' @@ -122,6 +123,15 @@ export function createDevToolsApi(hooks: Hookable