Kea2-python 1.1.0b1__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.
- kea2/__init__.py +8 -0
- kea2/absDriver.py +56 -0
- kea2/adbUtils.py +554 -0
- kea2/assets/config_version.json +16 -0
- kea2/assets/fastbot-thirdpart.jar +0 -0
- kea2/assets/fastbot_configs/abl.strings +2 -0
- kea2/assets/fastbot_configs/awl.strings +3 -0
- kea2/assets/fastbot_configs/max.config +7 -0
- kea2/assets/fastbot_configs/max.fuzzing.strings +699 -0
- kea2/assets/fastbot_configs/max.schema.strings +1 -0
- kea2/assets/fastbot_configs/max.strings +3 -0
- kea2/assets/fastbot_configs/max.tree.pruning +27 -0
- kea2/assets/fastbot_configs/teardown.py +18 -0
- kea2/assets/fastbot_configs/widget.block.py +38 -0
- kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so +0 -0
- kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so +0 -0
- kea2/assets/fastbot_libs/x86/libfastbot_native.so +0 -0
- kea2/assets/fastbot_libs/x86_64/libfastbot_native.so +0 -0
- kea2/assets/framework.jar +0 -0
- kea2/assets/kea2-thirdpart.jar +0 -0
- kea2/assets/monkeyq.jar +0 -0
- kea2/assets/quicktest.py +126 -0
- kea2/cli.py +216 -0
- kea2/fastbotManager.py +269 -0
- kea2/kea2_api.py +166 -0
- kea2/keaUtils.py +926 -0
- kea2/kea_launcher.py +299 -0
- kea2/logWatcher.py +92 -0
- kea2/mixin.py +0 -0
- kea2/report/__init__.py +0 -0
- kea2/report/bug_report_generator.py +879 -0
- kea2/report/mixin.py +496 -0
- kea2/report/report_merger.py +1066 -0
- kea2/report/templates/bug_report_template.html +4028 -0
- kea2/report/templates/merged_bug_report_template.html +3602 -0
- kea2/report/utils.py +10 -0
- kea2/result.py +257 -0
- kea2/resultSyncer.py +65 -0
- kea2/state.py +22 -0
- kea2/typedefs.py +32 -0
- kea2/u2Driver.py +612 -0
- kea2/utils.py +192 -0
- kea2/version_manager.py +102 -0
- kea2_python-1.1.0b1.dist-info/METADATA +447 -0
- kea2_python-1.1.0b1.dist-info/RECORD +49 -0
- kea2_python-1.1.0b1.dist-info/WHEEL +5 -0
- kea2_python-1.1.0b1.dist-info/entry_points.txt +2 -0
- kea2_python-1.1.0b1.dist-info/licenses/LICENSE +16 -0
- kea2_python-1.1.0b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,3602 @@
|
|
|
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 Merged 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
|
+
<style>
|
|
10
|
+
:root {
|
|
11
|
+
--primary-color: #3498db;
|
|
12
|
+
--secondary-color: #2ecc71;
|
|
13
|
+
--warning-color: #f39c12;
|
|
14
|
+
--danger-color: #e74c3c;
|
|
15
|
+
--dark-color: #2c3e50;
|
|
16
|
+
--light-color: #ecf0f1;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
body {
|
|
20
|
+
font-family: 'Segoe UI', Roboto, -apple-system, sans-serif;
|
|
21
|
+
background-color: #f8f9fa;
|
|
22
|
+
color: #333;
|
|
23
|
+
line-height: 1.6;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Custom container width - wider than Bootstrap default */
|
|
27
|
+
.container {
|
|
28
|
+
max-width: 98% !important;
|
|
29
|
+
width: 98% !important;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@media (min-width: 1200px) {
|
|
33
|
+
.container {
|
|
34
|
+
max-width: 1800px !important;
|
|
35
|
+
width: 95% !important;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@media (min-width: 1400px) {
|
|
40
|
+
.container {
|
|
41
|
+
max-width: 2000px !important;
|
|
42
|
+
width: 92% !important;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@media (min-width: 1600px) {
|
|
47
|
+
.container {
|
|
48
|
+
max-width: 2200px !important;
|
|
49
|
+
width: 90% !important;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@media (min-width: 1800px) {
|
|
54
|
+
.container {
|
|
55
|
+
max-width: 2400px !important;
|
|
56
|
+
width: 88% !important;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@media (min-width: 2000px) {
|
|
61
|
+
.container {
|
|
62
|
+
max-width: 2600px !important;
|
|
63
|
+
width: 85% !important;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.header {
|
|
68
|
+
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
|
|
69
|
+
color: white;
|
|
70
|
+
padding: 2.5rem 0;
|
|
71
|
+
margin-bottom: 3rem;
|
|
72
|
+
border-radius: 0 0 20px 20px;
|
|
73
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.stats-card {
|
|
77
|
+
border-radius: 12px;
|
|
78
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
|
79
|
+
transition: transform 0.3s, box-shadow 0.3s;
|
|
80
|
+
height: 100%;
|
|
81
|
+
overflow: hidden;
|
|
82
|
+
padding: 1rem;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.stats-card:hover {
|
|
86
|
+
transform: translateY(-5px);
|
|
87
|
+
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.card-header {
|
|
91
|
+
font-weight: 600;
|
|
92
|
+
padding: 1.25rem 1.5rem;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.card-body {
|
|
96
|
+
padding: 1.5rem;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.table-custom {
|
|
100
|
+
border-radius: 10px;
|
|
101
|
+
overflow: hidden;
|
|
102
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
|
103
|
+
width: 100%;
|
|
104
|
+
table-layout: auto;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.crash-analysis-panel {
|
|
108
|
+
background-color: transparent;
|
|
109
|
+
border-radius: 0;
|
|
110
|
+
padding: 0;
|
|
111
|
+
box-shadow: none;
|
|
112
|
+
border: none;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.crash-analysis-panel .btn-group .btn {
|
|
116
|
+
font-weight: 600;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.table-custom thead {
|
|
120
|
+
background-color: #495057;
|
|
121
|
+
color: white;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.table-custom th {
|
|
125
|
+
font-weight: 600;
|
|
126
|
+
padding: 15px 12px;
|
|
127
|
+
white-space: nowrap;
|
|
128
|
+
text-align: center;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.table-custom td {
|
|
132
|
+
padding: 15px 12px;
|
|
133
|
+
vertical-align: middle;
|
|
134
|
+
text-align: center;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Specific column widths for property statistics table */
|
|
138
|
+
.table-custom th:nth-child(1), .table-custom td:nth-child(1) { /* Index */
|
|
139
|
+
width: 8%;
|
|
140
|
+
min-width: 55px;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.table-custom th:nth-child(2), .table-custom td:nth-child(2) { /* Property Name */
|
|
144
|
+
width: 30%;
|
|
145
|
+
min-width: 200px;
|
|
146
|
+
text-align: left;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.table-custom th:nth-child(3), .table-custom td:nth-child(3) { /* Precondition Satisfied */
|
|
150
|
+
width: 15%;
|
|
151
|
+
min-width: 95px;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.table-custom th:nth-child(4), .table-custom td:nth-child(4) { /* Executed */
|
|
155
|
+
width: 12%;
|
|
156
|
+
min-width: 75px;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.table-custom th:nth-child(5), .table-custom td:nth-child(5) { /* Fails */
|
|
160
|
+
width: 12%;
|
|
161
|
+
min-width: 75px;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.table-custom th:nth-child(6), .table-custom td:nth-child(6) { /* Errors */
|
|
165
|
+
width: 12%;
|
|
166
|
+
min-width: 75px;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.table-custom tbody tr:nth-of-type(odd) {
|
|
170
|
+
background-color: rgba(0, 0, 0, 0.02);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.table-custom tbody tr:hover {
|
|
174
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Specific column widths for property source mapping table */
|
|
178
|
+
#property-source-container tr th:nth-child(1),
|
|
179
|
+
#property-source-container tr td:nth-child(1) { /* Index */
|
|
180
|
+
width: 8%;
|
|
181
|
+
min-width: 55px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
#property-source-container tr th:nth-child(2),
|
|
185
|
+
#property-source-container tr td:nth-child(2) { /* Property Name */
|
|
186
|
+
width: 35%;
|
|
187
|
+
min-width: 200px;
|
|
188
|
+
text-align: left;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
#property-source-container tr th:nth-child(3),
|
|
192
|
+
#property-source-container tr td:nth-child(3) { /* Source Directories */
|
|
193
|
+
width: 57%;
|
|
194
|
+
min-width: 300px;
|
|
195
|
+
text-align: center;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Property Source Mapping specific styles */
|
|
199
|
+
.property-source-row .badge-custom {
|
|
200
|
+
max-width: 100%;
|
|
201
|
+
word-break: break-word;
|
|
202
|
+
white-space: normal;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.property-source-row td:last-child {
|
|
206
|
+
line-height: 1.8;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.property-source-row .badge.bg-info {
|
|
210
|
+
transition: all 0.2s ease;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.property-source-row .badge.bg-info:hover {
|
|
214
|
+
background-color: #0d6efd !important;
|
|
215
|
+
transform: translateY(-1px);
|
|
216
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* Source directories toggle button styles */
|
|
220
|
+
.source-dirs-toggle {
|
|
221
|
+
border-radius: 12px;
|
|
222
|
+
transition: all 0.2s ease;
|
|
223
|
+
vertical-align: middle;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.source-dirs-toggle:hover {
|
|
227
|
+
transform: translateY(-1px);
|
|
228
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.source-dirs-toggle .bi {
|
|
232
|
+
transition: transform 0.2s ease;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.source-dirs-hidden {
|
|
236
|
+
display: inline;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.source-dirs-container {
|
|
240
|
+
line-height: 1.8;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.stat-value {
|
|
244
|
+
font-size: 2.2rem;
|
|
245
|
+
font-weight: 700;
|
|
246
|
+
display: block;
|
|
247
|
+
margin-bottom: 0.8rem;
|
|
248
|
+
line-height: 1.2;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.stat-label {
|
|
252
|
+
font-size: 1rem;
|
|
253
|
+
color: #666;
|
|
254
|
+
display: block;
|
|
255
|
+
margin-top: 5px;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.section-title {
|
|
259
|
+
position: relative;
|
|
260
|
+
padding-bottom: 15px;
|
|
261
|
+
margin-bottom: 30px;
|
|
262
|
+
font-weight: 600;
|
|
263
|
+
color: var(--dark-color);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.section-title::after {
|
|
267
|
+
content: '';
|
|
268
|
+
position: absolute;
|
|
269
|
+
bottom: 0;
|
|
270
|
+
left: 0;
|
|
271
|
+
height: 3px;
|
|
272
|
+
width: 50px;
|
|
273
|
+
background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
|
|
274
|
+
border-radius: 3px;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.section-block {
|
|
278
|
+
margin-bottom: 70px;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.value-highlight {
|
|
282
|
+
color: var(--primary-color);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.value-danger {
|
|
286
|
+
color: var(--danger-color);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.value-warning {
|
|
290
|
+
color: var(--warning-color);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.value-success {
|
|
294
|
+
color: var(--secondary-color);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.summary-card {
|
|
298
|
+
border-radius: 12px;
|
|
299
|
+
background-color: white;
|
|
300
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
|
301
|
+
padding: 30px;
|
|
302
|
+
margin-bottom: 40px;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.badge-custom {
|
|
306
|
+
padding: 6px 12px;
|
|
307
|
+
border-radius: 50px;
|
|
308
|
+
font-weight: 500;
|
|
309
|
+
font-size: 0.9rem;
|
|
310
|
+
margin: 0 2px;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
.activities-container {
|
|
316
|
+
display: flex;
|
|
317
|
+
flex-direction: column;
|
|
318
|
+
height: 650px;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.pagination-container {
|
|
322
|
+
padding: 10px 0;
|
|
323
|
+
background-color: white;
|
|
324
|
+
border-radius: 0 0 8px 8px;
|
|
325
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/* Modern Activity Item Styling */
|
|
329
|
+
.activity-item {
|
|
330
|
+
background: #ffffff;
|
|
331
|
+
border: 1px solid #f3f4f6;
|
|
332
|
+
border-radius: 12px;
|
|
333
|
+
padding: 16px 20px;
|
|
334
|
+
margin-bottom: 8px;
|
|
335
|
+
transition: all 0.2s ease;
|
|
336
|
+
display: flex;
|
|
337
|
+
align-items: center;
|
|
338
|
+
justify-content: space-between;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.activity-item:hover {
|
|
342
|
+
border-color: #e5e7eb;
|
|
343
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
344
|
+
transform: translateY(-1px);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.activity-content {
|
|
348
|
+
display: flex;
|
|
349
|
+
align-items: center;
|
|
350
|
+
gap: 12px;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.activity-name {
|
|
354
|
+
font-weight: 500;
|
|
355
|
+
color: #374151;
|
|
356
|
+
font-size: 14px;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.traversal-badge {
|
|
360
|
+
background: linear-gradient(135deg, #3b82f6, #1d4ed8) !important;
|
|
361
|
+
border: none;
|
|
362
|
+
border-radius: 20px;
|
|
363
|
+
padding: 6px 12px;
|
|
364
|
+
font-size: 12px;
|
|
365
|
+
font-weight: 500;
|
|
366
|
+
box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/* Modern Activity List Container */
|
|
370
|
+
.activity-list {
|
|
371
|
+
background: #ffffff;
|
|
372
|
+
border: 1px solid #e5e7eb;
|
|
373
|
+
border-radius: 12px;
|
|
374
|
+
padding: 16px;
|
|
375
|
+
height: 550px;
|
|
376
|
+
overflow-y: auto;
|
|
377
|
+
scrollbar-width: thin;
|
|
378
|
+
scrollbar-color: var(--primary-color) #eee;
|
|
379
|
+
margin-bottom: 15px;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.activity-list::-webkit-scrollbar {
|
|
383
|
+
width: 8px;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.activity-list::-webkit-scrollbar-track {
|
|
387
|
+
background: #f1f1f1;
|
|
388
|
+
border-radius: 10px;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.activity-list::-webkit-scrollbar-thumb {
|
|
392
|
+
background-color: var(--primary-color);
|
|
393
|
+
border-radius: 10px;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.activity-list::-webkit-scrollbar-thumb:hover {
|
|
397
|
+
background-color: #2980b9;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.nav-tabs .nav-link {
|
|
401
|
+
color: #666;
|
|
402
|
+
border: 1px solid transparent;
|
|
403
|
+
border-radius: 6px 6px 0 0;
|
|
404
|
+
font-weight: 500;
|
|
405
|
+
transition: all 0.3s ease;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.nav-tabs .nav-link:hover {
|
|
409
|
+
color: var(--primary-color);
|
|
410
|
+
border-color: rgba(52, 152, 219, 0.2);
|
|
411
|
+
background-color: rgba(52, 152, 219, 0.05);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.nav-tabs .nav-link.active {
|
|
415
|
+
color: var(--primary-color);
|
|
416
|
+
background-color: white;
|
|
417
|
+
border-color: #dee2e6 #dee2e6 #fff;
|
|
418
|
+
font-weight: 600;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.tab-content {
|
|
422
|
+
border: 1px solid #dee2e6;
|
|
423
|
+
border-top: none;
|
|
424
|
+
border-radius: 0 0 8px 8px;
|
|
425
|
+
padding: 20px;
|
|
426
|
+
background-color: #fafafa;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.sorting-controls {
|
|
430
|
+
background-color: #f8f9fa;
|
|
431
|
+
border: 1px solid #e9ecef;
|
|
432
|
+
border-radius: 8px;
|
|
433
|
+
padding: 15px;
|
|
434
|
+
margin-bottom: 20px;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.sorting-controls .form-select {
|
|
438
|
+
min-width: 140px;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.sorting-controls .btn {
|
|
442
|
+
transition: all 0.3s ease;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.sorting-controls .btn:hover {
|
|
446
|
+
transform: translateY(-1px);
|
|
447
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.sort-icon {
|
|
451
|
+
margin-left: 8px;
|
|
452
|
+
transition: all 0.3s ease;
|
|
453
|
+
font-size: 1.4rem;
|
|
454
|
+
color: #ffffff !important;
|
|
455
|
+
opacity: 0.6;
|
|
456
|
+
text-shadow: 0 0 3px rgba(0,0,0,0.3);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.sort-icon:hover {
|
|
460
|
+
opacity: 1;
|
|
461
|
+
transform: scale(1.2);
|
|
462
|
+
text-shadow: 0 0 5px rgba(0,0,0,0.5);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.sort-icon.active {
|
|
466
|
+
opacity: 1;
|
|
467
|
+
font-weight: bold;
|
|
468
|
+
text-shadow: 0 0 5px rgba(0,0,0,0.5);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.sort-icon.asc.active {
|
|
472
|
+
color: #40e0d0 !important;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.sort-icon.desc.active {
|
|
476
|
+
color: #ff6b6b !important;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/* Modern Sorting Controls Styling */
|
|
480
|
+
.sorting-controls-modern {
|
|
481
|
+
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
|
482
|
+
border: 1px solid #e3e6ea;
|
|
483
|
+
border-radius: 12px;
|
|
484
|
+
padding: 20px 24px;
|
|
485
|
+
margin-bottom: 24px;
|
|
486
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
487
|
+
transition: all 0.3s ease;
|
|
488
|
+
position: relative;
|
|
489
|
+
overflow: hidden;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.sorting-controls-modern::before {
|
|
493
|
+
content: '';
|
|
494
|
+
position: absolute;
|
|
495
|
+
top: 0;
|
|
496
|
+
left: 0;
|
|
497
|
+
right: 0;
|
|
498
|
+
height: 3px;
|
|
499
|
+
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
|
|
500
|
+
border-radius: 12px 12px 0 0;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.sorting-controls-modern:hover {
|
|
504
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
|
505
|
+
transform: translateY(-1px);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.sort-label-section {
|
|
509
|
+
display: flex;
|
|
510
|
+
align-items: center;
|
|
511
|
+
gap: 16px;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.sort-icon-wrapper {
|
|
515
|
+
width: 48px;
|
|
516
|
+
height: 48px;
|
|
517
|
+
background: linear-gradient(135deg, #3498db, #2980b9);
|
|
518
|
+
border-radius: 12px;
|
|
519
|
+
display: flex;
|
|
520
|
+
align-items: center;
|
|
521
|
+
justify-content: center;
|
|
522
|
+
box-shadow: 0 2px 8px rgba(52, 152, 219, 0.3);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.sort-icon-wrapper i {
|
|
526
|
+
color: white;
|
|
527
|
+
font-size: 20px;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.sort-text {
|
|
531
|
+
display: flex;
|
|
532
|
+
flex-direction: column;
|
|
533
|
+
gap: 4px;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
.sort-title {
|
|
537
|
+
font-size: 16px;
|
|
538
|
+
font-weight: 600;
|
|
539
|
+
color: #2c3e50;
|
|
540
|
+
line-height: 1.2;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.sort-subtitle {
|
|
544
|
+
font-size: 13px;
|
|
545
|
+
color: #7f8c8d;
|
|
546
|
+
font-weight: 400;
|
|
547
|
+
line-height: 1.2;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.sort-button-section {
|
|
551
|
+
display: flex;
|
|
552
|
+
align-items: center;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.btn-sort-modern {
|
|
556
|
+
background: linear-gradient(135deg, #27ae60, #2ecc71);
|
|
557
|
+
border: none;
|
|
558
|
+
border-radius: 10px;
|
|
559
|
+
padding: 12px 20px;
|
|
560
|
+
color: white;
|
|
561
|
+
font-weight: 500;
|
|
562
|
+
font-size: 14px;
|
|
563
|
+
cursor: pointer;
|
|
564
|
+
transition: all 0.3s ease;
|
|
565
|
+
box-shadow: 0 2px 8px rgba(46, 204, 113, 0.3);
|
|
566
|
+
position: relative;
|
|
567
|
+
overflow: hidden;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.btn-sort-modern::before {
|
|
571
|
+
content: '';
|
|
572
|
+
position: absolute;
|
|
573
|
+
top: 0;
|
|
574
|
+
left: -100%;
|
|
575
|
+
width: 100%;
|
|
576
|
+
height: 100%;
|
|
577
|
+
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
|
578
|
+
transition: left 0.5s ease;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
.btn-sort-modern:hover {
|
|
582
|
+
transform: translateY(-2px);
|
|
583
|
+
box-shadow: 0 4px 16px rgba(46, 204, 113, 0.4);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.btn-sort-modern:hover::before {
|
|
587
|
+
left: 100%;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.btn-sort-modern:active {
|
|
591
|
+
transform: translateY(0px);
|
|
592
|
+
box-shadow: 0 2px 8px rgba(46, 204, 113, 0.3);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.btn-content {
|
|
596
|
+
display: flex;
|
|
597
|
+
align-items: center;
|
|
598
|
+
gap: 8px;
|
|
599
|
+
position: relative;
|
|
600
|
+
z-index: 1;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
.btn-icon {
|
|
604
|
+
font-size: 16px;
|
|
605
|
+
opacity: 0.9;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.btn-text {
|
|
609
|
+
font-size: 14px;
|
|
610
|
+
font-weight: 500;
|
|
611
|
+
white-space: nowrap;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.btn-arrow {
|
|
615
|
+
font-size: 14px;
|
|
616
|
+
transition: transform 0.3s ease;
|
|
617
|
+
opacity: 0.8;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
.btn-sort-modern:hover .btn-arrow {
|
|
621
|
+
transform: scale(1.1);
|
|
622
|
+
opacity: 1;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/* Search Controls Styling */
|
|
626
|
+
.search-controls-modern {
|
|
627
|
+
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
|
628
|
+
border: 1px solid #e3e6ea;
|
|
629
|
+
border-radius: 12px;
|
|
630
|
+
padding: 20px 24px;
|
|
631
|
+
margin-bottom: 24px;
|
|
632
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
633
|
+
transition: all 0.3s ease;
|
|
634
|
+
position: relative;
|
|
635
|
+
overflow: hidden;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
.search-controls-modern::before {
|
|
639
|
+
content: '';
|
|
640
|
+
position: absolute;
|
|
641
|
+
top: 0;
|
|
642
|
+
left: 0;
|
|
643
|
+
right: 0;
|
|
644
|
+
height: 3px;
|
|
645
|
+
background: linear-gradient(90deg, #17a2b8, #20c997);
|
|
646
|
+
border-radius: 12px 12px 0 0;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.search-controls-modern:hover {
|
|
650
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
|
651
|
+
transform: translateY(-1px);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.search-icon-wrapper {
|
|
655
|
+
width: 48px;
|
|
656
|
+
height: 48px;
|
|
657
|
+
background: linear-gradient(135deg, #17a2b8, #138496);
|
|
658
|
+
border-radius: 12px;
|
|
659
|
+
display: flex;
|
|
660
|
+
align-items: center;
|
|
661
|
+
justify-content: center;
|
|
662
|
+
box-shadow: 0 2px 8px rgba(23, 162, 184, 0.3);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
.search-icon-wrapper i {
|
|
666
|
+
color: white;
|
|
667
|
+
font-size: 20px;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/* Combined Search and Sort Controls */
|
|
671
|
+
.search-sort-controls-modern {
|
|
672
|
+
background: #ffffff;
|
|
673
|
+
border: 1px solid #e5e7eb;
|
|
674
|
+
border-radius: 16px;
|
|
675
|
+
padding: 20px 24px;
|
|
676
|
+
margin-bottom: 20px;
|
|
677
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
678
|
+
transition: all 0.2s ease;
|
|
679
|
+
position: relative;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
.search-sort-controls-modern:hover {
|
|
683
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.06);
|
|
684
|
+
border-color: #d1d5db;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
.search-section {
|
|
688
|
+
min-width: 0; /* Allow flex item to shrink */
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
.sort-section {
|
|
692
|
+
flex-shrink: 0; /* Prevent sort section from shrinking */
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.sort-label {
|
|
696
|
+
white-space: nowrap;
|
|
697
|
+
font-size: 14px;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/* Responsive design for combined controls */
|
|
701
|
+
@media (max-width: 768px) {
|
|
702
|
+
.search-sort-controls-modern .d-flex {
|
|
703
|
+
flex-direction: column;
|
|
704
|
+
gap: 16px !important;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.search-section {
|
|
708
|
+
width: 100% !important;
|
|
709
|
+
max-width: none !important;
|
|
710
|
+
flex-shrink: 1 !important;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.sort-section {
|
|
714
|
+
justify-content: center;
|
|
715
|
+
width: 100%;
|
|
716
|
+
margin-left: 0 !important;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
@media (max-width: 576px) {
|
|
721
|
+
.search-section {
|
|
722
|
+
max-width: none !important;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
.search-icon-wrapper {
|
|
726
|
+
width: 40px;
|
|
727
|
+
height: 40px;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.search-icon-wrapper i {
|
|
731
|
+
font-size: 18px;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/* Modern Search Input */
|
|
736
|
+
.activity-search-input {
|
|
737
|
+
border: 1px solid #e5e7eb;
|
|
738
|
+
border-radius: 12px;
|
|
739
|
+
padding: 12px 16px;
|
|
740
|
+
font-size: 14px;
|
|
741
|
+
transition: all 0.2s ease;
|
|
742
|
+
background: #f9fafb;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
.activity-search-input:focus {
|
|
746
|
+
border-color: #3b82f6;
|
|
747
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
748
|
+
background: #ffffff;
|
|
749
|
+
outline: none;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.search-btn {
|
|
753
|
+
border-radius: 12px;
|
|
754
|
+
padding: 12px 16px;
|
|
755
|
+
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
|
|
756
|
+
border: none;
|
|
757
|
+
color: white;
|
|
758
|
+
transition: all 0.2s ease;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
.search-btn:hover {
|
|
762
|
+
background: linear-gradient(135deg, #2563eb, #1e40af);
|
|
763
|
+
transform: translateY(-1px);
|
|
764
|
+
box-shadow: 0 4px 8px rgba(59, 130, 246, 0.3);
|
|
765
|
+
color: white;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.search-btn:focus {
|
|
769
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
770
|
+
color: white;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.search-clear-btn {
|
|
774
|
+
border-radius: 0 8px 8px 0;
|
|
775
|
+
border-left: none;
|
|
776
|
+
padding: 12px 16px;
|
|
777
|
+
transition: all 0.3s ease;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
.search-clear-btn:hover {
|
|
781
|
+
background-color: #dc3545;
|
|
782
|
+
border-color: #dc3545;
|
|
783
|
+
color: white;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.search-results-count {
|
|
787
|
+
display: block;
|
|
788
|
+
margin-top: 8px;
|
|
789
|
+
font-size: 12px;
|
|
790
|
+
font-style: italic;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
@media (max-width: 768px) {
|
|
794
|
+
.container {
|
|
795
|
+
max-width: 98% !important;
|
|
796
|
+
width: 98% !important;
|
|
797
|
+
padding-left: 10px !important;
|
|
798
|
+
padding-right: 10px !important;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
.stat-value {
|
|
802
|
+
font-size: 1.5rem;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
.table-custom {
|
|
806
|
+
font-size: 0.9rem;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.table-custom th, .table-custom td {
|
|
810
|
+
padding: 10px 6px;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
.badge-custom {
|
|
814
|
+
font-size: 0.8rem;
|
|
815
|
+
padding: 4px 8px;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
@media (max-width: 576px) {
|
|
820
|
+
.container {
|
|
821
|
+
max-width: 100% !important;
|
|
822
|
+
width: 100% !important;
|
|
823
|
+
padding-left: 5px !important;
|
|
824
|
+
padding-right: 5px !important;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
.table-custom {
|
|
828
|
+
font-size: 0.8rem;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
.table-custom th, .table-custom td {
|
|
832
|
+
padding: 8px 4px;
|
|
833
|
+
white-space: normal;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/* Merge Information Styles */
|
|
838
|
+
.merge-info-section {
|
|
839
|
+
margin-bottom: 1.5rem;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
.merge-info-card {
|
|
843
|
+
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
|
844
|
+
border: 1px solid #e3f2fd;
|
|
845
|
+
border-radius: 12px;
|
|
846
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
847
|
+
overflow: hidden;
|
|
848
|
+
transition: all 0.3s ease;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
.merge-info-card:hover {
|
|
852
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
|
|
853
|
+
transform: translateY(-1px);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.merge-info-header {
|
|
857
|
+
padding: 16px 20px;
|
|
858
|
+
background: linear-gradient(135deg, #e3f2fd 0%, #f0f8ff 100%);
|
|
859
|
+
border-bottom: 1px solid rgba(23, 162, 184, 0.2);
|
|
860
|
+
cursor: pointer;
|
|
861
|
+
transition: all 0.3s ease;
|
|
862
|
+
user-select: none;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
.merge-info-header:hover {
|
|
866
|
+
background: linear-gradient(135deg, #d1ecf1 0%, #e8f4f8 100%);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
.merge-icon-wrapper {
|
|
870
|
+
width: 40px;
|
|
871
|
+
height: 40px;
|
|
872
|
+
background: linear-gradient(135deg, #17a2b8, #138496);
|
|
873
|
+
border-radius: 10px;
|
|
874
|
+
display: flex;
|
|
875
|
+
align-items: center;
|
|
876
|
+
justify-content: center;
|
|
877
|
+
box-shadow: 0 2px 8px rgba(23, 162, 184, 0.3);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.merge-icon-wrapper i {
|
|
881
|
+
color: white;
|
|
882
|
+
font-size: 18px;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
.merge-title {
|
|
886
|
+
font-size: 16px;
|
|
887
|
+
font-weight: 600;
|
|
888
|
+
color: #2c3e50;
|
|
889
|
+
margin-bottom: 2px;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
.merge-subtitle {
|
|
893
|
+
font-size: 13px;
|
|
894
|
+
color: #6c757d;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
.merge-count-badge {
|
|
898
|
+
font-size: 13px;
|
|
899
|
+
font-weight: 500;
|
|
900
|
+
padding: 6px 12px;
|
|
901
|
+
border-radius: 20px;
|
|
902
|
+
background: linear-gradient(135deg, #007bff, #0056b3) !important;
|
|
903
|
+
box-shadow: 0 2px 4px rgba(0, 123, 255, 0.3);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
.collapse-icon {
|
|
907
|
+
font-size: 16px;
|
|
908
|
+
color: #6c757d;
|
|
909
|
+
transition: transform 0.3s ease;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
.merge-info-header[aria-expanded="true"] .collapse-icon {
|
|
913
|
+
transform: rotate(180deg);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
.merge-info-body {
|
|
917
|
+
padding: 20px;
|
|
918
|
+
background: #ffffff;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
.merge-directories-header h6 {
|
|
922
|
+
color: #495057;
|
|
923
|
+
font-weight: 600;
|
|
924
|
+
font-size: 15px;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
.merged-directories-list {
|
|
928
|
+
max-height: 200px;
|
|
929
|
+
overflow-y: auto;
|
|
930
|
+
overflow-x: hidden;
|
|
931
|
+
padding: 12px;
|
|
932
|
+
padding-right: 8px; /* Make room for scrollbar */
|
|
933
|
+
background: #f8f9fa;
|
|
934
|
+
border-radius: 8px;
|
|
935
|
+
border: 1px solid #e9ecef;
|
|
936
|
+
font-family: 'Courier New', monospace;
|
|
937
|
+
line-height: 1.6;
|
|
938
|
+
/* Force scrollbar to always be visible when content overflows */
|
|
939
|
+
scrollbar-width: thin;
|
|
940
|
+
scrollbar-color: #c1c1c1 #f1f1f1;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
.directory-list-item {
|
|
944
|
+
display: flex;
|
|
945
|
+
align-items: center;
|
|
946
|
+
padding: 6px 8px;
|
|
947
|
+
margin-bottom: 4px;
|
|
948
|
+
background: white;
|
|
949
|
+
border-radius: 4px;
|
|
950
|
+
border: 1px solid #e9ecef;
|
|
951
|
+
transition: all 0.2s ease;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
.directory-summary {
|
|
955
|
+
display: flex;
|
|
956
|
+
align-items: center;
|
|
957
|
+
gap: 6px;
|
|
958
|
+
flex-wrap: wrap;
|
|
959
|
+
margin-left: 12px;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
.directory-summary-item {
|
|
963
|
+
display: flex;
|
|
964
|
+
flex-direction: column;
|
|
965
|
+
align-items: center;
|
|
966
|
+
justify-content: center;
|
|
967
|
+
padding: 4px 6px;
|
|
968
|
+
min-width: 64px;
|
|
969
|
+
background: #f8f9fa;
|
|
970
|
+
border-radius: 6px;
|
|
971
|
+
border: 1px solid #e9ecef;
|
|
972
|
+
line-height: 1.1;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
.directory-summary-item .summary-value {
|
|
976
|
+
font-weight: 600;
|
|
977
|
+
font-size: 12px;
|
|
978
|
+
color: #2c3e50;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
.directory-summary-item .summary-label {
|
|
982
|
+
font-size: 10px;
|
|
983
|
+
color: #6c757d;
|
|
984
|
+
text-transform: uppercase;
|
|
985
|
+
letter-spacing: 0.4px;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
.directory-list-item:hover {
|
|
989
|
+
background: #e3f2fd;
|
|
990
|
+
border-color: #17a2b8;
|
|
991
|
+
transform: translateX(4px);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
.directory-list-item:last-child {
|
|
995
|
+
margin-bottom: 0;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
/* Property Search Container Styles */
|
|
999
|
+
.property-search-container {
|
|
1000
|
+
position: relative;
|
|
1001
|
+
display: flex;
|
|
1002
|
+
align-items: center;
|
|
1003
|
+
width: 100%;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
.property-search-input {
|
|
1007
|
+
border-radius: 25px !important;
|
|
1008
|
+
border: 1px solid #dee2e6 !important;
|
|
1009
|
+
padding: 8px 45px 8px 16px !important;
|
|
1010
|
+
font-size: 14px;
|
|
1011
|
+
transition: all 0.3s ease;
|
|
1012
|
+
background-color: #ffffff;
|
|
1013
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
.property-search-input:focus {
|
|
1017
|
+
border-color: #007bff !important;
|
|
1018
|
+
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25) !important;
|
|
1019
|
+
outline: none;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
.property-search-input::placeholder {
|
|
1023
|
+
color: #6c757d;
|
|
1024
|
+
font-style: italic;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
.property-search-icon-btn {
|
|
1028
|
+
position: absolute;
|
|
1029
|
+
right: 8px;
|
|
1030
|
+
top: 50%;
|
|
1031
|
+
transform: translateY(-50%);
|
|
1032
|
+
background: none;
|
|
1033
|
+
border: none;
|
|
1034
|
+
color: #6c757d;
|
|
1035
|
+
font-size: 16px;
|
|
1036
|
+
padding: 4px 8px;
|
|
1037
|
+
cursor: pointer;
|
|
1038
|
+
transition: color 0.3s ease;
|
|
1039
|
+
z-index: 10;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
.property-search-icon-btn.search-btn:hover {
|
|
1043
|
+
color: #495057 !important;
|
|
1044
|
+
background: rgba(0, 0, 0, 0.04) !important;
|
|
1045
|
+
border-radius: 4px !important;
|
|
1046
|
+
transform: translateY(-50%) !important;
|
|
1047
|
+
box-shadow: none !important;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
.property-search-icon-btn.search-btn:focus {
|
|
1051
|
+
outline: none;
|
|
1052
|
+
color: #495057 !important;
|
|
1053
|
+
background: rgba(0, 0, 0, 0.04) !important;
|
|
1054
|
+
border-radius: 4px !important;
|
|
1055
|
+
transform: translateY(-50%) !important;
|
|
1056
|
+
box-shadow: none !important;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
.directory-list-item .directory-index {
|
|
1060
|
+
font-weight: 600;
|
|
1061
|
+
color: #17a2b8;
|
|
1062
|
+
margin-right: 8px;
|
|
1063
|
+
min-width: 25px;
|
|
1064
|
+
font-size: 14px;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/* Activities Coverage table styling */
|
|
1068
|
+
.table-activities thead {
|
|
1069
|
+
background-color: #007bff !important;
|
|
1070
|
+
color: white;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
.table-activities .sort-icon {
|
|
1074
|
+
color: #ffffff !important;
|
|
1075
|
+
text-shadow: 0 0 3px rgba(0,0,0,0.4);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
.activities-sort-icon {
|
|
1079
|
+
cursor: pointer;
|
|
1080
|
+
transition: all 0.3s ease;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
.activities-sort-icon:hover {
|
|
1084
|
+
transform: scale(1.1);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
.table-activities .sort-icon:hover {
|
|
1088
|
+
opacity: 1;
|
|
1089
|
+
transform: scale(1.2);
|
|
1090
|
+
text-shadow: 0 0 5px rgba(0,0,0,0.6);
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
.table-activities .activities-sort-icon:hover {
|
|
1094
|
+
opacity: 1;
|
|
1095
|
+
transform: scale(1.2);
|
|
1096
|
+
text-shadow: 0 0 5px rgba(0,0,0,0.6);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/* Column widths for activities table */
|
|
1100
|
+
.table-activities th:nth-child(1), .table-activities td:nth-child(1) { /* Activity Name */
|
|
1101
|
+
width: 70%;
|
|
1102
|
+
min-width: 300px;
|
|
1103
|
+
text-align: left;
|
|
1104
|
+
padding-left: 180px;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
.table-activities th:nth-child(2), .table-activities td:nth-child(2) { /* Visit Count */
|
|
1108
|
+
width: 30%;
|
|
1109
|
+
min-width: 150px;
|
|
1110
|
+
text-align: center;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
.activity-name {
|
|
1114
|
+
font-weight: 500;
|
|
1115
|
+
color: #374151;
|
|
1116
|
+
font-size: 14px;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/* Activities Coverage table styling */
|
|
1120
|
+
.table-activities thead {
|
|
1121
|
+
background-color: #007bff !important;
|
|
1122
|
+
color: white;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
.table-activities .sort-icon {
|
|
1126
|
+
color: #ffffff !important;
|
|
1127
|
+
text-shadow: 0 0 3px rgba(0,0,0,0.4);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
.directory-list-item .directory-name {
|
|
1131
|
+
font-size: 14px;
|
|
1132
|
+
color: #2c3e50;
|
|
1133
|
+
word-break: break-all;
|
|
1134
|
+
flex: 1;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
.merged-directories-list::-webkit-scrollbar {
|
|
1138
|
+
width: 8px;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
.merged-directories-list::-webkit-scrollbar-track {
|
|
1142
|
+
background: #f1f1f1;
|
|
1143
|
+
border-radius: 4px;
|
|
1144
|
+
margin: 2px;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
.merged-directories-list::-webkit-scrollbar-thumb {
|
|
1148
|
+
background: #17a2b8;
|
|
1149
|
+
border-radius: 4px;
|
|
1150
|
+
border: 1px solid #f1f1f1;
|
|
1151
|
+
min-height: 20px;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
.merged-directories-list::-webkit-scrollbar-thumb:hover {
|
|
1155
|
+
background: #138496;
|
|
1156
|
+
border-color: #e9ecef;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
.merged-directories-list::-webkit-scrollbar-thumb:active {
|
|
1160
|
+
background: #0f6674;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
/* Scroll indicator for merged directories */
|
|
1164
|
+
.merged-directories-container {
|
|
1165
|
+
position: relative;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
.merged-directories-container::after {
|
|
1169
|
+
content: "";
|
|
1170
|
+
position: absolute;
|
|
1171
|
+
top: 0;
|
|
1172
|
+
right: 0;
|
|
1173
|
+
width: 2px;
|
|
1174
|
+
height: 100%;
|
|
1175
|
+
background: linear-gradient(to bottom, transparent 0%, rgba(23, 162, 184, 0.3) 50%, transparent 100%);
|
|
1176
|
+
pointer-events: none;
|
|
1177
|
+
opacity: 0;
|
|
1178
|
+
transition: opacity 0.3s ease;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
.merged-directories-container:hover::after {
|
|
1182
|
+
opacity: 1;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
/* Animation for collapse */
|
|
1186
|
+
.collapse {
|
|
1187
|
+
transition: height 0.35s ease;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
/* Responsive adjustments */
|
|
1191
|
+
@media (max-width: 768px) {
|
|
1192
|
+
.merged-directories-list {
|
|
1193
|
+
font-size: 13px;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
.directory-list-item .directory-name {
|
|
1197
|
+
font-size: 13px;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
.merge-info-header {
|
|
1201
|
+
padding: 12px 16px;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
.merge-info-body {
|
|
1205
|
+
padding: 16px;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
.merge-icon-wrapper {
|
|
1209
|
+
width: 36px;
|
|
1210
|
+
height: 36px;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
.merge-title {
|
|
1214
|
+
font-size: 14px;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
.merge-subtitle {
|
|
1218
|
+
font-size: 12px;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
.directory-name {
|
|
1222
|
+
font-size: 14px;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
.directory-index {
|
|
1226
|
+
font-size: 12px;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
.directory-icon {
|
|
1230
|
+
width: 32px;
|
|
1231
|
+
height: 32px;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
.directory-icon i {
|
|
1235
|
+
font-size: 14px;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
</style>
|
|
1239
|
+
</head>
|
|
1240
|
+
|
|
1241
|
+
<body>
|
|
1242
|
+
<!-- Header -->
|
|
1243
|
+
<header class="header text-center">
|
|
1244
|
+
<div class="container">
|
|
1245
|
+
<h1><i class="bi bi-bug"></i> Kea2 Merged Test Report</h1>
|
|
1246
|
+
<p class="lead">Test Time: {{ timestamp }}</p>
|
|
1247
|
+
</div>
|
|
1248
|
+
</header>
|
|
1249
|
+
|
|
1250
|
+
<div class="container mb-5">
|
|
1251
|
+
<!-- Test Summary -->
|
|
1252
|
+
<div class="row mb-4">
|
|
1253
|
+
<div class="col-12">
|
|
1254
|
+
<div class="summary-card">
|
|
1255
|
+
<h2 class="section-title">Test Summary</h2>
|
|
1256
|
+
|
|
1257
|
+
<!-- Statistics Cards -->
|
|
1258
|
+
<div class="row g-4">
|
|
1259
|
+
<div class="col-lg-3 col-md-6 col-sm-12">
|
|
1260
|
+
<div class="text-center">
|
|
1261
|
+
<i class="bi bi-bug text-danger" style="font-size: 2rem;"></i>
|
|
1262
|
+
<span class="stat-value value-danger">{{ bugs_found }}</span>
|
|
1263
|
+
<span class="stat-label">Property Violations</span>
|
|
1264
|
+
</div>
|
|
1265
|
+
</div>
|
|
1266
|
+
<div class="col-lg-3 col-md-6 col-sm-12">
|
|
1267
|
+
<div class="text-center">
|
|
1268
|
+
<i class="bi bi-shield-exclamation text-warning" style="font-size: 2rem;"></i>
|
|
1269
|
+
<span class="stat-value value-warning">{{ invariant_violations_count }}</span>
|
|
1270
|
+
<span class="stat-label">Invariant Violations</span>
|
|
1271
|
+
</div>
|
|
1272
|
+
</div>
|
|
1273
|
+
<div class="col-lg-3 col-md-6 col-sm-12">
|
|
1274
|
+
<div class="text-center">
|
|
1275
|
+
<i class="bi bi-x-circle text-danger" style="font-size: 2rem;"></i>
|
|
1276
|
+
<span class="stat-value value-danger">{{ total_crash_count|default(0) }}</span>
|
|
1277
|
+
<span class="stat-label">Crashes</span>
|
|
1278
|
+
</div>
|
|
1279
|
+
</div>
|
|
1280
|
+
<div class="col-lg-3 col-md-6 col-sm-12">
|
|
1281
|
+
<div class="text-center">
|
|
1282
|
+
<i class="bi bi-clock text-warning" style="font-size: 2rem;"></i>
|
|
1283
|
+
<span class="stat-value value-warning">{{ total_anr_count|default(0) }}</span>
|
|
1284
|
+
<span class="stat-label">ANRs</span>
|
|
1285
|
+
</div>
|
|
1286
|
+
</div>
|
|
1287
|
+
<div class="col-lg-3 col-md-6 col-sm-12">
|
|
1288
|
+
<div class="text-center">
|
|
1289
|
+
<i class="bi bi-pie-chart text-info" style="font-size: 2rem;"></i>
|
|
1290
|
+
<span class="stat-value value-highlight">{{ "%.2f"|format(coverage_percent) }}%</span>
|
|
1291
|
+
<span class="stat-label">Activity Coverage</span>
|
|
1292
|
+
</div>
|
|
1293
|
+
</div>
|
|
1294
|
+
<div class="col-lg-3 col-md-6 col-sm-12">
|
|
1295
|
+
<div class="text-center">
|
|
1296
|
+
<i class="bi bi-list-check text-primary" style="font-size: 2rem;"></i>
|
|
1297
|
+
<span class="stat-value value-highlight">{{ all_properties_count }}</span>
|
|
1298
|
+
<span class="stat-label">All Properties</span>
|
|
1299
|
+
</div>
|
|
1300
|
+
</div>
|
|
1301
|
+
<div class="col-lg-3 col-md-6 col-sm-12">
|
|
1302
|
+
<div class="text-center">
|
|
1303
|
+
<i class="bi bi-shield text-warning" style="font-size: 2rem;"></i>
|
|
1304
|
+
<span class="stat-value value-warning">{{ property_kind_summary.invariant|default(0) }}</span>
|
|
1305
|
+
<span class="stat-label">All Invariants</span>
|
|
1306
|
+
</div>
|
|
1307
|
+
</div>
|
|
1308
|
+
<div class="col-lg-3 col-md-6 col-sm-12">
|
|
1309
|
+
<div class="text-center">
|
|
1310
|
+
<i class="bi bi-check-square text-success" style="font-size: 2rem;"></i>
|
|
1311
|
+
<span class="stat-value value-success">{{ executed_properties_count }}</span>
|
|
1312
|
+
<span class="stat-label">Executed Properties</span>
|
|
1313
|
+
</div>
|
|
1314
|
+
</div>
|
|
1315
|
+
</div>
|
|
1316
|
+
|
|
1317
|
+
<!-- Merge Information Section -->
|
|
1318
|
+
{% if merge_info %}
|
|
1319
|
+
<div class="merge-info-section mt-4">
|
|
1320
|
+
<div class="merge-info-card">
|
|
1321
|
+
<!-- Collapsible Header -->
|
|
1322
|
+
<div class="merge-info-header" data-bs-toggle="collapse" data-bs-target="#mergeInfoCollapse" aria-expanded="false" aria-controls="mergeInfoCollapse">
|
|
1323
|
+
<div class="d-flex align-items-center justify-content-between">
|
|
1324
|
+
<div class="d-flex align-items-center">
|
|
1325
|
+
<div class="merge-icon-wrapper me-3">
|
|
1326
|
+
<i class="bi bi-layers"></i>
|
|
1327
|
+
</div>
|
|
1328
|
+
<div>
|
|
1329
|
+
<h6 class="mb-0 merge-title">Merged Report</h6>
|
|
1330
|
+
<small class="text-muted merge-subtitle">
|
|
1331
|
+
<i class="bi bi-clock me-1"></i>
|
|
1332
|
+
Generated at {{ merge_info.merge_timestamp }}
|
|
1333
|
+
</small>
|
|
1334
|
+
</div>
|
|
1335
|
+
</div>
|
|
1336
|
+
<div class="d-flex align-items-center">
|
|
1337
|
+
<span class="badge bg-primary me-3 merge-count-badge">
|
|
1338
|
+
<i class="bi bi-folder2-open me-1"></i>
|
|
1339
|
+
{{ merge_info.source_count }} directories
|
|
1340
|
+
</span>
|
|
1341
|
+
<i class="bi bi-chevron-down collapse-icon"></i>
|
|
1342
|
+
</div>
|
|
1343
|
+
</div>
|
|
1344
|
+
</div>
|
|
1345
|
+
|
|
1346
|
+
<!-- Collapsible Content -->
|
|
1347
|
+
<div class="collapse" id="mergeInfoCollapse">
|
|
1348
|
+
<div class="merge-info-body">
|
|
1349
|
+
<div class="merge-directories-header">
|
|
1350
|
+
<h6 class="mb-3">
|
|
1351
|
+
<i class="bi bi-list-ul me-2"></i>
|
|
1352
|
+
Merged Directories
|
|
1353
|
+
</h6>
|
|
1354
|
+
</div>
|
|
1355
|
+
<div class="merged-directories-container">
|
|
1356
|
+
<div class="merged-directories-list">
|
|
1357
|
+
{% if merge_info.source_summaries %}
|
|
1358
|
+
{% for summary in merge_info.source_summaries %}
|
|
1359
|
+
<div class="directory-list-item">
|
|
1360
|
+
<span class="directory-index">{{ loop.index }}.</span>
|
|
1361
|
+
<span class="directory-name">{{ summary.dir_name }}</span>
|
|
1362
|
+
<div class="directory-summary">
|
|
1363
|
+
<div class="directory-summary-item" title="Property Violations">
|
|
1364
|
+
<span class="summary-value text-danger">{{ summary.property_violations }}</span>
|
|
1365
|
+
<span class="summary-label">PV</span>
|
|
1366
|
+
</div>
|
|
1367
|
+
<div class="directory-summary-item" title="Invariant Violations">
|
|
1368
|
+
<span class="summary-value text-warning">{{ summary.invariant_violations }}</span>
|
|
1369
|
+
<span class="summary-label">IV</span>
|
|
1370
|
+
</div>
|
|
1371
|
+
<div class="directory-summary-item" title="Total Testing Time">
|
|
1372
|
+
<span class="summary-value text-primary">{{ summary.total_testing_time }}</span>
|
|
1373
|
+
<span class="summary-label">Time</span>
|
|
1374
|
+
</div>
|
|
1375
|
+
<div class="directory-summary-item" title="Executed Events">
|
|
1376
|
+
<span class="summary-value text-success">{{ summary.executed_events }}</span>
|
|
1377
|
+
<span class="summary-label">Events</span>
|
|
1378
|
+
</div>
|
|
1379
|
+
<div class="directory-summary-item" title="Activity Coverage">
|
|
1380
|
+
<span class="summary-value text-info">{{ summary.coverage_percent }}</span>
|
|
1381
|
+
<span class="summary-label">Cover</span>
|
|
1382
|
+
</div>
|
|
1383
|
+
<div class="directory-summary-item" title="Executed Properties">
|
|
1384
|
+
<span class="summary-value text-primary">{{ summary.executed_properties }}</span>
|
|
1385
|
+
<span class="summary-label">Props</span>
|
|
1386
|
+
</div>
|
|
1387
|
+
<div class="directory-summary-item" title="Crashes">
|
|
1388
|
+
<span class="summary-value text-danger">{{ summary.crash_count }}</span>
|
|
1389
|
+
<span class="summary-label">Crash</span>
|
|
1390
|
+
</div>
|
|
1391
|
+
<div class="directory-summary-item" title="ANRs">
|
|
1392
|
+
<span class="summary-value text-warning">{{ summary.anr_count }}</span>
|
|
1393
|
+
<span class="summary-label">ANR</span>
|
|
1394
|
+
</div>
|
|
1395
|
+
</div>
|
|
1396
|
+
</div>
|
|
1397
|
+
{% endfor %}
|
|
1398
|
+
{% else %}
|
|
1399
|
+
{% for dir_name in merge_info.source_directories %}
|
|
1400
|
+
<div class="directory-list-item">
|
|
1401
|
+
<span class="directory-index">{{ loop.index }}.</span>
|
|
1402
|
+
<span class="directory-name">{{ dir_name }}</span>
|
|
1403
|
+
</div>
|
|
1404
|
+
{% endfor %}
|
|
1405
|
+
{% endif %}
|
|
1406
|
+
</div>
|
|
1407
|
+
</div>
|
|
1408
|
+
</div>
|
|
1409
|
+
</div>
|
|
1410
|
+
</div>
|
|
1411
|
+
</div>
|
|
1412
|
+
{% endif %}
|
|
1413
|
+
</div>
|
|
1414
|
+
</div>
|
|
1415
|
+
</div>
|
|
1416
|
+
|
|
1417
|
+
<!-- Activities Coverage -->
|
|
1418
|
+
<div class="section-block">
|
|
1419
|
+
<h2 class="section-title">Activities Coverage</h2>
|
|
1420
|
+
|
|
1421
|
+
<!-- Search Controls for Activities -->
|
|
1422
|
+
<div class="mb-4">
|
|
1423
|
+
<div class="d-flex align-items-center">
|
|
1424
|
+
<div style="width: 33%;">
|
|
1425
|
+
<div class="property-search-container">
|
|
1426
|
+
<input type="text" class="form-control property-search-input property-stats-search-simple"
|
|
1427
|
+
id="activities-search"
|
|
1428
|
+
placeholder="Search activities by name..."
|
|
1429
|
+
data-target="activities-container"
|
|
1430
|
+
data-item-class="activity-row"
|
|
1431
|
+
data-pagination="activities-pagination"
|
|
1432
|
+
data-page-size="activities-page-size">
|
|
1433
|
+
<button class="property-search-icon-btn search-btn" type="button" id="activities-search-btn">
|
|
1434
|
+
<i class="bi bi-search"></i>
|
|
1435
|
+
</button>
|
|
1436
|
+
</div>
|
|
1437
|
+
</div>
|
|
1438
|
+
<div class="ms-3">
|
|
1439
|
+
<small class="text-muted search-results-count" id="activities-search-results"></small>
|
|
1440
|
+
</div>
|
|
1441
|
+
</div>
|
|
1442
|
+
</div>
|
|
1443
|
+
|
|
1444
|
+
<div class="table-responsive">
|
|
1445
|
+
<table class="table table-custom table-activities">
|
|
1446
|
+
<thead>
|
|
1447
|
+
<tr>
|
|
1448
|
+
<th>Activity Name <span class="badge bg-primary ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ tested_activities_count }}/{{ total_activities_count }}</span></th>
|
|
1449
|
+
<th>Visit Count <i class="bi bi-arrow-down-up text-muted sort-icon activities-sort-icon" id="visit-count-sort" data-column="visit-count" data-order="none" style="cursor: pointer;"></i></th>
|
|
1450
|
+
</tr>
|
|
1451
|
+
</thead>
|
|
1452
|
+
<tbody id="activities-container">
|
|
1453
|
+
{% if total_activities|length > 0 %}
|
|
1454
|
+
{% for activity in total_activities %}
|
|
1455
|
+
<tr class="activity-row" data-page="1"
|
|
1456
|
+
data-activity-name="{{ activity }}"
|
|
1457
|
+
data-visit-count="{{ activity_count_history[activity] if activity in activity_count_history else 0 }}">
|
|
1458
|
+
<td>
|
|
1459
|
+
{% if activity in tested_activities %}
|
|
1460
|
+
<i class="bi bi-check-circle-fill text-success me-2"></i>
|
|
1461
|
+
{% else %}
|
|
1462
|
+
<i class="bi bi-dash-circle text-secondary me-2"></i>
|
|
1463
|
+
{% endif %}
|
|
1464
|
+
<span class="activity-name">{{ activity }}</span>
|
|
1465
|
+
</td>
|
|
1466
|
+
<td>
|
|
1467
|
+
{% if activity in activity_count_history %}
|
|
1468
|
+
<span class="badge bg-info text-white">
|
|
1469
|
+
<i class="bi bi-eye"></i> {{ activity_count_history[activity] }} times
|
|
1470
|
+
</span>
|
|
1471
|
+
{% else %}
|
|
1472
|
+
<span class="badge bg-secondary text-white">
|
|
1473
|
+
<i class="bi bi-dash"></i> 0 times
|
|
1474
|
+
</span>
|
|
1475
|
+
{% endif %}
|
|
1476
|
+
</td>
|
|
1477
|
+
</tr>
|
|
1478
|
+
{% endfor %}
|
|
1479
|
+
{% else %}
|
|
1480
|
+
<tr>
|
|
1481
|
+
<td colspan="2" class="text-center text-muted">No activities found</td>
|
|
1482
|
+
</tr>
|
|
1483
|
+
{% endif %}
|
|
1484
|
+
</tbody>
|
|
1485
|
+
</table>
|
|
1486
|
+
</div>
|
|
1487
|
+
|
|
1488
|
+
<!-- Pagination for Activities -->
|
|
1489
|
+
<div class="d-flex justify-content-between align-items-center mt-3">
|
|
1490
|
+
<div class="d-flex align-items-center">
|
|
1491
|
+
<label for="activities-page-size" class="form-label me-2 mb-0">Show:</label>
|
|
1492
|
+
<select class="form-select form-select-sm" id="activities-page-size" style="width: auto;">
|
|
1493
|
+
<option value="5">5</option>
|
|
1494
|
+
<option value="10" selected>10</option>
|
|
1495
|
+
<option value="20">20</option>
|
|
1496
|
+
<option value="50">50</option>
|
|
1497
|
+
<option value="100">100</option>
|
|
1498
|
+
</select>
|
|
1499
|
+
</div>
|
|
1500
|
+
<nav aria-label="Activities pagination">
|
|
1501
|
+
<ul class="pagination pagination-sm mb-0" id="activities-pagination">
|
|
1502
|
+
<!-- Pagination will be generated by JavaScript -->
|
|
1503
|
+
</ul>
|
|
1504
|
+
</nav>
|
|
1505
|
+
</div>
|
|
1506
|
+
</div>
|
|
1507
|
+
|
|
1508
|
+
<!-- Crash Analysis Section -->
|
|
1509
|
+
{% if crash_events or anr_events %}
|
|
1510
|
+
<div class="section-block">
|
|
1511
|
+
<h2 class="section-title">
|
|
1512
|
+
<i class="bi bi-exclamation-triangle text-danger"></i> Crash and ANR Events
|
|
1513
|
+
</h2>
|
|
1514
|
+
|
|
1515
|
+
<!-- Detailed Crash Information -->
|
|
1516
|
+
<div class="crash-analysis-panel">
|
|
1517
|
+
<!-- Event Filter -->
|
|
1518
|
+
<div class="mb-3">
|
|
1519
|
+
<div class="btn-group" role="group" aria-label="Event filter">
|
|
1520
|
+
<input type="radio" class="btn-check" name="event-filter" id="all-events" autocomplete="off" checked>
|
|
1521
|
+
<label class="btn btn-outline-primary" for="all-events">All Events ({{ (crash_events|length) + (anr_events|length) }})</label>
|
|
1522
|
+
|
|
1523
|
+
<input type="radio" class="btn-check" name="event-filter" id="crashes-only" autocomplete="off">
|
|
1524
|
+
<label class="btn btn-outline-danger" for="crashes-only">Crashes Only ({{ crash_events|length }})</label>
|
|
1525
|
+
|
|
1526
|
+
<input type="radio" class="btn-check" name="event-filter" id="anr-only" autocomplete="off">
|
|
1527
|
+
<label class="btn btn-outline-warning" for="anr-only">ANR Only ({{ anr_events|length }})</label>
|
|
1528
|
+
</div>
|
|
1529
|
+
</div>
|
|
1530
|
+
|
|
1531
|
+
|
|
1532
|
+
<!-- Events Table -->
|
|
1533
|
+
<div class="table-responsive">
|
|
1534
|
+
<table class="table table-custom">
|
|
1535
|
+
<thead>
|
|
1536
|
+
<tr>
|
|
1537
|
+
<th>Type</th>
|
|
1538
|
+
<th>Time</th>
|
|
1539
|
+
<th>Exception</th>
|
|
1540
|
+
<th>Process</th>
|
|
1541
|
+
<th>Report Source</th>
|
|
1542
|
+
<th>Details</th>
|
|
1543
|
+
</tr>
|
|
1544
|
+
</thead>
|
|
1545
|
+
<tbody id="crash-events-container">
|
|
1546
|
+
{% for crash in crash_events %}
|
|
1547
|
+
<tr class="event-row" data-type="crash" data-page="1">
|
|
1548
|
+
<td><span class="badge bg-danger">CRASH</span></td>
|
|
1549
|
+
<td>{{ crash.time }}</td>
|
|
1550
|
+
<td>{{ crash.exception_type }}</td>
|
|
1551
|
+
<td>{{ crash.process }}</td>
|
|
1552
|
+
<td>
|
|
1553
|
+
{% if crash.report_path %}
|
|
1554
|
+
<a href="{{ crash.report_path }}" target="_blank" class="text-decoration-none">
|
|
1555
|
+
<span class="badge bg-info text-white me-2 mb-1"
|
|
1556
|
+
style="font-family: 'Courier New', monospace; font-size: 0.8em; padding: 0.4em 0.6em; cursor: pointer;"
|
|
1557
|
+
title="Click to open original report"
|
|
1558
|
+
onmouseover="this.style.backgroundColor='#0056b3'" onmouseout="this.style.backgroundColor='#0dcaf0'">
|
|
1559
|
+
<i class="bi bi-folder me-1"></i>{{ crash.source_directory or 'Unknown' }}
|
|
1560
|
+
<i class="bi bi-box-arrow-up-right ms-1" style="font-size: 0.7em;"></i>
|
|
1561
|
+
</span>
|
|
1562
|
+
</a>
|
|
1563
|
+
{% elif crash.source_directory %}
|
|
1564
|
+
<span class="badge bg-info text-white me-2 mb-1"
|
|
1565
|
+
style="font-family: 'Courier New', monospace; font-size: 0.8em; padding: 0.4em 0.6em;">
|
|
1566
|
+
<i class="bi bi-folder me-1"></i>{{ crash.source_directory }}
|
|
1567
|
+
</span>
|
|
1568
|
+
{% else %}
|
|
1569
|
+
<span class="text-muted">N/A</span>
|
|
1570
|
+
{% endif %}
|
|
1571
|
+
</td>
|
|
1572
|
+
<td>
|
|
1573
|
+
<button class="btn btn-sm btn-outline-primary" type="button"
|
|
1574
|
+
data-bs-toggle="collapse" data-bs-target="#crash-detail-{{ loop.index }}"
|
|
1575
|
+
aria-expanded="false" aria-controls="crash-detail-{{ loop.index }}">
|
|
1576
|
+
<i class="bi bi-eye"></i> Details
|
|
1577
|
+
</button>
|
|
1578
|
+
<button class="btn btn-sm btn-outline-secondary copy-stack-btn"
|
|
1579
|
+
data-stack-index="{{ loop.index }}">
|
|
1580
|
+
<i class="bi bi-clipboard"></i> Copy
|
|
1581
|
+
</button>
|
|
1582
|
+
</td>
|
|
1583
|
+
</tr>
|
|
1584
|
+
<tr class="collapse" id="crash-detail-{{ loop.index }}">
|
|
1585
|
+
<td colspan="6">
|
|
1586
|
+
<div class="bg-light p-3 rounded">
|
|
1587
|
+
<h6 class="text-danger">Stack Trace:</h6>
|
|
1588
|
+
<pre class="text-danger mb-0 text-start" id="stack-trace-{{ loop.index }}" style="font-size: 0.9em; white-space: pre-wrap; text-align: left;">{{ crash.stack_trace }}</pre>
|
|
1589
|
+
</div>
|
|
1590
|
+
</td>
|
|
1591
|
+
</tr>
|
|
1592
|
+
{% endfor %}
|
|
1593
|
+
|
|
1594
|
+
|
|
1595
|
+
{% for anr in anr_events %}
|
|
1596
|
+
<tr class="event-row" data-type="anr" data-page="1">
|
|
1597
|
+
<td><span class="badge bg-warning text-dark">ANR</span></td>
|
|
1598
|
+
<td>{{ anr.time }}</td>
|
|
1599
|
+
<td>{{ anr.reason }}</td>
|
|
1600
|
+
<td>{{ anr.process }}</td>
|
|
1601
|
+
<td>
|
|
1602
|
+
{% if anr.report_path %}
|
|
1603
|
+
<a href="{{ anr.report_path }}" target="_blank" class="text-decoration-none">
|
|
1604
|
+
<span class="badge bg-info text-white me-2 mb-1"
|
|
1605
|
+
style="font-family: 'Courier New', monospace; font-size: 0.8em; padding: 0.4em 0.6em; cursor: pointer;"
|
|
1606
|
+
title="Click to open original report"
|
|
1607
|
+
onmouseover="this.style.backgroundColor='#0056b3'" onmouseout="this.style.backgroundColor='#0dcaf0'">
|
|
1608
|
+
<i class="bi bi-folder me-1"></i>{{ anr.source_directory or 'Unknown' }}
|
|
1609
|
+
<i class="bi bi-box-arrow-up-right ms-1" style="font-size: 0.7em;"></i>
|
|
1610
|
+
</span>
|
|
1611
|
+
</a>
|
|
1612
|
+
{% elif anr.source_directory %}
|
|
1613
|
+
<span class="badge bg-info text-white me-2 mb-1"
|
|
1614
|
+
style="font-family: 'Courier New', monospace; font-size: 0.8em; padding: 0.4em 0.6em;">
|
|
1615
|
+
<i class="bi bi-folder me-1"></i>{{ anr.source_directory }}
|
|
1616
|
+
</span>
|
|
1617
|
+
{% else %}
|
|
1618
|
+
<span class="text-muted">N/A</span>
|
|
1619
|
+
{% endif %}
|
|
1620
|
+
</td>
|
|
1621
|
+
<td>
|
|
1622
|
+
<button class="btn btn-sm btn-outline-primary" type="button"
|
|
1623
|
+
data-bs-toggle="collapse" data-bs-target="#anr-detail-{{ loop.index }}"
|
|
1624
|
+
aria-expanded="false" aria-controls="anr-detail-{{ loop.index }}">
|
|
1625
|
+
<i class="bi bi-eye"></i> Details
|
|
1626
|
+
</button>
|
|
1627
|
+
<button class="btn btn-sm btn-outline-secondary copy-stack-btn"
|
|
1628
|
+
data-stack-index="anr-{{ loop.index }}">
|
|
1629
|
+
<i class="bi bi-clipboard"></i> Copy
|
|
1630
|
+
</button>
|
|
1631
|
+
</td>
|
|
1632
|
+
</tr>
|
|
1633
|
+
<tr class="collapse" id="anr-detail-{{ loop.index }}">
|
|
1634
|
+
<td colspan="6">
|
|
1635
|
+
<div class="bg-light p-3 rounded">
|
|
1636
|
+
<h6 class="text-dark">ANR Details:</h6>
|
|
1637
|
+
<pre class="text-dark mb-0 text-start" id="stack-trace-anr-{{ loop.index }}" style="font-size: 0.9em; white-space: pre-wrap; text-align: left;">{{ anr.trace }}</pre>
|
|
1638
|
+
</div>
|
|
1639
|
+
</td>
|
|
1640
|
+
</tr>
|
|
1641
|
+
{% endfor %}
|
|
1642
|
+
</tbody>
|
|
1643
|
+
</table>
|
|
1644
|
+
</div>
|
|
1645
|
+
|
|
1646
|
+
<!-- Pagination for Crash Events -->
|
|
1647
|
+
<div class="d-flex justify-content-between align-items-center mt-3 pagination-container pagination-violations">
|
|
1648
|
+
<div class="d-flex align-items-center gap-3">
|
|
1649
|
+
<label for="events-page-size" class="form-label me-2 mb-0">Show:</label>
|
|
1650
|
+
<select class="form-select form-select-sm" id="events-page-size" style="width: auto;">
|
|
1651
|
+
<option value="5">5</option>
|
|
1652
|
+
<option value="10" selected>10</option>
|
|
1653
|
+
<option value="20">20</option>
|
|
1654
|
+
<option value="50">50</option>
|
|
1655
|
+
<option value="100">100</option>
|
|
1656
|
+
</select>
|
|
1657
|
+
</div>
|
|
1658
|
+
<nav aria-label="Crash Events Pagination">
|
|
1659
|
+
<ul class="pagination pagination-sm mb-0" id="events-pagination">
|
|
1660
|
+
<!-- Pagination will be generated by JavaScript -->
|
|
1661
|
+
</ul>
|
|
1662
|
+
</nav>
|
|
1663
|
+
</div>
|
|
1664
|
+
</div>
|
|
1665
|
+
</div>
|
|
1666
|
+
{% else %}
|
|
1667
|
+
<div class="section-block">
|
|
1668
|
+
<h2 class="section-title">
|
|
1669
|
+
<i class="bi bi-exclamation-triangle text-danger"></i> Crash and ANR Events
|
|
1670
|
+
</h2>
|
|
1671
|
+
<div class="alert alert-info text-center">
|
|
1672
|
+
<i class="bi bi-info-circle"></i> No crash or ANR events detected in this test session.
|
|
1673
|
+
</div>
|
|
1674
|
+
</div>
|
|
1675
|
+
{% endif %}
|
|
1676
|
+
|
|
1677
|
+
<!-- Property Checking Statistics -->
|
|
1678
|
+
<div class="section-block">
|
|
1679
|
+
<h2 class="section-title">Property Checking Statistics</h2>
|
|
1680
|
+
|
|
1681
|
+
<!-- Search Controls for Property Statistics -->
|
|
1682
|
+
<div class="mb-4">
|
|
1683
|
+
<div style="width: 33%;">
|
|
1684
|
+
<div class="property-search-container">
|
|
1685
|
+
<input type="text" class="form-control property-search-input property-stats-search-simple"
|
|
1686
|
+
id="property-stats-search"
|
|
1687
|
+
placeholder="Search properties by name..."
|
|
1688
|
+
data-target="property-stats-container"
|
|
1689
|
+
data-item-class="property-stat-row"
|
|
1690
|
+
data-pagination="stats-pagination"
|
|
1691
|
+
data-page-size="stats-page-size">
|
|
1692
|
+
<button class="property-search-icon-btn search-btn" type="button"
|
|
1693
|
+
data-target="property-stats-search">
|
|
1694
|
+
<i class="bi bi-search"></i>
|
|
1695
|
+
</button>
|
|
1696
|
+
</div>
|
|
1697
|
+
</div>
|
|
1698
|
+
<small class="text-muted search-results-count" id="property-search-results"></small>
|
|
1699
|
+
</div>
|
|
1700
|
+
|
|
1701
|
+
<div class="mb-3">
|
|
1702
|
+
<div class="btn-group" role="group" aria-label="Property kind filter">
|
|
1703
|
+
<input type="radio" class="btn-check" name="property-kind-filter" id="property-kind-all" autocomplete="off" checked>
|
|
1704
|
+
<label class="btn btn-outline-primary" for="property-kind-all">All ({{ property_kind_summary.all|default(0) }})</label>
|
|
1705
|
+
|
|
1706
|
+
<input type="radio" class="btn-check" name="property-kind-filter" id="property-kind-property" autocomplete="off">
|
|
1707
|
+
<label class="btn btn-outline-info" for="property-kind-property">Property ({{ property_kind_summary.property|default(0) }})</label>
|
|
1708
|
+
|
|
1709
|
+
<input type="radio" class="btn-check" name="property-kind-filter" id="property-kind-invariant" autocomplete="off">
|
|
1710
|
+
<label class="btn btn-outline-warning" for="property-kind-invariant">Invariant ({{ property_kind_summary.invariant|default(0) }})</label>
|
|
1711
|
+
</div>
|
|
1712
|
+
</div>
|
|
1713
|
+
|
|
1714
|
+
<div class="table-responsive">
|
|
1715
|
+
<table class="table table-custom">
|
|
1716
|
+
<thead>
|
|
1717
|
+
<tr>
|
|
1718
|
+
<th>Index</th>
|
|
1719
|
+
<th>Property Name <span class="badge bg-primary ms-2" id="property-stats-total-properties" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_properties if property_stats_summary is defined else property_stats|length }}</span></th>
|
|
1720
|
+
<th>Precondition Satisfied <span class="badge bg-success ms-2" id="property-stats-total-precond" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_precond_satisfied if property_stats_summary is defined else 0 }}</span></th>
|
|
1721
|
+
<th>Total Executions <span class="badge bg-info ms-2" id="property-stats-total-executed" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_executed if property_stats_summary is defined else 0 }}</span></th>
|
|
1722
|
+
<th>Passes <span class="badge bg-secondary ms-2" id="property-stats-total-pass" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_passes if property_stats_summary is defined else 0 }}</span></th>
|
|
1723
|
+
<th>Fails <span class="badge bg-danger ms-2" id="property-stats-total-fail" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_fails if property_stats_summary is defined else 0 }}</span> <i class="bi bi-arrow-down-up text-muted sort-icon" id="fails-sort" data-column="fails" data-order="none" style="cursor: pointer;"></i></th>
|
|
1724
|
+
<th>Errors <span class="badge bg-warning ms-2" id="property-stats-total-error" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_errors if property_stats_summary is defined else 0 }}</span> <i class="bi bi-arrow-down-up text-muted sort-icon" id="errors-sort" data-column="errors" data-order="none" style="cursor: pointer;"></i></th>
|
|
1725
|
+
<th>Skipped <span class="badge bg-light text-dark ms-2" id="property-stats-total-skipped" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_not_executed if property_stats_summary is defined else 0 }}</span></th>
|
|
1726
|
+
</tr>
|
|
1727
|
+
</thead>
|
|
1728
|
+
<tbody id="property-stats-container">
|
|
1729
|
+
{% for property_name, test_result in property_stats.items() %}
|
|
1730
|
+
<tr class="property-stat-row" data-page="1"
|
|
1731
|
+
data-index="{{ loop.index }}"
|
|
1732
|
+
data-property-name="{{ property_name }}"
|
|
1733
|
+
data-kind="{{ test_result.kind|default('unknown') }}"
|
|
1734
|
+
data-precond-satisfied="{{ test_result.precond_satisfied|default(0) }}"
|
|
1735
|
+
data-executed="{{ test_result.executed_total|default(test_result.executed|default(0)) }}"
|
|
1736
|
+
data-pass="{{ test_result.pass_count|default(0) }}"
|
|
1737
|
+
data-fails="{{ test_result.fail|default(0) }}"
|
|
1738
|
+
data-errors="{{ test_result.error|default(0) }}"
|
|
1739
|
+
data-not-executed="{{ test_result.not_executed|default(0) }}">
|
|
1740
|
+
<td>{{ loop.index }}</td>
|
|
1741
|
+
<td>
|
|
1742
|
+
<span class="badge bg-light text-dark badge-custom">{{ property_name }}</span>
|
|
1743
|
+
{% set kind_label = test_result.kind|default('unknown') %}
|
|
1744
|
+
{% set is_invariant = kind_label == 'invariant' %}
|
|
1745
|
+
<span class="badge ms-1 {% if kind_label == 'property' %}bg-info text-dark{% elif kind_label == 'invariant' %}bg-warning text-dark{% else %}bg-secondary text-white{% endif %}">
|
|
1746
|
+
{{ kind_label|capitalize }}
|
|
1747
|
+
</span>
|
|
1748
|
+
</td>
|
|
1749
|
+
<td>{{ '/' if is_invariant else test_result.precond_satisfied|default(0) }}</td>
|
|
1750
|
+
<td>{{ '/' if is_invariant else test_result.executed_total|default(test_result.executed|default(0)) }}</td>
|
|
1751
|
+
<td>{{ '/' if is_invariant else test_result.pass_count|default(0) }}</td>
|
|
1752
|
+
<td><span class="badge bg-danger text-white">{{ test_result.fail|default(0) }}</span></td>
|
|
1753
|
+
<td><span class="badge bg-warning text-dark">{{ test_result.error|default(0) }}</span></td>
|
|
1754
|
+
<td>{{ '/' if is_invariant else test_result.not_executed|default(0) }}</td>
|
|
1755
|
+
</tr>
|
|
1756
|
+
{% endfor %}
|
|
1757
|
+
</tbody>
|
|
1758
|
+
</table>
|
|
1759
|
+
|
|
1760
|
+
<!-- Pagination for Property Checking Statistics -->
|
|
1761
|
+
<div class="d-flex justify-content-between align-items-center mt-3">
|
|
1762
|
+
<div class="d-flex align-items-center">
|
|
1763
|
+
<label for="stats-page-size" class="form-label me-2 mb-0">Show:</label>
|
|
1764
|
+
<select class="form-select form-select-sm" id="stats-page-size" style="width: auto;">
|
|
1765
|
+
<option value="5">5</option>
|
|
1766
|
+
<option value="10" selected>10</option>
|
|
1767
|
+
<option value="20">20</option>
|
|
1768
|
+
<option value="50">50</option>
|
|
1769
|
+
<option value="100">100</option>
|
|
1770
|
+
</select>
|
|
1771
|
+
</div>
|
|
1772
|
+
<nav aria-label="Property Stats Pagination">
|
|
1773
|
+
<ul class="pagination pagination-sm mb-0" id="stats-pagination">
|
|
1774
|
+
<!-- Pagination will be generated by JavaScript -->
|
|
1775
|
+
</ul>
|
|
1776
|
+
</nav>
|
|
1777
|
+
</div>
|
|
1778
|
+
</div>
|
|
1779
|
+
</div>
|
|
1780
|
+
|
|
1781
|
+
<!-- Property Source Mapping -->
|
|
1782
|
+
{% if property_source_mapping %}
|
|
1783
|
+
<div class="section-block">
|
|
1784
|
+
<h2 class="section-title">
|
|
1785
|
+
<i class="bi bi-folder2-open text-info"></i> Property Source Mapping
|
|
1786
|
+
</h2>
|
|
1787
|
+
|
|
1788
|
+
<div class="alert alert-info mb-4" style="border-left: 4px solid #17a2b8; background-color: #f8f9fa;">
|
|
1789
|
+
<div class="d-flex align-items-start">
|
|
1790
|
+
<i class="bi bi-info-circle me-2 mt-1"></i>
|
|
1791
|
+
<div>
|
|
1792
|
+
<strong>Source Directory Information:</strong>
|
|
1793
|
+
<p class="mb-0 mt-1">This section shows which test directories contain properties with failures or errors.
|
|
1794
|
+
Use this information to locate the original test reports for detailed error analysis.</p>
|
|
1795
|
+
</div>
|
|
1796
|
+
</div>
|
|
1797
|
+
</div>
|
|
1798
|
+
|
|
1799
|
+
<!-- Search Controls for Property Source Mapping -->
|
|
1800
|
+
<div class="mb-4">
|
|
1801
|
+
<div style="width: 33%;">
|
|
1802
|
+
<div class="property-search-container">
|
|
1803
|
+
<input type="text" class="form-control property-search-input property-stats-search-simple"
|
|
1804
|
+
id="property-source-search"
|
|
1805
|
+
placeholder="Search properties by name..."
|
|
1806
|
+
data-target="property-source-container"
|
|
1807
|
+
data-item-class="property-source-row"
|
|
1808
|
+
data-pagination="source-pagination"
|
|
1809
|
+
data-page-size="source-page-size">
|
|
1810
|
+
<button class="property-search-icon-btn search-btn" type="button"
|
|
1811
|
+
data-target="property-source-search">
|
|
1812
|
+
<i class="bi bi-search"></i>
|
|
1813
|
+
</button>
|
|
1814
|
+
</div>
|
|
1815
|
+
</div>
|
|
1816
|
+
<small class="text-muted search-results-count" id="property-source-search-results"></small>
|
|
1817
|
+
</div>
|
|
1818
|
+
|
|
1819
|
+
<div class="mb-3">
|
|
1820
|
+
<div class="btn-group" role="group" aria-label="Property source kind filter">
|
|
1821
|
+
<input type="radio" class="btn-check" name="property-source-kind-filter" id="property-source-kind-all" autocomplete="off" checked>
|
|
1822
|
+
<label class="btn btn-outline-primary" for="property-source-kind-all">All ({{ property_source_kind_summary.all|default(0) }})</label>
|
|
1823
|
+
|
|
1824
|
+
<input type="radio" class="btn-check" name="property-source-kind-filter" id="property-source-kind-property" autocomplete="off">
|
|
1825
|
+
<label class="btn btn-outline-info" for="property-source-kind-property">Property ({{ property_source_kind_summary.property|default(0) }})</label>
|
|
1826
|
+
|
|
1827
|
+
<input type="radio" class="btn-check" name="property-source-kind-filter" id="property-source-kind-invariant" autocomplete="off">
|
|
1828
|
+
<label class="btn btn-outline-warning" for="property-source-kind-invariant">Invariant ({{ property_source_kind_summary.invariant|default(0) }})</label>
|
|
1829
|
+
</div>
|
|
1830
|
+
</div>
|
|
1831
|
+
|
|
1832
|
+
<div class="table-responsive">
|
|
1833
|
+
<table class="table table-custom">
|
|
1834
|
+
<thead>
|
|
1835
|
+
<tr>
|
|
1836
|
+
<th>Index</th>
|
|
1837
|
+
<th>Property Name</th>
|
|
1838
|
+
<th>Source Directories</th>
|
|
1839
|
+
</tr>
|
|
1840
|
+
</thead>
|
|
1841
|
+
<tbody id="property-source-container">
|
|
1842
|
+
{% for property_name, source_dirs in property_source_mapping.items() %}
|
|
1843
|
+
{% set kind_label = property_stats[property_name].kind if property_stats is defined and property_name in property_stats else 'unknown' %}
|
|
1844
|
+
<tr class="property-source-row" data-page="1"
|
|
1845
|
+
data-index="{{ loop.index }}"
|
|
1846
|
+
data-property-name="{{ property_name }}"
|
|
1847
|
+
data-kind="{{ kind_label }}">
|
|
1848
|
+
<td>{{ loop.index }}</td>
|
|
1849
|
+
<td>
|
|
1850
|
+
<span class="badge bg-light text-dark badge-custom">{{ property_name }}</span>
|
|
1851
|
+
</td>
|
|
1852
|
+
<td>
|
|
1853
|
+
{% set max_visible = 3 %}
|
|
1854
|
+
{% if source_dirs|length <= max_visible %}
|
|
1855
|
+
<!-- Show all directories if count is small -->
|
|
1856
|
+
{% for dir_info in source_dirs %}
|
|
1857
|
+
{% if dir_info.report_path %}
|
|
1858
|
+
<a href="{{ dir_info.report_path }}" target="_blank" class="text-decoration-none">
|
|
1859
|
+
<span class="badge bg-info text-white me-2 mb-1" style="font-family: 'Courier New', monospace; font-size: 0.8em; padding: 0.4em 0.6em; cursor: pointer;"
|
|
1860
|
+
title="Click to open original report"
|
|
1861
|
+
onmouseover="this.style.backgroundColor='#0056b3'" onmouseout="this.style.backgroundColor='#0dcaf0'">
|
|
1862
|
+
<i class="bi bi-folder me-1"></i>{{ dir_info.dir_name }}
|
|
1863
|
+
<i class="bi bi-box-arrow-up-right ms-1" style="font-size: 0.7em;"></i>
|
|
1864
|
+
</span>
|
|
1865
|
+
</a>
|
|
1866
|
+
{% else %}
|
|
1867
|
+
<span class="badge bg-info text-white me-2 mb-1" style="font-family: 'Courier New', monospace; font-size: 0.8em; padding: 0.4em 0.6em;">
|
|
1868
|
+
<i class="bi bi-folder me-1"></i>{{ dir_info.dir_name }}
|
|
1869
|
+
</span>
|
|
1870
|
+
{% endif %}
|
|
1871
|
+
{% endfor %}
|
|
1872
|
+
{% else %}
|
|
1873
|
+
<!-- Show limited directories with expand/collapse -->
|
|
1874
|
+
<div class="source-dirs-container" data-property="{{ property_name }}">
|
|
1875
|
+
<!-- Always visible directories -->
|
|
1876
|
+
{% for dir_info in source_dirs[:max_visible] %}
|
|
1877
|
+
{% if dir_info.report_path %}
|
|
1878
|
+
<a href="{{ dir_info.report_path }}" target="_blank" class="text-decoration-none">
|
|
1879
|
+
<span class="badge bg-info text-white me-2 mb-1" style="font-family: 'Courier New', monospace; font-size: 0.8em; padding: 0.4em 0.6em; cursor: pointer;"
|
|
1880
|
+
title="Click to open original report"
|
|
1881
|
+
onmouseover="this.style.backgroundColor='#0056b3'" onmouseout="this.style.backgroundColor='#0dcaf0'">
|
|
1882
|
+
<i class="bi bi-folder me-1"></i>{{ dir_info.dir_name }}
|
|
1883
|
+
<i class="bi bi-box-arrow-up-right ms-1" style="font-size: 0.7em;"></i>
|
|
1884
|
+
</span>
|
|
1885
|
+
</a>
|
|
1886
|
+
{% else %}
|
|
1887
|
+
<span class="badge bg-info text-white me-2 mb-1" style="font-family: 'Courier New', monospace; font-size: 0.8em; padding: 0.4em 0.6em;">
|
|
1888
|
+
<i class="bi bi-folder me-1"></i>{{ dir_info.dir_name }}
|
|
1889
|
+
</span>
|
|
1890
|
+
{% endif %}
|
|
1891
|
+
{% endfor %}
|
|
1892
|
+
|
|
1893
|
+
<!-- Hidden directories -->
|
|
1894
|
+
<div class="source-dirs-hidden" id="hidden-dirs-{{ loop.index }}" style="display: none;">
|
|
1895
|
+
{% for dir_info in source_dirs[max_visible:] %}
|
|
1896
|
+
{% if dir_info.report_path %}
|
|
1897
|
+
<a href="{{ dir_info.report_path }}" target="_blank" class="text-decoration-none">
|
|
1898
|
+
<span class="badge bg-info text-white me-2 mb-1" style="font-family: 'Courier New', monospace; font-size: 0.8em; padding: 0.4em 0.6em; cursor: pointer;"
|
|
1899
|
+
title="Click to open original report"
|
|
1900
|
+
onmouseover="this.style.backgroundColor='#0056b3'" onmouseout="this.style.backgroundColor='#0dcaf0'">
|
|
1901
|
+
<i class="bi bi-folder me-1"></i>{{ dir_info.dir_name }}
|
|
1902
|
+
<i class="bi bi-box-arrow-up-right ms-1" style="font-size: 0.7em;"></i>
|
|
1903
|
+
</span>
|
|
1904
|
+
</a>
|
|
1905
|
+
{% else %}
|
|
1906
|
+
<span class="badge bg-info text-white me-2 mb-1" style="font-family: 'Courier New', monospace; font-size: 0.8em; padding: 0.4em 0.6em;">
|
|
1907
|
+
<i class="bi bi-folder me-1"></i>{{ dir_info.dir_name }}
|
|
1908
|
+
</span>
|
|
1909
|
+
{% endif %}
|
|
1910
|
+
{% endfor %}
|
|
1911
|
+
</div>
|
|
1912
|
+
|
|
1913
|
+
<!-- Toggle button -->
|
|
1914
|
+
<button class="btn btn-sm btn-outline-info source-dirs-toggle"
|
|
1915
|
+
data-target="hidden-dirs-{{ loop.index }}"
|
|
1916
|
+
data-total="{{ source_dirs|length }}"
|
|
1917
|
+
data-visible="{{ max_visible }}"
|
|
1918
|
+
style="font-size: 0.75em; padding: 0.2em 0.5em; margin-left: 0.25em;">
|
|
1919
|
+
<i class="bi bi-chevron-down"></i>
|
|
1920
|
+
<span class="toggle-text">+{{ source_dirs|length - max_visible }} more</span>
|
|
1921
|
+
</button>
|
|
1922
|
+
</div>
|
|
1923
|
+
{% endif %}
|
|
1924
|
+
</td>
|
|
1925
|
+
</tr>
|
|
1926
|
+
{% endfor %}
|
|
1927
|
+
</tbody>
|
|
1928
|
+
</table>
|
|
1929
|
+
|
|
1930
|
+
<!-- Pagination for Property Source Mapping -->
|
|
1931
|
+
<div class="d-flex justify-content-between align-items-center mt-3">
|
|
1932
|
+
<div class="d-flex align-items-center">
|
|
1933
|
+
<label for="source-page-size" class="form-label me-2 mb-0">Show:</label>
|
|
1934
|
+
<select class="form-select form-select-sm" id="source-page-size" style="width: auto;">
|
|
1935
|
+
<option value="5">5</option>
|
|
1936
|
+
<option value="10" selected>10</option>
|
|
1937
|
+
<option value="20">20</option>
|
|
1938
|
+
<option value="50">50</option>
|
|
1939
|
+
<option value="100">100</option>
|
|
1940
|
+
</select>
|
|
1941
|
+
</div>
|
|
1942
|
+
<nav aria-label="Property Source Pagination">
|
|
1943
|
+
<ul class="pagination pagination-sm mb-0" id="source-pagination">
|
|
1944
|
+
<!-- Pagination will be generated by JavaScript -->
|
|
1945
|
+
</ul>
|
|
1946
|
+
</nav>
|
|
1947
|
+
</div>
|
|
1948
|
+
</div>
|
|
1949
|
+
</div>
|
|
1950
|
+
{% endif %}
|
|
1951
|
+
</div>
|
|
1952
|
+
|
|
1953
|
+
<!-- Footer -->
|
|
1954
|
+
<footer class="bg-dark text-white text-center py-4">
|
|
1955
|
+
<div class="container">
|
|
1956
|
+
<p class="mb-0">Kea2 Merged Test Report | Generated at: {{ timestamp }}</p>
|
|
1957
|
+
</div>
|
|
1958
|
+
</footer>
|
|
1959
|
+
|
|
1960
|
+
<!-- JavaScript -->
|
|
1961
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
1962
|
+
<script>
|
|
1963
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
1964
|
+
// Initialize merge info collapse functionality
|
|
1965
|
+
initMergeInfoCollapse();
|
|
1966
|
+
|
|
1967
|
+
// Initialize merged directories scrollbar enhancement
|
|
1968
|
+
initMergedDirectoriesScrollbar();
|
|
1969
|
+
|
|
1970
|
+
// Initialize pagination for Activities
|
|
1971
|
+
initPagination('activities-container', 'activity-row', 'activities-pagination', 'activities-page-size');
|
|
1972
|
+
|
|
1973
|
+
// Initialize activity sorting
|
|
1974
|
+
initActivitiesSorting();
|
|
1975
|
+
|
|
1976
|
+
// Initialize activity searching
|
|
1977
|
+
initActivitiesSearching();
|
|
1978
|
+
|
|
1979
|
+
// Initialize activities page size selector
|
|
1980
|
+
initActivitiesPageSize();
|
|
1981
|
+
|
|
1982
|
+
// Initialize property statistics searching
|
|
1983
|
+
initPropertySearching();
|
|
1984
|
+
initPropertyKindFilter();
|
|
1985
|
+
|
|
1986
|
+
// Initialize pagination for Property tables
|
|
1987
|
+
initPagination('property-stats-container', 'property-stat-row', 'stats-pagination', 'stats-page-size');
|
|
1988
|
+
|
|
1989
|
+
// Initialize sorting for Property Checking Statistics
|
|
1990
|
+
initSorting();
|
|
1991
|
+
|
|
1992
|
+
// Initialize property source mapping searching and pagination
|
|
1993
|
+
initPropertySourceSearching();
|
|
1994
|
+
initPropertySourceKindFilter();
|
|
1995
|
+
initPagination('property-source-container', 'property-source-row', 'source-pagination', 'source-page-size');
|
|
1996
|
+
|
|
1997
|
+
// Initialize source directories expand/collapse functionality
|
|
1998
|
+
initSourceDirsToggle();
|
|
1999
|
+
|
|
2000
|
+
// Initialize crash events functionality (only if crash analysis section exists)
|
|
2001
|
+
setTimeout(function() {
|
|
2002
|
+
const crashContainer = document.getElementById('crash-events-container');
|
|
2003
|
+
if (crashContainer) {
|
|
2004
|
+
initCrashAnalysis();
|
|
2005
|
+
// Pagination will be set up automatically by initEventFiltering
|
|
2006
|
+
}
|
|
2007
|
+
}, 100);
|
|
2008
|
+
|
|
2009
|
+
function setupCrashEventsPagination() {
|
|
2010
|
+
const container = document.getElementById('crash-events-container');
|
|
2011
|
+
const paginationElement = document.getElementById('events-pagination');
|
|
2012
|
+
const pageSizeSelect = document.getElementById('events-page-size');
|
|
2013
|
+
|
|
2014
|
+
if (!container || !paginationElement || !pageSizeSelect) {
|
|
2015
|
+
return;
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
const allEventRows = Array.from(container.querySelectorAll('.event-row'));
|
|
2019
|
+
|
|
2020
|
+
// Get currently filtered visible rows (those not hidden by filter)
|
|
2021
|
+
const filteredRows = allEventRows.filter(row => {
|
|
2022
|
+
// Check if row should be visible based on current filter
|
|
2023
|
+
const eventType = row.dataset.type;
|
|
2024
|
+
const currentFilter = getCurrentFilter();
|
|
2025
|
+
|
|
2026
|
+
switch(currentFilter) {
|
|
2027
|
+
case 'all-events':
|
|
2028
|
+
return true;
|
|
2029
|
+
case 'crashes-only':
|
|
2030
|
+
return eventType === 'crash';
|
|
2031
|
+
case 'anr-only':
|
|
2032
|
+
return eventType === 'anr';
|
|
2033
|
+
default:
|
|
2034
|
+
return true;
|
|
2035
|
+
}
|
|
2036
|
+
});
|
|
2037
|
+
|
|
2038
|
+
const pageSize = parseInt(pageSizeSelect.value) || 10;
|
|
2039
|
+
const totalPages = Math.ceil(filteredRows.length / pageSize);
|
|
2040
|
+
|
|
2041
|
+
// Clear pagination first
|
|
2042
|
+
paginationElement.innerHTML = '';
|
|
2043
|
+
|
|
2044
|
+
// Show/hide pagination container based on whether pagination is needed
|
|
2045
|
+
const paginationContainer = paginationElement.closest('.pagination-container');
|
|
2046
|
+
if (paginationContainer) {
|
|
2047
|
+
if (totalPages > 1) {
|
|
2048
|
+
paginationContainer.style.display = '';
|
|
2049
|
+
} else {
|
|
2050
|
+
paginationContainer.style.display = 'none';
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
// Hide all rows first
|
|
2055
|
+
allEventRows.forEach(row => {
|
|
2056
|
+
row.style.display = 'none';
|
|
2057
|
+
const detailRow = row.nextElementSibling;
|
|
2058
|
+
if (detailRow && detailRow.classList.contains('collapse')) {
|
|
2059
|
+
detailRow.style.display = 'none';
|
|
2060
|
+
}
|
|
2061
|
+
});
|
|
2062
|
+
|
|
2063
|
+
// Show only the first page of filtered rows
|
|
2064
|
+
for (let i = 0; i < Math.min(pageSize, filteredRows.length); i++) {
|
|
2065
|
+
const row = filteredRows[i];
|
|
2066
|
+
row.style.display = '';
|
|
2067
|
+
const detailRow = row.nextElementSibling;
|
|
2068
|
+
if (detailRow && detailRow.classList.contains('collapse')) {
|
|
2069
|
+
detailRow.style.display = '';
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
// Create pagination if needed
|
|
2074
|
+
if (totalPages > 1) {
|
|
2075
|
+
createPaginationControls(totalPages, 1);
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
function getCurrentFilter() {
|
|
2079
|
+
const filterButtons = document.querySelectorAll('input[name="event-filter"]');
|
|
2080
|
+
for (let button of filterButtons) {
|
|
2081
|
+
if (button.checked) {
|
|
2082
|
+
return button.id;
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
return 'all-events'; // default
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
function createPaginationControls(totalPages, currentPage) {
|
|
2089
|
+
paginationElement.innerHTML = '';
|
|
2090
|
+
|
|
2091
|
+
// Previous button
|
|
2092
|
+
const prevLi = document.createElement('li');
|
|
2093
|
+
prevLi.className = 'page-item' + (currentPage === 1 ? ' disabled' : '');
|
|
2094
|
+
prevLi.innerHTML = '<a class="page-link" href="#" aria-label="Previous"><span aria-hidden="true">«</span></a>';
|
|
2095
|
+
prevLi.addEventListener('click', function(e) {
|
|
2096
|
+
e.preventDefault();
|
|
2097
|
+
if (currentPage > 1) {
|
|
2098
|
+
showCrashEventsPage(currentPage - 1, totalPages);
|
|
2099
|
+
}
|
|
2100
|
+
});
|
|
2101
|
+
paginationElement.appendChild(prevLi);
|
|
2102
|
+
|
|
2103
|
+
// Page numbers
|
|
2104
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
2105
|
+
const pageLi = document.createElement('li');
|
|
2106
|
+
pageLi.className = i === currentPage ? 'page-item active' : 'page-item';
|
|
2107
|
+
pageLi.innerHTML = `<a class="page-link" href="#">${i}</a>`;
|
|
2108
|
+
pageLi.addEventListener('click', function(e) {
|
|
2109
|
+
e.preventDefault();
|
|
2110
|
+
showCrashEventsPage(i, totalPages);
|
|
2111
|
+
});
|
|
2112
|
+
paginationElement.appendChild(pageLi);
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
// Next button
|
|
2116
|
+
const nextLi = document.createElement('li');
|
|
2117
|
+
nextLi.className = 'page-item' + (currentPage === totalPages ? ' disabled' : '');
|
|
2118
|
+
nextLi.innerHTML = '<a class="page-link" href="#" aria-label="Next"><span aria-hidden="true">»</span></a>';
|
|
2119
|
+
nextLi.addEventListener('click', function(e) {
|
|
2120
|
+
e.preventDefault();
|
|
2121
|
+
if (currentPage < totalPages) {
|
|
2122
|
+
showCrashEventsPage(currentPage + 1, totalPages);
|
|
2123
|
+
}
|
|
2124
|
+
});
|
|
2125
|
+
paginationElement.appendChild(nextLi);
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
function showCrashEventsPage(pageNum, totalPages) {
|
|
2129
|
+
// Get current page size
|
|
2130
|
+
const currentPageSize = parseInt(pageSizeSelect.value) || 10;
|
|
2131
|
+
|
|
2132
|
+
// Recalculate filtered rows based on current filter
|
|
2133
|
+
const currentFilteredRows = allEventRows.filter(row => {
|
|
2134
|
+
const eventType = row.dataset.type;
|
|
2135
|
+
const currentFilter = getCurrentFilter();
|
|
2136
|
+
|
|
2137
|
+
switch(currentFilter) {
|
|
2138
|
+
case 'all-events':
|
|
2139
|
+
return true;
|
|
2140
|
+
case 'crashes-only':
|
|
2141
|
+
return eventType === 'crash';
|
|
2142
|
+
case 'anr-only':
|
|
2143
|
+
return eventType === 'anr';
|
|
2144
|
+
default:
|
|
2145
|
+
return true;
|
|
2146
|
+
}
|
|
2147
|
+
});
|
|
2148
|
+
|
|
2149
|
+
const startIndex = (pageNum - 1) * currentPageSize;
|
|
2150
|
+
const endIndex = startIndex + currentPageSize;
|
|
2151
|
+
|
|
2152
|
+
// Hide all rows first
|
|
2153
|
+
allEventRows.forEach(row => {
|
|
2154
|
+
row.style.display = 'none';
|
|
2155
|
+
const detailRow = row.nextElementSibling;
|
|
2156
|
+
if (detailRow && detailRow.classList.contains('collapse')) {
|
|
2157
|
+
detailRow.style.display = 'none';
|
|
2158
|
+
}
|
|
2159
|
+
});
|
|
2160
|
+
|
|
2161
|
+
// Show only the rows for current page
|
|
2162
|
+
for (let i = startIndex; i < endIndex && i < currentFilteredRows.length; i++) {
|
|
2163
|
+
const row = currentFilteredRows[i];
|
|
2164
|
+
row.style.display = '';
|
|
2165
|
+
const detailRow = row.nextElementSibling;
|
|
2166
|
+
if (detailRow && detailRow.classList.contains('collapse')) {
|
|
2167
|
+
detailRow.style.display = '';
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
// Update pagination controls and container visibility
|
|
2172
|
+
const paginationContainer = paginationElement.closest('.pagination-container');
|
|
2173
|
+
if (paginationContainer) {
|
|
2174
|
+
if (totalPages > 1) {
|
|
2175
|
+
paginationContainer.style.display = '';
|
|
2176
|
+
createPaginationControls(totalPages, pageNum);
|
|
2177
|
+
} else {
|
|
2178
|
+
paginationContainer.style.display = 'none';
|
|
2179
|
+
paginationElement.innerHTML = '';
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
// Activity sorting function
|
|
2186
|
+
function initActivitySorting() {
|
|
2187
|
+
const sortButtons = document.querySelectorAll('.activity-sort-btn');
|
|
2188
|
+
|
|
2189
|
+
sortButtons.forEach(function(button) {
|
|
2190
|
+
button.addEventListener('click', function() {
|
|
2191
|
+
const sortType = this.dataset.sort;
|
|
2192
|
+
const currentOrder = this.dataset.order;
|
|
2193
|
+
const parentTab = this.closest('.tab-pane');
|
|
2194
|
+
const isTestedTab = parentTab.id === 'tested-activities';
|
|
2195
|
+
|
|
2196
|
+
// Toggle sort order
|
|
2197
|
+
const newOrder = currentOrder === 'asc' ? 'desc' : 'asc';
|
|
2198
|
+
|
|
2199
|
+
this.dataset.order = newOrder;
|
|
2200
|
+
const icon = this.querySelector('.sort-icon');
|
|
2201
|
+
|
|
2202
|
+
if (newOrder === 'asc') {
|
|
2203
|
+
icon.className = 'bi bi-arrow-up sort-icon btn-arrow';
|
|
2204
|
+
} else {
|
|
2205
|
+
icon.className = 'bi bi-arrow-down sort-icon btn-arrow';
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
// Sort activities
|
|
2209
|
+
sortActivities(sortType, newOrder, isTestedTab);
|
|
2210
|
+
});
|
|
2211
|
+
});
|
|
2212
|
+
|
|
2213
|
+
function sortActivities(sortType, order, isTestedTab) {
|
|
2214
|
+
const containerId = isTestedTab ? 'tested-activities-container' : 'all-activities-container';
|
|
2215
|
+
const itemClass = isTestedTab ? 'tested-activity' : 'all-activity';
|
|
2216
|
+
const paginationId = isTestedTab ? 'tested-pagination' : 'all-pagination';
|
|
2217
|
+
const pageSizeSelectId = isTestedTab ? 'tested-page-size' : 'all-page-size';
|
|
2218
|
+
|
|
2219
|
+
const container = document.getElementById(containerId);
|
|
2220
|
+
const items = Array.from(container.getElementsByClassName(itemClass));
|
|
2221
|
+
|
|
2222
|
+
// Check if there's an active search
|
|
2223
|
+
const searchInputId = isTestedTab ? 'tested-activity-search' : 'all-activity-search';
|
|
2224
|
+
const searchInput = document.getElementById(searchInputId);
|
|
2225
|
+
const hasActiveSearch = searchInput && searchInput.value.trim() !== '';
|
|
2226
|
+
const searchTerm = hasActiveSearch ? searchInput.value.toLowerCase().trim() : '';
|
|
2227
|
+
|
|
2228
|
+
// Store current search visibility state before sorting
|
|
2229
|
+
const searchStates = new Map();
|
|
2230
|
+
if (hasActiveSearch) {
|
|
2231
|
+
items.forEach(function(item) {
|
|
2232
|
+
const searchVisible = item.getAttribute('data-search-visible');
|
|
2233
|
+
searchStates.set(item, searchVisible);
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
// Sort all items
|
|
2238
|
+
items.sort(function(a, b) {
|
|
2239
|
+
const badgeA = a.querySelector('.traversal-badge');
|
|
2240
|
+
const badgeB = b.querySelector('.traversal-badge');
|
|
2241
|
+
|
|
2242
|
+
// Extract traversal count from badge text like " 5 times"
|
|
2243
|
+
const valueA = badgeA ? parseInt(badgeA.textContent.match(/\d+/)[0]) || 0 : 0;
|
|
2244
|
+
const valueB = badgeB ? parseInt(badgeB.textContent.match(/\d+/)[0]) || 0 : 0;
|
|
2245
|
+
|
|
2246
|
+
if (order === 'asc') {
|
|
2247
|
+
return valueA - valueB;
|
|
2248
|
+
} else {
|
|
2249
|
+
return valueB - valueA;
|
|
2250
|
+
}
|
|
2251
|
+
});
|
|
2252
|
+
|
|
2253
|
+
// Clear container and append sorted items
|
|
2254
|
+
container.innerHTML = '';
|
|
2255
|
+
items.forEach(function(item) {
|
|
2256
|
+
container.appendChild(item);
|
|
2257
|
+
});
|
|
2258
|
+
|
|
2259
|
+
// Restore search state and apply filtering
|
|
2260
|
+
if (hasActiveSearch) {
|
|
2261
|
+
let visibleCount = 0;
|
|
2262
|
+
items.forEach(function(item) {
|
|
2263
|
+
const activityNameElement = item.querySelector('.activity-name');
|
|
2264
|
+
if (activityNameElement) {
|
|
2265
|
+
const activityName = activityNameElement.textContent.toLowerCase();
|
|
2266
|
+
|
|
2267
|
+
if (activityName.includes(searchTerm)) {
|
|
2268
|
+
item.setAttribute('data-search-visible', 'true');
|
|
2269
|
+
visibleCount++;
|
|
2270
|
+
} else {
|
|
2271
|
+
item.setAttribute('data-search-visible', 'false');
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
});
|
|
2275
|
+
|
|
2276
|
+
// Update search results count
|
|
2277
|
+
const resultsElement = document.getElementById(searchInput.id.replace('-search', '-search-results'));
|
|
2278
|
+
if (resultsElement) {
|
|
2279
|
+
resultsElement.textContent = `Found ${visibleCount} of ${items.length} activities`;
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
// Re-initialize pagination with filtered results
|
|
2283
|
+
initPagination(containerId, itemClass, paginationId, pageSizeSelectId);
|
|
2284
|
+
} else {
|
|
2285
|
+
// No active search, just re-initialize pagination
|
|
2286
|
+
initPagination(containerId, itemClass, paginationId, pageSizeSelectId);
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
// Simplified sorting function for Fails and Errors columns
|
|
2292
|
+
function initSorting() {
|
|
2293
|
+
// Exclude activities sort icons to avoid conflicts
|
|
2294
|
+
const sortIcons = document.querySelectorAll('.sort-icon:not(.activities-sort-icon)');
|
|
2295
|
+
|
|
2296
|
+
console.log('initSorting: Found', sortIcons.length, 'sort icons (excluding activities)');
|
|
2297
|
+
|
|
2298
|
+
sortIcons.forEach(function(icon) {
|
|
2299
|
+
icon.addEventListener('click', function() {
|
|
2300
|
+
const column = this.dataset.column;
|
|
2301
|
+
const currentOrder = this.dataset.order;
|
|
2302
|
+
|
|
2303
|
+
// Reset all other sort icons
|
|
2304
|
+
sortIcons.forEach(function(otherIcon) {
|
|
2305
|
+
if (otherIcon !== icon) {
|
|
2306
|
+
otherIcon.dataset.order = 'none';
|
|
2307
|
+
otherIcon.className = 'bi bi-arrow-down-up sort-icon';
|
|
2308
|
+
otherIcon.style.color = '#6c757d';
|
|
2309
|
+
}
|
|
2310
|
+
});
|
|
2311
|
+
|
|
2312
|
+
// Toggle current sort order
|
|
2313
|
+
let newOrder;
|
|
2314
|
+
if (currentOrder === 'none' || currentOrder === 'desc') {
|
|
2315
|
+
newOrder = 'asc';
|
|
2316
|
+
this.className = 'bi bi-arrow-up sort-icon active asc';
|
|
2317
|
+
this.style.color = '#28a745';
|
|
2318
|
+
} else {
|
|
2319
|
+
newOrder = 'desc';
|
|
2320
|
+
this.className = 'bi bi-arrow-down sort-icon active desc';
|
|
2321
|
+
this.style.color = '#dc3545';
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
this.dataset.order = newOrder;
|
|
2325
|
+
sortTable(column, newOrder);
|
|
2326
|
+
});
|
|
2327
|
+
});
|
|
2328
|
+
|
|
2329
|
+
function sortTable(column, order) {
|
|
2330
|
+
const container = document.getElementById('property-stats-container');
|
|
2331
|
+
const rows = Array.from(container.getElementsByClassName('property-stat-row'));
|
|
2332
|
+
|
|
2333
|
+
rows.sort(function(a, b) {
|
|
2334
|
+
let valueA, valueB;
|
|
2335
|
+
|
|
2336
|
+
if (column === 'fails') {
|
|
2337
|
+
valueA = parseInt(a.dataset.fails);
|
|
2338
|
+
valueB = parseInt(b.dataset.fails);
|
|
2339
|
+
} else if (column === 'errors') {
|
|
2340
|
+
valueA = parseInt(a.dataset.errors);
|
|
2341
|
+
valueB = parseInt(b.dataset.errors);
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
if (order === 'asc') {
|
|
2345
|
+
return valueA - valueB;
|
|
2346
|
+
} else {
|
|
2347
|
+
return valueB - valueA;
|
|
2348
|
+
}
|
|
2349
|
+
});
|
|
2350
|
+
|
|
2351
|
+
// Clear container and append sorted rows
|
|
2352
|
+
container.innerHTML = '';
|
|
2353
|
+
rows.forEach(function(row) {
|
|
2354
|
+
container.appendChild(row);
|
|
2355
|
+
});
|
|
2356
|
+
|
|
2357
|
+
// Re-initialize pagination after sorting
|
|
2358
|
+
initPagination('property-stats-container', 'property-stat-row', 'stats-pagination', 'stats-page-size');
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
|
|
2362
|
+
// Function to handle page navigation
|
|
2363
|
+
function goToPage(pageNumber, containerId, itemClass, itemsPerPage, paginationId) {
|
|
2364
|
+
const container = document.getElementById(containerId);
|
|
2365
|
+
const allItems = Array.from(container.getElementsByClassName(itemClass));
|
|
2366
|
+
const paginationElement = document.getElementById(paginationId);
|
|
2367
|
+
|
|
2368
|
+
// Get items that should be visible based on search filter
|
|
2369
|
+
const filteredItems = allItems.filter(item => {
|
|
2370
|
+
const searchVisible = item.getAttribute('data-search-visible');
|
|
2371
|
+
const kindVisible = item.getAttribute('data-kind-visible');
|
|
2372
|
+
const shouldShow = (searchVisible === null || searchVisible === 'true') &&
|
|
2373
|
+
(kindVisible === null || kindVisible === 'true');
|
|
2374
|
+
return shouldShow;
|
|
2375
|
+
});
|
|
2376
|
+
|
|
2377
|
+
// Update pagination active state
|
|
2378
|
+
if (paginationElement) {
|
|
2379
|
+
const pageItems = paginationElement.getElementsByClassName('page-item');
|
|
2380
|
+
const totalPages = Math.max(1, Math.ceil(filteredItems.length / itemsPerPage));
|
|
2381
|
+
|
|
2382
|
+
for (let i = 0; i < pageItems.length; i++) {
|
|
2383
|
+
const pageText = pageItems[i].textContent.trim();
|
|
2384
|
+
if (pageText === pageNumber.toString()) {
|
|
2385
|
+
pageItems[i].className = 'page-item active';
|
|
2386
|
+
} else if (pageText !== '«' && pageText !== '»') {
|
|
2387
|
+
pageItems[i].className = 'page-item';
|
|
2388
|
+
} else if (pageText === '«') {
|
|
2389
|
+
// Previous button
|
|
2390
|
+
pageItems[i].className = pageNumber <= 1 ? 'page-item disabled' : 'page-item';
|
|
2391
|
+
} else if (pageText === '»') {
|
|
2392
|
+
// Next button
|
|
2393
|
+
pageItems[i].className = pageNumber >= totalPages ? 'page-item disabled' : 'page-item';
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
// Hide all items first
|
|
2399
|
+
allItems.forEach((item, index) => {
|
|
2400
|
+
item.style.display = 'none';
|
|
2401
|
+
});
|
|
2402
|
+
|
|
2403
|
+
// Show items for current page (only from filtered items)
|
|
2404
|
+
const startIndex = (pageNumber - 1) * itemsPerPage;
|
|
2405
|
+
const endIndex = Math.min(startIndex + itemsPerPage, filteredItems.length);
|
|
2406
|
+
|
|
2407
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
2408
|
+
if (filteredItems[i]) {
|
|
2409
|
+
filteredItems[i].style.display = '';
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
// Pagination initialization function
|
|
2415
|
+
function initPagination(containerId, itemClass, paginationId, pageSizeSelectId) {
|
|
2416
|
+
const container = document.getElementById(containerId);
|
|
2417
|
+
const pageSizeSelect = document.getElementById(pageSizeSelectId);
|
|
2418
|
+
if (!container) return;
|
|
2419
|
+
|
|
2420
|
+
// Remove existing event listener to prevent duplicate bindings
|
|
2421
|
+
if (pageSizeSelect && !pageSizeSelect.hasAttribute('data-listener-bound')) {
|
|
2422
|
+
pageSizeSelect.addEventListener('change', function() {
|
|
2423
|
+
const newItemsPerPage = parseInt(this.value);
|
|
2424
|
+
renderPagination();
|
|
2425
|
+
goToPage(1, containerId, itemClass, newItemsPerPage, paginationId);
|
|
2426
|
+
});
|
|
2427
|
+
// Mark as having listener bound
|
|
2428
|
+
pageSizeSelect.setAttribute('data-listener-bound', 'true');
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
function renderPagination() {
|
|
2432
|
+
const allItems = Array.from(container.getElementsByClassName(itemClass));
|
|
2433
|
+
|
|
2434
|
+
// Always get current page size from select element
|
|
2435
|
+
const currentPageSizeSelect = document.getElementById(pageSizeSelectId);
|
|
2436
|
+
const currentItemsPerPage = currentPageSizeSelect ? parseInt(currentPageSizeSelect.value) : 10;
|
|
2437
|
+
|
|
2438
|
+
// Use same filtering logic as goToPage function
|
|
2439
|
+
const filteredItems = allItems.filter(item => {
|
|
2440
|
+
const searchVisible = item.getAttribute('data-search-visible');
|
|
2441
|
+
const kindVisible = item.getAttribute('data-kind-visible');
|
|
2442
|
+
// If no filters are applied, show all items
|
|
2443
|
+
return (searchVisible === null || searchVisible === 'true') &&
|
|
2444
|
+
(kindVisible === null || kindVisible === 'true');
|
|
2445
|
+
});
|
|
2446
|
+
|
|
2447
|
+
const totalItems = filteredItems.length;
|
|
2448
|
+
const totalPages = Math.max(1, Math.ceil(totalItems / currentItemsPerPage));
|
|
2449
|
+
|
|
2450
|
+
// Create pagination
|
|
2451
|
+
const paginationElement = document.getElementById(paginationId);
|
|
2452
|
+
if (!paginationElement) return;
|
|
2453
|
+
|
|
2454
|
+
// Clear pagination
|
|
2455
|
+
paginationElement.innerHTML = '';
|
|
2456
|
+
|
|
2457
|
+
// Don't show pagination if there's only one page or no items
|
|
2458
|
+
if (totalPages <= 1) {
|
|
2459
|
+
// Hide the entire pagination container when not needed
|
|
2460
|
+
const paginationContainer = paginationElement.closest('.pagination-container');
|
|
2461
|
+
if (paginationContainer) {
|
|
2462
|
+
paginationContainer.style.display = 'none';
|
|
2463
|
+
}
|
|
2464
|
+
return;
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
// Show the pagination container when needed
|
|
2468
|
+
const paginationContainer = paginationElement.closest('.pagination-container');
|
|
2469
|
+
if (paginationContainer) {
|
|
2470
|
+
paginationContainer.style.display = '';
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
// Previous button
|
|
2474
|
+
const prevLi = document.createElement('li');
|
|
2475
|
+
prevLi.className = 'page-item disabled';
|
|
2476
|
+
prevLi.innerHTML = '<a class="page-link" href="#" aria-label="Previous"><span aria-hidden="true">«</span></a>';
|
|
2477
|
+
prevLi.addEventListener('click', function(e) {
|
|
2478
|
+
e.preventDefault();
|
|
2479
|
+
const activePage = paginationElement.querySelector('.page-item.active');
|
|
2480
|
+
if (activePage) {
|
|
2481
|
+
const currentPageNum = parseInt(activePage.textContent.trim());
|
|
2482
|
+
if (currentPageNum > 1) {
|
|
2483
|
+
goToPage(currentPageNum - 1, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
});
|
|
2487
|
+
paginationElement.appendChild(prevLi);
|
|
2488
|
+
|
|
2489
|
+
// Add page numbers
|
|
2490
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
2491
|
+
const pageLi = document.createElement('li');
|
|
2492
|
+
pageLi.className = i === 1 ? 'page-item active' : 'page-item';
|
|
2493
|
+
pageLi.innerHTML = `<a class="page-link" href="#">${i}</a>`;
|
|
2494
|
+
pageLi.addEventListener('click', function(e) {
|
|
2495
|
+
e.preventDefault();
|
|
2496
|
+
goToPage(i, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
2497
|
+
});
|
|
2498
|
+
paginationElement.appendChild(pageLi);
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
// Next button
|
|
2502
|
+
const nextLi = document.createElement('li');
|
|
2503
|
+
nextLi.className = totalPages <= 1 ? 'page-item disabled' : 'page-item';
|
|
2504
|
+
nextLi.innerHTML = '<a class="page-link" href="#" aria-label="Next"><span aria-hidden="true">»</span></a>';
|
|
2505
|
+
nextLi.addEventListener('click', function(e) {
|
|
2506
|
+
e.preventDefault();
|
|
2507
|
+
const activePage = paginationElement.querySelector('.page-item.active');
|
|
2508
|
+
if (activePage) {
|
|
2509
|
+
const currentPageNum = parseInt(activePage.textContent.trim());
|
|
2510
|
+
if (currentPageNum < totalPages) {
|
|
2511
|
+
goToPage(currentPageNum + 1, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
});
|
|
2515
|
+
paginationElement.appendChild(nextLi);
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
// Initial render
|
|
2519
|
+
renderPagination();
|
|
2520
|
+
// Always call goToPage to ensure items are displayed correctly, even if no pagination is shown
|
|
2521
|
+
const currentItemsPerPage = pageSizeSelect ? parseInt(pageSizeSelect.value) : 10;
|
|
2522
|
+
goToPage(1, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
// Activity searching function
|
|
2526
|
+
function initActivitySearching() {
|
|
2527
|
+
const searchInputs = document.querySelectorAll('.activity-search-input');
|
|
2528
|
+
|
|
2529
|
+
searchInputs.forEach(function(searchInput) {
|
|
2530
|
+
const searchButton = document.querySelector('.search-btn[data-target="' + searchInput.id + '"]');
|
|
2531
|
+
const clearButton = document.querySelector('[data-target="' + searchInput.id + '"].search-clear-btn');
|
|
2532
|
+
|
|
2533
|
+
// Search on Enter key
|
|
2534
|
+
searchInput.addEventListener('keydown', function(e) {
|
|
2535
|
+
if (e.key === 'Enter') {
|
|
2536
|
+
e.preventDefault();
|
|
2537
|
+
performActivitySearch(this);
|
|
2538
|
+
} else if (e.key === 'Escape') {
|
|
2539
|
+
clearActivitySearch(this);
|
|
2540
|
+
}
|
|
2541
|
+
});
|
|
2542
|
+
|
|
2543
|
+
// Search button functionality
|
|
2544
|
+
if (searchButton) {
|
|
2545
|
+
searchButton.addEventListener('click', function() {
|
|
2546
|
+
performActivitySearch(searchInput);
|
|
2547
|
+
});
|
|
2548
|
+
}
|
|
2549
|
+
|
|
2550
|
+
// Clear button functionality
|
|
2551
|
+
if (clearButton) {
|
|
2552
|
+
clearButton.addEventListener('click', function() {
|
|
2553
|
+
clearActivitySearch(searchInput);
|
|
2554
|
+
});
|
|
2555
|
+
}
|
|
2556
|
+
});
|
|
2557
|
+
|
|
2558
|
+
function performActivitySearch(searchInput) {
|
|
2559
|
+
const searchTerm = searchInput.value.toLowerCase().trim();
|
|
2560
|
+
const containerId = searchInput.dataset.target;
|
|
2561
|
+
const itemClass = searchInput.dataset.itemClass;
|
|
2562
|
+
const paginationId = searchInput.dataset.pagination;
|
|
2563
|
+
const pageSizeSelectId = searchInput.dataset.pageSize;
|
|
2564
|
+
|
|
2565
|
+
const container = document.getElementById(containerId);
|
|
2566
|
+
const items = Array.from(container.getElementsByClassName(itemClass));
|
|
2567
|
+
|
|
2568
|
+
let visibleCount = 0;
|
|
2569
|
+
let totalCount = items.length;
|
|
2570
|
+
|
|
2571
|
+
// Filter items based on search term
|
|
2572
|
+
items.forEach(function(item) {
|
|
2573
|
+
const activityNameElement = item.querySelector('.activity-name');
|
|
2574
|
+
if (activityNameElement) {
|
|
2575
|
+
const activityName = activityNameElement.textContent.toLowerCase();
|
|
2576
|
+
|
|
2577
|
+
if (searchTerm === '' || activityName.includes(searchTerm)) {
|
|
2578
|
+
item.setAttribute('data-search-visible', 'true');
|
|
2579
|
+
visibleCount++;
|
|
2580
|
+
} else {
|
|
2581
|
+
item.setAttribute('data-search-visible', 'false');
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
});
|
|
2585
|
+
|
|
2586
|
+
// Update search results count
|
|
2587
|
+
const resultsElement = document.getElementById(searchInput.id.replace('-search', '-search-results'));
|
|
2588
|
+
if (resultsElement) {
|
|
2589
|
+
if (searchTerm === '') {
|
|
2590
|
+
resultsElement.textContent = '';
|
|
2591
|
+
} else {
|
|
2592
|
+
resultsElement.textContent = `Found ${visibleCount} of ${totalCount} activities`;
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
|
|
2596
|
+
// Re-initialize pagination with filtered results
|
|
2597
|
+
initPagination(containerId, itemClass, paginationId, pageSizeSelectId);
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2600
|
+
function clearActivitySearch(searchInput) {
|
|
2601
|
+
searchInput.value = '';
|
|
2602
|
+
performActivitySearch(searchInput);
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
function getCurrentPropertyKindFilter() {
|
|
2607
|
+
const selected = document.querySelector('input[name="property-kind-filter"]:checked');
|
|
2608
|
+
if (!selected) {
|
|
2609
|
+
return 'all';
|
|
2610
|
+
}
|
|
2611
|
+
if (selected.id === 'property-kind-property') {
|
|
2612
|
+
return 'property';
|
|
2613
|
+
}
|
|
2614
|
+
if (selected.id === 'property-kind-invariant') {
|
|
2615
|
+
return 'invariant';
|
|
2616
|
+
}
|
|
2617
|
+
return 'all';
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
function updatePropertySearchResults(visibleCount, totalCount, searchTerm) {
|
|
2621
|
+
const resultsElement = document.getElementById('property-search-results');
|
|
2622
|
+
if (resultsElement) {
|
|
2623
|
+
if (searchTerm === '') {
|
|
2624
|
+
resultsElement.textContent = '';
|
|
2625
|
+
} else {
|
|
2626
|
+
resultsElement.textContent = `Found ${visibleCount} of ${totalCount} properties`;
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2631
|
+
function updatePropertyHeaderSummary(summary) {
|
|
2632
|
+
const totalEl = document.getElementById('property-stats-total-properties');
|
|
2633
|
+
if (totalEl) {
|
|
2634
|
+
totalEl.textContent = summary.total;
|
|
2635
|
+
}
|
|
2636
|
+
const precondEl = document.getElementById('property-stats-total-precond');
|
|
2637
|
+
if (precondEl) {
|
|
2638
|
+
precondEl.textContent = summary.precond;
|
|
2639
|
+
}
|
|
2640
|
+
const executedEl = document.getElementById('property-stats-total-executed');
|
|
2641
|
+
if (executedEl) {
|
|
2642
|
+
executedEl.textContent = summary.executed;
|
|
2643
|
+
}
|
|
2644
|
+
const passEl = document.getElementById('property-stats-total-pass');
|
|
2645
|
+
if (passEl) {
|
|
2646
|
+
passEl.textContent = summary.pass;
|
|
2647
|
+
}
|
|
2648
|
+
const failEl = document.getElementById('property-stats-total-fail');
|
|
2649
|
+
if (failEl) {
|
|
2650
|
+
failEl.textContent = summary.fail;
|
|
2651
|
+
}
|
|
2652
|
+
const errorEl = document.getElementById('property-stats-total-error');
|
|
2653
|
+
if (errorEl) {
|
|
2654
|
+
errorEl.textContent = summary.error;
|
|
2655
|
+
}
|
|
2656
|
+
const skippedEl = document.getElementById('property-stats-total-skipped');
|
|
2657
|
+
if (skippedEl) {
|
|
2658
|
+
skippedEl.textContent = summary.skipped;
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
function applyPropertyFilters() {
|
|
2663
|
+
const searchInput = document.getElementById('property-stats-search');
|
|
2664
|
+
const rawSearchTerm = searchInput ? searchInput.value.trim() : '';
|
|
2665
|
+
const searchTerm = rawSearchTerm.toLowerCase();
|
|
2666
|
+
const container = document.getElementById('property-stats-container');
|
|
2667
|
+
if (!container) {
|
|
2668
|
+
return;
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
const items = Array.from(container.getElementsByClassName('property-stat-row'));
|
|
2672
|
+
const kindFilter = getCurrentPropertyKindFilter();
|
|
2673
|
+
let visibleCount = 0;
|
|
2674
|
+
let totalCount = 0;
|
|
2675
|
+
const summary = {
|
|
2676
|
+
total: 0,
|
|
2677
|
+
precond: 0,
|
|
2678
|
+
executed: 0,
|
|
2679
|
+
pass: 0,
|
|
2680
|
+
fail: 0,
|
|
2681
|
+
error: 0,
|
|
2682
|
+
skipped: 0,
|
|
2683
|
+
};
|
|
2684
|
+
|
|
2685
|
+
items.forEach(function(item) {
|
|
2686
|
+
const rowKind = (item.dataset.kind || 'unknown').toLowerCase();
|
|
2687
|
+
const kindMatches = kindFilter === 'all' || rowKind === kindFilter;
|
|
2688
|
+
item.setAttribute('data-kind-visible', kindMatches ? 'true' : 'false');
|
|
2689
|
+
if (kindMatches) {
|
|
2690
|
+
totalCount += 1;
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2693
|
+
const propertyNameElement = item.querySelector('.badge-custom');
|
|
2694
|
+
const propertyName = propertyNameElement ? propertyNameElement.textContent.toLowerCase() : '';
|
|
2695
|
+
const searchMatches = searchTerm === '' || propertyName.includes(searchTerm);
|
|
2696
|
+
item.setAttribute('data-search-visible', searchMatches ? 'true' : 'false');
|
|
2697
|
+
if (kindMatches && searchMatches) {
|
|
2698
|
+
visibleCount += 1;
|
|
2699
|
+
summary.total += 1;
|
|
2700
|
+
summary.precond += parseInt(item.dataset.precondSatisfied || '0', 10);
|
|
2701
|
+
summary.executed += parseInt(item.dataset.executed || '0', 10);
|
|
2702
|
+
summary.pass += parseInt(item.dataset.pass || '0', 10);
|
|
2703
|
+
summary.fail += parseInt(item.dataset.fails || '0', 10);
|
|
2704
|
+
summary.error += parseInt(item.dataset.errors || '0', 10);
|
|
2705
|
+
summary.skipped += parseInt(item.dataset.notExecuted || '0', 10);
|
|
2706
|
+
}
|
|
2707
|
+
});
|
|
2708
|
+
|
|
2709
|
+
updatePropertySearchResults(visibleCount, totalCount, rawSearchTerm);
|
|
2710
|
+
|
|
2711
|
+
const headerSummary = {
|
|
2712
|
+
total: summary.total,
|
|
2713
|
+
precond: summary.precond,
|
|
2714
|
+
executed: summary.executed,
|
|
2715
|
+
pass: summary.pass,
|
|
2716
|
+
fail: summary.fail,
|
|
2717
|
+
error: summary.error,
|
|
2718
|
+
skipped: summary.skipped,
|
|
2719
|
+
};
|
|
2720
|
+
if (kindFilter === 'invariant') {
|
|
2721
|
+
headerSummary.precond = '/';
|
|
2722
|
+
headerSummary.executed = '/';
|
|
2723
|
+
headerSummary.pass = '/';
|
|
2724
|
+
headerSummary.skipped = '/';
|
|
2725
|
+
}
|
|
2726
|
+
updatePropertyHeaderSummary(headerSummary);
|
|
2727
|
+
initPagination('property-stats-container', 'property-stat-row', 'stats-pagination', 'stats-page-size');
|
|
2728
|
+
const currentPageSize = document.getElementById('stats-page-size') ?
|
|
2729
|
+
parseInt(document.getElementById('stats-page-size').value) : 10;
|
|
2730
|
+
goToPage(1, 'property-stats-container', 'property-stat-row', currentPageSize, 'stats-pagination');
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
function initPropertyKindFilter() {
|
|
2734
|
+
const filterButtons = document.querySelectorAll('input[name="property-kind-filter"]');
|
|
2735
|
+
if (!filterButtons.length) {
|
|
2736
|
+
return;
|
|
2737
|
+
}
|
|
2738
|
+
filterButtons.forEach(function(button) {
|
|
2739
|
+
button.addEventListener('change', function() {
|
|
2740
|
+
applyPropertyFilters();
|
|
2741
|
+
});
|
|
2742
|
+
});
|
|
2743
|
+
applyPropertyFilters();
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2746
|
+
// Property statistics searching function
|
|
2747
|
+
function initPropertySearching() {
|
|
2748
|
+
const searchInput = document.getElementById('property-stats-search');
|
|
2749
|
+
const searchButton = document.querySelector('.search-btn[data-target="property-stats-search"]');
|
|
2750
|
+
const clearButton = document.querySelector('[data-target="property-stats-search"].search-clear-btn');
|
|
2751
|
+
|
|
2752
|
+
if (!searchInput) return;
|
|
2753
|
+
|
|
2754
|
+
// Search on Enter key
|
|
2755
|
+
searchInput.addEventListener('keydown', function(e) {
|
|
2756
|
+
if (e.key === 'Enter') {
|
|
2757
|
+
e.preventDefault();
|
|
2758
|
+
applyPropertyFilters();
|
|
2759
|
+
} else if (e.key === 'Escape') {
|
|
2760
|
+
searchInput.value = '';
|
|
2761
|
+
applyPropertyFilters();
|
|
2762
|
+
}
|
|
2763
|
+
});
|
|
2764
|
+
|
|
2765
|
+
// Search button functionality
|
|
2766
|
+
if (searchButton) {
|
|
2767
|
+
searchButton.addEventListener('click', function() {
|
|
2768
|
+
applyPropertyFilters();
|
|
2769
|
+
});
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
// Clear button functionality
|
|
2773
|
+
if (clearButton) {
|
|
2774
|
+
clearButton.addEventListener('click', function() {
|
|
2775
|
+
searchInput.value = '';
|
|
2776
|
+
applyPropertyFilters();
|
|
2777
|
+
});
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
|
|
2781
|
+
// Property source mapping searching function
|
|
2782
|
+
function initPropertySourceSearching() {
|
|
2783
|
+
const searchInput = document.getElementById('property-source-search');
|
|
2784
|
+
const searchButton = document.querySelector('.search-btn[data-target="property-source-search"]');
|
|
2785
|
+
const clearButton = document.querySelector('[data-target="property-source-search"].search-clear-btn');
|
|
2786
|
+
|
|
2787
|
+
if (!searchInput) return;
|
|
2788
|
+
|
|
2789
|
+
// Search on Enter key
|
|
2790
|
+
searchInput.addEventListener('keydown', function(e) {
|
|
2791
|
+
if (e.key === 'Enter') {
|
|
2792
|
+
e.preventDefault();
|
|
2793
|
+
applyPropertySourceFilters();
|
|
2794
|
+
} else if (e.key === 'Escape') {
|
|
2795
|
+
searchInput.value = '';
|
|
2796
|
+
applyPropertySourceFilters();
|
|
2797
|
+
}
|
|
2798
|
+
});
|
|
2799
|
+
|
|
2800
|
+
// Search button functionality
|
|
2801
|
+
if (searchButton) {
|
|
2802
|
+
searchButton.addEventListener('click', function() {
|
|
2803
|
+
applyPropertySourceFilters();
|
|
2804
|
+
});
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2807
|
+
// Clear button functionality
|
|
2808
|
+
if (clearButton) {
|
|
2809
|
+
clearButton.addEventListener('click', function() {
|
|
2810
|
+
searchInput.value = '';
|
|
2811
|
+
applyPropertySourceFilters();
|
|
2812
|
+
});
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
function getCurrentPropertySourceKindFilter() {
|
|
2817
|
+
const selected = document.querySelector('input[name="property-source-kind-filter"]:checked');
|
|
2818
|
+
if (!selected) {
|
|
2819
|
+
return 'all';
|
|
2820
|
+
}
|
|
2821
|
+
if (selected.id === 'property-source-kind-property') {
|
|
2822
|
+
return 'property';
|
|
2823
|
+
}
|
|
2824
|
+
if (selected.id === 'property-source-kind-invariant') {
|
|
2825
|
+
return 'invariant';
|
|
2826
|
+
}
|
|
2827
|
+
return 'all';
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
function updatePropertySourceSearchResults(visibleCount, totalCount, searchTerm) {
|
|
2831
|
+
const resultsElement = document.getElementById('property-source-search-results');
|
|
2832
|
+
if (resultsElement) {
|
|
2833
|
+
if (searchTerm === '') {
|
|
2834
|
+
resultsElement.textContent = '';
|
|
2835
|
+
} else {
|
|
2836
|
+
resultsElement.textContent = `Found ${visibleCount} of ${totalCount} properties`;
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
function applyPropertySourceFilters() {
|
|
2842
|
+
const searchInput = document.getElementById('property-source-search');
|
|
2843
|
+
const rawSearchTerm = searchInput ? searchInput.value.trim() : '';
|
|
2844
|
+
const searchTerm = rawSearchTerm.toLowerCase();
|
|
2845
|
+
const container = document.getElementById('property-source-container');
|
|
2846
|
+
if (!container) {
|
|
2847
|
+
return;
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
const items = Array.from(container.getElementsByClassName('property-source-row'));
|
|
2851
|
+
const kindFilter = getCurrentPropertySourceKindFilter();
|
|
2852
|
+
let visibleCount = 0;
|
|
2853
|
+
let totalCount = 0;
|
|
2854
|
+
|
|
2855
|
+
items.forEach(function(item) {
|
|
2856
|
+
const rowKind = (item.dataset.kind || 'unknown').toLowerCase();
|
|
2857
|
+
const kindMatches = kindFilter === 'all' || rowKind === kindFilter;
|
|
2858
|
+
item.setAttribute('data-kind-visible', kindMatches ? 'true' : 'false');
|
|
2859
|
+
if (kindMatches) {
|
|
2860
|
+
totalCount += 1;
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2863
|
+
const propertyNameElement = item.querySelector('.badge-custom');
|
|
2864
|
+
const propertyName = propertyNameElement ? propertyNameElement.textContent.toLowerCase() : '';
|
|
2865
|
+
const searchMatches = searchTerm === '' || propertyName.includes(searchTerm);
|
|
2866
|
+
item.setAttribute('data-search-visible', searchMatches ? 'true' : 'false');
|
|
2867
|
+
if (kindMatches && searchMatches) {
|
|
2868
|
+
visibleCount += 1;
|
|
2869
|
+
}
|
|
2870
|
+
});
|
|
2871
|
+
|
|
2872
|
+
updatePropertySourceSearchResults(visibleCount, totalCount, rawSearchTerm);
|
|
2873
|
+
initPagination('property-source-container', 'property-source-row', 'source-pagination', 'source-page-size');
|
|
2874
|
+
const currentPageSize = document.getElementById('source-page-size') ?
|
|
2875
|
+
parseInt(document.getElementById('source-page-size').value) : 10;
|
|
2876
|
+
goToPage(1, 'property-source-container', 'property-source-row', currentPageSize, 'source-pagination');
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
function initPropertySourceKindFilter() {
|
|
2880
|
+
const filterButtons = document.querySelectorAll('input[name="property-source-kind-filter"]');
|
|
2881
|
+
if (!filterButtons.length) {
|
|
2882
|
+
return;
|
|
2883
|
+
}
|
|
2884
|
+
filterButtons.forEach(function(button) {
|
|
2885
|
+
button.addEventListener('change', function() {
|
|
2886
|
+
applyPropertySourceFilters();
|
|
2887
|
+
});
|
|
2888
|
+
});
|
|
2889
|
+
applyPropertySourceFilters();
|
|
2890
|
+
}
|
|
2891
|
+
|
|
2892
|
+
// Activities table searching function
|
|
2893
|
+
function initActivitiesSearching() {
|
|
2894
|
+
const searchInput = document.getElementById('activities-search');
|
|
2895
|
+
const searchButton = document.getElementById('activities-search-btn');
|
|
2896
|
+
|
|
2897
|
+
if (!searchInput) return;
|
|
2898
|
+
|
|
2899
|
+
// Search on Enter key and clear on Escape
|
|
2900
|
+
searchInput.addEventListener('keydown', function(e) {
|
|
2901
|
+
if (e.key === 'Enter') {
|
|
2902
|
+
e.preventDefault();
|
|
2903
|
+
performActivitiesSearch(this);
|
|
2904
|
+
} else if (e.key === 'Escape') {
|
|
2905
|
+
clearActivitiesSearch(this);
|
|
2906
|
+
}
|
|
2907
|
+
});
|
|
2908
|
+
|
|
2909
|
+
// Search button functionality
|
|
2910
|
+
if (searchButton) {
|
|
2911
|
+
searchButton.addEventListener('click', function() {
|
|
2912
|
+
performActivitiesSearch(searchInput);
|
|
2913
|
+
});
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
function performActivitiesSearch(searchInput) {
|
|
2917
|
+
const searchTerm = searchInput.value.toLowerCase().trim();
|
|
2918
|
+
const container = document.getElementById('activities-container');
|
|
2919
|
+
const rows = container.querySelectorAll('.activity-row');
|
|
2920
|
+
const resultsCount = document.getElementById('activities-search-results');
|
|
2921
|
+
|
|
2922
|
+
let visibleCount = 0;
|
|
2923
|
+
|
|
2924
|
+
rows.forEach(function(row) {
|
|
2925
|
+
const activityName = row.querySelector('.activity-name').textContent.toLowerCase();
|
|
2926
|
+
|
|
2927
|
+
// If no search term, show all rows
|
|
2928
|
+
if (!searchTerm) {
|
|
2929
|
+
row.removeAttribute('data-search-visible');
|
|
2930
|
+
visibleCount++;
|
|
2931
|
+
} else {
|
|
2932
|
+
const matches = activityName.includes(searchTerm);
|
|
2933
|
+
if (matches) {
|
|
2934
|
+
row.setAttribute('data-search-visible', 'true');
|
|
2935
|
+
visibleCount++;
|
|
2936
|
+
} else {
|
|
2937
|
+
row.setAttribute('data-search-visible', 'false');
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
});
|
|
2941
|
+
|
|
2942
|
+
console.log('Search performed:', {searchTerm, visibleCount, totalRows: rows.length});
|
|
2943
|
+
|
|
2944
|
+
// Update results count
|
|
2945
|
+
if (resultsCount) {
|
|
2946
|
+
if (searchTerm) {
|
|
2947
|
+
resultsCount.textContent = `Found ${visibleCount} of ${rows.length} activities`;
|
|
2948
|
+
} else {
|
|
2949
|
+
resultsCount.textContent = '';
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
// Immediately show/hide rows based on search before pagination update
|
|
2954
|
+
rows.forEach(function(row) {
|
|
2955
|
+
const searchVisible = row.getAttribute('data-search-visible');
|
|
2956
|
+
if (searchVisible === null || searchVisible === 'true') {
|
|
2957
|
+
row.style.display = '';
|
|
2958
|
+
} else {
|
|
2959
|
+
row.style.display = 'none';
|
|
2960
|
+
}
|
|
2961
|
+
});
|
|
2962
|
+
|
|
2963
|
+
console.log('Rows visibility updated, calling pagination update...');
|
|
2964
|
+
|
|
2965
|
+
// Update pagination after search
|
|
2966
|
+
updateActivitiesPagination();
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
function clearActivitiesSearch(searchInput) {
|
|
2970
|
+
searchInput.value = '';
|
|
2971
|
+
performActivitiesSearch(searchInput);
|
|
2972
|
+
searchInput.focus();
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2976
|
+
// Activities table sorting function - Simplified version
|
|
2977
|
+
function initActivitiesSorting() {
|
|
2978
|
+
console.log('Initializing activities sorting...');
|
|
2979
|
+
|
|
2980
|
+
// Use event delegation to avoid losing event listeners
|
|
2981
|
+
document.addEventListener('click', function(e) {
|
|
2982
|
+
// Check if clicked element is the sort icon
|
|
2983
|
+
if (e.target && e.target.id === 'visit-count-sort') {
|
|
2984
|
+
e.preventDefault();
|
|
2985
|
+
e.stopPropagation();
|
|
2986
|
+
|
|
2987
|
+
console.log('=== SORT CLICK EVENT START ===');
|
|
2988
|
+
console.log('Sort icon clicked via delegation');
|
|
2989
|
+
|
|
2990
|
+
const sortIcon = e.target;
|
|
2991
|
+
const currentOrder = sortIcon.dataset.order || 'none';
|
|
2992
|
+
|
|
2993
|
+
console.log('Current order:', currentOrder);
|
|
2994
|
+
|
|
2995
|
+
// Determine new order
|
|
2996
|
+
let newOrder;
|
|
2997
|
+
if (currentOrder === 'none' || currentOrder === 'desc') {
|
|
2998
|
+
newOrder = 'asc';
|
|
2999
|
+
} else {
|
|
3000
|
+
newOrder = 'desc';
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
console.log('New order:', newOrder);
|
|
3004
|
+
|
|
3005
|
+
// Update icon appearance
|
|
3006
|
+
sortIcon.classList.remove('bi-arrow-down-up', 'bi-arrow-up', 'bi-arrow-down');
|
|
3007
|
+
sortIcon.classList.add('text-primary');
|
|
3008
|
+
if (newOrder === 'asc') {
|
|
3009
|
+
sortIcon.classList.add('bi-arrow-up');
|
|
3010
|
+
} else {
|
|
3011
|
+
sortIcon.classList.add('bi-arrow-down');
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
// Store new order
|
|
3015
|
+
sortIcon.dataset.order = newOrder;
|
|
3016
|
+
|
|
3017
|
+
// Get container and rows
|
|
3018
|
+
const container = document.getElementById('activities-container');
|
|
3019
|
+
const rows = Array.from(container.querySelectorAll('.activity-row'));
|
|
3020
|
+
|
|
3021
|
+
console.log('Found rows for sorting:', rows.length);
|
|
3022
|
+
|
|
3023
|
+
// Sort rows
|
|
3024
|
+
rows.sort((a, b) => {
|
|
3025
|
+
const aCount = parseInt(a.dataset.visitCount) || 0;
|
|
3026
|
+
const bCount = parseInt(b.dataset.visitCount) || 0;
|
|
3027
|
+
|
|
3028
|
+
if (newOrder === 'asc') {
|
|
3029
|
+
return aCount - bCount;
|
|
3030
|
+
} else {
|
|
3031
|
+
return bCount - aCount;
|
|
3032
|
+
}
|
|
3033
|
+
});
|
|
3034
|
+
|
|
3035
|
+
console.log('Rows sorted, reordering DOM');
|
|
3036
|
+
|
|
3037
|
+
// Clear container and re-append sorted rows
|
|
3038
|
+
container.innerHTML = '';
|
|
3039
|
+
rows.forEach(function(row) {
|
|
3040
|
+
container.appendChild(row);
|
|
3041
|
+
});
|
|
3042
|
+
|
|
3043
|
+
console.log('DOM reordered, updating pagination');
|
|
3044
|
+
|
|
3045
|
+
// Update pagination after sorting
|
|
3046
|
+
updateActivitiesPagination();
|
|
3047
|
+
|
|
3048
|
+
console.log('=== SORT CLICK EVENT END ===');
|
|
3049
|
+
}
|
|
3050
|
+
});
|
|
3051
|
+
|
|
3052
|
+
console.log('Activities sorting initialized with event delegation');
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
// Function to update Activities pagination after sorting
|
|
3056
|
+
function updateActivitiesPagination() {
|
|
3057
|
+
const container = document.getElementById('activities-container');
|
|
3058
|
+
const pageSizeSelect = document.getElementById('activities-page-size');
|
|
3059
|
+
const paginationElement = document.getElementById('activities-pagination');
|
|
3060
|
+
|
|
3061
|
+
if (!container || !paginationElement) return;
|
|
3062
|
+
|
|
3063
|
+
const allRows = Array.from(container.querySelectorAll('.activity-row'));
|
|
3064
|
+
const itemsPerPage = pageSizeSelect ? parseInt(pageSizeSelect.value) : 10;
|
|
3065
|
+
|
|
3066
|
+
// Filter visible rows (considering search)
|
|
3067
|
+
const visibleRows = allRows.filter(row => {
|
|
3068
|
+
const searchVisible = row.getAttribute('data-search-visible');
|
|
3069
|
+
return searchVisible === null || searchVisible === 'true';
|
|
3070
|
+
});
|
|
3071
|
+
|
|
3072
|
+
const totalItems = visibleRows.length;
|
|
3073
|
+
const totalPages = Math.max(1, Math.ceil(totalItems / itemsPerPage));
|
|
3074
|
+
|
|
3075
|
+
console.log('Updating pagination:', {totalItems, itemsPerPage, totalPages});
|
|
3076
|
+
|
|
3077
|
+
// Get pagination container
|
|
3078
|
+
const paginationContainer = paginationElement.closest('.d-flex');
|
|
3079
|
+
|
|
3080
|
+
// Don't show pagination if there's only one page or no items
|
|
3081
|
+
if (totalPages <= 1) {
|
|
3082
|
+
if (paginationContainer) {
|
|
3083
|
+
paginationContainer.style.display = 'none';
|
|
3084
|
+
}
|
|
3085
|
+
// Show visible rows and hide invisible rows
|
|
3086
|
+
allRows.forEach(row => {
|
|
3087
|
+
const searchVisible = row.getAttribute('data-search-visible');
|
|
3088
|
+
if (searchVisible === null || searchVisible === 'true') {
|
|
3089
|
+
row.style.display = '';
|
|
3090
|
+
} else {
|
|
3091
|
+
row.style.display = 'none';
|
|
3092
|
+
}
|
|
3093
|
+
});
|
|
3094
|
+
return;
|
|
3095
|
+
}
|
|
3096
|
+
|
|
3097
|
+
// Show pagination container
|
|
3098
|
+
if (paginationContainer) {
|
|
3099
|
+
paginationContainer.style.display = '';
|
|
3100
|
+
}
|
|
3101
|
+
|
|
3102
|
+
// Clear existing pagination
|
|
3103
|
+
paginationElement.innerHTML = '';
|
|
3104
|
+
|
|
3105
|
+
// Previous button
|
|
3106
|
+
const prevLi = document.createElement('li');
|
|
3107
|
+
prevLi.className = 'page-item disabled';
|
|
3108
|
+
prevLi.innerHTML = '<a class="page-link" href="#" aria-label="Previous"><span aria-hidden="true">«</span></a>';
|
|
3109
|
+
paginationElement.appendChild(prevLi);
|
|
3110
|
+
|
|
3111
|
+
// Create pagination buttons
|
|
3112
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
3113
|
+
const li = document.createElement('li');
|
|
3114
|
+
li.className = `page-item ${i === 1 ? 'active' : ''}`;
|
|
3115
|
+
|
|
3116
|
+
const a = document.createElement('a');
|
|
3117
|
+
a.className = 'page-link';
|
|
3118
|
+
a.href = '#';
|
|
3119
|
+
a.textContent = i;
|
|
3120
|
+
a.addEventListener('click', function(e) {
|
|
3121
|
+
e.preventDefault();
|
|
3122
|
+
goToActivitiesPage(i, totalPages, itemsPerPage);
|
|
3123
|
+
});
|
|
3124
|
+
|
|
3125
|
+
li.appendChild(a);
|
|
3126
|
+
paginationElement.appendChild(li);
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
// Next button
|
|
3130
|
+
const nextLi = document.createElement('li');
|
|
3131
|
+
nextLi.className = totalPages <= 1 ? 'page-item disabled' : 'page-item';
|
|
3132
|
+
nextLi.innerHTML = '<a class="page-link" href="#" aria-label="Next"><span aria-hidden="true">»</span></a>';
|
|
3133
|
+
paginationElement.appendChild(nextLi);
|
|
3134
|
+
|
|
3135
|
+
// Add event listeners to prev/next buttons
|
|
3136
|
+
const prevButton = paginationElement.firstChild;
|
|
3137
|
+
const nextButton = paginationElement.lastChild;
|
|
3138
|
+
|
|
3139
|
+
prevButton.addEventListener('click', function(e) {
|
|
3140
|
+
e.preventDefault();
|
|
3141
|
+
const activePage = paginationElement.querySelector('.page-item.active');
|
|
3142
|
+
if (activePage && activePage.previousElementSibling && activePage.previousElementSibling !== prevButton) {
|
|
3143
|
+
const pageNum = parseInt(activePage.textContent) - 1;
|
|
3144
|
+
if (pageNum >= 1) {
|
|
3145
|
+
goToActivitiesPage(pageNum, totalPages, itemsPerPage);
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
});
|
|
3149
|
+
|
|
3150
|
+
nextButton.addEventListener('click', function(e) {
|
|
3151
|
+
e.preventDefault();
|
|
3152
|
+
const activePage = paginationElement.querySelector('.page-item.active');
|
|
3153
|
+
if (activePage && activePage.nextElementSibling && activePage.nextElementSibling !== nextButton) {
|
|
3154
|
+
const pageNum = parseInt(activePage.textContent) + 1;
|
|
3155
|
+
if (pageNum <= totalPages) {
|
|
3156
|
+
goToActivitiesPage(pageNum, totalPages, itemsPerPage);
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
});
|
|
3160
|
+
|
|
3161
|
+
// Show first page
|
|
3162
|
+
goToActivitiesPage(1, totalPages, itemsPerPage);
|
|
3163
|
+
}
|
|
3164
|
+
|
|
3165
|
+
// Function to navigate to specific page
|
|
3166
|
+
function goToActivitiesPage(pageNumber, totalPages, itemsPerPage) {
|
|
3167
|
+
const container = document.getElementById('activities-container');
|
|
3168
|
+
const allRows = Array.from(container.querySelectorAll('.activity-row'));
|
|
3169
|
+
|
|
3170
|
+
// Filter visible rows (considering search)
|
|
3171
|
+
const visibleRows = allRows.filter(row => {
|
|
3172
|
+
const searchVisible = row.getAttribute('data-search-visible');
|
|
3173
|
+
return searchVisible === null || searchVisible === 'true';
|
|
3174
|
+
});
|
|
3175
|
+
|
|
3176
|
+
const startIndex = (pageNumber - 1) * itemsPerPage;
|
|
3177
|
+
const endIndex = startIndex + itemsPerPage;
|
|
3178
|
+
|
|
3179
|
+
console.log('Going to page:', {pageNumber, startIndex, endIndex, totalVisible: visibleRows.length});
|
|
3180
|
+
|
|
3181
|
+
// Hide all rows first
|
|
3182
|
+
allRows.forEach(row => {
|
|
3183
|
+
row.style.display = 'none';
|
|
3184
|
+
});
|
|
3185
|
+
|
|
3186
|
+
// Show only rows for current page
|
|
3187
|
+
visibleRows.slice(startIndex, endIndex).forEach(row => {
|
|
3188
|
+
row.style.display = '';
|
|
3189
|
+
});
|
|
3190
|
+
|
|
3191
|
+
// Update pagination active state
|
|
3192
|
+
const paginationElement = document.getElementById('activities-pagination');
|
|
3193
|
+
if (paginationElement) {
|
|
3194
|
+
const pageItems = paginationElement.querySelectorAll('.page-item');
|
|
3195
|
+
const prevButton = pageItems[0]; // First item is previous button
|
|
3196
|
+
const nextButton = pageItems[pageItems.length - 1]; // Last item is next button
|
|
3197
|
+
|
|
3198
|
+
// Update page number buttons (skip first and last which are prev/next)
|
|
3199
|
+
pageItems.forEach((item, index) => {
|
|
3200
|
+
// Skip prev/next buttons
|
|
3201
|
+
if (index === 0 || index === pageItems.length - 1) return;
|
|
3202
|
+
|
|
3203
|
+
const pageNum = index; // Adjusted for prev button at index 0
|
|
3204
|
+
if (pageNum === pageNumber) {
|
|
3205
|
+
item.classList.add('active');
|
|
3206
|
+
} else {
|
|
3207
|
+
item.classList.remove('active');
|
|
3208
|
+
}
|
|
3209
|
+
});
|
|
3210
|
+
|
|
3211
|
+
// Update prev/next button states
|
|
3212
|
+
if (prevButton) {
|
|
3213
|
+
if (pageNumber <= 1) {
|
|
3214
|
+
prevButton.classList.add('disabled');
|
|
3215
|
+
} else {
|
|
3216
|
+
prevButton.classList.remove('disabled');
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
|
|
3220
|
+
if (nextButton) {
|
|
3221
|
+
if (pageNumber >= totalPages) {
|
|
3222
|
+
nextButton.classList.add('disabled');
|
|
3223
|
+
} else {
|
|
3224
|
+
nextButton.classList.remove('disabled');
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
// Initialize Activities page size selector
|
|
3231
|
+
function initActivitiesPageSize() {
|
|
3232
|
+
const pageSizeSelect = document.getElementById('activities-page-size');
|
|
3233
|
+
|
|
3234
|
+
if (!pageSizeSelect) return;
|
|
3235
|
+
|
|
3236
|
+
// Remove existing event listener to prevent duplicate bindings
|
|
3237
|
+
if (!pageSizeSelect.hasAttribute('data-activities-listener-bound')) {
|
|
3238
|
+
pageSizeSelect.addEventListener('change', function() {
|
|
3239
|
+
console.log('Activities page size changed to:', this.value);
|
|
3240
|
+
updateActivitiesPagination();
|
|
3241
|
+
});
|
|
3242
|
+
// Mark as having listener bound
|
|
3243
|
+
pageSizeSelect.setAttribute('data-activities-listener-bound', 'true');
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
|
|
3247
|
+
// Source directories expand/collapse functionality
|
|
3248
|
+
function initSourceDirsToggle() {
|
|
3249
|
+
const toggleButtons = document.querySelectorAll('.source-dirs-toggle');
|
|
3250
|
+
|
|
3251
|
+
toggleButtons.forEach(function(button) {
|
|
3252
|
+
button.addEventListener('click', function() {
|
|
3253
|
+
const targetId = this.getAttribute('data-target');
|
|
3254
|
+
const hiddenDirs = document.getElementById(targetId);
|
|
3255
|
+
const icon = this.querySelector('.bi');
|
|
3256
|
+
const toggleText = this.querySelector('.toggle-text');
|
|
3257
|
+
const total = parseInt(this.getAttribute('data-total'));
|
|
3258
|
+
const visible = parseInt(this.getAttribute('data-visible'));
|
|
3259
|
+
|
|
3260
|
+
if (hiddenDirs.style.display === 'none') {
|
|
3261
|
+
// Show hidden directories
|
|
3262
|
+
hiddenDirs.style.display = 'inline';
|
|
3263
|
+
icon.className = 'bi bi-chevron-up';
|
|
3264
|
+
toggleText.textContent = 'Show less';
|
|
3265
|
+
this.classList.remove('btn-outline-info');
|
|
3266
|
+
this.classList.add('btn-outline-secondary');
|
|
3267
|
+
} else {
|
|
3268
|
+
// Hide directories
|
|
3269
|
+
hiddenDirs.style.display = 'none';
|
|
3270
|
+
icon.className = 'bi bi-chevron-down';
|
|
3271
|
+
toggleText.textContent = `+${total - visible} more`;
|
|
3272
|
+
this.classList.remove('btn-outline-secondary');
|
|
3273
|
+
this.classList.add('btn-outline-info');
|
|
3274
|
+
}
|
|
3275
|
+
});
|
|
3276
|
+
});
|
|
3277
|
+
}
|
|
3278
|
+
|
|
3279
|
+
function updatePaginationControls(paginationId, currentPage, totalPages, onPageClick) {
|
|
3280
|
+
var pagination = document.getElementById(paginationId);
|
|
3281
|
+
if (!pagination) return;
|
|
3282
|
+
|
|
3283
|
+
pagination.innerHTML = '';
|
|
3284
|
+
|
|
3285
|
+
if (totalPages <= 1) {
|
|
3286
|
+
// Hide the entire pagination container when not needed
|
|
3287
|
+
var paginationContainer = pagination.closest('.pagination-container');
|
|
3288
|
+
if (paginationContainer) {
|
|
3289
|
+
paginationContainer.style.display = 'none';
|
|
3290
|
+
}
|
|
3291
|
+
return;
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3294
|
+
// Show the pagination container when needed
|
|
3295
|
+
var paginationContainer = pagination.closest('.pagination-container');
|
|
3296
|
+
if (paginationContainer) {
|
|
3297
|
+
paginationContainer.style.display = '';
|
|
3298
|
+
}
|
|
3299
|
+
|
|
3300
|
+
// Previous button
|
|
3301
|
+
var prevLi = document.createElement('li');
|
|
3302
|
+
prevLi.className = 'page-item' + (currentPage === 1 ? ' disabled' : '');
|
|
3303
|
+
var prevLink = document.createElement('a');
|
|
3304
|
+
prevLink.className = 'page-link';
|
|
3305
|
+
prevLink.href = '#';
|
|
3306
|
+
prevLink.setAttribute('aria-label', 'Previous');
|
|
3307
|
+
prevLink.innerHTML = '<span aria-hidden="true">«</span>';
|
|
3308
|
+
|
|
3309
|
+
prevLink.addEventListener('click', function(e) {
|
|
3310
|
+
e.preventDefault();
|
|
3311
|
+
e.stopPropagation();
|
|
3312
|
+
// Get current page dynamically to avoid stale closure values
|
|
3313
|
+
var currentActivePage = getCurrentPageNumber(paginationId);
|
|
3314
|
+
if (currentActivePage > 1 && !prevLi.classList.contains('disabled')) {
|
|
3315
|
+
onPageClick(currentActivePage - 1);
|
|
3316
|
+
}
|
|
3317
|
+
});
|
|
3318
|
+
|
|
3319
|
+
prevLi.appendChild(prevLink);
|
|
3320
|
+
pagination.appendChild(prevLi);
|
|
3321
|
+
|
|
3322
|
+
// Page numbers
|
|
3323
|
+
for (var i = 1; i <= totalPages; i++) {
|
|
3324
|
+
var li = document.createElement('li');
|
|
3325
|
+
li.className = 'page-item' + (i === currentPage ? ' active' : '');
|
|
3326
|
+
var link = document.createElement('a');
|
|
3327
|
+
link.className = 'page-link';
|
|
3328
|
+
link.href = '#';
|
|
3329
|
+
link.textContent = i;
|
|
3330
|
+
link.addEventListener('click', (function(page) {
|
|
3331
|
+
return function(e) {
|
|
3332
|
+
e.preventDefault();
|
|
3333
|
+
e.stopPropagation();
|
|
3334
|
+
onPageClick(page);
|
|
3335
|
+
};
|
|
3336
|
+
})(i));
|
|
3337
|
+
li.appendChild(link);
|
|
3338
|
+
pagination.appendChild(li);
|
|
3339
|
+
}
|
|
3340
|
+
|
|
3341
|
+
// Next button
|
|
3342
|
+
var nextLi = document.createElement('li');
|
|
3343
|
+
nextLi.className = 'page-item' + (currentPage === totalPages ? ' disabled' : '');
|
|
3344
|
+
var nextLink = document.createElement('a');
|
|
3345
|
+
nextLink.className = 'page-link';
|
|
3346
|
+
nextLink.href = '#';
|
|
3347
|
+
nextLink.setAttribute('aria-label', 'Next');
|
|
3348
|
+
nextLink.innerHTML = '<span aria-hidden="true">»</span>';
|
|
3349
|
+
|
|
3350
|
+
nextLink.addEventListener('click', function(e) {
|
|
3351
|
+
e.preventDefault();
|
|
3352
|
+
e.stopPropagation();
|
|
3353
|
+
// Get current page dynamically to avoid stale closure values
|
|
3354
|
+
var currentActivePage = getCurrentPageNumber(paginationId);
|
|
3355
|
+
if (currentActivePage < totalPages && !nextLi.classList.contains('disabled')) {
|
|
3356
|
+
onPageClick(currentActivePage + 1);
|
|
3357
|
+
}
|
|
3358
|
+
});
|
|
3359
|
+
|
|
3360
|
+
nextLi.appendChild(nextLink);
|
|
3361
|
+
pagination.appendChild(nextLi);
|
|
3362
|
+
}
|
|
3363
|
+
|
|
3364
|
+
function getCurrentPageNumber(paginationId) {
|
|
3365
|
+
var pagination = document.getElementById(paginationId);
|
|
3366
|
+
if (!pagination) return 1;
|
|
3367
|
+
|
|
3368
|
+
var activeItem = pagination.querySelector('.page-item.active');
|
|
3369
|
+
if (activeItem) {
|
|
3370
|
+
var pageText = activeItem.textContent.trim();
|
|
3371
|
+
var pageNum = parseInt(pageText);
|
|
3372
|
+
return isNaN(pageNum) ? 1 : pageNum;
|
|
3373
|
+
}
|
|
3374
|
+
return 1;
|
|
3375
|
+
}
|
|
3376
|
+
|
|
3377
|
+
function initMergeInfoCollapse() {
|
|
3378
|
+
// Initialize merge info collapse functionality if needed
|
|
3379
|
+
// This function can be expanded based on specific merge info requirements
|
|
3380
|
+
console.log('Merge info collapse initialized');
|
|
3381
|
+
}
|
|
3382
|
+
|
|
3383
|
+
function initMergedDirectoriesScrollbar() {
|
|
3384
|
+
const directoriesList = document.querySelector('.merged-directories-list');
|
|
3385
|
+
const directoriesContainer = document.querySelector('.merged-directories-container');
|
|
3386
|
+
|
|
3387
|
+
if (!directoriesList || !directoriesContainer) return;
|
|
3388
|
+
|
|
3389
|
+
// Function to check if scrollbar is needed
|
|
3390
|
+
function checkScrollbar() {
|
|
3391
|
+
const hasScrollbar = directoriesList.scrollHeight > directoriesList.clientHeight;
|
|
3392
|
+
|
|
3393
|
+
if (hasScrollbar) {
|
|
3394
|
+
directoriesContainer.classList.add('has-scrollbar');
|
|
3395
|
+
// Add scroll indicator
|
|
3396
|
+
if (!directoriesContainer.querySelector('.scroll-indicator')) {
|
|
3397
|
+
const indicator = document.createElement('div');
|
|
3398
|
+
indicator.className = 'scroll-indicator';
|
|
3399
|
+
indicator.innerHTML = '<i class="bi bi-chevron-down"></i>';
|
|
3400
|
+
indicator.style.cssText = `
|
|
3401
|
+
position: absolute;
|
|
3402
|
+
bottom: 5px;
|
|
3403
|
+
right: 5px;
|
|
3404
|
+
background: rgba(23, 162, 184, 0.8);
|
|
3405
|
+
color: white;
|
|
3406
|
+
border-radius: 50%;
|
|
3407
|
+
width: 20px;
|
|
3408
|
+
height: 20px;
|
|
3409
|
+
display: flex;
|
|
3410
|
+
align-items: center;
|
|
3411
|
+
justify-content: center;
|
|
3412
|
+
font-size: 10px;
|
|
3413
|
+
pointer-events: none;
|
|
3414
|
+
opacity: 0.7;
|
|
3415
|
+
transition: opacity 0.3s ease;
|
|
3416
|
+
`;
|
|
3417
|
+
directoriesContainer.appendChild(indicator);
|
|
3418
|
+
}
|
|
3419
|
+
} else {
|
|
3420
|
+
directoriesContainer.classList.remove('has-scrollbar');
|
|
3421
|
+
const indicator = directoriesContainer.querySelector('.scroll-indicator');
|
|
3422
|
+
if (indicator) {
|
|
3423
|
+
indicator.remove();
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
3427
|
+
|
|
3428
|
+
// Check on load
|
|
3429
|
+
checkScrollbar();
|
|
3430
|
+
|
|
3431
|
+
// Check on window resize
|
|
3432
|
+
window.addEventListener('resize', checkScrollbar);
|
|
3433
|
+
|
|
3434
|
+
// Add scroll event listener to hide indicator when scrolled to bottom
|
|
3435
|
+
directoriesList.addEventListener('scroll', function() {
|
|
3436
|
+
const indicator = directoriesContainer.querySelector('.scroll-indicator');
|
|
3437
|
+
if (indicator) {
|
|
3438
|
+
const isAtBottom = this.scrollTop + this.clientHeight >= this.scrollHeight - 5;
|
|
3439
|
+
indicator.style.opacity = isAtBottom ? '0' : '0.7';
|
|
3440
|
+
}
|
|
3441
|
+
});
|
|
3442
|
+
|
|
3443
|
+
// Enhance scrollbar visibility on hover
|
|
3444
|
+
directoriesContainer.addEventListener('mouseenter', function() {
|
|
3445
|
+
directoriesList.style.scrollbarWidth = 'auto';
|
|
3446
|
+
});
|
|
3447
|
+
|
|
3448
|
+
directoriesContainer.addEventListener('mouseleave', function() {
|
|
3449
|
+
directoriesList.style.scrollbarWidth = 'thin';
|
|
3450
|
+
});
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
// Crash Analysis Functions
|
|
3454
|
+
function initCrashAnalysis() {
|
|
3455
|
+
// Initialize event filtering first (this will set initial visibility)
|
|
3456
|
+
initEventFiltering();
|
|
3457
|
+
|
|
3458
|
+
// Initialize pagination for crash events (using specialized function)
|
|
3459
|
+
initCrashEventsPagination();
|
|
3460
|
+
|
|
3461
|
+
// Initialize copy stack trace functionality
|
|
3462
|
+
initCopyStackTrace();
|
|
3463
|
+
}
|
|
3464
|
+
|
|
3465
|
+
function initEventFiltering() {
|
|
3466
|
+
const filterButtons = document.querySelectorAll('input[name="event-filter"]');
|
|
3467
|
+
|
|
3468
|
+
filterButtons.forEach(button => {
|
|
3469
|
+
button.addEventListener('change', function() {
|
|
3470
|
+
const filterType = this.id;
|
|
3471
|
+
filterEvents(filterType);
|
|
3472
|
+
});
|
|
3473
|
+
});
|
|
3474
|
+
|
|
3475
|
+
// Initialize with default filter (all-events)
|
|
3476
|
+
filterEvents('all-events');
|
|
3477
|
+
}
|
|
3478
|
+
|
|
3479
|
+
function filterEvents(filterType) {
|
|
3480
|
+
const eventRows = document.querySelectorAll('.event-row');
|
|
3481
|
+
|
|
3482
|
+
eventRows.forEach(row => {
|
|
3483
|
+
const eventType = row.dataset.type;
|
|
3484
|
+
let shouldShow = false;
|
|
3485
|
+
|
|
3486
|
+
switch(filterType) {
|
|
3487
|
+
case 'all-events':
|
|
3488
|
+
shouldShow = true;
|
|
3489
|
+
break;
|
|
3490
|
+
case 'crashes-only':
|
|
3491
|
+
shouldShow = eventType === 'crash';
|
|
3492
|
+
break;
|
|
3493
|
+
case 'anr-only':
|
|
3494
|
+
shouldShow = eventType === 'anr';
|
|
3495
|
+
break;
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3498
|
+
// Set the display style to control visibility
|
|
3499
|
+
row.style.display = shouldShow ? '' : 'none';
|
|
3500
|
+
|
|
3501
|
+
// Also control the corresponding detail row
|
|
3502
|
+
const detailRow = row.nextElementSibling;
|
|
3503
|
+
if (detailRow && detailRow.classList.contains('collapse')) {
|
|
3504
|
+
detailRow.style.display = shouldShow ? '' : 'none';
|
|
3505
|
+
}
|
|
3506
|
+
});
|
|
3507
|
+
|
|
3508
|
+
// Re-setup pagination after filtering
|
|
3509
|
+
setTimeout(function() {
|
|
3510
|
+
setupCrashEventsPagination();
|
|
3511
|
+
}, 10);
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3514
|
+
|
|
3515
|
+
|
|
3516
|
+
function initCrashEventsPagination() {
|
|
3517
|
+
const pageSizeSelect = document.getElementById('events-page-size');
|
|
3518
|
+
|
|
3519
|
+
if (pageSizeSelect) {
|
|
3520
|
+
// Add event listener for page size change
|
|
3521
|
+
pageSizeSelect.addEventListener('change', function() {
|
|
3522
|
+
setupCrashEventsPagination();
|
|
3523
|
+
});
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
|
|
3527
|
+
|
|
3528
|
+
|
|
3529
|
+
|
|
3530
|
+
|
|
3531
|
+
|
|
3532
|
+
function initCopyStackTrace() {
|
|
3533
|
+
const copyButtons = document.querySelectorAll('.copy-stack-btn');
|
|
3534
|
+
|
|
3535
|
+
copyButtons.forEach(button => {
|
|
3536
|
+
button.addEventListener('click', function() {
|
|
3537
|
+
const stackIndex = this.dataset.stackIndex;
|
|
3538
|
+
copyStackTrace(stackIndex);
|
|
3539
|
+
});
|
|
3540
|
+
});
|
|
3541
|
+
}
|
|
3542
|
+
|
|
3543
|
+
function copyStackTrace(stackIndex) {
|
|
3544
|
+
const stackElement = document.getElementById(`stack-trace-${stackIndex}`);
|
|
3545
|
+
if (!stackElement) return;
|
|
3546
|
+
|
|
3547
|
+
const stackText = stackElement.textContent;
|
|
3548
|
+
|
|
3549
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
3550
|
+
navigator.clipboard.writeText(stackText).then(() => {
|
|
3551
|
+
showCopyNotification('Stack trace copied to clipboard!');
|
|
3552
|
+
}).catch(err => {
|
|
3553
|
+
console.error('Failed to copy stack trace: ', err);
|
|
3554
|
+
showCopyNotification('Failed to copy stack trace', 'error');
|
|
3555
|
+
});
|
|
3556
|
+
} else {
|
|
3557
|
+
// Fallback for older browsers
|
|
3558
|
+
const textArea = document.createElement('textarea');
|
|
3559
|
+
textArea.value = stackText;
|
|
3560
|
+
document.body.appendChild(textArea);
|
|
3561
|
+
textArea.select();
|
|
3562
|
+
try {
|
|
3563
|
+
document.execCommand('copy');
|
|
3564
|
+
showCopyNotification('Stack trace copied to clipboard!');
|
|
3565
|
+
} catch (err) {
|
|
3566
|
+
console.error('Fallback copy failed: ', err);
|
|
3567
|
+
showCopyNotification('Failed to copy stack trace', 'error');
|
|
3568
|
+
}
|
|
3569
|
+
document.body.removeChild(textArea);
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
|
|
3573
|
+
function showCopyNotification(message, type) {
|
|
3574
|
+
type = type || 'success';
|
|
3575
|
+
|
|
3576
|
+
// Create notification element
|
|
3577
|
+
const notification = document.createElement('div');
|
|
3578
|
+
notification.className = 'alert alert-' + (type === 'error' ? 'danger' : 'success') + ' position-fixed';
|
|
3579
|
+
notification.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px; opacity: 0; transition: opacity 0.3s ease-in-out;';
|
|
3580
|
+
notification.innerHTML = '<i class="bi bi-' + (type === 'error' ? 'exclamation-triangle' : 'check-circle') + '"></i> ' + message;
|
|
3581
|
+
|
|
3582
|
+
document.body.appendChild(notification);
|
|
3583
|
+
|
|
3584
|
+
// Fade in animation
|
|
3585
|
+
setTimeout(function() {
|
|
3586
|
+
notification.style.opacity = '1';
|
|
3587
|
+
}, 10);
|
|
3588
|
+
|
|
3589
|
+
// Auto remove after 3 seconds with fade out
|
|
3590
|
+
setTimeout(function() {
|
|
3591
|
+
notification.style.opacity = '0';
|
|
3592
|
+
setTimeout(function() {
|
|
3593
|
+
if (notification.parentNode) {
|
|
3594
|
+
notification.parentNode.removeChild(notification);
|
|
3595
|
+
}
|
|
3596
|
+
}, 300);
|
|
3597
|
+
}, 3000);
|
|
3598
|
+
}
|
|
3599
|
+
});
|
|
3600
|
+
</script>
|
|
3601
|
+
</body>
|
|
3602
|
+
</html>
|