Kea2-python 0.1.0b0__py3-none-any.whl → 0.1.2__py3-none-any.whl
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.
Potentially problematic release.
This version of Kea2-python might be problematic. Click here for more details.
- kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so +0 -0
- kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so +0 -0
- kea2/assets/kea2-thirdpart.jar +0 -0
- kea2/assets/monkeyq.jar +0 -0
- kea2/assets/quicktest.py +3 -1
- kea2/bug_report_generator.py +479 -0
- kea2/fastbotManager.py +155 -0
- kea2/keaUtils.py +56 -133
- kea2/kea_launcher.py +10 -0
- kea2/logWatcher.py +11 -4
- kea2/templates/bug_report_template.html +937 -0
- kea2/utils.py +1 -5
- {kea2_python-0.1.0b0.dist-info → kea2_python-0.1.2.dist-info}/METADATA +14 -17
- {kea2_python-0.1.0b0.dist-info → kea2_python-0.1.2.dist-info}/RECORD +18 -14
- {kea2_python-0.1.0b0.dist-info → kea2_python-0.1.2.dist-info}/WHEEL +0 -0
- {kea2_python-0.1.0b0.dist-info → kea2_python-0.1.2.dist-info}/entry_points.txt +0 -0
- {kea2_python-0.1.0b0.dist-info → kea2_python-0.1.2.dist-info}/licenses/LICENSE +0 -0
- {kea2_python-0.1.0b0.dist-info → kea2_python-0.1.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,937 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Kea2 Test Report</title>
|
|
7
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
8
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
10
|
+
<style>
|
|
11
|
+
:root {
|
|
12
|
+
--primary-color: #3498db;
|
|
13
|
+
--secondary-color: #2ecc71;
|
|
14
|
+
--warning-color: #f39c12;
|
|
15
|
+
--danger-color: #e74c3c;
|
|
16
|
+
--dark-color: #2c3e50;
|
|
17
|
+
--light-color: #ecf0f1;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
body {
|
|
21
|
+
font-family: 'Segoe UI', Roboto, -apple-system, sans-serif;
|
|
22
|
+
background-color: #f8f9fa;
|
|
23
|
+
color: #333;
|
|
24
|
+
line-height: 1.6;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.header {
|
|
28
|
+
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
|
|
29
|
+
color: white;
|
|
30
|
+
padding: 2.5rem 0;
|
|
31
|
+
margin-bottom: 3rem;
|
|
32
|
+
border-radius: 0 0 20px 20px;
|
|
33
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.stats-card {
|
|
37
|
+
border-radius: 12px;
|
|
38
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
|
39
|
+
transition: transform 0.3s, box-shadow 0.3s;
|
|
40
|
+
height: 100%;
|
|
41
|
+
overflow: hidden;
|
|
42
|
+
padding: 1rem;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.stats-card:hover {
|
|
46
|
+
transform: translateY(-5px);
|
|
47
|
+
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.card-header {
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
padding: 1.25rem 1.5rem;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.card-body {
|
|
56
|
+
padding: 1.5rem;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.screenshots-container {
|
|
60
|
+
display: flex;
|
|
61
|
+
overflow-x: auto;
|
|
62
|
+
gap: 15px;
|
|
63
|
+
padding: 15px 0;
|
|
64
|
+
scrollbar-width: thin;
|
|
65
|
+
scrollbar-color: var(--primary-color) #eee;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.screenshots-container::-webkit-scrollbar {
|
|
69
|
+
height: 8px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.screenshots-container::-webkit-scrollbar-track {
|
|
73
|
+
background: #eee;
|
|
74
|
+
border-radius: 10px;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.screenshots-container::-webkit-scrollbar-thumb {
|
|
78
|
+
background-color: var(--primary-color);
|
|
79
|
+
border-radius: 10px;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.screenshot-item {
|
|
83
|
+
flex: 0 0 auto;
|
|
84
|
+
width: 250px;
|
|
85
|
+
position: relative;
|
|
86
|
+
transition: transform 0.2s;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.screenshot-item:hover {
|
|
90
|
+
transform: scale(1.03);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.screenshot-img {
|
|
94
|
+
width: 250px;
|
|
95
|
+
height: 400px;
|
|
96
|
+
object-fit: contain;
|
|
97
|
+
border-radius: 8px;
|
|
98
|
+
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.screenshot-caption {
|
|
102
|
+
font-size: 14px;
|
|
103
|
+
color: #555;
|
|
104
|
+
padding: 8px 4px;
|
|
105
|
+
text-overflow: ellipsis;
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
font-weight: 500;
|
|
108
|
+
text-align: center;
|
|
109
|
+
background-color: white;
|
|
110
|
+
border-radius: 0 0 8px 8px;
|
|
111
|
+
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.table-custom {
|
|
115
|
+
border-radius: 10px;
|
|
116
|
+
overflow: hidden;
|
|
117
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.table-custom thead {
|
|
121
|
+
background-color: var(--primary-color);
|
|
122
|
+
color: white;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.table-custom th {
|
|
126
|
+
font-weight: 600;
|
|
127
|
+
padding: 15px 20px;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.table-custom td {
|
|
131
|
+
padding: 15px 20px;
|
|
132
|
+
vertical-align: middle;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.table-custom tbody tr:nth-of-type(odd) {
|
|
136
|
+
background-color: rgba(0, 0, 0, 0.02);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.table-custom tbody tr:hover {
|
|
140
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.stat-value {
|
|
144
|
+
font-size: 2.2rem;
|
|
145
|
+
font-weight: 700;
|
|
146
|
+
display: block;
|
|
147
|
+
margin-bottom: 0.8rem;
|
|
148
|
+
line-height: 1.2;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.stat-label {
|
|
152
|
+
font-size: 1rem;
|
|
153
|
+
color: #666;
|
|
154
|
+
display: block;
|
|
155
|
+
margin-top: 5px;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.chart-container {
|
|
159
|
+
background-color: white;
|
|
160
|
+
border-radius: 12px;
|
|
161
|
+
padding: 30px;
|
|
162
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
|
163
|
+
margin-bottom: 40px;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.section-title {
|
|
167
|
+
position: relative;
|
|
168
|
+
padding-bottom: 15px;
|
|
169
|
+
margin-bottom: 30px;
|
|
170
|
+
font-weight: 600;
|
|
171
|
+
color: var(--dark-color);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.section-title::after {
|
|
175
|
+
content: '';
|
|
176
|
+
position: absolute;
|
|
177
|
+
bottom: 0;
|
|
178
|
+
left: 0;
|
|
179
|
+
height: 3px;
|
|
180
|
+
width: 50px;
|
|
181
|
+
background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
|
|
182
|
+
border-radius: 3px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* 增加板块间距 */
|
|
186
|
+
.section-block {
|
|
187
|
+
margin-bottom: 70px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.value-highlight {
|
|
191
|
+
color: var(--primary-color);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.value-danger {
|
|
195
|
+
color: var(--danger-color);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.value-warning {
|
|
199
|
+
color: var(--warning-color);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.value-success {
|
|
203
|
+
color: var(--secondary-color);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.summary-card {
|
|
207
|
+
border-radius: 12px;
|
|
208
|
+
background-color: white;
|
|
209
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
|
210
|
+
padding: 30px;
|
|
211
|
+
margin-bottom: 40px;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.link-button {
|
|
215
|
+
color: var(--primary-color);
|
|
216
|
+
text-decoration: none;
|
|
217
|
+
font-weight: 500;
|
|
218
|
+
transition: color 0.2s;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.link-button:hover {
|
|
222
|
+
color: var(--secondary-color);
|
|
223
|
+
text-decoration: underline;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.badge-custom {
|
|
227
|
+
padding: 6px 12px;
|
|
228
|
+
border-radius: 50px;
|
|
229
|
+
font-weight: 500;
|
|
230
|
+
font-size: 0.9rem;
|
|
231
|
+
margin: 0 2px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.activity-list {
|
|
235
|
+
height: 300px; /* 固定高度 */
|
|
236
|
+
overflow-y: auto;
|
|
237
|
+
border-radius: 8px;
|
|
238
|
+
border: 1px solid rgba(0,0,0,0.1);
|
|
239
|
+
padding: 15px;
|
|
240
|
+
background-color: rgba(255,255,255,0.5);
|
|
241
|
+
scrollbar-width: thin;
|
|
242
|
+
scrollbar-color: var(--primary-color) #eee;
|
|
243
|
+
margin-bottom: 15px; /* 为翻页按钮留出空间 */
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.activity-list::-webkit-scrollbar {
|
|
247
|
+
width: 8px;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.activity-list::-webkit-scrollbar-track {
|
|
251
|
+
background: #eee;
|
|
252
|
+
border-radius: 10px;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.activity-list::-webkit-scrollbar-thumb {
|
|
256
|
+
background-color: var(--primary-color);
|
|
257
|
+
border-radius: 10px;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.activities-container {
|
|
261
|
+
display: flex;
|
|
262
|
+
flex-direction: column;
|
|
263
|
+
height: 400px; /* 容器总高度 */
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.pagination-container {
|
|
267
|
+
padding: 10px 0;
|
|
268
|
+
background-color: white;
|
|
269
|
+
border-radius: 0 0 8px 8px;
|
|
270
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.activity-item {
|
|
274
|
+
padding: 10px 15px;
|
|
275
|
+
border-radius: 6px;
|
|
276
|
+
margin-bottom: 10px;
|
|
277
|
+
font-size: 0.95rem;
|
|
278
|
+
word-break: break-all;
|
|
279
|
+
background-color: white;
|
|
280
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
|
281
|
+
transition: all 0.2s;
|
|
282
|
+
line-height: 1.5;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.activity-item:hover {
|
|
286
|
+
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
|
287
|
+
transform: translateX(3px);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* Responsive adjustments */
|
|
291
|
+
@media (max-width: 768px) {
|
|
292
|
+
.stat-value {
|
|
293
|
+
font-size: 1.5rem;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.screenshot-item {
|
|
297
|
+
width: 200px;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.screenshot-img {
|
|
301
|
+
width: 200px;
|
|
302
|
+
height: 320px;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
</style>
|
|
306
|
+
</head>
|
|
307
|
+
|
|
308
|
+
<body>
|
|
309
|
+
<!-- Header -->
|
|
310
|
+
<header class="header text-center">
|
|
311
|
+
<div class="container">
|
|
312
|
+
<h1><i class="bi bi-bug"></i> Kea2 Test Report</h1>
|
|
313
|
+
<p class="lead">Test Time: {{ timestamp }}</p>
|
|
314
|
+
</div>
|
|
315
|
+
</header>
|
|
316
|
+
|
|
317
|
+
<div class="container mb-5">
|
|
318
|
+
<!-- Test Summary -->
|
|
319
|
+
<div class="row mb-4">
|
|
320
|
+
<div class="col-12">
|
|
321
|
+
<div class="summary-card">
|
|
322
|
+
<h2 class="section-title">Test Summary</h2>
|
|
323
|
+
<div class="row g-4">
|
|
324
|
+
<div class="col-md-3 col-sm-6">
|
|
325
|
+
<div class="text-center">
|
|
326
|
+
<i class="bi bi-bug text-danger" style="font-size: 2rem;"></i>
|
|
327
|
+
<span class="stat-value value-danger">{{ bugs_found }}</span>
|
|
328
|
+
<span class="stat-label">Bugs Found</span>
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
<div class="col-md-3 col-sm-6">
|
|
332
|
+
<div class="text-center">
|
|
333
|
+
<i class="bi bi-clock-history text-primary" style="font-size: 2rem;"></i>
|
|
334
|
+
<span class="stat-value value-highlight">{{ (total_testing_time / 60)|int }} min: {{ (total_testing_time % 60)|int }} sec</span>
|
|
335
|
+
<span class="stat-label">Total Testing Time</span>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
<div class="col-md-3 col-sm-6">
|
|
339
|
+
<div class="text-center">
|
|
340
|
+
<i class="bi bi-activity text-success" style="font-size: 2rem;"></i>
|
|
341
|
+
<span class="stat-value value-success">{{ executed_events }}</span>
|
|
342
|
+
<span class="stat-label">Executed Events</span>
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
<div class="col-md-3 col-sm-6">
|
|
346
|
+
<div class="text-center">
|
|
347
|
+
<i class="bi bi-pie-chart text-warning" style="font-size: 2rem;"></i>
|
|
348
|
+
<span class="stat-value value-warning">{{ coverage_percent }}%</span>
|
|
349
|
+
<span class="stat-label">Activity Coverage</span>
|
|
350
|
+
</div>
|
|
351
|
+
</div>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
355
|
+
</div>
|
|
356
|
+
|
|
357
|
+
<!-- Key Statistics -->
|
|
358
|
+
<div class="row g-4 mb-4">
|
|
359
|
+
<div class="col-md-6">
|
|
360
|
+
<div class="stats-card">
|
|
361
|
+
<div class="card-header bg-primary text-white">
|
|
362
|
+
<i class="bi bi-stopwatch"></i> Time Statistics
|
|
363
|
+
</div>
|
|
364
|
+
<div class="card-body">
|
|
365
|
+
<div class="mb-3">
|
|
366
|
+
<h5 class="d-flex justify-content-between">
|
|
367
|
+
<span>First Bug Discovery Time:</span>
|
|
368
|
+
<span class="value-danger">{{ (first_bug_time / 60)|int }} min: {{ (first_bug_time % 60)|int }} sec</span>
|
|
369
|
+
</h5>
|
|
370
|
+
<div class="progress">
|
|
371
|
+
<div class="progress-bar bg-danger" role="progressbar"
|
|
372
|
+
style="width: calc({{ first_bug_time }} / {{ total_testing_time }} * 100%);"
|
|
373
|
+
aria-valuenow="{{ first_bug_time }}" aria-valuemin="0" aria-valuemax="{{ total_testing_time }}"></div>
|
|
374
|
+
</div>
|
|
375
|
+
</div>
|
|
376
|
+
<div class="mb-3">
|
|
377
|
+
<h5 class="d-flex justify-content-between">
|
|
378
|
+
<span>First Precondition Satisfaction Time:</span>
|
|
379
|
+
<span class="value-success">{{ (first_precondition_time / 60)|int }} min: {{ (first_precondition_time % 60)|int }} sec</span>
|
|
380
|
+
</h5>
|
|
381
|
+
<div class="progress">
|
|
382
|
+
<div class="progress-bar bg-success" role="progressbar"
|
|
383
|
+
style="width: calc({{ first_precondition_time }} / {{ total_testing_time }} * 100%);"
|
|
384
|
+
aria-valuenow="{{ first_precondition_time }}" aria-valuemin="0" aria-valuemax="{{ total_testing_time }}"></div>
|
|
385
|
+
</div>
|
|
386
|
+
</div>
|
|
387
|
+
<div>
|
|
388
|
+
<h5 class="d-flex justify-content-between">
|
|
389
|
+
<span>Total Testing Time:</span>
|
|
390
|
+
<span class="value-primary">{{ (total_testing_time / 60)|int }} min: {{ (total_testing_time % 60)|int }} sec</span>
|
|
391
|
+
</h5>
|
|
392
|
+
<div class="progress">
|
|
393
|
+
<div class="progress-bar bg-primary" role="progressbar" style="width: 100%;"
|
|
394
|
+
aria-valuenow="{{ total_testing_time }}" aria-valuemin="0" aria-valuemax="{{ total_testing_time }}"></div>
|
|
395
|
+
</div>
|
|
396
|
+
</div>
|
|
397
|
+
</div>
|
|
398
|
+
</div>
|
|
399
|
+
</div>
|
|
400
|
+
<div class="col-md-6">
|
|
401
|
+
<div class="stats-card">
|
|
402
|
+
<div class="card-header bg-success text-white">
|
|
403
|
+
<i class="bi bi-bar-chart"></i> Coverage Statistics
|
|
404
|
+
</div>
|
|
405
|
+
<div class="card-body">
|
|
406
|
+
<div class="mb-3">
|
|
407
|
+
<h5 class="d-flex justify-content-between">
|
|
408
|
+
<span>Activity Coverage:</span>
|
|
409
|
+
<span class="value-warning">{{ coverage_percent }}%</span>
|
|
410
|
+
</h5>
|
|
411
|
+
<div class="progress">
|
|
412
|
+
<div class="progress-bar bg-warning" role="progressbar"
|
|
413
|
+
style="width: {{ coverage_percent }}%;"
|
|
414
|
+
aria-valuenow="{{ coverage_percent }}" aria-valuemin="0" aria-valuemax="100"></div>
|
|
415
|
+
</div>
|
|
416
|
+
</div>
|
|
417
|
+
<div class="row mt-4">
|
|
418
|
+
<div class="col-6 text-center">
|
|
419
|
+
<div class="stat-value value-primary">{{ total_activities_count }}</div>
|
|
420
|
+
<div class="stat-label">Total Activities</div>
|
|
421
|
+
</div>
|
|
422
|
+
<div class="col-6 text-center">
|
|
423
|
+
<div class="stat-value value-success">{{ tested_activities_count }}</div>
|
|
424
|
+
<div class="stat-label">Tested Activities</div>
|
|
425
|
+
</div>
|
|
426
|
+
</div>
|
|
427
|
+
</div>
|
|
428
|
+
</div>
|
|
429
|
+
</div>
|
|
430
|
+
</div>
|
|
431
|
+
|
|
432
|
+
<!-- Tested Activities List -->
|
|
433
|
+
<div class="section-block">
|
|
434
|
+
<h2 class="section-title">Activities Coverage</h2>
|
|
435
|
+
|
|
436
|
+
<div class="row g-4">
|
|
437
|
+
<!-- Tested Activities Panel -->
|
|
438
|
+
<div class="col-md-6">
|
|
439
|
+
<div class="card">
|
|
440
|
+
<div class="card-header bg-success text-white">
|
|
441
|
+
<div class="d-flex justify-content-between align-items-center">
|
|
442
|
+
<span><i class="bi bi-check-circle"></i> Tested Activities ({{ tested_activities|length }})</span>
|
|
443
|
+
<span class="badge bg-light text-dark">{{ tested_activities|length }} / {{ total_activities_count }}</span>
|
|
444
|
+
</div>
|
|
445
|
+
</div>
|
|
446
|
+
<div class="card-body">
|
|
447
|
+
<div class="activities-container">
|
|
448
|
+
<div class="activity-list">
|
|
449
|
+
{% if tested_activities|length > 0 %}
|
|
450
|
+
<div id="tested-activities-container">
|
|
451
|
+
{% for activity in tested_activities %}
|
|
452
|
+
<div class="activity-item tested-activity" data-page="1">
|
|
453
|
+
<i class="bi bi-check-circle-fill text-success me-2"></i>
|
|
454
|
+
{{ activity }}
|
|
455
|
+
</div>
|
|
456
|
+
{% endfor %}
|
|
457
|
+
</div>
|
|
458
|
+
{% else %}
|
|
459
|
+
<div class="alert alert-warning">
|
|
460
|
+
No tested activities detected
|
|
461
|
+
</div>
|
|
462
|
+
{% endif %}
|
|
463
|
+
</div>
|
|
464
|
+
<!-- Pagination for Tested Activities -->
|
|
465
|
+
<div class="pagination-container d-flex justify-content-center">
|
|
466
|
+
<nav aria-label="Tested Activities Pagination">
|
|
467
|
+
<ul class="pagination pagination-sm" id="tested-pagination">
|
|
468
|
+
<!-- Pagination will be generated by JavaScript -->
|
|
469
|
+
</ul>
|
|
470
|
+
</nav>
|
|
471
|
+
</div>
|
|
472
|
+
</div>
|
|
473
|
+
</div>
|
|
474
|
+
</div>
|
|
475
|
+
</div>
|
|
476
|
+
|
|
477
|
+
<!-- All Activities Panel -->
|
|
478
|
+
<div class="col-md-6">
|
|
479
|
+
<div class="card">
|
|
480
|
+
<div class="card-header bg-primary text-white">
|
|
481
|
+
<div class="d-flex justify-content-between align-items-center">
|
|
482
|
+
<span><i class="bi bi-app"></i> All Activities ({{ total_activities|length }})</span>
|
|
483
|
+
<span class="badge bg-light text-dark">Coverage: {{ coverage_percent }}%</span>
|
|
484
|
+
</div>
|
|
485
|
+
</div>
|
|
486
|
+
<div class="card-body">
|
|
487
|
+
<div class="activities-container">
|
|
488
|
+
<div class="activity-list">
|
|
489
|
+
{% if total_activities|length > 0 %}
|
|
490
|
+
<div id="all-activities-container">
|
|
491
|
+
{% for activity in total_activities %}
|
|
492
|
+
<div class="activity-item all-activity" data-page="1">
|
|
493
|
+
{% if activity in tested_activities %}
|
|
494
|
+
<i class="bi bi-check-circle-fill text-success me-2"></i>
|
|
495
|
+
{% else %}
|
|
496
|
+
<i class="bi bi-dash-circle text-secondary me-2"></i>
|
|
497
|
+
{% endif %}
|
|
498
|
+
{{ activity }}
|
|
499
|
+
</div>
|
|
500
|
+
{% endfor %}
|
|
501
|
+
</div>
|
|
502
|
+
{% else %}
|
|
503
|
+
<div class="alert alert-warning">
|
|
504
|
+
No activities information available
|
|
505
|
+
</div>
|
|
506
|
+
{% endif %}
|
|
507
|
+
</div>
|
|
508
|
+
<!-- Pagination for All Activities -->
|
|
509
|
+
<div class="pagination-container d-flex justify-content-center">
|
|
510
|
+
<nav aria-label="All Activities Pagination">
|
|
511
|
+
<ul class="pagination pagination-sm" id="all-pagination">
|
|
512
|
+
<!-- Pagination will be generated by JavaScript -->
|
|
513
|
+
</ul>
|
|
514
|
+
</nav>
|
|
515
|
+
</div>
|
|
516
|
+
</div>
|
|
517
|
+
</div>
|
|
518
|
+
</div>
|
|
519
|
+
</div>
|
|
520
|
+
</div>
|
|
521
|
+
</div>
|
|
522
|
+
|
|
523
|
+
<!-- Screenshots Section -->
|
|
524
|
+
{% if take_screenshots %}
|
|
525
|
+
<div class="section-block">
|
|
526
|
+
<h2 class="section-title">Test Screenshots</h2>
|
|
527
|
+
<div class="card">
|
|
528
|
+
<div class="card-body">
|
|
529
|
+
<div class="screenshots-container" id="screenshots">
|
|
530
|
+
{% for screenshot in screenshots %}
|
|
531
|
+
<div class="screenshot-item">
|
|
532
|
+
<a href="{{ screenshot.path }}" target="_blank">
|
|
533
|
+
<img src="{{ screenshot.path }}" class="screenshot-img" id="{{ screenshot.id }}">
|
|
534
|
+
</a>
|
|
535
|
+
<div class="screenshot-caption">{{ screenshot.caption }}</div>
|
|
536
|
+
</div>
|
|
537
|
+
{% endfor %}
|
|
538
|
+
</div>
|
|
539
|
+
</div>
|
|
540
|
+
</div>
|
|
541
|
+
</div>
|
|
542
|
+
{% endif %}
|
|
543
|
+
|
|
544
|
+
<!-- Coverage Trend Chart -->
|
|
545
|
+
<div class="section-block">
|
|
546
|
+
<h2 class="section-title">Coverage Trend</h2>
|
|
547
|
+
<div class="chart-container">
|
|
548
|
+
<canvas id="coverageChart"></canvas>
|
|
549
|
+
</div>
|
|
550
|
+
</div>
|
|
551
|
+
|
|
552
|
+
<!-- Property Violations List -->
|
|
553
|
+
{% if take_screenshots %}
|
|
554
|
+
<div class="section-block">
|
|
555
|
+
<h2 class="section-title">Property Violations</h2>
|
|
556
|
+
<div class="table-responsive">
|
|
557
|
+
<table class="table table-custom">
|
|
558
|
+
<thead>
|
|
559
|
+
<tr>
|
|
560
|
+
<th>Index</th>
|
|
561
|
+
<th>Property Name</th>
|
|
562
|
+
<th>Precondition Page</th>
|
|
563
|
+
<th>Interaction Scenario Pages</th>
|
|
564
|
+
<th>Postcondition Page</th>
|
|
565
|
+
</tr>
|
|
566
|
+
</thead>
|
|
567
|
+
<tbody id="property-violations-container">
|
|
568
|
+
{% for violation in property_violations %}
|
|
569
|
+
<tr class="property-violation-row" data-page="1">
|
|
570
|
+
<td>{{ violation.index }}</td>
|
|
571
|
+
<td><span class="badge bg-light text-dark badge-custom">{{ violation.property_name }}</span></td>
|
|
572
|
+
<td><a href="#{{ violation.precondition_page }}" class="link-button">{{ violation.precondition_page }}</a></td>
|
|
573
|
+
<td><a href="#{{ violation.interaction_pages[0] }}" class="link-button">{{ violation.interaction_pages[0] }} ~ {{ violation.interaction_pages[1] }}</a></td>
|
|
574
|
+
<td><a href="#{{ violation.postcondition_page }}" class="link-button">{{ violation.postcondition_page }}</a></td>
|
|
575
|
+
</tr>
|
|
576
|
+
{% endfor %}
|
|
577
|
+
</tbody>
|
|
578
|
+
</table>
|
|
579
|
+
|
|
580
|
+
<!-- Pagination for Property Violations -->
|
|
581
|
+
<div class="d-flex justify-content-center mt-3">
|
|
582
|
+
<nav aria-label="Property Violations Pagination">
|
|
583
|
+
<ul class="pagination pagination-sm" id="violations-pagination">
|
|
584
|
+
<!-- Pagination will be generated by JavaScript -->
|
|
585
|
+
</ul>
|
|
586
|
+
</nav>
|
|
587
|
+
</div>
|
|
588
|
+
</div>
|
|
589
|
+
</div>
|
|
590
|
+
{% endif %}
|
|
591
|
+
|
|
592
|
+
<!-- Property Checking Statistics -->
|
|
593
|
+
<div class="section-block">
|
|
594
|
+
<h2 class="section-title">Property Checking Statistics</h2>
|
|
595
|
+
<div class="table-responsive">
|
|
596
|
+
<table class="table table-custom">
|
|
597
|
+
<thead>
|
|
598
|
+
<tr>
|
|
599
|
+
<th>Index</th>
|
|
600
|
+
<th>Property Name</th>
|
|
601
|
+
<th>Precondition Satisfied</th>
|
|
602
|
+
<th>Executed</th>
|
|
603
|
+
<th>Fails</th>
|
|
604
|
+
<th>Errors</th>
|
|
605
|
+
</tr>
|
|
606
|
+
</thead>
|
|
607
|
+
<tbody id="property-stats-container">
|
|
608
|
+
{% for stat in property_stats %}
|
|
609
|
+
<tr class="property-stat-row" data-page="1">
|
|
610
|
+
<td>{{ stat.index }}</td>
|
|
611
|
+
<td><span class="badge bg-light text-dark badge-custom">{{ stat.property_name }}</span></td>
|
|
612
|
+
<td>{{ stat.precond_satisfied }}</td>
|
|
613
|
+
<td>{{ stat.precond_checked }}</td>
|
|
614
|
+
<td><span class="badge bg-danger text-white">{{ stat.postcond_violated }}</span></td>
|
|
615
|
+
<td><span class="badge bg-warning text-dark">{{ stat.error }}</span></td>
|
|
616
|
+
</tr>
|
|
617
|
+
{% endfor %}
|
|
618
|
+
</tbody>
|
|
619
|
+
</table>
|
|
620
|
+
|
|
621
|
+
<!-- Pagination for Property Checking Statistics -->
|
|
622
|
+
<div class="d-flex justify-content-center mt-3">
|
|
623
|
+
<nav aria-label="Property Stats Pagination">
|
|
624
|
+
<ul class="pagination pagination-sm" id="stats-pagination">
|
|
625
|
+
<!-- Pagination will be generated by JavaScript -->
|
|
626
|
+
</ul>
|
|
627
|
+
</nav>
|
|
628
|
+
</div>
|
|
629
|
+
</div>
|
|
630
|
+
</div>
|
|
631
|
+
</div>
|
|
632
|
+
|
|
633
|
+
<!-- Footer -->
|
|
634
|
+
<footer class="bg-dark text-white text-center py-4">
|
|
635
|
+
<div class="container">
|
|
636
|
+
<p class="mb-0">Kea2 Test Report | Generated at: {{ timestamp }}</p>
|
|
637
|
+
</div>
|
|
638
|
+
</footer>
|
|
639
|
+
|
|
640
|
+
<!-- JavaScript -->
|
|
641
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
642
|
+
<script>
|
|
643
|
+
// Draw coverage trend chart
|
|
644
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
645
|
+
var coverageData = {{ coverage_data|safe }};
|
|
646
|
+
console.log("Coverage data points:", coverageData.length);
|
|
647
|
+
|
|
648
|
+
coverageData.sort(function(a, b) {
|
|
649
|
+
return a.steps - b.steps;
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
var steps = coverageData.map(function(item) { return item.steps; });
|
|
653
|
+
var coverages = coverageData.map(function(item) { return item.coverage; });
|
|
654
|
+
var testedActivities = coverageData.map(function(item) { return item.tested_activities_count; });
|
|
655
|
+
|
|
656
|
+
if (steps.length > 0 && steps[0] > 0) {
|
|
657
|
+
steps.unshift(0);
|
|
658
|
+
coverages.unshift(0);
|
|
659
|
+
testedActivities.unshift(0);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
console.log("Steps with zero point:", steps);
|
|
663
|
+
console.log("Coverage values with zero point:", coverages);
|
|
664
|
+
|
|
665
|
+
var ctx = document.getElementById('coverageChart').getContext('2d');
|
|
666
|
+
var chart = new Chart(ctx, {
|
|
667
|
+
type: 'line',
|
|
668
|
+
data: {
|
|
669
|
+
labels: steps,
|
|
670
|
+
datasets: [
|
|
671
|
+
{
|
|
672
|
+
label: 'Activity Coverage (%)',
|
|
673
|
+
data: coverages.map((value, index) => ({x: steps[index], y: value})),
|
|
674
|
+
borderColor: '#3498db',
|
|
675
|
+
backgroundColor: 'rgba(52, 152, 219, 0.1)',
|
|
676
|
+
borderWidth: 3,
|
|
677
|
+
fill: true,
|
|
678
|
+
tension: 0.4,
|
|
679
|
+
yAxisID: 'y',
|
|
680
|
+
pointRadius: 4,
|
|
681
|
+
pointHoverRadius: 6
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
label: 'Tested Activities',
|
|
685
|
+
data: testedActivities.map((value, index) => ({x: steps[index], y: value})),
|
|
686
|
+
borderColor: '#2ecc71',
|
|
687
|
+
backgroundColor: 'rgba(46, 204, 113, 0.1)',
|
|
688
|
+
borderWidth: 3,
|
|
689
|
+
fill: true,
|
|
690
|
+
tension: 0.4,
|
|
691
|
+
yAxisID: 'y1',
|
|
692
|
+
pointRadius: 4,
|
|
693
|
+
pointHoverRadius: 6
|
|
694
|
+
}
|
|
695
|
+
]
|
|
696
|
+
},
|
|
697
|
+
options: {
|
|
698
|
+
responsive: true,
|
|
699
|
+
maintainAspectRatio: false,
|
|
700
|
+
aspectRatio: 2,
|
|
701
|
+
plugins: {
|
|
702
|
+
legend: {
|
|
703
|
+
position: 'top',
|
|
704
|
+
labels: {
|
|
705
|
+
boxWidth: 15,
|
|
706
|
+
usePointStyle: true,
|
|
707
|
+
pointStyle: 'circle'
|
|
708
|
+
}
|
|
709
|
+
},
|
|
710
|
+
tooltip: {
|
|
711
|
+
mode: 'index',
|
|
712
|
+
intersect: false,
|
|
713
|
+
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
714
|
+
titleColor: '#fff',
|
|
715
|
+
bodyColor: '#fff',
|
|
716
|
+
borderColor: 'rgba(255, 255, 255, 0.2)',
|
|
717
|
+
borderWidth: 1,
|
|
718
|
+
padding: 10,
|
|
719
|
+
displayColors: true,
|
|
720
|
+
callbacks: {
|
|
721
|
+
label: function(context) {
|
|
722
|
+
var label = context.dataset.label || '';
|
|
723
|
+
if (label) {
|
|
724
|
+
label += ': ';
|
|
725
|
+
}
|
|
726
|
+
if (context.datasetIndex === 0) {
|
|
727
|
+
label += context.parsed.y.toFixed(2) + '%';
|
|
728
|
+
} else {
|
|
729
|
+
label += context.parsed.y;
|
|
730
|
+
}
|
|
731
|
+
return label;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
scales: {
|
|
737
|
+
x: {
|
|
738
|
+
type: 'linear',
|
|
739
|
+
beginAtZero: true,
|
|
740
|
+
grid: {
|
|
741
|
+
display: false
|
|
742
|
+
},
|
|
743
|
+
title: {
|
|
744
|
+
display: true,
|
|
745
|
+
text: 'Steps Count',
|
|
746
|
+
font: {
|
|
747
|
+
size: 14
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
ticks: {
|
|
751
|
+
stepSize: Math.max(10, Math.ceil(Math.max(...steps) / 10)),
|
|
752
|
+
callback: function(value) {
|
|
753
|
+
return value;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
},
|
|
757
|
+
y: {
|
|
758
|
+
beginAtZero: true,
|
|
759
|
+
title: {
|
|
760
|
+
display: true,
|
|
761
|
+
text: 'Activity Coverage (%)',
|
|
762
|
+
font: {
|
|
763
|
+
size: 14
|
|
764
|
+
}
|
|
765
|
+
},
|
|
766
|
+
grid: {
|
|
767
|
+
borderDash: [5, 5]
|
|
768
|
+
}
|
|
769
|
+
},
|
|
770
|
+
y1: {
|
|
771
|
+
position: 'right',
|
|
772
|
+
beginAtZero: true,
|
|
773
|
+
title: {
|
|
774
|
+
display: true,
|
|
775
|
+
text: 'Tested Activities',
|
|
776
|
+
font: {
|
|
777
|
+
size: 14
|
|
778
|
+
}
|
|
779
|
+
},
|
|
780
|
+
grid: {
|
|
781
|
+
display: false
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
},
|
|
785
|
+
interaction: {
|
|
786
|
+
mode: 'index',
|
|
787
|
+
intersect: false
|
|
788
|
+
},
|
|
789
|
+
hover: {
|
|
790
|
+
mode: 'index',
|
|
791
|
+
intersect: false
|
|
792
|
+
},
|
|
793
|
+
animation: {
|
|
794
|
+
duration: 1000,
|
|
795
|
+
easing: 'easeOutQuart'
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
// Initialize pagination for Activities lists
|
|
801
|
+
initPagination('tested-activities-container', 'tested-activity', 'tested-pagination', {{ items_per_page }});
|
|
802
|
+
initPagination('all-activities-container', 'all-activity', 'all-pagination', {{ items_per_page }});
|
|
803
|
+
|
|
804
|
+
// Initialize pagination for Property tables
|
|
805
|
+
initPagination('property-violations-container', 'property-violation-row', 'violations-pagination', {{ items_per_page }});
|
|
806
|
+
initPagination('property-stats-container', 'property-stat-row', 'stats-pagination', {{ items_per_page }});
|
|
807
|
+
|
|
808
|
+
// Pagination function
|
|
809
|
+
function initPagination(containerId, itemClass, paginationId, itemsPerPage) {
|
|
810
|
+
const container = document.getElementById(containerId);
|
|
811
|
+
if (!container) return;
|
|
812
|
+
|
|
813
|
+
const items = container.getElementsByClassName(itemClass);
|
|
814
|
+
const totalItems = items.length;
|
|
815
|
+
const totalPages = Math.max(1, Math.ceil(totalItems / itemsPerPage));
|
|
816
|
+
|
|
817
|
+
// Create pagination
|
|
818
|
+
const paginationElement = document.getElementById(paginationId);
|
|
819
|
+
if (!paginationElement) return;
|
|
820
|
+
|
|
821
|
+
// Clear pagination
|
|
822
|
+
paginationElement.innerHTML = '';
|
|
823
|
+
|
|
824
|
+
// Previous button
|
|
825
|
+
const prevLi = document.createElement('li');
|
|
826
|
+
prevLi.className = 'page-item disabled';
|
|
827
|
+
prevLi.innerHTML = '<a class="page-link" href="#" aria-label="Previous"><span aria-hidden="true">«</span></a>';
|
|
828
|
+
paginationElement.appendChild(prevLi);
|
|
829
|
+
|
|
830
|
+
// Add page numbers
|
|
831
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
832
|
+
const pageLi = document.createElement('li');
|
|
833
|
+
pageLi.className = i === 1 ? 'page-item active' : 'page-item';
|
|
834
|
+
pageLi.innerHTML = `<a class="page-link" href="#">${i}</a>`;
|
|
835
|
+
pageLi.addEventListener('click', function(e) {
|
|
836
|
+
e.preventDefault();
|
|
837
|
+
goToPage(i, containerId, itemClass, itemsPerPage, paginationId);
|
|
838
|
+
});
|
|
839
|
+
paginationElement.appendChild(pageLi);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// Next button
|
|
843
|
+
const nextLi = document.createElement('li');
|
|
844
|
+
nextLi.className = totalPages <= 1 ? 'page-item disabled' : 'page-item';
|
|
845
|
+
nextLi.innerHTML = '<a class="page-link" href="#" aria-label="Next"><span aria-hidden="true">»</span></a>';
|
|
846
|
+
paginationElement.appendChild(nextLi);
|
|
847
|
+
|
|
848
|
+
// Initialize page 1
|
|
849
|
+
goToPage(1, containerId, itemClass, itemsPerPage, paginationId);
|
|
850
|
+
|
|
851
|
+
// Add event listeners to prev/next buttons
|
|
852
|
+
if (paginationElement.firstChild) {
|
|
853
|
+
paginationElement.firstChild.addEventListener('click', function(e) {
|
|
854
|
+
e.preventDefault();
|
|
855
|
+
const activePage = paginationElement.querySelector('.active');
|
|
856
|
+
if (activePage && activePage.previousElementSibling && activePage.previousElementSibling.previousElementSibling) {
|
|
857
|
+
const pageNum = parseInt(activePage.textContent) - 1;
|
|
858
|
+
if (pageNum >= 1) {
|
|
859
|
+
goToPage(pageNum, containerId, itemClass, itemsPerPage, paginationId);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
if (paginationElement.lastChild) {
|
|
866
|
+
paginationElement.lastChild.addEventListener('click', function(e) {
|
|
867
|
+
e.preventDefault();
|
|
868
|
+
const activePage = paginationElement.querySelector('.active');
|
|
869
|
+
if (activePage && activePage.nextElementSibling && activePage.nextElementSibling.nextElementSibling) {
|
|
870
|
+
const pageNum = parseInt(activePage.textContent) + 1;
|
|
871
|
+
if (pageNum <= totalPages) {
|
|
872
|
+
goToPage(pageNum, containerId, itemClass, itemsPerPage, paginationId);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// Function to handle page navigation
|
|
880
|
+
function goToPage(pageNumber, containerId, itemClass, itemsPerPage, paginationId) {
|
|
881
|
+
const container = document.getElementById(containerId);
|
|
882
|
+
const items = container.getElementsByClassName(itemClass);
|
|
883
|
+
const paginationElement = document.getElementById(paginationId);
|
|
884
|
+
|
|
885
|
+
// Update pagination active state
|
|
886
|
+
if (paginationElement) {
|
|
887
|
+
const pageItems = paginationElement.getElementsByClassName('page-item');
|
|
888
|
+
for (let i = 0; i < pageItems.length; i++) {
|
|
889
|
+
if (pageItems[i].textContent.trim() === pageNumber.toString()) {
|
|
890
|
+
pageItems[i].className = 'page-item active';
|
|
891
|
+
} else if (pageItems[i].textContent.trim() !== '«' && pageItems[i].textContent.trim() !== '»') {
|
|
892
|
+
pageItems[i].className = 'page-item';
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
// Update prev/next buttons
|
|
897
|
+
if (pageNumber === 1) {
|
|
898
|
+
paginationElement.firstChild.className = 'page-item disabled';
|
|
899
|
+
} else {
|
|
900
|
+
paginationElement.firstChild.className = 'page-item';
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
const totalPages = Math.ceil(items.length / itemsPerPage);
|
|
904
|
+
if (pageNumber === totalPages) {
|
|
905
|
+
paginationElement.lastChild.className = 'page-item disabled';
|
|
906
|
+
} else {
|
|
907
|
+
paginationElement.lastChild.className = 'page-item';
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// Show/hide items based on page number
|
|
912
|
+
const startIndex = (pageNumber - 1) * itemsPerPage;
|
|
913
|
+
const endIndex = Math.min(startIndex + itemsPerPage, items.length);
|
|
914
|
+
|
|
915
|
+
for (let i = 0; i < items.length; i++) {
|
|
916
|
+
if (i >= startIndex && i < endIndex) {
|
|
917
|
+
items[i].style.display = '';
|
|
918
|
+
} else {
|
|
919
|
+
items[i].style.display = 'none';
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// Scroll functionality
|
|
925
|
+
const screenshots = document.getElementById('screenshots');
|
|
926
|
+
if (screenshots) {
|
|
927
|
+
screenshots.addEventListener('wheel', function(e) {
|
|
928
|
+
if (e.deltaY !== 0) {
|
|
929
|
+
e.preventDefault();
|
|
930
|
+
screenshots.scrollLeft += e.deltaY;
|
|
931
|
+
}
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
</script>
|
|
936
|
+
</body>
|
|
937
|
+
</html>
|