24
24
25
25
<div class =" p-3" v-if =" hasRecords" >
26
26
<BTable
27
+ ref =" repositoriesTable"
27
28
id =" repositories-table"
28
29
:items =" repositoryList"
29
30
:fields =" fields"
30
31
:current-page =" 1"
31
32
:per-page =" 0"
33
+ :selectable =" true"
34
+ :select-mode =" 'single'"
32
35
primary-key =" id_"
33
36
v-model =" currentItems"
34
37
responsive
35
38
small
36
39
head-variant =" light"
37
40
:tbody-tr-class =" rowClass"
38
- @row-clicked =" goToScanFindings "
41
+ @row-clicked =" handleRowClicked "
39
42
>
40
43
<!-- Repository Column -->
41
44
<template #cell (repository_name)="data">
42
- {{ ( data.item as RepositoryEnrichedRead) .repository_name }}
45
+ {{ data.item.repository_name }}
43
46
</template >
44
47
45
48
<template #cell (vcs_provider)="data">
46
- {{ formatVcsProvider(( data.item as RepositoryEnrichedRead) .vcs_provider) }}
49
+ {{ formatVcsProvider(data.item.vcs_provider) }}
47
50
</template >
48
51
49
52
<template #cell (last_scan_timestamp)="data">
50
- {{ formatDate(( data.item as RepositoryEnrichedRead) .last_scan_timestamp ?? '') }}
53
+ {{ formatDate(data.item.last_scan_timestamp ?? '') }}
51
54
</template >
52
55
53
56
<!-- Health Bar Column -->
54
57
<template #cell (findings)="data">
55
58
<HealthBar
56
- :truePositive =" ( data.item as RepositoryEnrichedRead) .true_positive"
57
- :falsePositive =" ( data.item as RepositoryEnrichedRead) .false_positive"
58
- :notAnalyzed =" ( data.item as RepositoryEnrichedRead) .not_analyzed"
59
- :notAccessible =" ( data.item as RepositoryEnrichedRead) .not_accessible"
60
- :clarificationRequired =" ( data.item as RepositoryEnrichedRead) .clarification_required"
61
- :outdated =" ( data.item as RepositoryEnrichedRead) .outdated"
62
- :totalCount =" ( data.item as RepositoryEnrichedRead) .total_findings_count"
59
+ :truePositive =" data.item.true_positive"
60
+ :falsePositive =" data.item.false_positive"
61
+ :notAnalyzed =" data.item.not_analyzed"
62
+ :notAccessible =" data.item.not_accessible"
63
+ :clarificationRequired =" data.item.clarification_required"
64
+ :outdated =" data.item.outdated"
65
+ :totalCount =" data.item.total_findings_count"
63
66
/>
64
67
</template >
65
68
</BTable >
@@ -97,6 +100,7 @@ import { onKeyStroke } from '@vueuse/core';
97
100
import { shouldIgnoreKeystroke } from ' @/utils/keybind-utils' ;
98
101
99
102
const loadedData = ref (false );
103
+ const repositoriesTable = ref ();
100
104
const router = useRouter ();
101
105
102
106
type TableRepositoryEnrichedRead = RepositoryEnrichedRead & TableItem ;
@@ -113,6 +117,7 @@ const repositoryFilter = ref(undefined as string | undefined);
113
117
const projectFilter = ref (undefined as string | undefined );
114
118
const projectNames = ref ([] as string []);
115
119
const repositoryNames = ref ([] as string []);
120
+ const selectedIndex = ref (undefined as number | undefined );
116
121
const includeZeroFindingRepos = ref (false );
117
122
const includeDeletedRepositories = ref (false );
118
123
const onlyIfHasUntriagedFindings = ref (false );
@@ -192,9 +197,13 @@ function handlePageSizeChange(pageSize: number) {
192
197
fetchPaginatedRepositories ();
193
198
}
194
199
195
- function goToScanFindings(record : TableItem ) {
196
- // Casting back to RepositoryEnrichedRead
197
- const recordItem = record as RepositoryEnrichedRead ;
200
+ function handleRowClicked(_row : TableItem , index : number ) {
201
+ selectedIndex .value = index ;
202
+ goToScanFindings ();
203
+ }
204
+
205
+ function goToScanFindings() {
206
+ const recordItem = getCurrentRepositorySelected () as RepositoryEnrichedRead ;
198
207
if (recordItem .last_scan_id ) {
199
208
const routeData = router .resolve ({
200
209
name: ' ScanFindings' ,
@@ -243,6 +252,7 @@ function fetchPaginatedRepositories() {
243
252
loadedData .value = true ;
244
253
})
245
254
.catch ((error ) => {
255
+ /* istanbul ignore next @preserve */
246
256
AxiosConfig .handleError (error );
247
257
});
248
258
}
@@ -261,6 +271,7 @@ function fetchDistinctProjects() {
261
271
}
262
272
})
263
273
.catch ((error ) => {
274
+ /* istanbul ignore next @preserve */
264
275
AxiosConfig .handleError (error );
265
276
});
266
277
}
@@ -279,15 +290,49 @@ function fetchDistinctRepositories() {
279
290
}
280
291
})
281
292
.catch ((error ) => {
293
+ /* istanbul ignore next @preserve */
282
294
AxiosConfig .handleError (error );
283
295
});
284
296
}
285
297
298
+ function getCurrentRepositorySelected(): RepositoryEnrichedRead | undefined {
299
+ if (selectedIndex .value === undefined ) {
300
+ return undefined ;
301
+ }
302
+
303
+ return repositoryList .value [selectedIndex .value ];
304
+ }
305
+
306
+ function selectUp(): boolean {
307
+ selectedIndex .value = Math .max (0 , (selectedIndex .value ?? 1 ) - 1 );
308
+ repositoriesTable .value .clearSelected ();
309
+ repositoriesTable .value .selectRow (selectedIndex .value );
310
+ return true ;
311
+ }
312
+
313
+ function selectDown(): boolean {
314
+ selectedIndex .value = ((selectedIndex .value ?? - 1 ) + 1 ) % repositoryList .value .length ;
315
+ repositoriesTable .value .clearSelected ();
316
+ repositoriesTable .value .selectRow (selectedIndex .value );
317
+ return true ;
318
+ }
319
+
286
320
/* istanbul ignore next @preserve */
287
321
onKeyStroke (' r' , () => ! shouldIgnoreKeystroke () && fetchPaginatedRepositories (), {
288
322
eventName: ' keydown' ,
289
323
});
290
324
325
+ /* istanbul ignore next @preserve */
326
+ onKeyStroke ([' ArrowDown' , ' j' , ' J' ], () => ! shouldIgnoreKeystroke () && selectDown (), {
327
+ eventName: ' keydown' ,
328
+ });
329
+ /* istanbul ignore next @preserve */
330
+ onKeyStroke ([' ArrowUp' , ' k' , ' K' ], () => ! shouldIgnoreKeystroke () && selectUp (), {
331
+ eventName: ' keydown' ,
332
+ });
333
+ /* istanbul ignore next @preserve */
334
+ onKeyStroke (' o' , () => ! shouldIgnoreKeystroke () && goToScanFindings (), { eventName: ' keydown' });
335
+
291
336
onMounted (() => {
292
337
fetchDistinctProjects ();
293
338
fetchDistinctRepositories ();
0 commit comments