Skip to content

Commit

Permalink
feat: vue query panel (#381)
Browse files Browse the repository at this point in the history
  • Loading branch information
webfansplz authored May 15, 2024
1 parent c6cc8c9 commit 62bbdd4
Show file tree
Hide file tree
Showing 24 changed files with 557 additions and 17 deletions.
1 change: 1 addition & 0 deletions packages/applet/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ import 'floating-vue/dist/style.css'
export * from './modules/pinia'
export * from './modules/components'
export * from './modules/router'
export * from './modules/vue-query'
export * from './modules/vuex'
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<template>
<svg viewBox="0 0 566 154" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="300 0 261.76 226.69">
<path fill="#ffd94c" stroke="#002c4b" stroke-width="32.63" d="M156.77 42.75L126.55 95.1 96.32 42.75h-48.3l78.53 136 78.53-136z" />
</svg>
<path d="M152.571 118V46.1333H176.8C183.576 46.1333 189.77 47.468 195.383 50.1373C200.995 52.8067 205.478 56.8449 208.832 62.252C212.186 67.5907 213.863 74.1956 213.863 82.0667C213.863 89.8693 212.186 96.4742 208.832 101.881C205.478 107.288 200.995 111.327 195.383 113.996C189.77 116.665 183.576 118 176.8 118H152.571ZM175.157 104.653C181.796 104.653 187.306 102.874 191.687 99.3147C196.067 95.6871 198.257 89.9378 198.257 82.0667C198.257 74.1956 196.067 68.4462 191.687 64.8187C187.306 61.1911 181.796 59.3773 175.157 59.3773H167.971V104.653H175.157ZM270.18 100.444C269.153 105.988 266.381 110.437 261.864 113.791C257.347 117.144 251.905 118.821 245.54 118.821C239.928 118.821 235.102 117.555 231.064 115.023C227.094 112.422 224.083 109.068 222.029 104.961C219.976 100.855 218.949 96.5427 218.949 92.0253C218.949 87.4396 219.873 83.1276 221.721 79.0893C223.638 75.0511 226.513 71.7658 230.345 69.2333C234.247 66.7009 238.969 65.4347 244.513 65.4347C250.263 65.4347 255.054 66.6667 258.887 69.1307C262.72 71.5947 265.526 74.7431 267.305 78.576C269.153 82.4089 270.077 86.4471 270.077 90.6907C270.077 92.2649 270.009 93.8049 269.872 95.3107H232.707C233.254 99.0067 234.623 101.916 236.813 104.037C239.072 106.091 241.981 107.117 245.54 107.117C248.415 107.117 250.776 106.57 252.624 105.475C254.472 104.311 255.67 102.634 256.217 100.444H270.18ZM244.513 75.9067C241.228 75.9067 238.627 76.7622 236.711 78.4733C234.794 80.116 233.528 82.7169 232.912 86.276H255.807C255.601 83.2644 254.506 80.8004 252.521 78.884C250.537 76.8991 247.867 75.9067 244.513 75.9067ZM302.77 118H289.629L270.738 66.256H285.317L296.2 99.7253L306.98 66.256H321.661L302.77 118ZM359.731 118H344.331V59.3773H323.079V46.1333H380.983V59.3773H359.731V118ZM402.364 118.821C397.163 118.821 392.474 117.692 388.299 115.433C384.124 113.106 380.873 109.924 378.546 105.885C376.219 101.779 375.055 97.1929 375.055 92.128C375.055 87.0631 376.219 82.5116 378.546 78.4733C380.873 74.3667 384.124 71.184 388.299 68.9253C392.474 66.5982 397.163 65.4347 402.364 65.4347C407.566 65.4347 412.255 66.5982 416.43 68.9253C420.605 71.184 423.856 74.3667 426.183 78.4733C428.51 82.5116 429.674 87.0631 429.674 92.128C429.674 97.1929 428.51 101.779 426.183 105.885C423.856 109.924 420.605 113.106 416.43 115.433C412.255 117.692 407.566 118.821 402.364 118.821ZM402.364 106.501C406.197 106.501 409.311 105.167 411.707 102.497C414.103 99.828 415.3 96.3716 415.3 92.128C415.3 87.816 414.103 84.3253 411.707 81.656C409.311 78.9867 406.197 77.652 402.364 77.652C398.531 77.652 395.417 78.9867 393.022 81.656C390.626 84.3253 389.428 87.816 389.428 92.128C389.428 96.3716 390.626 99.828 393.022 102.497C395.417 105.167 398.531 106.501 402.364 106.501ZM462.12 118.821C456.918 118.821 452.229 117.692 448.054 115.433C443.879 113.106 440.628 109.924 438.301 105.885C435.974 101.779 434.81 97.1929 434.81 92.128C434.81 87.0631 435.974 82.5116 438.301 78.4733C440.628 74.3667 443.879 71.184 448.054 68.9253C452.229 66.5982 456.918 65.4347 462.12 65.4347C467.321 65.4347 472.01 66.5982 476.185 68.9253C480.36 71.184 483.611 74.3667 485.938 78.4733C488.265 82.5116 489.429 87.0631 489.429 92.128C489.429 97.1929 488.265 101.779 485.938 105.885C483.611 109.924 480.36 113.106 476.185 115.433C472.01 117.692 467.321 118.821 462.12 118.821ZM462.12 106.501C465.952 106.501 469.067 105.167 471.462 102.497C473.858 99.828 475.056 96.3716 475.056 92.128C475.056 87.816 473.858 84.3253 471.462 81.656C469.067 78.9867 465.952 77.652 462.12 77.652C458.287 77.652 455.172 78.9867 452.777 81.656C450.381 84.3253 449.184 87.816 449.184 92.128C449.184 96.3716 450.381 99.828 452.777 102.497C455.172 105.167 458.287 106.501 462.12 106.501ZM512.327 118H498.056V43.772H512.327V118ZM542.494 118.821C536.129 118.821 530.961 117.179 526.991 113.893C523.09 110.54 521.002 106.091 520.729 100.547H533.049C533.322 102.874 534.281 104.722 535.923 106.091C537.634 107.391 539.825 108.041 542.494 108.041C544.684 108.041 546.464 107.562 547.833 106.604C549.27 105.646 549.989 104.448 549.989 103.011C549.989 101.094 549.167 99.7596 547.525 99.0067C545.882 98.2538 543.281 97.5693 539.722 96.9533C536.026 96.2689 533.014 95.516 530.687 94.6947C528.36 93.8733 526.341 92.4018 524.63 90.28C522.987 88.0898 522.166 85.0098 522.166 81.04C522.166 78.0284 522.953 75.3591 524.527 73.032C526.17 70.6364 528.394 68.7884 531.201 67.488C534.007 66.1191 537.155 65.4347 540.646 65.4347C546.874 65.4347 551.905 66.9747 555.738 70.0547C559.639 73.1347 561.727 77.2071 562.001 82.272H549.578C549.304 80.1502 548.312 78.5076 546.601 77.344C544.958 76.112 543.11 75.496 541.057 75.496C539.003 75.496 537.361 75.9409 536.129 76.8307C534.897 77.7204 534.281 78.9524 534.281 80.5267C534.281 82.4431 535.068 83.7436 536.642 84.428C538.285 85.044 540.851 85.5916 544.342 86.0707C548.106 86.6182 551.186 87.3027 553.582 88.124C556.046 88.8769 558.168 90.3827 559.947 92.6413C561.727 94.9 562.617 98.1853 562.617 102.497C562.617 107.425 560.769 111.395 557.073 114.407C553.445 117.35 548.585 118.821 542.494 118.821Z" fill="currentColor" />
</svg>
</template>
52 changes: 52 additions & 0 deletions packages/applet/src/modules/vue-query/components/Home.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<script setup lang="ts">
import DevToolsLogo from './DevToolsLogo.vue'
import { useVirtualRouter } from '~/composables/virtual-router'
const virtualRouter = useVirtualRouter()
</script>

<template>
<div h-full w-full flex items-center>
<div flex="~ col gap2" ma px-5>
<div flex-auto />

<!-- Banner -->
<div flex="~ col" mt-20 items-center>
<div flex="~" mt--10 items-center justify-center>
<DevToolsLogo h-18 />
</div>
<div mb6 mt--1 text-center text-sm flex="~ gap-1">
<span op40>
Vue Query DevTools
</span>
</div>
</div>

<div flex-auto />

<div flex="~ gap2 wrap">
<div flex="~ col auto" min-w-40 p4 theme-card-lime @click="virtualRouter.push('/state')">
<div i-carbon-tree-view-alt text-3xl />
<code>State</code>
</div>
<div flex="~ col auto" min-w-40 p4 theme-card-lime @click="virtualRouter.push('/timeline')">
<div i-mdi:timeline-clock-outline text-3xl />
<div>Timeline</div>
</div>
</div>

<div flex="~ gap-6 wrap" mt-5 items-center justify-center>
<a href="https://github.com/TanStack/query/tree/main/packages/vue-query/" target="_blank" flex="~ gap1" items-center op50 hover="op100 text-blue" transition>
<div i-carbon-star />
Star on GitHub
</a>
<a href="https://tanstack.com/query/latest/docs/framework/vue/overview/" target="_blank" flex="~ gap1" items-center op50 hover="op100 text-yellow" transition>
<div i-carbon-document />
View Documentation
</a>
</div>

<div flex-auto />
</div>
</div>
</template>
130 changes: 130 additions & 0 deletions packages/applet/src/modules/vue-query/components/state/Index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { Pane, Splitpanes } from 'splitpanes'
import { callInspectorNodeAction, getInspectorNodeActions, getInspectorState, getInspectorTree, onInspectorStateUpdated, onInspectorTreeUpdated } from '@vue/devtools-core'
import { parse } from '@vue/devtools-kit'
import type { InspectorNodeTag, InspectorState } from '@vue/devtools-kit'
import { vTooltip } from '@vue/devtools-ui'
import Navbar from '~/components/basic/Navbar.vue'
import SelectiveList from '~/components/basic/SelectiveList.vue'
import DevToolsHeader from '~/components/basic/DevToolsHeader.vue'
import Empty from '~/components/basic/Empty.vue'
import RootStateViewer from '~/components/state/RootStateViewer.vue'
import { createExpandedContext } from '~/composables/toggle-expanded'
const { expanded: expandedStateNodes } = createExpandedContext('vue-query-state')
interface NodeAction {
icon: string
tooltip: string
actions?: (payload: unknown) => void
}
const inspectorId = 'vue-query'
const nodeActions = ref<NodeAction[]>([])
const selected = ref('')
const tree = ref<{ id: string, label: string, tags: InspectorNodeTag[] }[]>([])
const state = ref<Record<string, InspectorState[]>>({})
const emptyState = computed(() => !Object.keys(state.value).length)
function getNodeActions() {
getInspectorNodeActions(inspectorId).then((actions) => {
nodeActions.value = actions as NodeAction[]
})
}
getNodeActions()
function callNodeAction(index: number) {
callInspectorNodeAction(inspectorId, index, selected.value)
}
function filterEmptyState(data: Record<string, InspectorState[]>) {
for (const key in data) {
if (!data[key]?.length)
delete data[key]
}
return data
}
function getVueQueryState(nodeId: string) {
getInspectorState({ inspectorId, nodeId }).then((data) => {
state.value = filterEmptyState(parse(data!))
expandedStateNodes.value = Array.from({ length: Object.keys(state.value).length }, (_, i) => `${i}`)
})
}
function clearVueQueryState() {
state.value = {}
}
watch(selected, () => {
clearVueQueryState()
getVueQueryState(selected.value)
})
const getVueQueryInspectorTree = () => {
getInspectorTree({ inspectorId, filter: '' }).then((_data) => {
const data = parse(_data!)
tree.value = data
if (!selected.value && data.length) {
selected.value = data[0].id
getVueQueryState(data[0].id)
}
})
}
getVueQueryInspectorTree()
onInspectorTreeUpdated((data) => {
if (!data?.data.length || data.inspectorId !== inspectorId)
return
tree.value = data.data as unknown as { id: string, label: string, tags: InspectorNodeTag[] }[]
if ((!selected.value && data.data.length) || (selected.value && !data.data.find(node => node.id === selected.value))) {
selected.value = data.data[0].id
getVueQueryState(data.data[0].id)
}
})
onInspectorStateUpdated((data) => {
if (!data || data.inspectorId !== inspectorId)
return
state.value = filterEmptyState(data as any)
expandedStateNodes.value = Array.from({ length: Object.keys(state.value).length }, (_, i) => `${i}`)
})
</script>

<template>
<div class="h-full flex flex-col">
<DevToolsHeader doc-link="https://tanstack.com/query/latest/docs/framework/vue/overview/" github-repo-link="https://github.com/TanStack/query/tree/main/packages/vue-query/">
<Navbar />
</DevToolsHeader>
<template v-if="tree.length">
<Splitpanes class="flex-1 overflow-auto">
<Pane border="r base" size="40" h-full>
<div h-full select-none overflow-scroll class="no-scrollbar">
<SelectiveList v-model="selected" :data="tree" />
</div>
</Pane>
<Pane size="60">
<div class="h-full flex flex-col p2">
<div class="flex justify-end pb-1" border="b dashed base">
<div class="flex items-center gap-2 px-1">
<div v-for="(action, index) in nodeActions" :key="index" v-tooltip.bottom-end="{ content: action.tooltip }" class="flex items-center gap1" @click="callNodeAction(index)">
<i :class="`i-ic-baseline-${action.icon.replace(/\_/g, '-')}`" cursor-pointer op70 text-base hover:op100 />
</div>
</div>
</div>
<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" />
<Empty v-else>
No Data
</Empty>
</div>
</Pane>
</Splitpanes>
</template>
<Empty v-else>
No Data
</Empty>
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script setup lang="ts">
import Timeline from '~/components/timeline/index.vue'
const LAYER_IDS = ['vue-query']
</script>

<template>
<Timeline :layer-ids="LAYER_IDS" doc-link="https://tanstack.com/query/latest/docs/framework/vue/overview/" github-repo-link="https://github.com/TanStack/query/tree/main/packages/vue-query/" />
</template>
5 changes: 5 additions & 0 deletions packages/applet/src/modules/vue-query/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import VueQuery from './index.vue'

export {
VueQuery,
}
36 changes: 36 additions & 0 deletions packages/applet/src/modules/vue-query/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
import Home from './components/Home.vue'
import State from './components/state/Index.vue'
import Timeline from './components/timeline/Index.vue'
import { registerVirtualRouter } from '~/composables/virtual-router'
import { createDevToolsConnectStateContext } from '~/composables/connect-state'
createDevToolsConnectStateContext()
const { VirtualRouterView } = registerVirtualRouter([
{
path: '/',
name: 'Home',
component: Home,
icon: 'https://raw.githubusercontent.com/TanStack/query/main/packages/vue-query/media/vue-query.svg',
},
{
path: '/state',
name: 'State',
component: State,
icon: 'i-carbon-tree-view-alt',
},
{
path: '/timeline',
name: 'Timeline',
component: Timeline,
icon: 'i-mdi:timeline-clock-outline',
},
])
</script>

<template>
<div h-full w-full>
<VirtualRouterView />
</div>
</template>
6 changes: 6 additions & 0 deletions packages/applet/uno.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,11 @@ export default defineConfig(mergeConfigs([unoConfig, {
'literal-state-type',
'boolean-state-type',
'null-state-type',
'i-ic-baseline-alarm',
'i-ic-baseline-file-download',
'i-ic-baseline-delete',
'i-ic-baseline-settings-backup-restore',
'i-ic-baseline-hourglass-empty',
'i-ic-baseline-error-outline',
],
}])) as any
8 changes: 8 additions & 0 deletions packages/client/src/constants/tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ export const builtinTab: [string, ModuleBuiltinTab[]][] = [
path: 'pinia',
title: 'Pinia',
},
{
icon: 'https://raw.githubusercontent.com/TanStack/query/main/packages/vue-query/media/vue-query.svg',
name: 'vueQuery',
order: -100,
path: 'vue-query',
title: 'VueQuery',
},
{
icon: 'i-ic-baseline-storage',
name: 'vuex',
Expand Down Expand Up @@ -84,6 +91,7 @@ export const viteOnlyTabs = [
type Detective = NonNullable<DevtoolsBridgeAppRecord['moduleDetectives']>

const moduleDetectivesMapping = {
vueQuery: 'vueQuery',
pinia: 'pinia',
vuex: 'vuex',
router: 'vueRouter',
Expand Down
2 changes: 2 additions & 0 deletions packages/client/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import PiniaPage from '~/pages/pinia.vue'
import VuexPage from '~/pages/vuex.vue'
import RouterPage from '~/pages/router.vue'
import I18nPage from '~/pages/i18n.vue'
import VueQueryPage from '~/pages/vue-query.vue'
import Pages from '~/pages/pages.vue'
import Assets from '~/pages/assets.vue'
import Graph from '~/pages/graph.vue'
Expand All @@ -32,6 +33,7 @@ const routes = [
{ path: '/pinia', component: PiniaPage },
{ path: '/vuex', component: VuexPage },
{ path: '/router', component: RouterPage },
{ path: '/vue-query', component: VueQueryPage },
{ path: '/i18n', component: I18nPage },
{ path: '/pages', component: Pages },
{ path: '/assets', component: Assets },
Expand Down
8 changes: 8 additions & 0 deletions packages/client/src/pages/vue-query.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script setup lang="ts">
import { VueQuery as VueQueryPanel } from '@vue/devtools-applet'
import '@vue/devtools-applet/style.css'
</script>

<template>
<VueQueryPanel />
</template>
8 changes: 8 additions & 0 deletions packages/core/src/bridge-events/devtools-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ export const getInspectorTree = defineDevToolsAction('devtools:inspector-tree',
return stringify(res) as string
})

export const getInspectorNodeActions = defineDevToolsAction('devtools:inspector-node-actions', (devtools, payload) => {
return devtools.api.getInspectorNodeActions(payload)
})

export const callInspectorNodeAction = defineDevToolsAction('devtools:call-inspector-node-action', (devtools, inspectorId: string, actionIndex: number, nodeId: string) => {
return devtools.api.callInspectorNodeAction(inspectorId, actionIndex, nodeId)
})

export const getComponentBoundingRect = defineDevToolsAction('devtools:get-component-bounding-rect', (devtools, payload) => {
return devtools.api.getComponentBoundingRect(payload)
})
Expand Down
2 changes: 2 additions & 0 deletions packages/devtools-kit/__tests__/api/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,15 @@ describe('devtools api', () => {
// Originated from https://github.com/vuejs/devtools-next/blob/main/packages/devtools-kit/src/plugins/component.ts#L20-L24
const componentInspector = {
id: 'components',
nodeActions: [],
nodeId: '',
filter: '',
treeFilterPlaceholder: 'Search components',
}
const inspectorData = {
id: 'vueuse',
label: 'VueUse',
nodeActions: [],
nodeId: '',
filter: '',
treeFilterPlaceholder: 'Search',
Expand Down
24 changes: 17 additions & 7 deletions packages/devtools-kit/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,25 @@ export class DevToolsPluginApi {
nodeId: '',
filter: '',
treeFilterPlaceholder: payload.treeFilterPlaceholder || '',
nodeActions: payload.nodeActions || [],
})
}

// get inspector node action
getInspectorNodeActions(inspectorId: string) {
const inspector = getInspector(inspectorId)
return inspector?.nodeActions?.map(({ icon, tooltip }) => ({ icon, tooltip })) || []
}

// call inspector node action
callInspectorNodeAction(inspectorId: string, actionIndex: number, nodeId: string) {
const inspector = getInspector(inspectorId)
if (inspector && inspector.nodeActions) {
const item = inspector.nodeActions[actionIndex]
item.action?.(nodeId)
}
}

highlightElement(instance: VueAppInstance) {
highlightElement(instance)
}
Expand Down Expand Up @@ -105,7 +121,7 @@ export class DevToolsPluginApi {
// @ts-expect-error TODO: types
const state = _payload.state

delete state.instance
delete state?.instance
return state
}

Expand Down Expand Up @@ -166,12 +182,6 @@ export class DevToolsPluginApi {
return nowFn()
}

getSettings() {
return {
logStoreChanges: null,
}
}

// #endregion compatible with old devtools

// #region highlighter
Expand Down
1 change: 1 addition & 0 deletions packages/devtools-kit/src/api/on.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const on = {
visitComponentTree(fn: DevToolsEvent[DevToolsEvents.VISIT_COMPONENT_TREE]) {
registerInstanceHook(DevToolsEvents.VISIT_COMPONENT_TREE, fn)
},
setPluginSettings() {},
getInspectorTree(fn: DevToolsEvent[DevToolsEvents.GET_INSPECTOR_TREE]) {
registerInstanceHook(DevToolsEvents.GET_INSPECTOR_TREE, fn)
},
Expand Down
Loading

0 comments on commit 62bbdd4

Please sign in to comment.