mirror of
https://github.com/vitest-dev/vitest.git
synced 2025-12-08 18:26:03 +00:00
* feat: vitest html report * chore: copy ui to vitest dist * feat: report copy ui dist * feat: ui report version builder * fix: copy file * chore: remove * feat: html metadata path * feat: add declare * feat: static file client * feat: mock rpc * fix: mock error * chore: update meta * chore: compress json * chore: comment * chore: update merge config * chore: lock * feat: remove all control command from ui * chore: remove * feat: report command * feat: version tag * chore: reset lock file * feat: remove hooks * chore: update * fix: runningPromise * chore: update debug mode and disable click on transform * docs: report * chore: remove the version mark * feat: report * fix: lint * chore: copy ui from @vitest/ui * chore: export report from ui * chore: update * fix: lint * docs: ui html report * feat: ensurePackageInstalled * update * feat: more info * chore: improve documentation and tests * chore: fix UI bundle size * chore: ui tests * perf: remove output report using the global variable to judge report mode * chore: update * fix: build * fix: report * fix: parse * chore: fix html reporters test * chore: don't store config in html reporter test * chore: update ui docs * feat: log * chore: fix tests * test: fix html reporter tests * docs add vitest fo UI reporter Co-authored-by: Vladimir <sleuths.slews0s@icloud.com>
218 lines
5.3 KiB
Vue
218 lines
5.3 KiB
Vue
<script setup lang="ts">
|
|
import type { ResizeContext } from 'd3-graph-controller'
|
|
import { GraphController, Markers, PositionInitializers, defineGraphConfig } from 'd3-graph-controller'
|
|
import type { Selection } from 'd3-selection'
|
|
import { isReport } from '~/composables/client'
|
|
import type { ModuleGraph, ModuleGraphController, ModuleLink, ModuleNode, ModuleType } from '~/composables/module-graph'
|
|
|
|
const props = defineProps<{
|
|
graph: ModuleGraph
|
|
}>()
|
|
|
|
const { graph } = toRefs(props)
|
|
|
|
const el = ref<HTMLDivElement>()
|
|
|
|
const modalShow = ref(false)
|
|
const selectedModule = ref<string | null>()
|
|
const controller = ref<ModuleGraphController | undefined>()
|
|
|
|
watchEffect(() => {
|
|
if (modalShow.value === false)
|
|
setTimeout(() => selectedModule.value = undefined, 300)
|
|
}, { flush: 'post' })
|
|
|
|
onMounted(() => {
|
|
resetGraphController()
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
controller.value?.shutdown()
|
|
})
|
|
|
|
watch(graph, resetGraphController)
|
|
|
|
function setFilter(name: ModuleType, value: boolean) {
|
|
controller.value?.filterNodesByType(value, name)
|
|
}
|
|
|
|
function setSelectedModule(id: string) {
|
|
selectedModule.value = id
|
|
modalShow.value = true
|
|
}
|
|
|
|
function resetGraphController() {
|
|
controller.value?.shutdown()
|
|
if (!graph.value || !el.value)
|
|
return
|
|
|
|
controller.value = new GraphController(
|
|
el.value!,
|
|
graph.value,
|
|
// See https://graph-controller.yeger.eu/config/ for more options
|
|
defineGraphConfig<ModuleType, ModuleNode, ModuleLink>({
|
|
nodeRadius: 10,
|
|
autoResize: true,
|
|
simulation: {
|
|
alphas: {
|
|
initialize: 1,
|
|
resize: ({ newHeight, newWidth }: ResizeContext) => {
|
|
const willBeHidden = newHeight === 0 && newWidth === 0
|
|
if (willBeHidden)
|
|
return 0
|
|
return 0.25
|
|
},
|
|
},
|
|
forces: {
|
|
collision: {
|
|
radiusMultiplier: 10,
|
|
},
|
|
link: {
|
|
length: 240,
|
|
},
|
|
},
|
|
},
|
|
marker: Markers.Arrow(2),
|
|
modifiers: {
|
|
node: bindOnClick,
|
|
},
|
|
positionInitializer: graph.value.nodes.length > 1
|
|
? PositionInitializers.Randomized
|
|
: PositionInitializers.Centered,
|
|
zoom: {
|
|
min: 0.5,
|
|
max: 2,
|
|
},
|
|
}),
|
|
)
|
|
}
|
|
|
|
function bindOnClick(selection: Selection<SVGCircleElement, ModuleNode, SVGGElement, undefined>) {
|
|
if (isReport)
|
|
return
|
|
// Only trigger on left-click and primary touch
|
|
const isValidClick = (event: PointerEvent) => event.button === 0
|
|
|
|
let px = 0
|
|
let py = 0
|
|
let pt = 0
|
|
|
|
selection
|
|
.on('pointerdown', (event: PointerEvent, node) => {
|
|
if (node.type === 'external')
|
|
return
|
|
if (!node.x || !node.y || !isValidClick(event))
|
|
return
|
|
px = node.x
|
|
py = node.y
|
|
pt = Date.now()
|
|
})
|
|
.on('pointerup', (event: PointerEvent, node: ModuleNode) => {
|
|
if (node.type === 'external')
|
|
return
|
|
if (!node.x || !node.y || !isValidClick(event))
|
|
return
|
|
if (Date.now() - pt > 500)
|
|
return
|
|
const dx = node.x - px
|
|
const dy = node.y - py
|
|
if (dx ** 2 + dy ** 2 < 100)
|
|
setSelectedModule(node.id)
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div h-full min-h-75 flex-1 overflow="hidden">
|
|
<div>
|
|
<div flex items-center gap-4 px-3 py-2>
|
|
<div
|
|
v-for="node of controller?.nodeTypes.sort()"
|
|
:key="node"
|
|
flex="~ gap-1"
|
|
items-center
|
|
select-none
|
|
>
|
|
<input
|
|
:id="`type-${node}`"
|
|
type="checkbox"
|
|
:checked="controller?.nodeTypeFilter.includes(node)"
|
|
@change="setFilter(node, ($event as any).target.checked)"
|
|
>
|
|
<label
|
|
font-light
|
|
text-sm
|
|
ws-nowrap
|
|
overflow-hidden
|
|
capitalize
|
|
truncate
|
|
:for="`type-${node}`"
|
|
border-b-2
|
|
:style="{ 'border-color': `var(--color-node-${node})` }"
|
|
>{{ node }} Modules</label>
|
|
</div>
|
|
<div flex-auto />
|
|
<div>
|
|
<IconButton v-tooltip.bottom="'Reset'" icon="i-carbon-reset" @click="resetGraphController" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div ref="el" />
|
|
<Modal v-model="modalShow" direction="right">
|
|
<template v-if="selectedModule">
|
|
<Suspense>
|
|
<ModuleTransformResultView :id="selectedModule" @close="modalShow = false" />
|
|
</Suspense>
|
|
</template>
|
|
</Modal>
|
|
</div>
|
|
</template>
|
|
|
|
<style>
|
|
:root {
|
|
--color-link-label: var(--color-text);
|
|
--color-link: #ddd;
|
|
--color-node-external: #c0ad79;
|
|
--color-node-inline: #8bc4a0;
|
|
--color-node-root: #6e9aa5;
|
|
--color-node-label: var(--color-text);
|
|
--color-node-stroke: var(--color-text);
|
|
}
|
|
|
|
html.dark {
|
|
--color-text: #fff;
|
|
--color-link: #333;
|
|
--color-node-external: #857a40;
|
|
--color-node-inline: #468b60;
|
|
--color-node-root: #467d8b;
|
|
}
|
|
|
|
.graph {
|
|
/* The graph container is offset in its parent. Thus we can't use the default 100% height and have to subtract the offset. */
|
|
height: calc(100% - 39px) !important;
|
|
}
|
|
|
|
.graph .node {
|
|
stroke-width: 2px;
|
|
stroke-opacity: 0.5;
|
|
}
|
|
|
|
.graph .link {
|
|
stroke-width: 2px;
|
|
}
|
|
|
|
.graph .node:hover:not(.focused) {
|
|
filter: none !important;
|
|
}
|
|
|
|
.graph .node__label {
|
|
transform: translateY(20px);
|
|
font-weight: 100;
|
|
filter: brightness(0.5);
|
|
}
|
|
|
|
html.dark .graph .node__label {
|
|
filter: brightness(1.2);
|
|
}
|
|
</style>
|