2
2
import type { Task , TaskState } from ' @vitest/runner'
3
3
import { nextTick } from ' vue'
4
4
import { hasFailedSnapshot } from ' @vitest/ws-client'
5
+ import { Tooltip as VueTooltip } from ' floating-vue'
5
6
import { client , isReport , runFiles } from ' ~/composables/client'
6
7
import { coverageEnabled } from ' ~/composables/navigation'
7
8
import type { TaskTreeNodeType } from ' ~/composables/explorer/types'
8
9
import { explorerTree } from ' ~/composables/explorer'
9
10
import { search } from ' ~/composables/explorer/state'
11
+ import { showSource } from ' ~/composables/codemirror'
10
12
11
13
// TODO: better handling of "opened" - it means to forcefully open the tree item and set in TasksList right now
12
14
const {
@@ -19,6 +21,7 @@ const {
19
21
expandable,
20
22
typecheck,
21
23
type,
24
+ disableTaskLocation,
22
25
onItemClick,
23
26
} = defineProps <{
24
27
taskId: string
@@ -34,12 +37,21 @@ const {
34
37
search? : string
35
38
projectName? : string
36
39
projectNameColor: string
40
+ disableTaskLocation? : boolean
37
41
onItemClick? : (task : Task ) => void
38
42
}>()
39
43
40
44
const task = computed (() => client .state .idMap .get (taskId ))
41
45
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
+ })
43
55
44
56
function toggleOpen() {
45
57
if (! expandable ) {
@@ -86,10 +98,9 @@ const gridStyles = computed(() => {
86
98
}
87
99
// text content
88
100
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
+
93
104
// all the vertical lines with width 1rem and mx-2: always centered
94
105
return ` grid-template-columns: ${
95
106
entries .map (() => ' 1rem' ).join (' ' )
@@ -107,6 +118,26 @@ const highlighted = computed(() => {
107
118
? name .replace (regex , match => ` <span class="highlight">${match }</span> ` )
108
119
: name
109
120
})
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
+ }
110
141
</script >
111
142
112
143
<template >
@@ -136,7 +167,6 @@ const highlighted = computed(() => {
136
167
<div v-if =" type === 'suite' && typecheck" class =" i-logos:typescript-icon" flex-shrink-0 mr-2 />
137
168
<div flex items-end gap-2 :text =" state === 'fail' ? 'red-500' : ''" overflow-hidden >
138
169
<span text-sm truncate font-light >
139
- <!-- only show [] in files view -->
140
170
<span v-if =" type === 'file' && projectName" :style =" { color: projectNameColor }" >
141
171
[{{ projectName }}]
142
172
</span >
@@ -146,29 +176,46 @@ const highlighted = computed(() => {
146
176
{{ duration > 0 ? duration : '< 1' }}ms
147
177
</span >
148
178
</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" >
150
180
<IconAction
151
181
v-if =" !isReport && failedSnapshot"
152
182
v-tooltip.bottom =" 'Fix failed snapshot(s)'"
153
183
data-testid =" btn-fix-snapshot"
154
184
title =" Fix failed snapshot(s)"
155
- icon =" i-carbon- result-old"
185
+ icon =" i-carbon: result-old"
156
186
@click.prevent.stop =" updateSnapshot(task)"
157
187
/>
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
166
212
v-if =" !isReport"
167
213
v-tooltip.bottom =" 'Run current test'"
168
214
data-testid =" btn-run-test"
169
215
title =" Run current test"
170
216
icon =" i-carbon:play-filled-alt"
171
217
text-green5
218
+ :disabled =" type !== 'file'"
172
219
@click.prevent.stop =" onRun(task)"
173
220
/>
174
221
</div >
@@ -185,8 +232,7 @@ const highlighted = computed(() => {
185
232
.test-actions {
186
233
display : none ;
187
234
}
188
- .item-wrapper :hover .test-actions ,
189
- .item-wrapper [data-current = " true" ] .test-actions {
235
+ .item-wrapper :hover .test-actions {
190
236
display : flex ;
191
237
}
192
238
</style >
0 commit comments