Skip to content

Commit

Permalink
feat(timeline): list view
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Jul 13, 2023
1 parent c48176c commit 9601cb4
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 70 deletions.
73 changes: 73 additions & 0 deletions packages/devtools/client/components/TimelineList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<script setup lang="ts">
import type { TimelineEvent, TimelineMetrics } from '../../types'
defineProps<{
data: TimelineMetrics
}>()
const emit = defineEmits<{
(event: 'select', record: TimelineEvent): void
}>()
</script>

<template>
<div border="t base" flex="~ col" h-full of-y-auto text-sm>
<button
v-for="event, idx in data.events" :key="idx"
border="b base" px3 py2
flex="~ items-center gap-2"
hover="bg-active"
@click="emit('select', event)"
>
<template v-if="event.type === 'function'">
<div i-carbon-function op50 />
<div
font-mono
:style="{
color: event.type === 'function'
? getHashColorFromString(event.name, 50, 60)
: '',
}"
>
{{ event.name }}
</div>
<div flex="~" font-mono>
<div op30>
(
</div>
<template v-for="a, idx in event.args " :key="idx">
<div v-if="idx" mr2 op30>
,
</div>
<div op75>
{{ a === null ? 'null' : a === undefined ? 'undefined' : typeof a === 'function' ? `[function]` : Array.isArray(a) ? '[Array]' : typeof a === 'object' ? '[object]' : JSON.stringify(a) }}
</div>
</template>
<div op30>
)
</div>
</div>
</template>
<template v-else>
<div mr-1 h-7 w-7 flex rounded-lg bg-primary:5 p1 text-green6>
<div i-carbon-direction-rotary-right ma text-lg />
</div>
<div flex="~ col items-start">
<div text-xs font-mono op30>
{{ event.from }}
</div>
<div font-bold font-mono text-green>
{{ event.to }}
</div>
</div>
</template>
<div flex-auto />
<DurationDisplay
v-if="event.end"
:duration="event.end - event.start"
:color="event.type === 'function'"
/>
</button>
<div min-h-100 />
</div>
</template>
107 changes: 52 additions & 55 deletions packages/devtools/client/components/TimelineTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,72 +74,69 @@ useEventListener(scroller, 'wheel', (e: WheelEvent) => {
</script>

<template>
<div h-screen w-full flex flex-col>
<slot />
<div relative>
<div ref="minimap" border="t b base" relative h-50px ws-nowrap border-base>
<div relative>
<div ref="minimap" border="t b base" relative h-50px ws-nowrap border-base>
<div
v-for="segment, idx of segments"
:key="idx"
relative h-full flex-inline
:style="{
width: `${Math.max(100, segment.duration / 10) / (scrollWidth) * 100}%`,
}"
>
<div
v-for="segment, idx of segments"
:key="idx"
relative h-full flex-inline
v-for="item, iidx of segment.functions"
:key="iidx"
h-3px rounded
:style="{
width: `${Math.max(100, segment.duration / 10) / (scrollWidth) * 100}%`,
width: `max(${item.relativeWidth * 100}%, 10px)`,
position: 'absolute',
top: `${item.layer * 4}px`,
left: `${item.relativeStart * 100}%`,
backgroundColor: getHashColorFromString(item.event.name, 50, 60),
}"
>
/>
<template v-if="segment.route">
<div
v-for="item, iidx of segment.functions"
:key="iidx"
h-3px rounded
absolute top-0 h-full w-px border-l border-green6 op10
:style="{
width: `max(${item.relativeWidth * 100}%, 10px)`,
position: 'absolute',
top: `${item.layer * 4}px`,
left: `${item.relativeStart * 100}%`,
backgroundColor: getHashColorFromString(item.event.name, 50, 60),
left: `${segment.route.relativeStart * 100}%`,
}"
/>
<template v-if="segment.route">
<div
absolute top-0 h-full w-px border-l border-green6 op10
:style="{
left: `${segment.route.relativeStart * 100}%`,
}"
/>
</template>
</div>
</div>
<div ref="minimapScroller" class="timeline-scroller" absolute inset-0 h-full w-full of-x-scroll>
<div
ref="minimapScrollerInner"
h-1px
/>
</template>
</div>
</div>
<div ref="scroller" relative h-full w-full of-x-scroll of-y-hidden ws-nowrap n-panel-grids>
<template v-for="segment, idx of segments" :key="idx">
<div
v-if="segment.previousGap && segment.previousGap >= 200"
border="x base"
h-full flex-inline bg-true-gray-1 py4 text-xs write-vertical-left dark:bg-true-gray-9
>
<DurationDisplay
op50
:duration="segment.previousGap"
:color="false"
/>
</div>
<TimelineSegment
flex-inline of-x-hidden hover:of-x-visible bg-base
:class="idx === segments.length - 1 ? 'border-r border-base' : ''"
:segment="segment"
:style="{
width: `${Math.max(100, segment.duration / 10)}px`,
}"
@select="emit('select', $event)"
/>
</template>
<div ref="minimapScroller" class="timeline-scroller" absolute inset-0 h-full w-full of-x-scroll>
<div
ref="minimapScrollerInner"
h-1px
/>
</div>
</div>
<div ref="scroller" relative h-full w-full of-x-scroll of-y-hidden ws-nowrap n-panel-grids>
<template v-for="segment, idx of segments" :key="idx">
<div
v-if="segment.previousGap && segment.previousGap >= 200"
border="x base"
h-full flex-inline bg-true-gray-1 py15 text-xs write-vertical-left op50 dark:bg-true-gray-9
>
<DurationDisplay
op50
:duration="segment.previousGap"
:color="false"
/>
</div>
<TimelineSegment
flex-inline of-x-hidden hover:of-x-visible bg-base
:class="idx === segments.length - 1 ? 'border-r border-base' : ''"
:segment="segment"
:style="{
width: `${Math.max(100, segment.duration / 10)}px`,
}"
@select="emit('select', $event)"
/>
</template>
</div>
</template>

