-
-
Notifications
You must be signed in to change notification settings - Fork 77
Expand file tree
/
Copy pathPluginDetailsLoader.vue
More file actions
183 lines (170 loc) · 5.73 KB
/
PluginDetailsLoader.vue
File metadata and controls
183 lines (170 loc) · 5.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
<script setup lang="ts">
import type { SessionContext } from '~~/shared/types'
import { useRoute } from '#app/composables/router'
import { useRpc } from '#imports'
import { useAsyncState } from '@vueuse/core'
import { computed } from 'vue'
import { settings } from '~~/app/state/settings'
import { formatDuration } from '~/utils/format'
const props = defineProps<{
session: SessionContext
}>()
const emit = defineEmits<{
(e: 'close'): void
}>()
const route = useRoute()
const rpc = useRpc()
const { state, isLoading } = useAsyncState(
async () => {
const res = await rpc.value!['vite:rolldown:get-plugin-details']?.({
session: props.session.id,
id: route.query.plugin as string,
})
return res
},
null,
)
const processedModules = computed(() => {
const seen = new Set()
return state.value?.calls?.filter((call) => {
if (seen.has(call.module)) {
return false
}
seen.add(call.module)
return true
}) ?? []
})
type Interval = [number, number]
function calculateTotalDuration(intervals: Interval[]): number {
if (!intervals?.length)
return 0
const arr = intervals
.sort((a, b) => a[0] - b[0])
let total = 0
let [currentStart, currentEnd] = arr[0]!
for (let i = 1; i < arr.length; i++) {
const [start, end] = arr[i]!
// Non-overlapping time intervals, add the time to the total duration, and update the current time interval
if (start > currentEnd) {
total += (currentEnd - currentStart)
currentStart = start
currentEnd = end
}
else {
// Overlap time intervals are directly merged
currentEnd = Math.max(currentEnd, end)
}
}
// Add the last time interval to the total duration
total += (currentEnd - currentStart)
return total
}
const hookLoadDuration = computed(() =>
calculateTotalDuration(state.value?.loadMetrics.map(item => [item.timestamp_start, item.timestamp_end]) ?? []),
)
const hookTransformDuration = computed(() =>
calculateTotalDuration(state.value?.transformMetrics.map(item => [item.timestamp_start, item.timestamp_end]) ?? []),
)
const hookResolveIdDuration = computed(() =>
calculateTotalDuration(state.value?.resolveIdMetrics.map(item => [item.timestamp_start, item.timestamp_end]) ?? []),
)
const totalDuration = computed(() =>
calculateTotalDuration(state.value?.calls?.map(item => [item.timestamp_start, item.timestamp_end]) ?? []),
)
</script>
<template>
<VisualLoading v-if="isLoading" />
<div v-else-if="state?.calls?.length" relative h-full w-full>
<DisplayCloseButton
absolute right-2 top-1.5
@click="emit('close')"
/>
<div
bg-glass absolute left-2 top-2 z-panel-content p2
border="~ base rounded-lg"
flex="~ col gap-2"
>
<DisplayPluginName :name="state?.plugin_name!" />
<div text-xs font-mono flex="~ items-center gap-3" ml2>
<DisplayDuration
:duration="hookResolveIdDuration" flex="~ gap-1 items-center"
:title="`Resolve Id hooks cost: ${formatDuration(hookResolveIdDuration, true)}`"
>
<span i-ph-magnifying-glass-duotone inline-block />
</DisplayDuration>
<DisplayDuration
:duration="hookLoadDuration" flex="~ gap-1 items-center"
:title="`Load hooks cost: ${formatDuration(hookLoadDuration, true)}`"
>
<span i-ph-upload-simple-duotone inline-block />
</DisplayDuration>
<DisplayDuration
:duration="hookTransformDuration" flex="~ gap-1 items-center"
:title="`Transform hooks cost: ${formatDuration(hookTransformDuration, true)}`"
>
<span i-ph-magic-wand-duotone inline-block />
</DisplayDuration>
<span op40>|</span>
<DisplayDuration
:duration="totalDuration" flex="~ gap-1 items-center"
:title="`Total build cost: ${formatDuration(totalDuration, true)}`"
>
<span i-ph-clock-duotone inline-block />
</DisplayDuration>
<span op40>|</span>
<DisplayNumberBadge
:number="processedModules.length" icon="i-catppuccin-java-class-abstract"
color="transparent color-scale-neutral"
:title="`Module processed: ${processedModules.length}`"
/>
<span op40>|</span>
<DisplayNumberBadge
:number="state?.calls?.length ?? 0" icon="i-ph:arrow-counter-clockwise"
color="transparent color-scale-neutral"
:title="`Total calls: ${state?.calls?.length ?? 0}`"
/>
</div>
<div flex="~ gap-2">
<button
:class="settings.pluginDetailsViewType === 'flow' ? 'text-primary' : ''"
flex="~ gap-2 items-center justify-center"
px2 py1 w-40
border="~ base rounded-lg"
hover="bg-active"
@click="settings.pluginDetailsViewType = 'flow'"
>
<div i-ph-git-branch-duotone rotate-180 />
Build Flow
</button>
<button
:class="settings.pluginDetailsViewType === 'charts' ? 'text-primary' : ''"
flex="~ gap-2 items-center justify-center"
px2 py1 w-40
border="~ base rounded-lg"
hover="bg-active"
@click="settings.pluginDetailsViewType = 'charts'"
>
<div i-ph-chart-donut-duotone />
Charts
</button>
</div>
</div>
<div of-auto h-full pt-30>
<FlowmapPluginFlow
v-if="settings.pluginDetailsViewType === 'flow'"
:session="session"
:build-metrics="state"
/>
<ChartPluginFlamegraph
v-if="settings.pluginDetailsViewType === 'charts'"
:session="session"
:build-metrics="state"
/>
</div>
</div>
<div v-else flex="~ items-center justify-center" w-full h-full>
<span italic op50>
No data
</span>
</div>
</template>