Skip to content

Commit c6cc8c9

Browse files
feat: vuex panel (#289)
Co-authored-by: arlo <[email protected]>
1 parent 07a840e commit c6cc8c9

File tree

30 files changed

+449
-293
lines changed

30 files changed

+449
-293
lines changed
File renamed without changes.
File renamed without changes.
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<script setup lang="ts">
2+
import { Pane, Splitpanes } from 'splitpanes'
3+
import { onAddTimelineEvent } from '@vue/devtools-core'
4+
import { computed, ref } from 'vue'
5+
6+
import type { InspectorState, TimelineEvent } from '@vue/devtools-kit'
7+
import EventList from './EventList.vue'
8+
import Navbar from '~/components/basic/Navbar.vue'
9+
import Empty from '~/components/basic/Empty.vue'
10+
import RootStateViewer from '~/components/state/RootStateViewer.vue'
11+
import { createExpandedContext } from '~/composables/toggle-expanded'
12+
import DevToolsHeader from '~/components/basic/DevToolsHeader.vue'
13+
14+
const props = defineProps<{
15+
layerIds: string[]
16+
docLink: string
17+
githubRepoLink: string
18+
}>()
19+
20+
const { expanded: expandedStateNodes } = createExpandedContext('timeline-state')
21+
22+
// event info + group info = [0, 1]
23+
expandedStateNodes.value = ['0', '1']
24+
25+
const eventList = ref<TimelineEvent['event'][]>([])
26+
const groupList = ref<Map<number, TimelineEvent['event'][]>>(new Map())
27+
const selectedEventIndex = ref(0)
28+
const selectedEventInfo = computed(() => eventList.value[selectedEventIndex.value] ?? null)
29+
// event info
30+
const normalizedEventInfo = computed(() => {
31+
const info: InspectorState[] = []
32+
for (const key in selectedEventInfo.value?.data) {
33+
info.push({
34+
key,
35+
type: key,
36+
editable: false,
37+
value: selectedEventInfo.value.data[key]!,
38+
})
39+
}
40+
return info
41+
})
42+
// group info
43+
const normalizedGroupInfo = computed(() => {
44+
const groupId = selectedEventInfo.value?.groupId
45+
const groupInfo = groupList.value.get(groupId)!
46+
if (groupInfo) {
47+
const duration = groupInfo[groupInfo.length - 1]?.time - (groupInfo[0]?.time ?? 0)
48+
return [{
49+
key: 'events',
50+
type: 'events',
51+
editable: false,
52+
value: groupInfo.length,
53+
}, duration && {
54+
key: 'duration',
55+
type: 'duration',
56+
editable: false,
57+
value: `${duration}ms`,
58+
}].filter(Boolean)
59+
}
60+
return undefined
61+
})
62+
63+
// normalize display info
64+
const displayedInfo = computed(() => {
65+
return { 'Event Info': normalizedEventInfo.value, ...(normalizedGroupInfo.value && { 'Group Info': normalizedGroupInfo.value }) } as unknown as Record<string, InspectorState[]>
66+
})
67+
68+
function normalizeGroupList(event: TimelineEvent['event']) {
69+
const groupId = event.groupId
70+
if (groupId !== undefined) {
71+
groupList.value.set(groupId, groupList.value.get(groupId) ?? [])
72+
groupList.value.get(groupId)?.push(event)
73+
}
74+
}
75+
76+
onAddTimelineEvent((payload) => {
77+
if (!payload)
78+
return
79+
80+
const { layerId, event } = payload
81+
if (!props.layerIds.includes(layerId))
82+
return
83+
84+
eventList.value.push(event)
85+
normalizeGroupList(event)
86+
})
87+
</script>
88+
89+
<template>
90+
<div class="h-full flex flex-col">
91+
<DevToolsHeader :doc-link="docLink" :github-repo-link="githubRepoLink">
92+
<Navbar />
93+
</DevToolsHeader>
94+
<template v-if="eventList.length">
95+
<div class="flex-1 overflow-hidden">
96+
<Splitpanes class="h-full">
97+
<Pane border="r base" size="40" h-full>
98+
<div h-full select-none overflow-scroll class="no-scrollbar">
99+
<EventList v-model="selectedEventIndex" :data="eventList" />
100+
</div>
101+
</Pane>
102+
<Pane size="60">
103+
<div h-full select-none overflow-scroll class="no-scrollbar">
104+
<RootStateViewer class="p3" :data="displayedInfo" node-id="" inspector-id="" :disable-edit="true" expanded-state-id="timeline-state" />
105+
</div>
106+
</Pane>
107+
</Splitpanes>
108+
</div>
109+
</template>
110+
<Empty v-else class="flex-1">
111+
No events
112+
</Empty>
113+
</div>
114+
</template>

packages/applet/src/components/tree/TreeViewer.vue

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import type { ComponentTreeNode } from '@vue/devtools-kit'
2+
import type { ComponentTreeNode, InspectorTree } from '@vue/devtools-kit'
33
import ToggleExpanded from '~/components/basic/ToggleExpanded.vue'
44
import ComponentTreeViewer from '~/components/tree/TreeViewer.vue'
55
import NodeTag from '~/components/basic/NodeTag.vue'
@@ -8,7 +8,7 @@ import { useToggleExpanded } from '~/composables/toggle-expanded'
88
import { useSelect } from '~/composables/select'
99
1010
withDefaults(defineProps<{
11-
data: ComponentTreeNode[]
11+
data: ComponentTreeNode[] | InspectorTree[]
1212
depth: number
1313
}>(), {
1414
depth: 0,
@@ -17,6 +17,10 @@ const selectedNodeId = defineModel()
1717
const { expanded, toggleExpanded } = useToggleExpanded()
1818
const { select: _select } = useSelect()
1919
20+
function normalizeLabel(item: ComponentTreeNode | InspectorTree) {
21+
return ('name' in item && item?.name) || ('label' in item && item.label)
22+
}
23+
2024
function select(id: string) {
2125
selectedNodeId.value = id
2226
}
@@ -46,7 +50,7 @@ function select(id: string) {
4650
<span v-else pl5 />
4751
<span font-state-field text-4>
4852
<span class="text-gray-400 dark:text-gray-600 group-hover:(text-white op50) [.active_&]:(op50 text-white!)">&lt;</span>
49-
<span group-hover:text-white class="ws-nowrap [.active_&]:(text-white)">{{ item.name }}</span>
53+
<span group-hover:text-white class="ws-nowrap [.active_&]:(text-white)">{{ normalizeLabel(item) }}</span>
5054
<span class="text-gray-400 dark:text-gray-600 group-hover:(text-white op50) [.active_&]:(op50 text-white!)">&gt;</span>
5155
</span>
5256
<NodeTag v-for="(_item, _index) in item.tags" :key="_index" :tag="_item" />

packages/applet/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ import 'floating-vue/dist/style.css'
66
export * from './modules/pinia'
77
export * from './modules/components'
88
export * from './modules/router'
9+
export * from './modules/vuex'

packages/applet/src/modules/pinia/components/store/Index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Pane, Splitpanes } from 'splitpanes'
44
import { getInspectorState, getInspectorTree, onInspectorStateUpdated, onInspectorTreeUpdated } from '@vue/devtools-core'
55
import { parse } from '@vue/devtools-kit'
66
import type { InspectorNodeTag, InspectorState } from '@vue/devtools-kit'
7-
import Navbar from '../Navbar.vue'
7+
import Navbar from '~/components/basic/Navbar.vue'
88
import SelectiveList from '~/components/basic/SelectiveList.vue'
99
import DevToolsHeader from '~/components/basic/DevToolsHeader.vue'
1010
import Empty from '~/components/basic/Empty.vue'
Lines changed: 3 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,9 @@
11
<script setup lang="ts">
2-
import { Pane, Splitpanes } from 'splitpanes'
3-
import { onAddTimelineEvent } from '@vue/devtools-core'
4-
import { computed, ref } from 'vue'
2+
import Timeline from '~/components/timeline/index.vue'
53
6-
import type { InspectorState, TimelineEvent } from '@vue/devtools-kit'
7-
import Navbar from '../Navbar.vue'
8-
import EventList from './EventList.vue'
9-
import Empty from '~/components/basic/Empty.vue'
10-
import RootStateViewer from '~/components/state/RootStateViewer.vue'
11-
import { createExpandedContext } from '~/composables/toggle-expanded'
12-
import DevToolsHeader from '~/components/basic/DevToolsHeader.vue'
13-
14-
const { expanded: expandedStateNodes } = createExpandedContext('timeline-state')
15-
16-
// event info + group info = [0, 1]
17-
expandedStateNodes.value = ['0', '1']
18-
19-
const LAYER_ID = 'pinia:mutations'
20-
const eventList = ref<TimelineEvent['event'][]>([])
21-
const groupList = ref<Map<number, TimelineEvent['event'][]>>(new Map())
22-
const selectedEventIndex = ref(0)
23-
const selectedEventInfo = computed(() => eventList.value[selectedEventIndex.value] ?? null)
24-
// event info
25-
const normalizedEventInfo = computed(() => {
26-
const info: InspectorState[] = []
27-
for (const key in selectedEventInfo.value?.data) {
28-
info.push({
29-
key,
30-
type: key,
31-
editable: false,
32-
value: selectedEventInfo.value.data[key]!,
33-
})
34-
}
35-
return info
36-
})
37-
// group info
38-
const normalizedGroupInfo = computed(() => {
39-
const groupId = selectedEventInfo.value?.groupId
40-
const groupInfo = groupList.value.get(groupId)!
41-
if (groupInfo) {
42-
const duration = groupInfo[groupInfo.length - 1]?.time - (groupInfo[0]?.time ?? 0)
43-
return [{
44-
key: 'events',
45-
type: 'events',
46-
editable: false,
47-
value: groupInfo.length,
48-
}, duration && {
49-
key: 'duration',
50-
type: 'duration',
51-
editable: false,
52-
value: `${duration}ms`,
53-
}].filter(Boolean)
54-
}
55-
return undefined
56-
})
57-
58-
// normalize display info
59-
const displayedInfo = computed(() => {
60-
return { 'Event Info': normalizedEventInfo.value, ...(normalizedGroupInfo.value && { 'Group Info': normalizedGroupInfo.value }) } as unknown as Record<string, InspectorState[]>
61-
})
62-
63-
function normalizeGroupList(event: TimelineEvent['event']) {
64-
const groupId = event.groupId
65-
if (groupId !== undefined) {
66-
groupList.value.set(groupId, groupList.value.get(groupId) ?? [])
67-
groupList.value.get(groupId)?.push(event)
68-
}
69-
}
70-
71-
onAddTimelineEvent((payload) => {
72-
if (!payload)
73-
return
74-
75-
const { layerId, event } = payload
76-
if (layerId !== LAYER_ID)
77-
return
78-
79-
eventList.value.push(event)
80-
normalizeGroupList(event)
81-
})
4+
const LAYER_IDS = ['pinia:mutations']
825
</script>
836

847
<template>
85-
<div class="h-full flex flex-col">
86-
<DevToolsHeader doc-link="https://pinia.vuejs.org/" github-repo-link="https://github.com/vuejs/pinia">
87-
<Navbar />
88-
</DevToolsHeader>
89-
<template v-if="eventList.length">
90-
<div class="flex-1 overflow-hidden">
91-
<Splitpanes class="h-full">
92-
<Pane border="r base" size="40" h-full>
93-
<div h-full select-none overflow-scroll class="no-scrollbar">
94-
<EventList v-model="selectedEventIndex" :data="eventList" />
95-
</div>
96-
</Pane>
97-
<Pane size="60">
98-
<div h-full select-none overflow-scroll class="no-scrollbar">
99-
<RootStateViewer class="p3" :data="displayedInfo" node-id="" inspector-id="" :disable-edit="true" expanded-state-id="timeline-state" />
100-
</div>
101-
</Pane>
102-
</Splitpanes>
103-
</div>
104-
</template>
105-
<Empty v-else class="flex-1">
106-
No events
107-
</Empty>
108-
</div>
8+
<Timeline :layer-ids="LAYER_IDS" doc-link="https://pinia.vuejs.org/" github-repo-link="https://github.com/vuejs/pinia" />
1099
</template>

packages/applet/src/modules/router/components/Navbar.vue

Lines changed: 0 additions & 22 deletions
This file was deleted.

packages/applet/src/modules/router/components/routes/Index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Pane, Splitpanes } from 'splitpanes'
44
import { getInspectorState, getInspectorTree, onInspectorStateUpdated, onInspectorTreeUpdated } from '@vue/devtools-core'
55
import { parse } from '@vue/devtools-kit'
66
import type { InspectorNodeTag, InspectorState } from '@vue/devtools-kit'
7-
import Navbar from '../Navbar.vue'
7+
import Navbar from '~/components/basic/Navbar.vue'
88
import SelectiveList from '~/components/basic/SelectiveList.vue'
99
import DevToolsHeader from '~/components/basic/DevToolsHeader.vue'
1010
import Empty from '~/components/basic/Empty.vue'

packages/applet/src/modules/router/components/timeline/EventList.vue

Lines changed: 0 additions & 57 deletions
This file was deleted.

0 commit comments

Comments
 (0)