<style scoped>
Expand Down
74 changes: 59 additions & 15 deletions packages/devtools/client/pages/modules/timeline.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { TimelineEvent, TimelineEventNormalized } from '../../../types'
import type { TimelineEvent } from '../../../types'
definePageMeta({
icon: 'i-carbon-roadmap',
Expand All @@ -17,28 +17,56 @@ definePageMeta({
const client = useClient()
const selected = ref<TimelineEventNormalized<TimelineEvent> | undefined>()
const view = ref<'table' | 'list'>('table')
const selected = ref<TimelineEvent | undefined>()
const metrics = computed(() => client.value?.clientTimelineMetrics)
function clear() {
if (metrics.value)
metrics.value.events = []
}
function toggleView() {
view.value = view.value === 'table' ? 'list' : 'table'
}
</script>

<template>
<div v-if="metrics" h-screen of-hidden>
<TimelineTable :data="{ ...metrics }" @select="s => selected = s">
<div h-10 flex="~ gap-4 items-center justify-end" p2>
<NCheckbox
v-model="metrics.options.enabled"
label="Enabled"
class="text-sm"
<div h-screen w-full flex flex-col>
<div h-10 flex="~ gap-2 items-center justify-end" p2 px3>
<VTooltip flex>
<div
text-lg
:class="metrics.options.enabled ? 'i-carbon-radio-button-checked text-primary animate-pulse' : 'i-carbon-pause-outline op30'"
/>
<template #popper>
<div text-sm>
{{ metrics.options.enabled ? 'Recording...' : 'Paused' }}
</div>
</template>
</VTooltip>

<NButton
v-if="!metrics.options.enabled"
size="small" ml1 text-sm
n="primary"
icon="i-carbon-play"
@click="metrics.options.enabled = true"
>
Start Tracking
</NButton>
<NButton
v-else
size="small" ml1 text-sm
n="orange"
icon="i-carbon-stop"
@click="metrics.options.enabled = false"
>
Enable Tracking
</NCheckbox>
<template v-if="metrics.options.enabled">
Stop Tracking
</NButton>
<!-- <template v-if="metrics.options.enabled">
<NCheckbox
v-model="metrics.options.stacktrace"
label="Enabled"
Expand All @@ -53,24 +81,40 @@ function clear() {
>
Record arguments
</NCheckbox>
</template>
</template> -->
<div flex-auto />
<NIconButton
:icon="view === 'table' ? 'i-carbon-roadmap' : 'i-carbon-list'"
class="ml-2"
title="Toggle View"
@click="toggleView"
/>
<NIconButton
icon="i-carbon-trash-can"
hover-text-red
class="ml-2"
@click="clear"
/>
</div>
</TimelineTable>
<TimelineTable
v-if="view === 'table'"
:data="{ ...metrics }"
@select="s => selected = s.event"
/>
<TimelineList
v-else
:data="{ ...metrics }"
@select="s => selected = s"
/>
</div>
<DrawerBottom
:model-value="!!selected"
auto-close
@close="selected = undefined"
>
<div min-h-50 px3 py2>
<TimelineDetailsFunction v-if="selected?.event.type === 'function'" :record="selected.event" />
<TimelineDetailsRoute v-else-if="selected?.event.type === 'route'" :record="selected.event" />
<TimelineDetailsFunction v-if="selected?.type === 'function'" :record="selected" />
<TimelineDetailsRoute v-else-if="selected?.type === 'route'" :record="selected" />
</div>
</DrawerBottom>
</div>
Expand Down

0 comments on commit 9601cb4

Please sign in to comment.