22import type { Task , TaskState } from ' @vitest/runner'
33import { nextTick } from ' vue'
44import { hasFailedSnapshot } from ' @vitest/ws-client'
5+ import { Tooltip as VueTooltip } from ' floating-vue'
56import { client , isReport , runFiles } from ' ~/composables/client'
67import { coverageEnabled } from ' ~/composables/navigation'
78import type { TaskTreeNodeType } from ' ~/composables/explorer/types'
89import { explorerTree } from ' ~/composables/explorer'
910import { search } from ' ~/composables/explorer/state'
11+ import { showSource } from ' ~/composables/codemirror'
1012
1113// TODO: better handling of "opened" - it means to forcefully open the tree item and set in TasksList right now
1214const {
@@ -19,6 +21,7 @@ const {
1921 expandable,
2022 typecheck,
2123 type,
24+ disableTaskLocation,
2225 onItemClick,
2326} = defineProps <{
2427 taskId: string
@@ -34,12 +37,21 @@ const {
3437 search? : string
3538 projectName? : string
3639 projectNameColor: string
40+ disableTaskLocation? : boolean
3741 onItemClick? : (task : Task ) => void
3842}>()
3943
4044const task = computed (() => client .state .idMap .get (taskId ))
4145
42- const failedSnapshot = computed (() => task .value && hasFailedSnapshot (task .value ))
46+ const failedSnapshot = computed (() => {
47+ // don't traverse the tree if it's a report
48+ if (isReport ) {
49+ return false
50+ }
51+
52+ const t = task .value
53+ return t && hasFailedSnapshot (t )
54+ })
4355
4456function toggleOpen() {
4557 if (! expandable ) {
@@ -86,10 +98,9 @@ const gridStyles = computed(() => {
8698 }
8799 // text content
88100 gridColumns .push (' minmax(0, 1fr)' )
89- // buttons
90- if (type === ' file' ) {
91- gridColumns .push (' min-content' )
92- }
101+ // action buttons
102+ gridColumns .push (' min-content' )
103+
93104 // all the vertical lines with width 1rem and mx-2: always centered
94105 return ` grid-template-columns: ${
95106 entries .map (() => ' 1rem' ).join (' ' )
@@ -107,6 +118,26 @@ const highlighted = computed(() => {
107118 ? name .replace (regex , match => ` <span class="highlight">${match }</span> ` )
108119 : name
109120})
121+
122+ const disableShowDetails = computed (() => type !== ' file' && disableTaskLocation )
123+ const showDetailsTooltip = computed (() => {
124+ return type === ' file'
125+ ? ' Open test details'
126+ : type === ' suite'
127+ ? ' View Suite Source Code'
128+ : ' View Test Source Code'
129+ })
130+ const showDetailsClasses = computed (() => disableShowDetails .value ? ' color-red5 dark:color-#f43f5e' : null )
131+
132+ function showDetails() {
133+ const t = task .value !
134+ if (type === ' file' ) {
135+ onItemClick ?.(t )
136+ }
137+ else {
138+ showSource (t )
139+ }
140+ }
110141 </script >
111142
112143<template >
@@ -136,7 +167,6 @@ const highlighted = computed(() => {
136167 <div v-if =" type === 'suite' && typecheck" class =" i-logos:typescript-icon" flex-shrink-0 mr-2 />
137168 <div flex items-end gap-2 :text =" state === 'fail' ? 'red-500' : ''" overflow-hidden >
138169 <span text-sm truncate font-light >
139- <!-- only show [] in files view -->
140170 <span v-if =" type === 'file' && projectName" :style =" { color: projectNameColor }" >
141171 [{{ projectName }}]
142172 </span >
@@ -146,29 +176,46 @@ const highlighted = computed(() => {
146176 {{ duration > 0 ? duration : '< 1' }}ms
147177 </span >
148178 </div >
149- <div v-if = " type === 'file' " gap-1 justify-end flex-grow-1 pl-1 class =" test-actions" >
179+ <div gap-1 justify-end flex-grow-1 pl-1 class =" test-actions" >
150180 <IconAction
151181 v-if =" !isReport && failedSnapshot"
152182 v-tooltip.bottom =" 'Fix failed snapshot(s)'"
153183 data-testid =" btn-fix-snapshot"
154184 title =" Fix failed snapshot(s)"
155- icon =" i-carbon- result-old"
185+ icon =" i-carbon: result-old"
156186 @click.prevent.stop =" updateSnapshot(task)"
157187 />
158- <IconAction
159- v-tooltip.bottom =" 'Open test details'"
160- data-testid =" btn-open-details"
161- title =" Open test details"
162- icon =" i-carbon-intrusion-prevention"
163- @click.prevent.stop =" onItemClick?.(task)"
164- />
165- <IconAction
188+ <VueTooltip
189+ placement =" bottom"
190+ class =" w-1.4em h-1.4em op100 rounded flex"
191+ :class =" showDetailsClasses"
192+ >
193+ <IconButton
194+ data-testid =" btn-open-details"
195+ icon =" i-carbon:intrusion-prevention"
196+ @click.prevent.stop =" showDetails"
197+ />
198+ <template #popper >
199+ <div v-if =" disableShowDetails" class =" op100 gap-1 p-y-1" grid =" ~ items-center cols-[1.5em_1fr]" >
200+ <div class =" i-carbon:information-square w-1.5em h-1.5em" />
201+ <div >{{ showDetailsTooltip }}: this feature is not available, you have disabled <span class =" text-[#add467]" >includeTaskLocation</span > in your configuration file.</div >
202+ <div style =" grid-column : 2 " >
203+ Clicking this button the code tab will position the cursor at first line in the source code since the UI doesn't have the information available.
204+ </div >
205+ </div >
206+ <div v-else >
207+ {{ showDetailsTooltip }}
208+ </div >
209+ </template >
210+ </VueTooltip >
211+ <IconButton
166212 v-if =" !isReport"
167213 v-tooltip.bottom =" 'Run current test'"
168214 data-testid =" btn-run-test"
169215 title =" Run current test"
170216 icon =" i-carbon:play-filled-alt"
171217 text-green5
218+ :disabled =" type !== 'file'"
172219 @click.prevent.stop =" onRun(task)"
173220 />
174221 </div >
@@ -185,8 +232,7 @@ const highlighted = computed(() => {
185232.test-actions {
186233 display : none ;
187234}
188- .item-wrapper :hover .test-actions ,
189- .item-wrapper [data-current = " true" ] .test-actions {
235+ .item-wrapper :hover .test-actions {
190236 display : flex ;
191237}
192238 </style >
0 commit comments