playwright-reborn 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/dist/render.js +1 -1
- package/dist/ui/report.css +349 -261
- package/dist/ui/report.js +174 -196
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.4
|
|
4
|
+
|
|
5
|
+
- Refresh the report UI with a persistent sidebar, dashboard overview, and clearer test exploration.
|
|
6
|
+
- Add Tags and Sort dropdowns, remembered light and dark themes, improved filter controls, and responsive long-name handling.
|
|
7
|
+
|
|
3
8
|
## 0.2.3
|
|
4
9
|
|
|
5
10
|
- `steps: 'user'` leaves expectations and `test.attach` calls out of the step tree.
|
package/dist/render.js
CHANGED
|
@@ -35,7 +35,7 @@ function renderHtml(json, assets) {
|
|
|
35
35
|
<title>Report</title>
|
|
36
36
|
${style}
|
|
37
37
|
</head>
|
|
38
|
-
<body style="margin:0;background:#
|
|
38
|
+
<body style="margin:0;background:#f3f7fd;color:#17324f">
|
|
39
39
|
<div class="light"></div>
|
|
40
40
|
<a class="skip" href="#tests">Skip to tests</a>
|
|
41
41
|
<main class="page" id="app"></main>
|
package/dist/ui/report.css
CHANGED
|
@@ -31,22 +31,30 @@
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
:root {
|
|
34
|
-
color-scheme:
|
|
35
|
-
--base: #
|
|
36
|
-
--surface: #
|
|
37
|
-
--
|
|
38
|
-
--
|
|
39
|
-
--
|
|
40
|
-
--
|
|
41
|
-
--
|
|
42
|
-
--
|
|
43
|
-
--
|
|
44
|
-
--
|
|
45
|
-
--
|
|
46
|
-
--
|
|
47
|
-
--
|
|
48
|
-
--
|
|
49
|
-
--
|
|
34
|
+
color-scheme: light;
|
|
35
|
+
--base: #f3f7fd;
|
|
36
|
+
--surface: #ffffff;
|
|
37
|
+
--control-active: #315386;
|
|
38
|
+
--pass-wash: #e8f5ee;
|
|
39
|
+
--fail-wash: #fff0f1;
|
|
40
|
+
--warning-wash: #fff4e5;
|
|
41
|
+
--heading: #315386;
|
|
42
|
+
--chart-2: #f58220;
|
|
43
|
+
--chart-3: #8aafd4;
|
|
44
|
+
--chart-4: #d0e0f3;
|
|
45
|
+
--border: #dbe5f0;
|
|
46
|
+
--text: #17324f;
|
|
47
|
+
--subtle: #5d7188;
|
|
48
|
+
--accent: #f58220;
|
|
49
|
+
--accent-hover: #aa4900;
|
|
50
|
+
--wash: #eaf2fc;
|
|
51
|
+
--hairline: rgba(49, 83, 134, 0.10);
|
|
52
|
+
--pass: #177b59;
|
|
53
|
+
--fail: #bd3740;
|
|
54
|
+
--flaky: #a15b08;
|
|
55
|
+
--skip: #7c8da2;
|
|
56
|
+
--timeout: #a15b08;
|
|
57
|
+
--interrupted: #6f7890;
|
|
50
58
|
--sans: Geist, "Segoe UI", sans-serif;
|
|
51
59
|
--display: Geist, "Segoe UI", sans-serif;
|
|
52
60
|
--mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
|
|
@@ -54,26 +62,26 @@
|
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
body[data-accent="red"] {
|
|
57
|
-
--accent: #
|
|
58
|
-
--accent-hover: #
|
|
65
|
+
--accent: #c64246;
|
|
66
|
+
--accent-hover: #a22c34;
|
|
59
67
|
--wash: rgba(255, 77, 77, 0.16);
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
body[data-accent="blue"] {
|
|
63
|
-
--accent: #
|
|
64
|
-
--accent-hover: #
|
|
71
|
+
--accent: #315386;
|
|
72
|
+
--accent-hover: #203e6b;
|
|
65
73
|
--wash: rgba(77, 163, 255, 0.16);
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
body[data-accent="amber"] {
|
|
69
|
-
--accent: #
|
|
70
|
-
--accent-hover: #
|
|
77
|
+
--accent: #a76500;
|
|
78
|
+
--accent-hover: #8c5100;
|
|
71
79
|
--wash: rgba(255, 176, 32, 0.16);
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
body[data-accent="violet"] {
|
|
75
|
-
--accent: #
|
|
76
|
-
--accent-hover: #
|
|
83
|
+
--accent: #7952b8;
|
|
84
|
+
--accent-hover: #5c3b92;
|
|
77
85
|
--wash: rgba(176, 124, 255, 0.16);
|
|
78
86
|
}
|
|
79
87
|
|
|
@@ -99,7 +107,7 @@ body {
|
|
|
99
107
|
left: 12px;
|
|
100
108
|
top: -40px;
|
|
101
109
|
background: var(--accent);
|
|
102
|
-
color:
|
|
110
|
+
color: var(--text);
|
|
103
111
|
padding: 8px 12px;
|
|
104
112
|
z-index: 10;
|
|
105
113
|
}
|
|
@@ -108,9 +116,9 @@ body {
|
|
|
108
116
|
|
|
109
117
|
|
|
110
118
|
|
|
111
|
-
button, input { font: inherit; color: inherit; }
|
|
119
|
+
button, input, select { font: inherit; color: inherit; }
|
|
112
120
|
button { cursor: pointer; }
|
|
113
|
-
:focus-visible { outline: 2px solid var(--
|
|
121
|
+
:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
|
|
114
122
|
::selection { background: var(--wash); color: var(--text); }
|
|
115
123
|
|
|
116
124
|
.top {
|
|
@@ -367,7 +375,7 @@ button { cursor: pointer; }
|
|
|
367
375
|
transform: none;
|
|
368
376
|
}
|
|
369
377
|
|
|
370
|
-
.segment[data-status="passed"] { background:
|
|
378
|
+
.segment[data-status="passed"] { background: var(--pass); }
|
|
371
379
|
.segment[data-status="failed"],
|
|
372
380
|
.segment[data-status="timedOut"] { background: var(--fail); }
|
|
373
381
|
.segment[data-status="interrupted"] { background: transparent; box-shadow: inset 0 0 0 1px var(--border); }
|
|
@@ -504,18 +512,18 @@ button { cursor: pointer; }
|
|
|
504
512
|
}
|
|
505
513
|
|
|
506
514
|
.run-row.is-dim { opacity: 0.28; }
|
|
507
|
-
.run-row:hover { background:
|
|
515
|
+
.run-row:hover { background: var(--wash); }
|
|
508
516
|
.run-row[aria-current="true"] { background: var(--wash); }
|
|
509
517
|
|
|
510
518
|
.run-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
|
|
511
519
|
|
|
512
520
|
.run-track {
|
|
513
521
|
height: 8px;
|
|
514
|
-
background:
|
|
522
|
+
background: var(--hairline);
|
|
515
523
|
overflow: hidden;
|
|
516
524
|
}
|
|
517
525
|
|
|
518
|
-
.run-fill { display: block; height: 100%; background:
|
|
526
|
+
.run-fill { display: block; height: 100%; background: var(--pass); }
|
|
519
527
|
.run-fill[data-status="failed"],
|
|
520
528
|
.run-fill[data-status="timedOut"],
|
|
521
529
|
.run-fill[data-status="flaky"] { background: var(--accent); }
|
|
@@ -602,7 +610,7 @@ button { cursor: pointer; }
|
|
|
602
610
|
.row[data-status="skipped"],
|
|
603
611
|
.row[data-status="interrupted"] { border-left-color: var(--border); }
|
|
604
612
|
.row[aria-current="true"] { background: var(--hairline); }
|
|
605
|
-
.row:hover { background:
|
|
613
|
+
.row:hover { background: var(--wash); }
|
|
606
614
|
|
|
607
615
|
.row-title {
|
|
608
616
|
font-weight: 500;
|
|
@@ -848,7 +856,7 @@ button { cursor: pointer; }
|
|
|
848
856
|
}
|
|
849
857
|
|
|
850
858
|
.tile {
|
|
851
|
-
border: 1px solid
|
|
859
|
+
border: 1px solid var(--hairline);
|
|
852
860
|
border-radius: 0;
|
|
853
861
|
overflow: hidden;
|
|
854
862
|
background: transparent;
|
|
@@ -862,7 +870,7 @@ button { cursor: pointer; }
|
|
|
862
870
|
|
|
863
871
|
.log-card, .file-card {
|
|
864
872
|
border: 0;
|
|
865
|
-
border-top: 1px solid
|
|
873
|
+
border-top: 1px solid var(--hairline);
|
|
866
874
|
border-radius: 0;
|
|
867
875
|
background: transparent;
|
|
868
876
|
box-shadow: none;
|
|
@@ -907,7 +915,7 @@ dialog .close-shot {
|
|
|
907
915
|
border-radius: 0;
|
|
908
916
|
padding: 6px 12px;
|
|
909
917
|
}
|
|
910
|
-
dialog::backdrop { background: rgba(
|
|
918
|
+
dialog::backdrop { background: rgba(23, 50, 79, 0.72); }
|
|
911
919
|
|
|
912
920
|
@keyframes rise {
|
|
913
921
|
from { opacity: 0; transform: translateY(40px); }
|
|
@@ -924,230 +932,6 @@ dialog::backdrop { background: rgba(8, 8, 8, 0.92); }
|
|
|
924
932
|
#tests { max-height: 45vh; overflow-y: auto; overscroll-behavior: contain; padding-bottom: 12px; }
|
|
925
933
|
}
|
|
926
934
|
|
|
927
|
-
.atmosphere {
|
|
928
|
-
position: fixed;
|
|
929
|
-
inset: 0;
|
|
930
|
-
z-index: 0;
|
|
931
|
-
pointer-events: none;
|
|
932
|
-
background: var(--base);
|
|
933
|
-
overflow: hidden;
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
.bands {
|
|
937
|
-
position: absolute;
|
|
938
|
-
left: 0;
|
|
939
|
-
right: 0;
|
|
940
|
-
top: 0;
|
|
941
|
-
width: 100%;
|
|
942
|
-
height: 100%;
|
|
943
|
-
display: block;
|
|
944
|
-
filter: blur(18px) saturate(1.05);
|
|
945
|
-
opacity: 0.3;
|
|
946
|
-
-webkit-mask-image: linear-gradient(180deg, #000 0%, #000 18%, rgba(0, 0, 0, 0.4) 34%, transparent 52%);
|
|
947
|
-
mask-image: linear-gradient(180deg, #000 0%, #000 18%, rgba(0, 0, 0, 0.4) 34%, transparent 52%);
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
.grain {
|
|
951
|
-
position: absolute;
|
|
952
|
-
inset: -20%;
|
|
953
|
-
opacity: 0.035;
|
|
954
|
-
mix-blend-mode: overlay;
|
|
955
|
-
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='0.85'/></svg>");
|
|
956
|
-
background-size: 180px 180px;
|
|
957
|
-
animation: grain 0.7s steps(2) infinite;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
.veil {
|
|
961
|
-
position: absolute;
|
|
962
|
-
inset: 0;
|
|
963
|
-
background: linear-gradient(180deg, rgba(5, 8, 6, 0) 0%, rgba(5, 8, 6, 0.12) 14%, rgba(5, 8, 6, 0.72) 30%, rgba(5, 8, 6, 0.9) 42%, rgba(5, 8, 6, 0.96) 100%);
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
.shell { position: relative; z-index: 1; }
|
|
967
|
-
|
|
968
|
-
@keyframes grain {
|
|
969
|
-
0% { transform: translate(0, 0); }
|
|
970
|
-
100% { transform: translate(-2%, 1%); }
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
.page { width: 100%; max-width: none; margin: 0; padding: 0; }
|
|
974
|
-
|
|
975
|
-
.shell {
|
|
976
|
-
display: flex;
|
|
977
|
-
flex-direction: column;
|
|
978
|
-
min-height: 100vh;
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
.rail {
|
|
982
|
-
position: sticky;
|
|
983
|
-
top: 0;
|
|
984
|
-
z-index: 5;
|
|
985
|
-
height: auto;
|
|
986
|
-
display: flex;
|
|
987
|
-
flex-direction: row;
|
|
988
|
-
align-items: center;
|
|
989
|
-
gap: 28px;
|
|
990
|
-
padding: 12px clamp(20px, 3vw, 48px);
|
|
991
|
-
border-right: 0;
|
|
992
|
-
background: rgba(8, 8, 8, 0.9);
|
|
993
|
-
backdrop-filter: blur(16px);
|
|
994
|
-
border-bottom: 1px solid var(--hairline);
|
|
995
|
-
transition: transform 220ms ease;
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
.rail.is-hidden {
|
|
999
|
-
transform: translateY(-110%);
|
|
1000
|
-
pointer-events: none;
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
.rail .meta { margin: 0 0 0 auto; flex-direction: row; gap: 16px; justify-content: flex-end; text-align: right; }
|
|
1004
|
-
.rail .meta { min-width: 0; }
|
|
1005
|
-
.rail .meta span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 30ch; }
|
|
1006
|
-
|
|
1007
|
-
.rail .tabbar {
|
|
1008
|
-
flex-direction: row;
|
|
1009
|
-
align-items: center;
|
|
1010
|
-
width: auto;
|
|
1011
|
-
flex: 1;
|
|
1012
|
-
min-width: 0;
|
|
1013
|
-
gap: 22px;
|
|
1014
|
-
margin: 0;
|
|
1015
|
-
padding: 0;
|
|
1016
|
-
border: 0;
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
.rail .tab {
|
|
1020
|
-
text-align: left;
|
|
1021
|
-
padding: 8px 0;
|
|
1022
|
-
color: rgba(240, 240, 240, 0.72);
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
.rail .tab[aria-selected="true"] {
|
|
1026
|
-
background: none;
|
|
1027
|
-
color: var(--text);
|
|
1028
|
-
box-shadow: inset 0 -1px 0 var(--accent);
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
.stage {
|
|
1032
|
-
width: min(1440px, 100%);
|
|
1033
|
-
margin: 0 auto;
|
|
1034
|
-
padding: 24px clamp(20px, 3vw, 48px) 48px;
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
.hero { margin: 8px 0 28px; }
|
|
1038
|
-
|
|
1039
|
-
.word {
|
|
1040
|
-
font-size: clamp(42px, 6vw, 80px);
|
|
1041
|
-
font-weight: 500;
|
|
1042
|
-
letter-spacing: -0.045em;
|
|
1043
|
-
max-width: 100%;
|
|
1044
|
-
overflow-wrap: anywhere;
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
#panel-tests,
|
|
1050
|
-
#panel-screenshots,
|
|
1051
|
-
#panel-logs,
|
|
1052
|
-
#panel-files {
|
|
1053
|
-
background: transparent;
|
|
1054
|
-
border: 0;
|
|
1055
|
-
padding: 0;
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
.console {
|
|
1059
|
-
background: transparent;
|
|
1060
|
-
border: 0;
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
.console-bar {
|
|
1064
|
-
display: flex;
|
|
1065
|
-
justify-content: space-between;
|
|
1066
|
-
gap: 16px;
|
|
1067
|
-
padding: 12px 18px;
|
|
1068
|
-
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
|
1069
|
-
color: var(--subtle);
|
|
1070
|
-
font-size: 13px;
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
.console-body { padding: 0; }
|
|
1074
|
-
|
|
1075
|
-
.console .section-label { margin-top: 18px; }
|
|
1076
|
-
|
|
1077
|
-
.console .strip-window,
|
|
1078
|
-
.console .longest {
|
|
1079
|
-
background: transparent;
|
|
1080
|
-
border: 0;
|
|
1081
|
-
box-shadow: none;
|
|
1082
|
-
animation: none;
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
#legend.legend {
|
|
1086
|
-
background: transparent;
|
|
1087
|
-
border: 0;
|
|
1088
|
-
gap: 0;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
#legend .count {
|
|
1092
|
-
background: transparent;
|
|
1093
|
-
min-height: 0;
|
|
1094
|
-
padding: 8px 18px 8px 0;
|
|
1095
|
-
border-right: 1px solid rgba(255, 255, 255, 0.06);
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
#legend .count:last-child { border-right: 0; }
|
|
1099
|
-
|
|
1100
|
-
.strip.timeline .segment { height: 18px; }
|
|
1101
|
-
|
|
1102
|
-
.section-label {
|
|
1103
|
-
margin: 32px 0 10px;
|
|
1104
|
-
color: var(--subtle);
|
|
1105
|
-
font-size: 13px;
|
|
1106
|
-
font-weight: 500;
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
#legend.legend {
|
|
1110
|
-
display: grid;
|
|
1111
|
-
grid-template-columns: repeat(6, minmax(0, 1fr));
|
|
1112
|
-
gap: 1px;
|
|
1113
|
-
margin-top: 0;
|
|
1114
|
-
background: transparent;
|
|
1115
|
-
border: 0;
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
#legend .count {
|
|
1119
|
-
display: flex;
|
|
1120
|
-
flex-direction: column;
|
|
1121
|
-
align-items: flex-start;
|
|
1122
|
-
gap: 4px;
|
|
1123
|
-
min-height: 0;
|
|
1124
|
-
padding: 4px 16px 4px 0;
|
|
1125
|
-
background: transparent;
|
|
1126
|
-
border: 0;
|
|
1127
|
-
color: var(--subtle);
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
#legend .count .n {
|
|
1131
|
-
font-size: 28px;
|
|
1132
|
-
line-height: 1;
|
|
1133
|
-
letter-spacing: -0.04em;
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
#legend .count[aria-pressed="true"] { background: transparent; }
|
|
1137
|
-
|
|
1138
|
-
.strip.timeline {
|
|
1139
|
-
display: block;
|
|
1140
|
-
position: relative;
|
|
1141
|
-
height: auto;
|
|
1142
|
-
min-width: 0;
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
.strip.timeline .segment {
|
|
1146
|
-
position: absolute;
|
|
1147
|
-
height: 18px;
|
|
1148
|
-
min-width: 0;
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
935
|
.evidence {
|
|
1152
936
|
display: grid;
|
|
1153
937
|
grid-template-columns: minmax(0, 1.1fr) minmax(220px, 0.9fr);
|
|
@@ -1218,7 +1002,7 @@ dialog::backdrop { background: rgba(8, 8, 8, 0.92); }
|
|
|
1218
1002
|
.row-meta { flex-wrap: wrap; gap: 2px 12px; }
|
|
1219
1003
|
.band { padding: 6px 0; }
|
|
1220
1004
|
.band:hover .band-label { color: var(--text); }
|
|
1221
|
-
.find { padding: 8px 10px; border: 1px solid var(--border); background:
|
|
1005
|
+
.find { padding: 8px 10px; border: 1px solid var(--border); background: var(--surface); border-radius: 6px; }
|
|
1222
1006
|
.find:focus { border-color: var(--accent); }
|
|
1223
1007
|
.list-summary { display: flex; align-items: center; gap: 16px; margin: 18px 0 10px; color: var(--subtle); font-size: 13px; }
|
|
1224
1008
|
.reset-filters { background: none; border: 0; color: var(--accent); padding: 4px 0; }
|
|
@@ -1229,7 +1013,7 @@ dialog::backdrop { background: rgba(8, 8, 8, 0.92); }
|
|
|
1229
1013
|
.row[aria-current="true"] { background: var(--wash); }
|
|
1230
1014
|
.error { border-left-color: var(--fail); }
|
|
1231
1015
|
.step.bad .mark { background: var(--fail); }
|
|
1232
|
-
.gallery .tile { border-radius: 8px; background:
|
|
1016
|
+
.gallery .tile { border-radius: 8px; background: var(--surface); }
|
|
1233
1017
|
.tile img { object-fit: contain; background: var(--base); }
|
|
1234
1018
|
.well pre { padding: 12px; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; }
|
|
1235
1019
|
dialog { border: 1px solid var(--border); border-radius: 8px; padding: 12px; max-height: 95vh; }
|
|
@@ -1246,3 +1030,307 @@ dialog img { max-width: calc(92vw - 26px); object-fit: contain; }
|
|
|
1246
1030
|
@media (prefers-reduced-motion: reduce) {
|
|
1247
1031
|
*, *::before, *::after { scroll-behavior: auto !important; }
|
|
1248
1032
|
}
|
|
1033
|
+
|
|
1034
|
+
/* Report workspace: persistent navigation and a data-focused dashboard. */
|
|
1035
|
+
body { background: var(--base) !important; color: var(--text) !important; }
|
|
1036
|
+
.light { display: none; }
|
|
1037
|
+
.page { width: 100%; max-width: none; margin: 0; padding: 0; }
|
|
1038
|
+
.shell { display: grid; grid-template-columns: 244px minmax(0, 1fr); min-height: 100vh; }
|
|
1039
|
+
.icon { width: 20px; height: 20px; flex-shrink: 0; }
|
|
1040
|
+
.rail {
|
|
1041
|
+
position: sticky;
|
|
1042
|
+
top: 0;
|
|
1043
|
+
height: 100vh;
|
|
1044
|
+
overflow-y: auto;
|
|
1045
|
+
display: flex;
|
|
1046
|
+
flex-direction: column;
|
|
1047
|
+
padding: 28px 18px 20px;
|
|
1048
|
+
background: var(--surface);
|
|
1049
|
+
border-right: 1px solid var(--border);
|
|
1050
|
+
z-index: 5;
|
|
1051
|
+
}
|
|
1052
|
+
.sidebar-brand { display: flex; align-items: center; gap: 12px; padding: 0 8px; font-size: 23px; font-weight: 600; letter-spacing: -.045em; }
|
|
1053
|
+
.sidebar-brand > .icon { width: 40px; height: 40px; padding: 8px; border-radius: 12px; color: #ffffff; background: #315386; stroke-width: 2.2; }
|
|
1054
|
+
.brand-caption { display: block; font-size: 11px; color: var(--subtle); font-weight: 400; letter-spacing: 0; margin-top: -2px; }
|
|
1055
|
+
.project-card { display: flex; align-items: center; gap: 12px; margin: 32px 0 28px; padding: 14px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface); }
|
|
1056
|
+
.project-card > .icon { color: var(--accent); }
|
|
1057
|
+
.project-card > div { min-width: 0; }
|
|
1058
|
+
.project-caption { display: block; font-size: 11px; color: var(--subtle); }
|
|
1059
|
+
.project-card strong { display: block; font-size: 14px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1060
|
+
.nav-caption { font-size: 12px; color: var(--subtle); margin: 0 12px 12px; }
|
|
1061
|
+
.rail .tabbar { display: flex; flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 6px; padding: 0; margin: 0; width: 100%; border: 0; }
|
|
1062
|
+
.rail .tab { display: flex; align-items: center; gap: 12px; min-height: 46px; padding: 12px; text-align: left; border: 1px solid transparent; border-radius: 8px; color: var(--subtle); font-size: 14px; font-weight: 500; }
|
|
1063
|
+
.rail .tab[aria-selected="true"] { color: var(--heading); background: var(--wash); border-color: var(--border); box-shadow: inset 3px 0 0 var(--accent); }
|
|
1064
|
+
.rail .tab:hover { background: var(--wash); color: var(--text); }
|
|
1065
|
+
.nav-count { margin-left: auto; min-width: 24px; padding: 1px 5px; border-radius: 4px; text-align: center; font-size: 11px; background: var(--hairline); }
|
|
1066
|
+
.sidebar-bottom { margin-top: auto; padding: 44px 12px 0; }
|
|
1067
|
+
.sidebar-bottom .nav-caption { margin-left: 0; }
|
|
1068
|
+
.sidebar-state { font-size: 12px; }
|
|
1069
|
+
.sidebar-note { font-size: 11px; color: var(--subtle); margin: 12px 0 22px; }
|
|
1070
|
+
.sidebar-note span { display: block; margin-top: 3px; }
|
|
1071
|
+
kbd { display: inline-grid; place-items: center; width: 22px; height: 22px; border: 1px solid var(--border); border-radius: 5px; font-family: var(--sans); font-size: 12px; color: var(--subtle); }
|
|
1072
|
+
.keyboard-hint { display: flex; gap: 10px; align-items: center; color: var(--subtle); font-size: 12px; padding-top: 16px; border-top: 1px solid var(--border); }
|
|
1073
|
+
.stage { min-width: 0; width: 100%; }
|
|
1074
|
+
.workspace-bar { height: 76px; display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 0 36px; border-bottom: 1px solid var(--border); background: var(--surface); }
|
|
1075
|
+
.breadcrumb { min-width: 0; display: flex; align-items: center; gap: 14px; font-size: 13px; color: var(--subtle); }
|
|
1076
|
+
#breadcrumb-company { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
|
1077
|
+
.breadcrumb strong { font-weight: 500; color: var(--text); }
|
|
1078
|
+
.breadcrumb-separator { color: #8296b1; }
|
|
1079
|
+
.report-content { max-width: 1600px; margin: 0 auto; padding: 30px 36px; }
|
|
1080
|
+
.panel { margin-top: 0; }
|
|
1081
|
+
.hero { margin: 0; gap: 18px; align-items: center; animation: none; }
|
|
1082
|
+
.dashboard-kicker { margin: 0 0 8px; font-size: 12px; color: var(--accent); }
|
|
1083
|
+
.word { font-size: 36px; font-weight: 600; letter-spacing: -.045em; line-height: 1.15; }
|
|
1084
|
+
.product { font-size: 15px; color: var(--subtle); letter-spacing: 0; margin-top: 10px; font-weight: 400; }
|
|
1085
|
+
.summary { font-size: 13px; margin-top: 6px; max-width: 65ch; }
|
|
1086
|
+
.summary:empty { display: none; }
|
|
1087
|
+
#meta { margin: 18px 0 0; font-size: 12px; gap: 6px 18px; }
|
|
1088
|
+
#meta span { overflow-wrap: anywhere; }
|
|
1089
|
+
.metric-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; margin: 26px 0 24px; }
|
|
1090
|
+
.metric { padding: 20px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; min-width: 0; }
|
|
1091
|
+
.metric-label { display: flex; align-items: center; justify-content: space-between; gap: 6px; color: var(--text); font-size: 12px; }
|
|
1092
|
+
.metric-label .icon { width: 17px; height: 17px; color: var(--heading); }
|
|
1093
|
+
.metric-value { display: block; margin: 12px 0 6px; font-size: clamp(26px, 3vw, 34px); line-height: 1.1; font-weight: 500; letter-spacing: -.045em; font-variant-numeric: tabular-nums; }
|
|
1094
|
+
.metric-note { font-size: 11px; color: var(--subtle); }
|
|
1095
|
+
.metric.positive .metric-value, .metric.positive .icon { color: var(--pass); }
|
|
1096
|
+
.metric.warning .metric-value, .metric.warning .icon { color: var(--flaky); }
|
|
1097
|
+
.dashboard-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr); gap: 24px; align-items: stretch; }
|
|
1098
|
+
.dashboard-card { min-width: 0; padding: 24px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; }
|
|
1099
|
+
.card-heading { display: flex; justify-content: space-between; align-items: center; gap: 16px; margin-bottom: 24px; }
|
|
1100
|
+
.card-heading h2, .range-head .section-label { margin: 0; font-size: 15px; color: var(--text); font-weight: 500; }
|
|
1101
|
+
.card-detail { font-size: 11px; color: var(--subtle); background: var(--hairline); border-radius: 5px; padding: 3px 8px; }
|
|
1102
|
+
.result-body { display: flex; align-items: center; gap: 28px; min-height: 185px; }
|
|
1103
|
+
.result-ring { width: 164px; height: 164px; flex: 0 0 164px; padding: 12px; border-radius: 50%; transform: rotate(0deg); }
|
|
1104
|
+
.result-ring > div { width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; border-radius: 50%; background: var(--surface); }
|
|
1105
|
+
.result-ring strong { font-size: 30px; font-weight: 500; letter-spacing: -.04em; }
|
|
1106
|
+
.result-ring span { font-size: 12px; color: var(--subtle); }
|
|
1107
|
+
#legend.legend { flex: 1; display: flex; flex-direction: column; align-items: stretch; gap: 2px; margin: 0; min-width: 0; }
|
|
1108
|
+
#legend .count { display: flex; flex-direction: row-reverse; align-items: center; justify-content: flex-end; gap: 10px; min-height: 29px; padding: 4px 0; border: 0; font-size: 12px; color: var(--subtle); background: transparent; }
|
|
1109
|
+
#legend .count[data-status="all"] { display: none; }
|
|
1110
|
+
#legend .count .n { font-size: 13px; font-weight: 500; margin: 0 0 0 auto; color: var(--text); line-height: 1.4; letter-spacing: 0; }
|
|
1111
|
+
#legend .count::after { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--skip); }
|
|
1112
|
+
#legend .count[data-status="passed"]::after { background: var(--pass); }
|
|
1113
|
+
#legend .count[data-status="failed"]::after, #legend .count[data-status="timedOut"]::after { background: var(--fail); }
|
|
1114
|
+
#legend .count[data-status="flaky"]::after { background: var(--flaky); }
|
|
1115
|
+
#legend .count[data-status="interrupted"]::after { background: var(--timeout); }
|
|
1116
|
+
#legend .count:hover { color: var(--text); }
|
|
1117
|
+
#legend .count[aria-pressed="true"] { box-shadow: none; }
|
|
1118
|
+
.card-note { font-size: 11px; color: var(--subtle); margin: 22px 0 0; line-height: 1.6; }
|
|
1119
|
+
.range-head { margin: 0 0 12px; align-items: center; }
|
|
1120
|
+
.views { padding: 3px; gap: 0; background: var(--base); border: 1px solid var(--border); border-radius: 6px; }
|
|
1121
|
+
.view { padding: 4px 10px; font-size: 11px; border-radius: 4px; min-height: 26px; }
|
|
1122
|
+
.view[aria-pressed="true"] { background: var(--control-active); color: #ffffff; box-shadow: none; }
|
|
1123
|
+
.section-note { margin: 0; font-size: 11px; line-height: 1.6; max-width: 60ch; }
|
|
1124
|
+
.charts { grid-template-columns: 130px minmax(0, 1fr); gap: 22px; margin-top: 28px; min-height: 164px; }
|
|
1125
|
+
.pie { width: 130px; height: auto; margin: 0; }
|
|
1126
|
+
.band { padding: 6px 0; grid-template-columns: 7px minmax(0, 1fr) auto; gap: 5px 8px; }
|
|
1127
|
+
.swatch { width: 7px; height: 7px; border-radius: 2px; margin-top: 5px; }
|
|
1128
|
+
.band-label { font-size: 11px; }
|
|
1129
|
+
.band .n { font-size: 12px; }
|
|
1130
|
+
.band-track, .band-fill { border-radius: 3px; }
|
|
1131
|
+
.band-track { height: 4px; }
|
|
1132
|
+
.strip-window { padding: 0; margin-top: 18px; background: transparent; border: 0; animation: none; max-height: 240px; overflow-y: auto; }
|
|
1133
|
+
.strip-scroll { overflow-x: hidden; }
|
|
1134
|
+
.console .run-row { grid-template-columns: 60px minmax(0, 1fr) auto; gap: 8px; padding: 7px 6px; font-size: 11px; }
|
|
1135
|
+
.console .run-track { display: none; }
|
|
1136
|
+
.console .run-time { font-size: 10px; }
|
|
1137
|
+
.dashboard-link { display: inline-flex; align-items: center; gap: 6px; padding: 0; border: 0; background: transparent; color: var(--accent); font-size: 11px; }
|
|
1138
|
+
.dashboard-link .icon { width: 14px; height: 14px; }
|
|
1139
|
+
.attention-card .card-heading { margin-bottom: 12px; }
|
|
1140
|
+
.attention-row { display: grid; grid-template-columns: 56px minmax(0, 1fr) auto; gap: 12px; align-items: center; width: 100%; padding: 16px 0; border: 0; border-top: 1px solid var(--hairline); color: var(--text); background: transparent; text-align: left; }
|
|
1141
|
+
.attention-row:hover { background: var(--wash); }
|
|
1142
|
+
.attention-status { font-size: 11px; }
|
|
1143
|
+
.attention-test { min-width: 0; }
|
|
1144
|
+
.attention-test strong { display: block; font-size: 12px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1145
|
+
.attention-test > span { display: block; color: var(--subtle); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 4px; }
|
|
1146
|
+
.attention-time { font-size: 11px; color: var(--subtle); }
|
|
1147
|
+
.environment-card .card-heading > .icon { width: 16px; color: var(--subtle); }
|
|
1148
|
+
.run-details { margin: 0; }
|
|
1149
|
+
.run-details > div { display: flex; justify-content: space-between; align-items: baseline; gap: 20px; margin: 14px 0; font-size: 12px; }
|
|
1150
|
+
.run-details dt { color: var(--subtle); }
|
|
1151
|
+
.run-details dd { margin: 0; text-align: right; overflow-wrap: anywhere; min-width: 0; }
|
|
1152
|
+
.info { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 16px; margin: 20px 0 0; padding-top: 20px; border-top: 1px solid var(--border); }
|
|
1153
|
+
.info dd { font-size: 12px; }
|
|
1154
|
+
.info dt { font-size: 11px; }
|
|
1155
|
+
.foot { font-size: 11px; margin-top: 28px; border-color: var(--border); }
|
|
1156
|
+
.page-heading { margin: 0 0 24px; }
|
|
1157
|
+
.page-heading h2, .panel > h2 { font-size: 30px; font-weight: 600; letter-spacing: -.035em; margin: 0 0 8px; }
|
|
1158
|
+
.page-heading p { font-size: 13px; color: var(--subtle); margin: 0; }
|
|
1159
|
+
#test-tools { padding: 16px; background: var(--surface); border: 1px solid var(--border); border-radius: 10px; gap: 12px 18px; }
|
|
1160
|
+
#test-tools .count { min-height: 30px; padding: 4px 8px; border-radius: 5px; }
|
|
1161
|
+
#test-tools .count[aria-pressed="true"] { background: var(--wash); border-color: transparent; color: var(--accent); }
|
|
1162
|
+
.split { margin-top: 16px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; overflow: clip; }
|
|
1163
|
+
#tests { padding: 8px 16px 16px; }
|
|
1164
|
+
.detail { padding: 24px; top: 20px; max-height: calc(100vh - 40px); }
|
|
1165
|
+
.detail h2 { font-size: 22px; line-height: 1.3; }
|
|
1166
|
+
.gallery .tile { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; }
|
|
1167
|
+
.log-card, .file-group { padding: 20px; background: var(--surface); border: 1px solid var(--border); border-radius: 10px; margin-top: 16px; }
|
|
1168
|
+
.log-card h3 { font-size: 16px; font-weight: 500; overflow-wrap: anywhere; }
|
|
1169
|
+
.well pre { background: var(--base); }
|
|
1170
|
+
.run-track, .run-fill { border-radius: 4px; }
|
|
1171
|
+
.banner { background: var(--fail-wash); padding: 14px; border-radius: 6px; font-size: 12px; }
|
|
1172
|
+
@media (min-width: 801px) and (max-width: 1200px) {
|
|
1173
|
+
.shell { grid-template-columns: 216px minmax(0, 1fr); }
|
|
1174
|
+
.workspace-bar { padding: 0 24px; }
|
|
1175
|
+
.report-content { padding: 28px 24px; }
|
|
1176
|
+
.dashboard-card { padding: 20px; }
|
|
1177
|
+
.result-body { gap: 16px; }
|
|
1178
|
+
.result-ring { width: 128px; height: 128px; flex-basis: 128px; padding: 10px; }
|
|
1179
|
+
.charts { grid-template-columns: 105px minmax(0, 1fr); gap: 14px; }
|
|
1180
|
+
.pie { width: 105px; }
|
|
1181
|
+
.metric { padding: 16px; }
|
|
1182
|
+
}
|
|
1183
|
+
@media (max-width: 1050px) and (min-width: 801px) {
|
|
1184
|
+
.dashboard-grid { grid-template-columns: 1fr; }
|
|
1185
|
+
.metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
1186
|
+
.result-body { justify-content: center; }
|
|
1187
|
+
#legend.legend { max-width: 280px; }
|
|
1188
|
+
.charts { grid-template-columns: 150px minmax(0, 1fr); }
|
|
1189
|
+
.pie { width: 150px; }
|
|
1190
|
+
}
|
|
1191
|
+
@media (max-width: 800px) {
|
|
1192
|
+
.shell { grid-template-columns: minmax(0, 1fr); }
|
|
1193
|
+
.rail { position: relative; top: 0; height: auto; overflow: visible; padding: 16px; border-right: 0; border-bottom: 1px solid var(--border); gap: 0; }
|
|
1194
|
+
.sidebar-brand { font-size: 20px; padding: 0; }
|
|
1195
|
+
.sidebar-brand > .icon { width: 34px; height: 34px; }
|
|
1196
|
+
.brand-caption { display: none; }
|
|
1197
|
+
.project-card { display: none; }
|
|
1198
|
+
.rail > .nav-caption, .sidebar-bottom { display: none; }
|
|
1199
|
+
.rail .tabbar { flex-direction: row; gap: 6px; overflow-x: auto; margin-top: 16px; padding-bottom: 2px; }
|
|
1200
|
+
.rail .tab { flex: 0 0 auto; min-height: 40px; padding: 8px 10px; font-size: 12px; gap: 7px; }
|
|
1201
|
+
.rail .tab .icon { width: 16px; height: 16px; }
|
|
1202
|
+
.rail .tab[aria-selected="true"] { box-shadow: none; }
|
|
1203
|
+
.nav-count { display: none; }
|
|
1204
|
+
.workspace-bar { height: 58px; padding: 0 16px; gap: 12px; }
|
|
1205
|
+
.breadcrumb { font-size: 11px; gap: 10px; }
|
|
1206
|
+
.report-content { padding: 24px 16px; }
|
|
1207
|
+
.hero { flex-direction: row; align-items: flex-start; gap: 12px; }
|
|
1208
|
+
.word { font-size: 30px; }
|
|
1209
|
+
.hero .run-state { font-size: 11px; padding: 5px 8px; margin-top: 24px; }
|
|
1210
|
+
.product { font-size: 13px; }
|
|
1211
|
+
#meta { font-size: 11px; }
|
|
1212
|
+
.metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin-top: 22px; }
|
|
1213
|
+
.metric { padding: 14px; }
|
|
1214
|
+
.metric-label { font-size: 11px; }
|
|
1215
|
+
.metric-value { font-size: 28px; }
|
|
1216
|
+
.metric-note { font-size: 10px; }
|
|
1217
|
+
.dashboard-grid { grid-template-columns: minmax(0, 1fr); gap: 16px; }
|
|
1218
|
+
.dashboard-card { padding: 18px; }
|
|
1219
|
+
.card-heading { gap: 12px; }
|
|
1220
|
+
.result-body { gap: 22px; justify-content: center; }
|
|
1221
|
+
.result-ring { width: 128px; height: 128px; flex-basis: 128px; padding: 10px; }
|
|
1222
|
+
#legend.legend { max-width: 250px; }
|
|
1223
|
+
#legend .count { min-height: 32px; }
|
|
1224
|
+
.charts { grid-template-columns: 104px minmax(0, 1fr); gap: 14px; margin-top: 20px; }
|
|
1225
|
+
.pie { width: 104px; }
|
|
1226
|
+
.band { min-height: 36px; }
|
|
1227
|
+
.band-label { font-size: 10px; }
|
|
1228
|
+
.views .view { min-height: 28px; }
|
|
1229
|
+
.attention-row { gap: 8px; grid-template-columns: 48px minmax(0, 1fr) auto; }
|
|
1230
|
+
.dashboard-link { font-size: 10px; }
|
|
1231
|
+
#test-tools { padding: 12px; }
|
|
1232
|
+
.detail { position: static; padding: 20px 16px; max-height: none; }
|
|
1233
|
+
#tests { padding: 8px 12px 12px; }
|
|
1234
|
+
.page-heading h2, .panel > h2 { font-size: 28px; }
|
|
1235
|
+
}
|
|
1236
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1237
|
+
.panel-enter { animation: none; }
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/* Light workspace theme with navy typography and warm accent details. */
|
|
1241
|
+
.sidebar-brand { color: var(--heading); }
|
|
1242
|
+
.sidebar-brand > .icon { border-radius: 13px; box-shadow: inset 0 -3px 0 var(--accent); }
|
|
1243
|
+
.project-card { background: var(--base); border-radius: 14px; }
|
|
1244
|
+
.project-card > .icon { color: var(--heading); }
|
|
1245
|
+
.rail .tab { border-radius: 24px; }
|
|
1246
|
+
.rail .tab[aria-selected="true"] { box-shadow: inset 3px 0 0 var(--accent); }
|
|
1247
|
+
.rail .tab:hover { color: var(--heading); }
|
|
1248
|
+
.workspace-bar { box-shadow: 0 1px 6px rgba(49, 83, 134, .025); }
|
|
1249
|
+
.dashboard-kicker { color: var(--heading); }
|
|
1250
|
+
.word { color: var(--heading); font-size: 40px; font-weight: 500; }
|
|
1251
|
+
.word::after { content: ''; display: block; width: 52px; height: 4px; margin-top: 14px; border-radius: 4px; background: var(--accent); }
|
|
1252
|
+
.hero .product { margin-top: 14px; }
|
|
1253
|
+
.metric, .dashboard-card { border-radius: 16px; border-color: var(--border); box-shadow: 0 3px 15px rgba(49, 83, 134, .035); }
|
|
1254
|
+
.metric-label .icon { box-sizing: content-box; padding: 7px; background: var(--wash); border-radius: 50%; }
|
|
1255
|
+
.metric-value { color: var(--heading); }
|
|
1256
|
+
.card-heading h2, .range-head .section-label, .page-heading h2, .panel > h2, .detail h2, .file-group h3, .log-card h3 { color: var(--heading); }
|
|
1257
|
+
.card-detail { background: var(--wash); color: var(--heading); border-radius: 12px; padding: 4px 10px; }
|
|
1258
|
+
.views { border-radius: 20px; padding: 4px; border-color: var(--border); }
|
|
1259
|
+
.view { border-radius: 16px; padding: 5px 12px; }
|
|
1260
|
+
.result-ring strong { color: var(--heading); }
|
|
1261
|
+
.dashboard-link { color: var(--heading); padding-bottom: 3px; border-bottom: 2px solid var(--accent); }
|
|
1262
|
+
.dashboard-link:hover { color: var(--accent-hover); }
|
|
1263
|
+
#test-tools .count[aria-pressed="true"] { color: var(--heading); }
|
|
1264
|
+
.subtab[aria-pressed="true"], .attempt[aria-pressed="true"], .order-btn[aria-pressed="true"] { color: var(--heading); box-shadow: inset 0 -2px 0 var(--accent); }
|
|
1265
|
+
.file-link, .open-test, .more, .reset-filters { color: var(--heading); }
|
|
1266
|
+
.file-link:hover, .open-test:hover { color: var(--accent-hover); }
|
|
1267
|
+
.attention-row { color: var(--text); }
|
|
1268
|
+
.row[aria-current="true"] .row-title { color: var(--heading); }
|
|
1269
|
+
.band[aria-pressed="true"] .band-label, .band[aria-pressed="true"] .n, .run-row[aria-current="true"] .run-name { color: var(--heading); }
|
|
1270
|
+
.log-card, .file-group, .gallery .tile, .split { border-radius: 14px; }
|
|
1271
|
+
.run-state { border-color: transparent; background: var(--wash); font-weight: 500; }
|
|
1272
|
+
.run-state[data-status="passed"] { background: var(--pass-wash); }
|
|
1273
|
+
.run-state[data-status="failed"] { background: var(--fail-wash); }
|
|
1274
|
+
.run-state[data-status="timedout"], .run-state[data-status="interrupted"] { background: var(--warning-wash); }
|
|
1275
|
+
.banner { border-left-color: var(--fail); }
|
|
1276
|
+
.find:focus { border-color: var(--heading); }
|
|
1277
|
+
.skip { background: var(--heading); color: #ffffff; }
|
|
1278
|
+
@media (max-width: 800px) {
|
|
1279
|
+
.word { font-size: 30px; }
|
|
1280
|
+
.rail .tab[aria-selected="true"] { box-shadow: none; }
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
/* Shared controls and theme tokens keep both appearances consistent. */
|
|
1284
|
+
body[data-theme="dark"] {
|
|
1285
|
+
color-scheme: dark;
|
|
1286
|
+
--base: #101b2b;
|
|
1287
|
+
--surface: #18263a;
|
|
1288
|
+
--border: #2c405a;
|
|
1289
|
+
--text: #e7eef8;
|
|
1290
|
+
--subtle: #a1b2ca;
|
|
1291
|
+
--heading: #aecaf0;
|
|
1292
|
+
--control-active: #315386;
|
|
1293
|
+
--wash: #223a58;
|
|
1294
|
+
--hairline: rgba(174, 202, 240, .12);
|
|
1295
|
+
--pass: #67d4a7;
|
|
1296
|
+
--fail: #ff8b92;
|
|
1297
|
+
--flaky: #f7bb61;
|
|
1298
|
+
--skip: #8b9bb0;
|
|
1299
|
+
--timeout: #f7bb61;
|
|
1300
|
+
--interrupted: #8b9bb0;
|
|
1301
|
+
--pass-wash: #193d35;
|
|
1302
|
+
--fail-wash: #452b3a;
|
|
1303
|
+
--warning-wash: #403528;
|
|
1304
|
+
--chart-3: #709bce;
|
|
1305
|
+
--chart-4: #3e597b;
|
|
1306
|
+
--accent-hover: #ffbc83;
|
|
1307
|
+
}
|
|
1308
|
+
.theme-toggle { display: inline-flex; flex: 0 0 auto; align-items: center; gap: 9px; background: transparent; border: 1px solid var(--border); border-radius: 20px; color: var(--subtle); padding: 8px 12px; font-size: 12px; }
|
|
1309
|
+
.theme-toggle .icon { width: 16px; height: 16px; }
|
|
1310
|
+
.theme-toggle:hover { color: var(--heading); background: var(--wash); }
|
|
1311
|
+
.theme-switch { width: 28px; height: 16px; padding: 2px; background: var(--border); border-radius: 9px; }
|
|
1312
|
+
.theme-switch::before { content: ''; display: block; width: 12px; height: 12px; background: var(--surface); border-radius: 50%; }
|
|
1313
|
+
.theme-toggle[aria-checked="true"] .theme-switch { background: var(--accent); }
|
|
1314
|
+
.theme-toggle[aria-checked="true"] .theme-switch::before { transform: translateX(12px); background: #ffffff; }
|
|
1315
|
+
.filter-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 24px; margin-top: 16px; }
|
|
1316
|
+
.filter-toolbar .tags, .filter-toolbar .order { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px; margin: 0; }
|
|
1317
|
+
.filter-control { display: inline-flex; align-items: center; gap: 10px; min-width: 0; font-size: 12px; color: var(--subtle); }
|
|
1318
|
+
.filter-select { min-width: 148px; max-width: 240px; height: 38px; padding: 7px 34px 7px 12px; border: 1px solid var(--border); border-radius: 8px; color: var(--text); background-color: var(--surface); appearance: auto; cursor: pointer; font-size: 12px; }
|
|
1319
|
+
.filter-select:disabled { cursor: default; opacity: .6; }
|
|
1320
|
+
.filter-select:hover:not(:disabled) { border-color: var(--heading); }
|
|
1321
|
+
.filter-select:focus-visible { outline: 2px solid var(--heading); outline-offset: 2px; }
|
|
1322
|
+
.filter-toolbar .band-clear { display: inline-flex; align-items: center; gap: 8px; padding: 6px 10px; border: 1px solid var(--border); border-radius: 16px; background: var(--wash); color: var(--heading); font-size: 11px; min-height: 30px; }
|
|
1323
|
+
.filter-toolbar .band-clear:hover { border-color: var(--heading); }
|
|
1324
|
+
.list-summary { margin: 14px 0 10px; }
|
|
1325
|
+
.row-title { white-space: normal; line-height: 1.4; overflow-wrap: anywhere; }
|
|
1326
|
+
.row-time { align-self: start; }
|
|
1327
|
+
#shot-filters .shot-filter { padding: 6px 12px; border-radius: 18px; border: 1px solid var(--border); }
|
|
1328
|
+
#shot-filters .shot-filter[aria-pressed="true"] { background: var(--wash); color: var(--heading); border-color: var(--heading); }
|
|
1329
|
+
@media (max-width: 800px) {
|
|
1330
|
+
.theme-toggle { padding: 8px; gap: 6px; }
|
|
1331
|
+
.theme-toggle > span:not(.theme-switch) { display: none; }
|
|
1332
|
+
.filter-toolbar { gap: 12px 18px; }
|
|
1333
|
+
.filter-toolbar .tags, .filter-toolbar .order { gap: 12px; }
|
|
1334
|
+
.filter-control { gap: 8px; }
|
|
1335
|
+
.filter-select { min-width: 115px; max-width: 190px; }
|
|
1336
|
+
}
|
package/dist/ui/report.js
CHANGED
|
@@ -47,18 +47,22 @@
|
|
|
47
47
|
var findTimer = 0;
|
|
48
48
|
|
|
49
49
|
app.innerHTML = [
|
|
50
|
-
'<div class="atmosphere" aria-hidden="true"><canvas class="bands"></canvas><div class="grain"></div><div class="veil"></div></div>',
|
|
51
50
|
'<div class="shell">',
|
|
52
51
|
'<aside class="rail">',
|
|
53
|
-
'<div class="
|
|
52
|
+
'<div class="sidebar-brand">' + icon('brand') + '<span>Reborn<span class="brand-caption">Test reports</span></span></div>',
|
|
53
|
+
'<div class="project-card">' + icon('folder') + '<div><span class="project-caption">Workspace</span><strong id="workspace-name"></strong></div></div>',
|
|
54
|
+
'<p class="nav-caption">Run workspace</p>',
|
|
55
|
+
'<div class="tabbar" role="tablist" aria-label="Report" aria-orientation="vertical">',
|
|
54
56
|
|
|
55
57
|
TABS.map(function (id) {
|
|
56
|
-
return tabButton(id, id.charAt(0).toUpperCase() + id.slice(1));
|
|
58
|
+
return tabButton(id, id === 'overview' ? 'Dashboard' : id.charAt(0).toUpperCase() + id.slice(1));
|
|
57
59
|
}).join(''),
|
|
58
60
|
'</div>',
|
|
59
|
-
'<p class="
|
|
61
|
+
'<div class="sidebar-bottom"><p class="nav-caption">Current run</p><p class="sidebar-state run-state" id="sidebar-state"></p><p class="sidebar-note">Completed <span id="sidebar-time"></span></p><div class="keyboard-hint"><kbd>/</kbd><span>Find a test</span></div></div>',
|
|
60
62
|
'</aside>',
|
|
61
63
|
'<div class="stage">',
|
|
64
|
+
'<header class="workspace-bar"><div class="breadcrumb"><span id="breadcrumb-company"></span><span class="breadcrumb-separator">/</span><strong id="page-name">Dashboard</strong></div><button class="theme-toggle" id="theme-toggle" type="button" role="switch" aria-checked="false" aria-label="Dark mode">' + icon('moon') + '<span>Dark mode</span><span class="theme-switch" aria-hidden="true"></span></button></header>',
|
|
65
|
+
'<div class="report-content">',
|
|
62
66
|
'<div id="panel-overview" role="tabpanel"></div>',
|
|
63
67
|
'<div id="panel-tests" role="tabpanel" hidden></div>',
|
|
64
68
|
'<div id="panel-screenshots" role="tabpanel" hidden></div>',
|
|
@@ -67,11 +71,16 @@
|
|
|
67
71
|
'<p class="foot" id="foot"></p>',
|
|
68
72
|
'</div>',
|
|
69
73
|
'</div>',
|
|
74
|
+
'</div>',
|
|
70
75
|
].join('');
|
|
71
76
|
|
|
72
77
|
document.body.dataset.accent = accentName();
|
|
78
|
+
applyTheme(readTheme());
|
|
73
79
|
document.title = companyName() + (data.summary ? ' · ' + data.summary : '');
|
|
74
|
-
|
|
80
|
+
document.getElementById('workspace-name').textContent = companyName();
|
|
81
|
+
document.getElementById('breadcrumb-company').textContent = companyName();
|
|
82
|
+
document.getElementById('sidebar-time').textContent = formatWhen(data.generatedAt);
|
|
83
|
+
setRunState(document.getElementById('sidebar-state'));
|
|
75
84
|
var footBits = [];
|
|
76
85
|
if (data.showCredit === true) footBits.push(el('span', null, ['Open source by World of Z']));
|
|
77
86
|
footBits.push(el('span', null, [formatWhen(data.generatedAt)]));
|
|
@@ -83,94 +92,41 @@
|
|
|
83
92
|
['3to5', '3 to 5 minutes'],
|
|
84
93
|
['over5', 'Over 5 minutes'],
|
|
85
94
|
];
|
|
86
|
-
var CHART_COLORS = ['var(--
|
|
95
|
+
var CHART_COLORS = ['var(--heading)', 'var(--chart-2)', 'var(--chart-3)', 'var(--chart-4)'];
|
|
87
96
|
|
|
97
|
+
syncTabOrientation();
|
|
98
|
+
window.addEventListener('resize', syncTabOrientation);
|
|
88
99
|
paintOverview();
|
|
89
100
|
showTab(state.tab, true);
|
|
90
101
|
bind();
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
var rect = canvas.getBoundingClientRect();
|
|
115
|
-
canvas.width = Math.max(1, Math.floor(rect.width * ratio));
|
|
116
|
-
canvas.height = Math.max(1, Math.floor(rect.height * ratio));
|
|
117
|
-
}
|
|
118
|
-
var rgb = accentParts();
|
|
119
|
-
function draw(now) {
|
|
120
|
-
var w = canvas.width;
|
|
121
|
-
var h = canvas.height;
|
|
122
|
-
var t = reduce ? 8 : now / 1000;
|
|
123
|
-
ctx.clearRect(0, 0, w, h);
|
|
124
|
-
var wash = ctx.createLinearGradient(0, 0, 0, h);
|
|
125
|
-
wash.addColorStop(0, 'rgba(' + rgb + ', 0.10)');
|
|
126
|
-
wash.addColorStop(0.42, '#080b0a');
|
|
127
|
-
wash.addColorStop(1, '#080808');
|
|
128
|
-
ctx.fillStyle = wash;
|
|
129
|
-
ctx.fillRect(0, 0, w, h);
|
|
130
|
-
columns.forEach(function (column) {
|
|
131
|
-
var sway = Math.sin(t * column.speed + column.phase) * 0.02;
|
|
132
|
-
var breath = 0.4 + 0.6 * (0.5 + 0.5 * Math.sin(t * column.speed * 1.4 + column.phase));
|
|
133
|
-
var x = (column.at + sway) * w;
|
|
134
|
-
var spread = Math.max(10, column.width * w * (0.55 + breath * 0.35));
|
|
135
|
-
var gradient = ctx.createLinearGradient(x - spread, 0, x + spread, 0);
|
|
136
|
-
var alpha = 0.28 + 0.62 * breath;
|
|
137
|
-
gradient.addColorStop(0, 'rgba(' + rgb + ', 0)');
|
|
138
|
-
gradient.addColorStop(0.42, 'rgba(' + rgb + ', ' + (alpha * 0.45).toFixed(3) + ')');
|
|
139
|
-
gradient.addColorStop(0.5, 'rgba(' + rgb + ', ' + alpha.toFixed(3) + ')');
|
|
140
|
-
gradient.addColorStop(0.58, 'rgba(' + rgb + ', ' + (alpha * 0.45).toFixed(3) + ')');
|
|
141
|
-
gradient.addColorStop(1, 'rgba(' + rgb + ', 0)');
|
|
142
|
-
ctx.fillStyle = gradient;
|
|
143
|
-
ctx.fillRect(x - spread, 0, spread * 2, h * 0.92);
|
|
144
|
-
});
|
|
145
|
-
if (!reduce && !document.hidden) curtainFrame = requestAnimationFrame(draw);
|
|
146
|
-
}
|
|
147
|
-
var curtainFrame = 0;
|
|
148
|
-
resize();
|
|
149
|
-
window.addEventListener('resize', function () { resize(); if (reduce) draw(0); });
|
|
150
|
-
document.addEventListener('visibilitychange', function () {
|
|
151
|
-
cancelAnimationFrame(curtainFrame);
|
|
152
|
-
if (!document.hidden) curtainFrame = requestAnimationFrame(draw);
|
|
153
|
-
});
|
|
154
|
-
curtainFrame = requestAnimationFrame(function (now) {
|
|
155
|
-
if (!canvas.width) resize();
|
|
156
|
-
draw(now);
|
|
157
|
-
});
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
function icon(name) {
|
|
105
|
+
var paths = {
|
|
106
|
+
brand: '<path d="m8 5-5 7 5 7m8-14 5 7-5 7m-8-7 3 3 5-6"/>',
|
|
107
|
+
overview: '<rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/>',
|
|
108
|
+
tests: '<path d="m9 11 2 2 4-4"/><rect x="5" y="4" width="14" height="17" rx="2"/><path d="M9 4V2h6v2"/>',
|
|
109
|
+
screenshots: '<rect x="3" y="3" width="18" height="18" rx="3"/><circle cx="8" cy="8" r="1.5"/><path d="m3 17 6-6 4 4 3-3 5 5"/>',
|
|
110
|
+
logs: '<path d="m5 6 4 4-4 4m7 3h7"/><rect x="2" y="2" width="20" height="20" rx="3"/>',
|
|
111
|
+
files: '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zm0 0v6h6M8 13h8m-8 4h5"/>',
|
|
112
|
+
folder: '<path d="M3 7V5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"/>',
|
|
113
|
+
search: '<circle cx="10.5" cy="10.5" r="6.5"/><path d="m16 16 5 5"/>',
|
|
114
|
+
clock: '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',
|
|
115
|
+
check: '<circle cx="12" cy="12" r="9"/><path d="m8 12 3 3 5-6"/>',
|
|
116
|
+
alert: '<path d="m12 3 10 18H2Z M12 9v4m0 3v1"/>',
|
|
117
|
+
moon: '<path d="M21 13a9 9 0 0 1-10-10 9 9 0 1 0 10 10Z"/>',
|
|
118
|
+
arrow: '<path d="M5 12h14m-5-5 5 5-5 5"/>',
|
|
119
|
+
};
|
|
120
|
+
return '<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' + (paths[name] || paths.tests) + '</svg>';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function syncTabOrientation() {
|
|
124
|
+
document.querySelector('.tabbar').setAttribute('aria-orientation', window.innerWidth <= 800 ? 'horizontal' : 'vertical');
|
|
158
125
|
}
|
|
159
126
|
|
|
160
|
-
function
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
rail.addEventListener('focusin', function () { rail.classList.remove('is-hidden'); });
|
|
164
|
-
var lastY = window.scrollY;
|
|
165
|
-
window.addEventListener('scroll', function () {
|
|
166
|
-
var y = window.scrollY;
|
|
167
|
-
var down = y > lastY + 6;
|
|
168
|
-
var up = y < lastY - 6;
|
|
169
|
-
if (y < 24) rail.classList.remove('is-hidden');
|
|
170
|
-
else if (down && !rail.contains(document.activeElement)) rail.classList.add('is-hidden');
|
|
171
|
-
else if (up) rail.classList.remove('is-hidden');
|
|
172
|
-
lastY = y;
|
|
173
|
-
}, { passive: true });
|
|
127
|
+
function setRunState(node) {
|
|
128
|
+
node.dataset.status = data.status;
|
|
129
|
+
node.textContent = { passed: 'Run passed', failed: 'Run failed', timedout: 'Run timed out', interrupted: 'Run interrupted' }[data.status] || 'Run finished';
|
|
174
130
|
}
|
|
175
131
|
|
|
176
132
|
function companyName() {
|
|
@@ -183,18 +139,22 @@
|
|
|
183
139
|
return allowed[data.accent] ? data.accent : 'green';
|
|
184
140
|
}
|
|
185
141
|
|
|
186
|
-
function
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
142
|
+
function readTheme() {
|
|
143
|
+
try {
|
|
144
|
+
var saved = localStorage.getItem('reborn-theme');
|
|
145
|
+
if (saved === 'light' || saved === 'dark') return saved;
|
|
146
|
+
} catch (error) { /* Storage may be unavailable for local reports. */ }
|
|
147
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function applyTheme(theme) {
|
|
151
|
+
document.body.dataset.theme = theme;
|
|
152
|
+
document.getElementById('theme-toggle').setAttribute('aria-checked', theme === 'dark' ? 'true' : 'false');
|
|
194
153
|
}
|
|
195
154
|
|
|
196
155
|
function tabButton(id, label) {
|
|
197
|
-
|
|
156
|
+
var count = id === 'tests' ? data.tests.length : null;
|
|
157
|
+
return '<button id="tab-' + id + '" class="tab" role="tab" type="button" data-tab="' + id + '" aria-selected="false" aria-controls="panel-' + id + '">' + icon(id) + '<span>' + label + '</span>' + (count === null ? '' : '<span class="nav-count" aria-hidden="true">' + count + '</span>') + '</button>';
|
|
198
158
|
}
|
|
199
159
|
|
|
200
160
|
function readRoute() {
|
|
@@ -216,6 +176,7 @@
|
|
|
216
176
|
function showTab(tab, quiet) {
|
|
217
177
|
if (TABS.indexOf(tab) === -1) tab = 'overview';
|
|
218
178
|
state.tab = tab;
|
|
179
|
+
document.getElementById('page-name').textContent = tab === 'overview' ? 'Dashboard' : tab.charAt(0).toUpperCase() + tab.slice(1);
|
|
219
180
|
document.querySelectorAll('[role="tab"]').forEach(function (button) {
|
|
220
181
|
button.setAttribute('aria-selected', button.dataset.tab === tab ? 'true' : 'false');
|
|
221
182
|
button.tabIndex = button.dataset.tab === tab ? 0 : -1;
|
|
@@ -254,38 +215,33 @@
|
|
|
254
215
|
var host = document.getElementById('panel-overview');
|
|
255
216
|
host.innerHTML = [
|
|
256
217
|
'<header class="hero">',
|
|
257
|
-
'<div><
|
|
218
|
+
'<div><p class="dashboard-kicker">Run overview</p><h1 class="word">Dashboard</h1><p class="product" id="product"></p><p class="summary" id="summary"></p></div>',
|
|
258
219
|
'<p class="run-state" id="run-state"></p>',
|
|
259
220
|
'</header>',
|
|
221
|
+
'<p class="meta" id="meta"></p>',
|
|
260
222
|
'<div id="errors"></div>',
|
|
261
|
-
'<
|
|
262
|
-
'<
|
|
263
|
-
'<div class="
|
|
264
|
-
'<
|
|
265
|
-
'<div class="legend" id="legend"></div>',
|
|
266
|
-
'<div class="
|
|
267
|
-
'<
|
|
268
|
-
'<div class="views" role="group" aria-label="Overview shape">',
|
|
269
|
-
'<
|
|
270
|
-
'<button type="button" class="view" data-overview="timeline">Timeline</button>',
|
|
271
|
-
'</div>',
|
|
272
|
-
'</div>',
|
|
273
|
-
'<p class="section-note" id="range-note"></p>',
|
|
274
|
-
'<div class="charts" id="duration"></div>',
|
|
223
|
+
'<div class="metric-grid" id="metrics"></div>',
|
|
224
|
+
'<div class="dashboard-grid">',
|
|
225
|
+
'<section class="dashboard-card result-card"><div class="card-heading"><h2>Test results</h2><span class="card-detail">This run</span></div>',
|
|
226
|
+
'<div class="result-body"><div class="result-ring" id="result-ring"><div><strong id="pass-percent"></strong><span>Passed</span></div></div>',
|
|
227
|
+
'<div class="legend" id="legend"></div></div><p class="card-note" id="result-note"></p></section>',
|
|
228
|
+
'<section class="dashboard-card console"><div class="console-body">',
|
|
229
|
+
'<div class="range-head"><h2 class="section-label" id="range-label">Duration</h2>',
|
|
230
|
+
'<div class="views" role="group" aria-label="Overview shape"><button type="button" class="view" data-overview="chart">Chart</button><button type="button" class="view" data-overview="timeline">Timeline</button></div></div>',
|
|
231
|
+
'<p class="section-note" id="range-note"></p><div class="charts" id="duration"></div>',
|
|
275
232
|
'<div class="strip-window" id="strip-window"><div class="strip-scroll"><div class="strip" id="strip" role="group" aria-label="Tests by time"></div></div></div>',
|
|
233
|
+
'</div></section>',
|
|
234
|
+
'<section class="dashboard-card attention-card"><div class="card-heading"><h2>Needs attention</h2><button type="button" class="dashboard-link" data-go-tests>View all tests ' + icon('arrow') + '</button></div><div id="attention-list"></div></section>',
|
|
235
|
+
'<section class="dashboard-card environment-card"><div class="card-heading"><h2>Run details</h2>' + icon('folder') + '</div><dl class="run-details" id="run-details"></dl><dl class="info" id="info"></dl></section>',
|
|
276
236
|
'</div>',
|
|
277
|
-
'</section>',
|
|
278
237
|
].join('');
|
|
279
|
-
var word = document.getElementById('word');
|
|
280
|
-
word.textContent = companyName();
|
|
281
|
-
var product = document.getElementById('product');
|
|
282
238
|
var subtitle = typeof data.productSubtitle === 'string' ? data.productSubtitle.trim() : 'Test Automation';
|
|
283
|
-
|
|
284
|
-
|
|
239
|
+
document.getElementById('product').textContent = subtitle;
|
|
240
|
+
document.getElementById('product').hidden = !subtitle;
|
|
285
241
|
document.getElementById('summary').textContent = data.summary || '';
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
242
|
+
fill(document.getElementById('meta'), metaBits().map(function (bit) { return el('span', null, [bit]); }));
|
|
243
|
+
setRunState(document.getElementById('run-state'));
|
|
244
|
+
paintDashboard();
|
|
289
245
|
paintErrors();
|
|
290
246
|
paintInfo();
|
|
291
247
|
paintCounts(document.getElementById('legend'), false);
|
|
@@ -294,6 +250,60 @@
|
|
|
294
250
|
applyOverview();
|
|
295
251
|
}
|
|
296
252
|
|
|
253
|
+
function paintDashboard() {
|
|
254
|
+
var counts = data.counts || {};
|
|
255
|
+
var total = data.tests.length;
|
|
256
|
+
var passed = counts.passed || 0;
|
|
257
|
+
var percent = total ? Math.round(passed / total * 100) : 0;
|
|
258
|
+
var problems = data.tests.filter(isProblem);
|
|
259
|
+
var metrics = [
|
|
260
|
+
['tests', 'Total tests', String(total), 'Across ' + uniqueValues(function (test) { return [test.file]; }).length + ' test files', ''],
|
|
261
|
+
['check', 'Pass rate', total ? percent + '%' : '—', passed + ' of ' + total + ' tests passed', 'positive'],
|
|
262
|
+
['clock', 'Run duration', formatDuration(data.duration || 0), 'Wall time including retries', ''],
|
|
263
|
+
['alert', 'Needs attention', String(problems.length), 'Failed, flaky or interrupted', problems.length ? 'warning' : 'positive'],
|
|
264
|
+
];
|
|
265
|
+
fill(document.getElementById('metrics'), metrics.map(function (metric) {
|
|
266
|
+
var node = el('div', { class: 'metric ' + metric[4] }, [
|
|
267
|
+
el('div', { class: 'metric-label' }, [metric[1]]),
|
|
268
|
+
el('strong', { class: 'metric-value' }, [metric[2]]),
|
|
269
|
+
el('span', { class: 'metric-note' }, [metric[3]]),
|
|
270
|
+
]);
|
|
271
|
+
node.querySelector('.metric-label').insertAdjacentHTML('beforeend', icon(metric[0]));
|
|
272
|
+
return node;
|
|
273
|
+
}));
|
|
274
|
+
document.getElementById('pass-percent').textContent = total ? percent + '%' : '—';
|
|
275
|
+
var colors = { passed: 'var(--pass)', failed: 'var(--fail)', timedOut: 'var(--fail)', flaky: 'var(--flaky)', skipped: 'var(--skip)', interrupted: 'var(--timeout)' };
|
|
276
|
+
var offset = 0;
|
|
277
|
+
var stops = [];
|
|
278
|
+
Object.keys(colors).forEach(function (status) {
|
|
279
|
+
var amount = counts[status] || 0;
|
|
280
|
+
if (!amount || !total) return;
|
|
281
|
+
var next = offset + amount / total * 100;
|
|
282
|
+
stops.push(colors[status] + ' ' + offset + '% ' + next + '%');
|
|
283
|
+
offset = next;
|
|
284
|
+
});
|
|
285
|
+
document.getElementById('result-ring').style.background = stops.length ? 'conic-gradient(' + stops.join(',') + ')' : 'var(--hairline)';
|
|
286
|
+
document.getElementById('result-note').textContent = 'Select a result to explore its tests. Pass rate includes skipped tests in the total.';
|
|
287
|
+
var attention = problems.slice(0, 5).map(function (test) {
|
|
288
|
+
return el('button', { type: 'button', class: 'attention-row open-test', 'data-id': test.id, 'data-attempt': String(failedAttempt(test)) }, [
|
|
289
|
+
el('span', { class: 'attention-status sw', 'data-status': test.status }, [statusLabel(test)]),
|
|
290
|
+
el('span', { class: 'attention-test' }, [el('strong', null, [test.title]), el('span', null, [test.file])]),
|
|
291
|
+
el('span', { class: 'attention-time' }, [formatDuration(test.duration)]),
|
|
292
|
+
]);
|
|
293
|
+
});
|
|
294
|
+
if (!attention.length) attention.push(el('p', { class: 'empty' }, [total ? 'No tests need attention. Your run is looking good.' : 'No tests ran. Run your test suite to see results here.']));
|
|
295
|
+
if (problems.length > 5) attention.push(el('p', { class: 'card-note' }, ['Showing 5 of ' + problems.length + ' tests. View all tests to explore the rest.']));
|
|
296
|
+
fill(document.getElementById('attention-list'), attention);
|
|
297
|
+
var rows = [['Started', formatWhen(data.startTime)], ['Workers', String(data.workers || 0)], ['Screenshots', { off: 'Off', failure: 'On failure', last: 'Last step', steps: 'Every step' }[data.screenshots] || 'Off']];
|
|
298
|
+
if (data.showProjects === true && (data.projects || []).length) rows.push(['Projects', data.projects.join(', ')]);
|
|
299
|
+
if (data.shard) rows.push(['Shard', data.shard]);
|
|
300
|
+
var customLabels = (data.info || []).map(function (row) { return String(row.label).toLowerCase(); });
|
|
301
|
+
rows = rows.filter(function (row) { return customLabels.indexOf(row[0].toLowerCase()) === -1; });
|
|
302
|
+
fill(document.getElementById('run-details'), rows.map(function (row) {
|
|
303
|
+
return el('div', null, [el('dt', null, [row[0]]), el('dd', null, [row[1]])]);
|
|
304
|
+
}));
|
|
305
|
+
}
|
|
306
|
+
|
|
297
307
|
function paintInfo() {
|
|
298
308
|
var host = document.getElementById('info');
|
|
299
309
|
if (!host) return;
|
|
@@ -367,7 +377,7 @@
|
|
|
367
377
|
empty.setAttribute('cx', '110');
|
|
368
378
|
empty.setAttribute('cy', '110');
|
|
369
379
|
empty.setAttribute('r', '96');
|
|
370
|
-
empty.setAttribute('fill', '
|
|
380
|
+
empty.setAttribute('fill', 'var(--hairline)');
|
|
371
381
|
svg.appendChild(empty);
|
|
372
382
|
return svg;
|
|
373
383
|
}
|
|
@@ -496,22 +506,9 @@
|
|
|
496
506
|
var buttons = filters.map(function (filter) {
|
|
497
507
|
return el('button', { class: 'count', type: 'button', 'data-status': filter[0], 'aria-pressed': 'false' }, [
|
|
498
508
|
el('span', { class: 'n' }, [String(filter[2])]),
|
|
499
|
-
filter[1],
|
|
509
|
+
' ' + filter[1],
|
|
500
510
|
]);
|
|
501
511
|
});
|
|
502
|
-
if (host.id === 'legend') {
|
|
503
|
-
buttons.unshift(el('div', { class: 'count count-static' }, [
|
|
504
|
-
el('span', { class: 'n' }, [formatDuration(data.duration || 0)]),
|
|
505
|
-
'total',
|
|
506
|
-
]));
|
|
507
|
-
buttons.forEach(function (button) {
|
|
508
|
-
if (button.classList.contains('count-static')) return;
|
|
509
|
-
var node = button.querySelector('.n');
|
|
510
|
-
var value = Number(node.textContent);
|
|
511
|
-
node.textContent = '0';
|
|
512
|
-
countUp(node, value, function (next) { return String(Math.round(next)); });
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
512
|
var children = buttons;
|
|
516
513
|
if (withFind) {
|
|
517
514
|
children = buttons.concat([el('div', { class: 'find-wrap' }, [
|
|
@@ -611,33 +608,25 @@
|
|
|
611
608
|
return Object.keys(seen).sort();
|
|
612
609
|
}
|
|
613
610
|
|
|
611
|
+
function selectControl(id, label, choices, current) {
|
|
612
|
+
var select = el('select', { id: id, class: 'filter-select' }, choices.map(function (choice) {
|
|
613
|
+
return el('option', { value: choice[0] }, [choice[1]]);
|
|
614
|
+
}));
|
|
615
|
+
select.value = current || '';
|
|
616
|
+
return el('label', { class: 'filter-control', for: id }, [el('span', null, [label]), select]);
|
|
617
|
+
}
|
|
618
|
+
|
|
614
619
|
function paintTags() {
|
|
615
620
|
var host = document.getElementById('tags');
|
|
616
621
|
if (!host) return;
|
|
617
622
|
var tags = uniqueValues(function (test) { return (test.tags || []).filter(keptTag); });
|
|
618
623
|
var projects = uniqueValues(function (test) { return test.project ? [test.project] : []; });
|
|
619
|
-
var nodes = [];
|
|
620
|
-
if (tags.length) {
|
|
621
|
-
nodes.push(el('span', { class: 'order-label' }, ['Tags']));
|
|
622
|
-
nodes.push(chip('tag-btn', '', 'All', state.tag || ''));
|
|
623
|
-
tags.forEach(function (tag) { nodes.push(chip('tag-btn', tag, tag, state.tag)); });
|
|
624
|
-
}
|
|
624
|
+
var nodes = [selectControl('tag-select', 'Tags', [['', 'All tags']].concat(tags.map(function (tag) { return [tag, tag]; })), state.tag)];
|
|
625
625
|
if (data.showProjectFilter === true && projects.length > 1) {
|
|
626
|
-
nodes.push(
|
|
627
|
-
nodes.push(chip('project-btn', '', 'All', state.projectFilter || ''));
|
|
628
|
-
projects.forEach(function (project) { nodes.push(chip('project-btn', project, project, state.projectFilter)); });
|
|
626
|
+
nodes.push(selectControl('project-select', 'Project', [['', 'All projects']].concat(projects.map(function (project) { return [project, project]; })), state.projectFilter));
|
|
629
627
|
}
|
|
630
|
-
host.hidden = nodes.length === 0;
|
|
631
628
|
fill(host, nodes);
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
function chip(className, value, label, current) {
|
|
635
|
-
return el('button', {
|
|
636
|
-
class: className,
|
|
637
|
-
type: 'button',
|
|
638
|
-
'data-value': value,
|
|
639
|
-
'aria-pressed': current === value ? 'true' : 'false',
|
|
640
|
-
}, [label]);
|
|
629
|
+
if (!tags.length) document.getElementById('tag-select').disabled = true;
|
|
641
630
|
}
|
|
642
631
|
|
|
643
632
|
function sortTests(tests) {
|
|
@@ -657,17 +646,10 @@
|
|
|
657
646
|
function paintOrder() {
|
|
658
647
|
var host = document.getElementById('order');
|
|
659
648
|
if (!host) return;
|
|
660
|
-
var orders = [['grouped', 'Grouped'], ['slowest', 'Slowest'], ['fastest', 'Fastest'], ['started', '
|
|
661
|
-
var nodes = [
|
|
662
|
-
return el('button', {
|
|
663
|
-
class: 'order-btn',
|
|
664
|
-
type: 'button',
|
|
665
|
-
'data-order': order[0],
|
|
666
|
-
'aria-pressed': state.order === order[0] ? 'true' : 'false',
|
|
667
|
-
}, [order[1]]);
|
|
668
|
-
}));
|
|
649
|
+
var orders = [['grouped', 'Grouped'], ['slowest', 'Slowest first'], ['fastest', 'Fastest first'], ['started', 'Start time']];
|
|
650
|
+
var nodes = [selectControl('sort-select', 'Sort', orders, state.order)];
|
|
669
651
|
if (state.band !== 'all') {
|
|
670
|
-
nodes.push(el('button', { class: 'band-clear', type: 'button', 'aria-
|
|
652
|
+
nodes.push(el('button', { class: 'band-clear', type: 'button', 'aria-label': 'Clear duration filter: ' + bandLabel(state.band) }, [bandLabel(state.band), el('span', { 'aria-hidden': 'true' }, [' ×'])]));
|
|
671
653
|
}
|
|
672
654
|
fill(host, nodes);
|
|
673
655
|
}
|
|
@@ -676,7 +658,7 @@
|
|
|
676
658
|
if (built.tests) return;
|
|
677
659
|
built.tests = true;
|
|
678
660
|
var host = document.getElementById('panel-tests');
|
|
679
|
-
host.innerHTML = '<
|
|
661
|
+
host.innerHTML = '<div class="page-heading"><h2>Tests</h2><p>Explore results, retries and the steps behind every test.</p></div><div class="legend" id="test-tools"></div><div class="filter-toolbar"><div class="tags" id="tags"></div><div class="order" id="order"></div></div><div class="list-summary" id="list-summary"></div><div class="split"><div id="tests"></div><section class="detail" id="detail"></section></div>';
|
|
680
662
|
paintCounts(document.getElementById('test-tools'), true);
|
|
681
663
|
paintTags();
|
|
682
664
|
paintOrder();
|
|
@@ -1070,6 +1052,17 @@
|
|
|
1070
1052
|
document.getElementById('find').focus();
|
|
1071
1053
|
return;
|
|
1072
1054
|
}
|
|
1055
|
+
if (target.closest('#theme-toggle')) {
|
|
1056
|
+
var theme = document.body.dataset.theme === 'dark' ? 'light' : 'dark';
|
|
1057
|
+
applyTheme(theme);
|
|
1058
|
+
try { localStorage.setItem('reborn-theme', theme); } catch (error) { /* Theme still works without storage. */ }
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
if (target.closest('[data-go-tests]')) {
|
|
1062
|
+
showTab('tests');
|
|
1063
|
+
document.getElementById('find').focus();
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1073
1066
|
var tab = target.closest('.tab');
|
|
1074
1067
|
if (tab) {
|
|
1075
1068
|
showTab(tab.dataset.tab);
|
|
@@ -1118,35 +1111,6 @@
|
|
|
1118
1111
|
paintDetail();
|
|
1119
1112
|
return;
|
|
1120
1113
|
}
|
|
1121
|
-
var tag = target.closest('.tag-btn');
|
|
1122
|
-
if (tag) {
|
|
1123
|
-
state.tag = tag.dataset.value || null;
|
|
1124
|
-
state.listLimit = 200;
|
|
1125
|
-
keepSelectionInFilter();
|
|
1126
|
-
paintTags();
|
|
1127
|
-
paintList();
|
|
1128
|
-
paintDetail();
|
|
1129
|
-
return;
|
|
1130
|
-
}
|
|
1131
|
-
var projectButton = target.closest('.project-btn');
|
|
1132
|
-
if (projectButton) {
|
|
1133
|
-
state.projectFilter = projectButton.dataset.value || null;
|
|
1134
|
-
state.listLimit = 200;
|
|
1135
|
-
keepSelectionInFilter();
|
|
1136
|
-
paintTags();
|
|
1137
|
-
paintList();
|
|
1138
|
-
paintDetail();
|
|
1139
|
-
return;
|
|
1140
|
-
}
|
|
1141
|
-
var order = target.closest('.order-btn');
|
|
1142
|
-
if (order) {
|
|
1143
|
-
state.order = order.dataset.order || 'grouped';
|
|
1144
|
-
keepSelectionInFilter();
|
|
1145
|
-
paintOrder();
|
|
1146
|
-
paintList();
|
|
1147
|
-
paintDetail();
|
|
1148
|
-
return;
|
|
1149
|
-
}
|
|
1150
1114
|
var count = target.closest('.count');
|
|
1151
1115
|
if (count && !count.classList.contains('shot-filter') && !count.classList.contains('count-static')) {
|
|
1152
1116
|
state.filter = count.dataset.status || 'all';
|
|
@@ -1209,6 +1173,19 @@
|
|
|
1209
1173
|
if (shot) openShot(shot.dataset.src, shot.dataset.alt || 'Screenshot');
|
|
1210
1174
|
});
|
|
1211
1175
|
|
|
1176
|
+
app.addEventListener('change', function (event) {
|
|
1177
|
+
var control = event.target;
|
|
1178
|
+
if (!control || ['tag-select', 'project-select', 'sort-select'].indexOf(control.id) === -1) return;
|
|
1179
|
+
if (control.id === 'tag-select') state.tag = control.value || null;
|
|
1180
|
+
if (control.id === 'project-select') state.projectFilter = control.value || null;
|
|
1181
|
+
if (control.id === 'sort-select') state.order = control.value || 'grouped';
|
|
1182
|
+
state.listLimit = 200;
|
|
1183
|
+
keepSelectionInFilter();
|
|
1184
|
+
paintList();
|
|
1185
|
+
paintDetail();
|
|
1186
|
+
markStrip();
|
|
1187
|
+
});
|
|
1188
|
+
|
|
1212
1189
|
app.addEventListener('input', function (event) {
|
|
1213
1190
|
if (!event.target) return;
|
|
1214
1191
|
if (event.target.id === 'find') {
|
|
@@ -1231,6 +1208,7 @@
|
|
|
1231
1208
|
|
|
1232
1209
|
document.addEventListener('keydown', function (event) {
|
|
1233
1210
|
if (event.defaultPrevented || event.isComposing || event.metaKey || event.ctrlKey || event.altKey || document.querySelector('dialog[open]')) return;
|
|
1211
|
+
if (event.target instanceof HTMLSelectElement) return;
|
|
1234
1212
|
var typing = event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement || event.target instanceof HTMLSelectElement || event.target.isContentEditable;
|
|
1235
1213
|
if (typing) {
|
|
1236
1214
|
if (event.key === 'Escape') {
|
|
@@ -1262,12 +1240,12 @@
|
|
|
1262
1240
|
if (find) find.focus();
|
|
1263
1241
|
return;
|
|
1264
1242
|
}
|
|
1265
|
-
if ((event.key === 'ArrowRight' || event.key === 'ArrowLeft' || event.key === 'Home' || event.key === 'End') && event.target.closest && event.target.closest('.tabbar')) {
|
|
1243
|
+
if ((event.key === 'ArrowRight' || event.key === 'ArrowLeft' || event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Home' || event.key === 'End') && event.target.closest && event.target.closest('.tabbar')) {
|
|
1266
1244
|
event.preventDefault();
|
|
1267
1245
|
var index = TABS.indexOf(state.tab);
|
|
1268
1246
|
if (event.key === 'Home') index = 0;
|
|
1269
1247
|
else if (event.key === 'End') index = TABS.length - 1;
|
|
1270
|
-
else if (event.key === 'ArrowRight') index = (index + 1) % TABS.length;
|
|
1248
|
+
else if (event.key === 'ArrowRight' || event.key === 'ArrowDown') index = (index + 1) % TABS.length;
|
|
1271
1249
|
else index = (index - 1 + TABS.length) % TABS.length;
|
|
1272
1250
|
showTab(TABS[index]);
|
|
1273
1251
|
var next = document.querySelector('.tab[data-tab="' + TABS[index] + '"]');
|
package/package.json
CHANGED