From a75be78e0d189d324c5f30ececb27cd1a61e7e77 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Tue, 1 Jun 2021 18:45:47 +0200 Subject: [PATCH] feat(devtools): add root state --- docs/.vitepress/theme/index.js | 4 +- docs/index.md | 4 +- src/devtools/formatting.ts | 78 ++++++++++++++++++++++++---------- src/devtools/plugin.ts | 55 ++++++++++++++---------- 4 files changed, 92 insertions(+), 49 deletions(-) diff --git a/docs/.vitepress/theme/index.js b/docs/.vitepress/theme/index.js index 4a1d56ee..bf5b9b08 100644 --- a/docs/.vitepress/theme/index.js +++ b/docs/.vitepress/theme/index.js @@ -2,7 +2,7 @@ import Theme from 'vitepress/theme' import { Layout } from './Layout' import './custom.css' import './code-theme.css' -// import { createPinia } from '../../../src' +import { createPinia } from '../../../src' /** @type {import('vitepress').Theme} */ const config = { @@ -11,7 +11,7 @@ const config = { Layout, enhanceApp({ app }) { - // app.use(createPinia()) + app.use(createPinia()) }, } diff --git a/docs/index.md b/docs/index.md index dd53b6dc..0bb20b45 100644 --- a/docs/index.md +++ b/docs/index.md @@ -24,12 +24,12 @@ footer: MIT Licensed | Copyright © 2019-present Eduardo San Martin Morote --- - + diff --git a/src/devtools/formatting.ts b/src/devtools/formatting.ts index 31465b1c..b37bb403 100644 --- a/src/devtools/formatting.ts +++ b/src/devtools/formatting.ts @@ -1,6 +1,7 @@ import { CustomInspectorNode, CustomInspectorState } from '@vue/devtools-api' -import { Store, GettersTree, MutationType, StateTree } from '../types' +import { Store, MutationType } from '../types' import { DebuggerEvent } from 'vue' +import { Pinia } from '../rootStore' export function formatDisplay(display: string) { return { @@ -10,36 +11,69 @@ export function formatDisplay(display: string) { } } -export function formatStoreForInspectorTree(store: Store): CustomInspectorNode { - return { - id: store.$id, - label: store.$id, - tags: [], - } +export const PINIA_ROOT_LABEL = '🍍 Pinia (root)' +export const PINIA_ROOT_ID = '_root' + +export function formatStoreForInspectorTree( + store: Store | Pinia +): CustomInspectorNode { + return '$id' in store + ? { + id: store.$id, + label: store.$id, + } + : { + id: PINIA_ROOT_ID, + label: PINIA_ROOT_LABEL, + } } export function formatStoreForInspectorState( - store: Store -): CustomInspectorState[string] { - const fields: CustomInspectorState[string] = [ - { editable: false, key: 'id', value: formatDisplay(store.$id) }, - { editable: true, key: 'state', value: store.$state }, - ] + store: Store | Pinia +): CustomInspectorState { + if (!('$id' in store)) { + const state: CustomInspectorState = { + state: Object.keys(store.state.value).map((storeId) => ({ + editable: true, + key: storeId, + value: store.state.value[storeId], + })), + } + // TODO: use this version when possible + // Object.keys(store.state.value).forEach((storeId) => { + // const currentState = store.state.value[storeId] + // state[storeId] = Object.keys(currentState).map((key) => ({ + // // is not possible to made editable because no way to get the storeId in + // // edit inspector state callback + // editable: false, + // key, + // value: currentState[key], + // })) + // }) + + return state + } + + const state: CustomInspectorState = { + state: Object.keys(store.$state).map((key) => ({ + editable: true, + key, + // @ts-expect-error + value: store.$state[key], + })), + } // avoid adding empty getters if (store._getters && store._getters.length) { - fields.push({ + state.getters = store._getters.map((getterName) => ({ editable: false, - key: 'getters', - value: store._getters.reduce((getters, key) => { - // @ts-expect-error - getters[key] = store[key] - return getters - }, {} as GettersTree), - }) + key: getterName, + // @ts-expect-error + value: store[getterName], + })) } - return fields + return state } export function formatEventData( diff --git a/src/devtools/plugin.ts b/src/devtools/plugin.ts index 330ebafa..9e90aae7 100644 --- a/src/devtools/plugin.ts +++ b/src/devtools/plugin.ts @@ -1,6 +1,6 @@ import { setupDevtoolsPlugin, TimelineEvent } from '@vue/devtools-api' import { App, ComponentPublicInstance } from 'vue' -import { PiniaPluginContext, setActivePinia } from '../rootStore' +import { Pinia, PiniaPluginContext, setActivePinia } from '../rootStore' import { Store, GettersTree, @@ -20,6 +20,8 @@ import { formatMutationType, formatStoreForInspectorState, formatStoreForInspectorTree, + PINIA_ROOT_ID, + PINIA_ROOT_LABEL, } from './formatting' import { toastMessage } from './utils' @@ -142,14 +144,19 @@ function addDevtools(app: App, store: Store) { api.on.getInspectorTree((payload) => { if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { - const stores = Array.from(registeredStores.values()) + let stores: Array = [store._p] + stores = stores.concat(Array.from(registeredStores.values())) payload.rootNodes = ( payload.filter ? stores.filter((store) => - store.$id - .toLowerCase() - .includes(payload.filter.toLowerCase()) + '$id' in store + ? store.$id + .toLowerCase() + .includes(payload.filter.toLowerCase()) + : PINIA_ROOT_LABEL.toLowerCase().includes( + payload.filter.toLowerCase() + ) ) : stores ).map(formatStoreForInspectorTree) @@ -158,28 +165,32 @@ function addDevtools(app: App, store: Store) { api.on.getInspectorState((payload) => { if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { - const store = registeredStores.get(payload.nodeId) + const inspectedStore = + payload.nodeId === PINIA_ROOT_ID + ? store._p + : registeredStores.get(payload.nodeId) - if (!store) { + if (!inspectedStore) { return toastMessage( `store "${payload.nodeId}" not found`, 'error' ) } - if (store) { - payload.state = { - options: formatStoreForInspectorState(store), - } + if (inspectedStore) { + payload.state = formatStoreForInspectorState(inspectedStore) } } }) - api.on.editInspectorState((payload) => { + api.on.editInspectorState((payload, ctx) => { if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { - const store = registeredStores.get(payload.nodeId) + const inspectedStore = + payload.nodeId === PINIA_ROOT_ID + ? store._p + : registeredStores.get(payload.nodeId) - if (!store) { + if (!inspectedStore) { return toastMessage( `store "${payload.nodeId}" not found`, 'error' @@ -187,17 +198,15 @@ function addDevtools(app: App, store: Store) { } const { path } = payload - if (path[0] !== 'state') { - return toastMessage( - `Invalid path for store "${payload.nodeId}":\n${path}\nOnly state can be modified.` - ) - } - // rewrite the first entry to be able to directly set the state as - // well as any other path - path[0] = '$state' + if ('$id' in inspectedStore) { + // access only the state + path.unshift('$state') + } else { + path.unshift('state', 'value') + } isTimelineActive = false - payload.set(store, path, payload.state.value) + payload.set(inspectedStore, path, payload.state.value) isTimelineActive = true } }) -- 2.47.2