|
3 | 3 | import { InvestigationStatusIcon, StatusBackgroundCSSClassMap, TestInvestigationStatus, TestInvestigationStatusStrings, TestStatus } from "../Common/TestStatus"; |
4 | 4 | import { subUnderscores, titleCase } from "../Common/TextUtils"; |
5 | 5 | import AssigneeList from "../WorkArea/AssigneeList.svelte"; |
| 6 | + import humanizeDuration from "humanize-duration"; |
6 | 7 | import { timestampToISODate } from "../Common/DateUtils"; |
7 | 8 | import Fa from "svelte-fa"; |
8 | | - import { faBug, faComment } from "@fortawesome/free-solid-svg-icons"; |
| 9 | + import { faBug, faComment, faSpider } from "@fortawesome/free-solid-svg-icons"; |
9 | 10 | import { getAssigneesForTest, shouldFilterOutByUser } from "./TestDashboard.svelte"; |
10 | 11 |
|
11 | 12 | let { |
|
15 | 16 | clickedTests, |
16 | 17 | doFilters |
17 | 18 | } = $props(); |
| 19 | +
|
| 20 | + let lastRun = testStats?.last_runs?.[0]; |
18 | 21 | const dispatch = createEventDispatcher(); |
19 | 22 | </script> |
20 | 23 |
|
21 | 24 | <!-- svelte-ignore a11y_click_events_have_key_events --> |
22 | 25 | <div |
| 26 | + role="button" |
| 27 | + tabindex="-1" |
23 | 28 | class:d-none={!doFilters(testStats)} |
24 | 29 | class:status-block-active={testStats.start_time != 0} |
25 | 30 | class:investigating={testStats?.investigation_status == TestInvestigationStatus.IN_PROGRESS} |
|
31 | 36 | > |
32 | 37 | <div |
33 | 38 | class="{StatusBackgroundCSSClassMap[ |
34 | | - testStats.status |
| 39 | + testStats.status as keyof typeof StatusBackgroundCSSClassMap |
35 | 40 | ]} text-center text-light p-1 border-bottom" |
36 | 41 | > |
37 | 42 | {testStats.status == "unknown" |
|
49 | 54 | </div> |
50 | 55 | </div> |
51 | 56 | <div class="d-flex flex-fill align-items-end justify-content-end p-1"> |
52 | | - <div class="p-1 me-auto"> |
| 57 | + <div class="p-1 me-auto text-small"> |
| 58 | + {#if (lastRun?.nemesis_data ?? []).length} |
| 59 | + <Fa icon={faSpider} /> {(lastRun?.nemesis_data ?? []).filter((n: {status: string}) => n.status == "failed").length} / {(lastRun?.nemesis_data ?? []).length} |
| 60 | + {/if} |
| 61 | + </div> |
| 62 | + <div class="p-1 me-2"> |
53 | 63 | {#if assigneeList.tests[testStats.test.id] || assigneeList.groups[groupStats.group.id] || testStats.last_runs?.[0]?.assignee} |
54 | 64 | <AssigneeList |
55 | 65 | smallImage={false} |
|
66 | 76 | <div |
67 | 77 | class="p-1" |
68 | 78 | title="Investigation: {TestInvestigationStatusStrings[ |
69 | | - testStats.investigation_status |
| 79 | + testStats.investigation_status as keyof typeof TestInvestigationStatusStrings |
70 | 80 | ]}" |
71 | 81 | > |
72 | 82 | <Fa |
73 | 83 | color="#000" |
74 | 84 | icon={InvestigationStatusIcon[ |
75 | | - testStats.investigation_status |
| 85 | + testStats.investigation_status as keyof typeof InvestigationStatusIcon |
76 | 86 | ]} |
77 | 87 | /> |
78 | 88 | </div> |
|
88 | 98 | </div> |
89 | 99 | {/if} |
90 | 100 | </div> |
| 101 | + {#if lastRun?.end_time && new Date(lastRun.end_time).getTime() > 1} |
| 102 | + <div class="border-top bg-light-two text-small text-center"> |
| 103 | + took {humanizeDuration((new Date(lastRun.end_time).getTime() - new Date(lastRun.start_time).getTime()), { units: ["d", "h", "m"], largest: 1, round: true })} |
| 104 | + </div> |
| 105 | + {/if} |
91 | 106 | </div> |
92 | 107 |
|
93 | 108 |
|
94 | 109 | <style> |
95 | 110 | .status-block { |
96 | 111 | width: 178px; |
97 | | - max-height: 160px; |
| 112 | + max-height: 220px; |
98 | 113 | box-sizing: border-box; |
99 | 114 | cursor: pointer; |
100 | 115 | } |
|
0 commit comments