Kea2-python 0.2.4__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Kea2-python might be problematic. Click here for more details.
- kea2/assets/monkeyq.jar +0 -0
- kea2/bug_report_generator.py +267 -7
- kea2/cli.py +71 -2
- kea2/report_merger.py +651 -0
- kea2/templates/bug_report_template.html +1583 -68
- kea2/templates/merged_bug_report_template.html +2547 -0
- {kea2_python-0.2.4.dist-info → kea2_python-0.3.0.dist-info}/METADATA +10 -3
- {kea2_python-0.2.4.dist-info → kea2_python-0.3.0.dist-info}/RECORD +12 -10
- {kea2_python-0.2.4.dist-info → kea2_python-0.3.0.dist-info}/WHEEL +0 -0
- {kea2_python-0.2.4.dist-info → kea2_python-0.3.0.dist-info}/entry_points.txt +0 -0
- {kea2_python-0.2.4.dist-info → kea2_python-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {kea2_python-0.2.4.dist-info → kea2_python-0.3.0.dist-info}/top_level.txt +0 -0
|
@@ -201,43 +201,86 @@
|
|
|
201
201
|
vertical-align: middle;
|
|
202
202
|
text-align: center;
|
|
203
203
|
}
|
|
204
|
+
|
|
205
|
+
/* Override text alignment for stack trace containers */
|
|
206
|
+
.table-custom td .bg-light {
|
|
207
|
+
text-align: left;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.table-custom td .bg-light pre {
|
|
211
|
+
text-align: left !important;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* Enhanced Error Details styling */
|
|
215
|
+
.table-custom td:nth-child(7) .collapse {
|
|
216
|
+
position: relative;
|
|
217
|
+
z-index: 10;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.table-custom td:nth-child(7) .card {
|
|
221
|
+
max-width: none;
|
|
222
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.table-custom td:nth-child(7) .card-body {
|
|
226
|
+
padding: 1rem;
|
|
227
|
+
max-height: 400px;
|
|
228
|
+
overflow-y: auto;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.table-custom td:nth-child(7) pre {
|
|
232
|
+
max-height: 200px;
|
|
233
|
+
overflow-y: auto;
|
|
234
|
+
font-size: 0.8rem;
|
|
235
|
+
line-height: 1.4;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.table-custom td:nth-child(7) details {
|
|
239
|
+
margin-top: 0.5rem;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.table-custom td:nth-child(7) summary {
|
|
243
|
+
cursor: pointer;
|
|
244
|
+
margin-bottom: 0.5rem;
|
|
245
|
+
}
|
|
204
246
|
|
|
205
247
|
/* Specific column widths for property statistics table */
|
|
206
248
|
.table-custom th:nth-child(1), .table-custom td:nth-child(1) { /* Index */
|
|
207
|
-
width:
|
|
208
|
-
min-width:
|
|
249
|
+
width: 5%;
|
|
250
|
+
min-width: 50px;
|
|
209
251
|
}
|
|
210
|
-
|
|
252
|
+
|
|
211
253
|
.table-custom th:nth-child(2), .table-custom td:nth-child(2) { /* Property Name */
|
|
212
|
-
width:
|
|
213
|
-
min-width:
|
|
254
|
+
width: 18%;
|
|
255
|
+
min-width: 180px;
|
|
214
256
|
text-align: left;
|
|
215
257
|
}
|
|
216
|
-
|
|
258
|
+
|
|
217
259
|
.table-custom th:nth-child(3), .table-custom td:nth-child(3) { /* Precondition Satisfied */
|
|
218
|
-
width:
|
|
219
|
-
min-width:
|
|
260
|
+
width: 9%;
|
|
261
|
+
min-width: 85px;
|
|
220
262
|
}
|
|
221
|
-
|
|
263
|
+
|
|
222
264
|
.table-custom th:nth-child(4), .table-custom td:nth-child(4) { /* Executed */
|
|
223
|
-
width:
|
|
224
|
-
min-width:
|
|
265
|
+
width: 8%;
|
|
266
|
+
min-width: 70px;
|
|
225
267
|
}
|
|
226
|
-
|
|
268
|
+
|
|
227
269
|
.table-custom th:nth-child(5), .table-custom td:nth-child(5) { /* Fails */
|
|
228
|
-
width:
|
|
229
|
-
min-width:
|
|
270
|
+
width: 7%;
|
|
271
|
+
min-width: 65px;
|
|
230
272
|
}
|
|
231
|
-
|
|
273
|
+
|
|
232
274
|
.table-custom th:nth-child(6), .table-custom td:nth-child(6) { /* Errors */
|
|
233
|
-
width:
|
|
234
|
-
min-width:
|
|
275
|
+
width: 8%;
|
|
276
|
+
min-width: 70px;
|
|
235
277
|
}
|
|
236
278
|
|
|
237
279
|
.table-custom th:nth-child(7), .table-custom td:nth-child(7) { /* Error Details */
|
|
238
|
-
width:
|
|
239
|
-
min-width:
|
|
240
|
-
text-align:
|
|
280
|
+
width: 45%;
|
|
281
|
+
min-width: 400px;
|
|
282
|
+
text-align: center;
|
|
283
|
+
position: relative;
|
|
241
284
|
}
|
|
242
285
|
|
|
243
286
|
.table-custom tbody tr:nth-of-type(odd) {
|
|
@@ -572,6 +615,418 @@
|
|
|
572
615
|
white-space: normal;
|
|
573
616
|
}
|
|
574
617
|
}
|
|
618
|
+
|
|
619
|
+
/* Modern Sorting Controls Styling */
|
|
620
|
+
.sorting-controls-modern {
|
|
621
|
+
background: #ffffff;
|
|
622
|
+
border: 1px solid #e5e7eb;
|
|
623
|
+
border-radius: 16px;
|
|
624
|
+
padding: 20px 24px;
|
|
625
|
+
margin-bottom: 16px;
|
|
626
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
627
|
+
transition: all 0.2s ease;
|
|
628
|
+
position: relative;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
.sorting-controls-modern:hover {
|
|
632
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.06);
|
|
633
|
+
border-color: #d1d5db;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.sort-label-section {
|
|
637
|
+
display: flex;
|
|
638
|
+
align-items: center;
|
|
639
|
+
gap: 16px;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.sort-icon-wrapper {
|
|
643
|
+
width: 48px;
|
|
644
|
+
height: 48px;
|
|
645
|
+
background: linear-gradient(135deg, #3498db, #2980b9);
|
|
646
|
+
border-radius: 12px;
|
|
647
|
+
display: flex;
|
|
648
|
+
align-items: center;
|
|
649
|
+
justify-content: center;
|
|
650
|
+
box-shadow: 0 2px 8px rgba(52, 152, 219, 0.3);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
.sort-icon-wrapper i {
|
|
654
|
+
color: white;
|
|
655
|
+
font-size: 20px;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.sort-text {
|
|
659
|
+
display: flex;
|
|
660
|
+
flex-direction: column;
|
|
661
|
+
gap: 4px;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.sort-title {
|
|
665
|
+
font-size: 16px;
|
|
666
|
+
font-weight: 600;
|
|
667
|
+
color: #2c3e50;
|
|
668
|
+
line-height: 1.2;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.sort-subtitle {
|
|
672
|
+
font-size: 13px;
|
|
673
|
+
color: #7f8c8d;
|
|
674
|
+
font-weight: 400;
|
|
675
|
+
line-height: 1.2;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
.sort-button-section {
|
|
679
|
+
display: flex;
|
|
680
|
+
align-items: center;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.btn-sort-modern {
|
|
684
|
+
background: linear-gradient(135deg, #27ae60, #2ecc71);
|
|
685
|
+
border: none;
|
|
686
|
+
border-radius: 10px;
|
|
687
|
+
padding: 12px 20px;
|
|
688
|
+
color: white;
|
|
689
|
+
font-weight: 500;
|
|
690
|
+
font-size: 14px;
|
|
691
|
+
cursor: pointer;
|
|
692
|
+
transition: all 0.3s ease;
|
|
693
|
+
box-shadow: 0 2px 8px rgba(46, 204, 113, 0.3);
|
|
694
|
+
position: relative;
|
|
695
|
+
overflow: hidden;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.btn-sort-modern::before {
|
|
699
|
+
content: '';
|
|
700
|
+
position: absolute;
|
|
701
|
+
top: 0;
|
|
702
|
+
left: -100%;
|
|
703
|
+
width: 100%;
|
|
704
|
+
height: 100%;
|
|
705
|
+
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
|
706
|
+
transition: left 0.5s ease;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
.btn-sort-modern:hover {
|
|
710
|
+
transform: translateY(-2px);
|
|
711
|
+
box-shadow: 0 4px 16px rgba(46, 204, 113, 0.4);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
.btn-sort-modern:hover::before {
|
|
715
|
+
left: 100%;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
.btn-sort-modern:active {
|
|
719
|
+
transform: translateY(0px);
|
|
720
|
+
box-shadow: 0 2px 8px rgba(46, 204, 113, 0.3);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
.btn-content {
|
|
724
|
+
display: flex;
|
|
725
|
+
align-items: center;
|
|
726
|
+
gap: 8px;
|
|
727
|
+
position: relative;
|
|
728
|
+
z-index: 1;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
.btn-icon {
|
|
732
|
+
font-size: 16px;
|
|
733
|
+
opacity: 0.9;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.btn-text {
|
|
737
|
+
font-size: 14px;
|
|
738
|
+
font-weight: 500;
|
|
739
|
+
white-space: nowrap;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
.btn-arrow {
|
|
743
|
+
font-size: 14px;
|
|
744
|
+
transition: transform 0.3s ease;
|
|
745
|
+
opacity: 0.8;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.btn-sort-modern:hover .btn-arrow {
|
|
749
|
+
transform: scale(1.1);
|
|
750
|
+
opacity: 1;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/* Responsive design for sorting controls */
|
|
754
|
+
@media (max-width: 768px) {
|
|
755
|
+
.sorting-controls-modern {
|
|
756
|
+
padding: 16px 20px;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
.sort-label-section {
|
|
760
|
+
gap: 12px;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
.sort-icon-wrapper {
|
|
764
|
+
width: 40px;
|
|
765
|
+
height: 40px;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.sort-icon-wrapper i {
|
|
769
|
+
font-size: 16px;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
.sort-title {
|
|
773
|
+
font-size: 14px;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
.sort-subtitle {
|
|
777
|
+
font-size: 12px;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
.btn-sort-modern {
|
|
781
|
+
padding: 10px 16px;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
.btn-text {
|
|
785
|
+
font-size: 13px;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
@media (max-width: 576px) {
|
|
790
|
+
.sorting-controls-modern {
|
|
791
|
+
flex-direction: column;
|
|
792
|
+
text-align: center;
|
|
793
|
+
gap: 16px;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
.sorting-controls-modern .d-flex {
|
|
797
|
+
flex-direction: column;
|
|
798
|
+
gap: 16px;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
.sort-label-section {
|
|
802
|
+
justify-content: center;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/* Search Controls Styling */
|
|
807
|
+
.search-controls-modern {
|
|
808
|
+
background: #ffffff;
|
|
809
|
+
border: 1px solid #e5e7eb;
|
|
810
|
+
border-radius: 16px;
|
|
811
|
+
padding: 20px 24px;
|
|
812
|
+
margin-bottom: 20px;
|
|
813
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
814
|
+
transition: all 0.2s ease;
|
|
815
|
+
position: relative;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
.search-controls-modern:hover {
|
|
819
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.06);
|
|
820
|
+
border-color: #d1d5db;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/* Modern Activity Item Styling */
|
|
824
|
+
.activity-item {
|
|
825
|
+
background: #ffffff;
|
|
826
|
+
border: 1px solid #f3f4f6;
|
|
827
|
+
border-radius: 12px;
|
|
828
|
+
padding: 16px 20px;
|
|
829
|
+
margin-bottom: 8px;
|
|
830
|
+
transition: all 0.2s ease;
|
|
831
|
+
display: flex;
|
|
832
|
+
align-items: center;
|
|
833
|
+
justify-content: space-between;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
.activity-item:hover {
|
|
837
|
+
border-color: #e5e7eb;
|
|
838
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
839
|
+
transform: translateY(-1px);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
.activity-content {
|
|
843
|
+
display: flex;
|
|
844
|
+
align-items: center;
|
|
845
|
+
gap: 12px;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
.activity-name {
|
|
849
|
+
font-weight: 500;
|
|
850
|
+
color: #374151;
|
|
851
|
+
font-size: 14px;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
.traversal-badge {
|
|
855
|
+
background: linear-gradient(135deg, #3b82f6, #1d4ed8) !important;
|
|
856
|
+
border: none;
|
|
857
|
+
border-radius: 20px;
|
|
858
|
+
padding: 6px 12px;
|
|
859
|
+
font-size: 12px;
|
|
860
|
+
font-weight: 500;
|
|
861
|
+
box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/* Modern Search Input */
|
|
865
|
+
.activity-search-input {
|
|
866
|
+
border: 1px solid #e5e7eb;
|
|
867
|
+
border-radius: 12px;
|
|
868
|
+
padding: 12px 16px;
|
|
869
|
+
font-size: 14px;
|
|
870
|
+
transition: all 0.2s ease;
|
|
871
|
+
background: #f9fafb;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
.activity-search-input:focus {
|
|
875
|
+
border-color: #3b82f6;
|
|
876
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
877
|
+
background: #ffffff;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.search-btn {
|
|
881
|
+
border-radius: 12px;
|
|
882
|
+
padding: 12px 16px;
|
|
883
|
+
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
|
|
884
|
+
border: none;
|
|
885
|
+
transition: all 0.2s ease;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
.search-btn:hover {
|
|
889
|
+
background: linear-gradient(135deg, #2563eb, #1e40af);
|
|
890
|
+
transform: translateY(-1px);
|
|
891
|
+
box-shadow: 0 4px 8px rgba(59, 130, 246, 0.3);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/* Combined Search and Sort Controls */
|
|
895
|
+
.search-sort-controls-modern {
|
|
896
|
+
background: #ffffff;
|
|
897
|
+
border: 1px solid #e5e7eb;
|
|
898
|
+
border-radius: 16px;
|
|
899
|
+
padding: 20px 24px;
|
|
900
|
+
margin-bottom: 20px;
|
|
901
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
902
|
+
transition: all 0.2s ease;
|
|
903
|
+
position: relative;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
.search-sort-controls-modern:hover {
|
|
907
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.06);
|
|
908
|
+
border-color: #d1d5db;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
.search-section {
|
|
912
|
+
min-width: 0; /* Allow flex item to shrink */
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
.sort-section {
|
|
916
|
+
flex-shrink: 0; /* Prevent sort section from shrinking */
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.sort-label {
|
|
920
|
+
white-space: nowrap;
|
|
921
|
+
font-size: 14px;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/* Responsive design for combined controls */
|
|
925
|
+
@media (max-width: 768px) {
|
|
926
|
+
.search-sort-controls-modern .d-flex {
|
|
927
|
+
flex-direction: column;
|
|
928
|
+
gap: 16px !important;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
.search-section {
|
|
932
|
+
width: 100% !important;
|
|
933
|
+
max-width: none !important;
|
|
934
|
+
flex-shrink: 1 !important;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
.sort-section {
|
|
938
|
+
justify-content: center;
|
|
939
|
+
width: 100%;
|
|
940
|
+
margin-left: 0 !important;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
@media (max-width: 576px) {
|
|
945
|
+
.search-section {
|
|
946
|
+
max-width: none !important;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
.search-icon-wrapper {
|
|
950
|
+
width: 40px;
|
|
951
|
+
height: 40px;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
.search-icon-wrapper i {
|
|
955
|
+
font-size: 18px;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.search-icon-wrapper {
|
|
960
|
+
width: 48px;
|
|
961
|
+
height: 48px;
|
|
962
|
+
background: linear-gradient(135deg, #17a2b8, #138496);
|
|
963
|
+
border-radius: 12px;
|
|
964
|
+
display: flex;
|
|
965
|
+
align-items: center;
|
|
966
|
+
justify-content: center;
|
|
967
|
+
box-shadow: 0 2px 8px rgba(23, 162, 184, 0.3);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
.search-icon-wrapper i {
|
|
971
|
+
color: white;
|
|
972
|
+
font-size: 20px;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
.activity-search-input {
|
|
976
|
+
border: 1px solid #ced4da;
|
|
977
|
+
border-radius: 8px 0 0 8px;
|
|
978
|
+
padding: 12px 16px;
|
|
979
|
+
font-size: 14px;
|
|
980
|
+
transition: all 0.3s ease;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
.activity-search-input:focus {
|
|
984
|
+
border-color: #17a2b8;
|
|
985
|
+
box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.25);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
.search-btn {
|
|
989
|
+
border-radius: 0;
|
|
990
|
+
border-left: none;
|
|
991
|
+
border-right: none;
|
|
992
|
+
padding: 12px 16px;
|
|
993
|
+
transition: all 0.3s ease;
|
|
994
|
+
background-color: #17a2b8;
|
|
995
|
+
border-color: #17a2b8;
|
|
996
|
+
color: white;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
.search-btn:hover {
|
|
1000
|
+
background-color: #138496;
|
|
1001
|
+
border-color: #117a8b;
|
|
1002
|
+
color: white;
|
|
1003
|
+
transform: translateY(-1px);
|
|
1004
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
.search-btn:focus {
|
|
1008
|
+
box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
.search-clear-btn {
|
|
1012
|
+
border-radius: 0 8px 8px 0;
|
|
1013
|
+
border-left: none;
|
|
1014
|
+
padding: 12px 16px;
|
|
1015
|
+
transition: all 0.3s ease;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
.search-clear-btn:hover {
|
|
1019
|
+
background-color: #dc3545;
|
|
1020
|
+
border-color: #dc3545;
|
|
1021
|
+
color: white;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
.search-results-count {
|
|
1025
|
+
display: block;
|
|
1026
|
+
margin-top: 8px;
|
|
1027
|
+
font-size: 12px;
|
|
1028
|
+
font-style: italic;
|
|
1029
|
+
}
|
|
575
1030
|
</style>
|
|
576
1031
|
</head>
|
|
577
1032
|
|
|
@@ -669,7 +1124,7 @@
|
|
|
669
1124
|
<div class="alert alert-info mb-3" style="border-left: 4px solid #17a2b8; background-color: #f8f9fa;">
|
|
670
1125
|
<small class="text-muted">
|
|
671
1126
|
<i class="bi bi-info-circle me-1"></i>
|
|
672
|
-
<strong>
|
|
1127
|
+
<strong>Visit Count Explanation:</strong>
|
|
673
1128
|
The number after the <i class="bi bi-eye"></i> icon indicates how many times each Activity was visited during testing.
|
|
674
1129
|
</small>
|
|
675
1130
|
</div>
|
|
@@ -701,7 +1156,54 @@
|
|
|
701
1156
|
<h5 class="mb-0 text-success">
|
|
702
1157
|
<i class="bi bi-check-circle-fill"></i> Tested Activities
|
|
703
1158
|
</h5>
|
|
704
|
-
<span class="badge bg-success">{{ tested_activities|length }} / {{ total_activities_count }}</span>
|
|
1159
|
+
<span class="badge bg-success" style="font-size: 1.0em; font-weight: 500;">{{ tested_activities|length }} / {{ total_activities_count }}</span>
|
|
1160
|
+
</div>
|
|
1161
|
+
|
|
1162
|
+
<!-- Combined Search and Sort Controls for Tested Activities -->
|
|
1163
|
+
<div class="search-sort-controls-modern mb-4">
|
|
1164
|
+
<div class="d-flex align-items-center gap-4">
|
|
1165
|
+
<!-- Search Section -->
|
|
1166
|
+
<div class="search-section d-flex align-items-center" style="width: 600px; flex-shrink: 0;">
|
|
1167
|
+
<div class="search-icon-wrapper me-3">
|
|
1168
|
+
<i class="bi bi-search"></i>
|
|
1169
|
+
</div>
|
|
1170
|
+
<div class="flex-grow-1">
|
|
1171
|
+
<div class="input-group">
|
|
1172
|
+
<input type="text" class="form-control activity-search-input"
|
|
1173
|
+
id="tested-activity-search"
|
|
1174
|
+
placeholder="Search activities..."
|
|
1175
|
+
data-target="tested-activities-container"
|
|
1176
|
+
data-item-class="tested-activity"
|
|
1177
|
+
data-pagination="tested-pagination"
|
|
1178
|
+
data-page-size="tested-page-size">
|
|
1179
|
+
<button class="btn search-btn" type="button"
|
|
1180
|
+
data-target="tested-activity-search">
|
|
1181
|
+
<i class="bi bi-search"></i>
|
|
1182
|
+
</button>
|
|
1183
|
+
<button class="btn btn-outline-secondary search-clear-btn" type="button"
|
|
1184
|
+
data-target="tested-activity-search">
|
|
1185
|
+
<i class="bi bi-x-lg"></i>
|
|
1186
|
+
</button>
|
|
1187
|
+
</div>
|
|
1188
|
+
<small class="text-muted search-results-count" id="tested-search-results"></small>
|
|
1189
|
+
</div>
|
|
1190
|
+
</div>
|
|
1191
|
+
|
|
1192
|
+
<!-- Sort Section -->
|
|
1193
|
+
<div class="sort-section d-flex align-items-center gap-3" style="margin-left: auto;">
|
|
1194
|
+
<div class="sort-label d-flex align-items-center gap-2">
|
|
1195
|
+
<i class="bi bi-funnel-fill text-muted"></i>
|
|
1196
|
+
<span class="text-muted fw-medium">Sort:</span>
|
|
1197
|
+
</div>
|
|
1198
|
+
<button type="button" class="btn-sort-modern activity-sort-btn" data-sort="traversal" data-order="desc">
|
|
1199
|
+
<div class="btn-content">
|
|
1200
|
+
<i class="bi bi-eye btn-icon"></i>
|
|
1201
|
+
<span class="btn-text">Visit Count</span>
|
|
1202
|
+
<i class="bi bi-arrow-down sort-icon btn-arrow"></i>
|
|
1203
|
+
</div>
|
|
1204
|
+
</button>
|
|
1205
|
+
</div>
|
|
1206
|
+
</div>
|
|
705
1207
|
</div>
|
|
706
1208
|
|
|
707
1209
|
<div class="activities-container">
|
|
@@ -711,7 +1213,7 @@
|
|
|
711
1213
|
{% for activity in tested_activities %}
|
|
712
1214
|
<div class="activity-item tested-activity" data-page="1">
|
|
713
1215
|
<div class="activity-content">
|
|
714
|
-
|
|
1216
|
+
<i class="bi bi-check-circle-fill text-success me-2"></i>
|
|
715
1217
|
<span class="activity-name">{{ activity }}</span>
|
|
716
1218
|
</div>
|
|
717
1219
|
{% if activity in activity_count_history %}
|
|
@@ -756,21 +1258,68 @@
|
|
|
756
1258
|
<h5 class="mb-0 text-primary">
|
|
757
1259
|
<i class="bi bi-app"></i> All Activities Overview
|
|
758
1260
|
</h5>
|
|
759
|
-
<span class="badge bg-primary">Total: {{ total_activities|length }}</span>
|
|
1261
|
+
<span class="badge bg-primary" style="font-size: 1.0em; font-weight: 500;">Total: {{ total_activities|length }}</span>
|
|
760
1262
|
</div>
|
|
761
1263
|
|
|
762
|
-
|
|
763
|
-
|
|
1264
|
+
<!-- Combined Search and Sort Controls for All Activities -->
|
|
1265
|
+
<div class="search-sort-controls-modern mb-4">
|
|
1266
|
+
<div class="d-flex align-items-center gap-4">
|
|
1267
|
+
<!-- Search Section -->
|
|
1268
|
+
<div class="search-section d-flex align-items-center" style="width: 600px; flex-shrink: 0;">
|
|
1269
|
+
<div class="search-icon-wrapper me-3">
|
|
1270
|
+
<i class="bi bi-search"></i>
|
|
1271
|
+
</div>
|
|
1272
|
+
<div class="flex-grow-1">
|
|
1273
|
+
<div class="input-group">
|
|
1274
|
+
<input type="text" class="form-control activity-search-input"
|
|
1275
|
+
id="all-activity-search"
|
|
1276
|
+
placeholder="Search activities..."
|
|
1277
|
+
data-target="all-activities-container"
|
|
1278
|
+
data-item-class="all-activity"
|
|
1279
|
+
data-pagination="all-pagination"
|
|
1280
|
+
data-page-size="all-page-size">
|
|
1281
|
+
<button class="btn search-btn" type="button"
|
|
1282
|
+
data-target="all-activity-search">
|
|
1283
|
+
<i class="bi bi-search"></i>
|
|
1284
|
+
</button>
|
|
1285
|
+
<button class="btn btn-outline-secondary search-clear-btn" type="button"
|
|
1286
|
+
data-target="all-activity-search">
|
|
1287
|
+
<i class="bi bi-x-lg"></i>
|
|
1288
|
+
</button>
|
|
1289
|
+
</div>
|
|
1290
|
+
<small class="text-muted search-results-count" id="all-search-results"></small>
|
|
1291
|
+
</div>
|
|
1292
|
+
</div>
|
|
1293
|
+
|
|
1294
|
+
<!-- Sort Section -->
|
|
1295
|
+
<div class="sort-section d-flex align-items-center gap-3" style="margin-left: auto;">
|
|
1296
|
+
<div class="sort-label d-flex align-items-center gap-2">
|
|
1297
|
+
<i class="bi bi-funnel-fill text-muted"></i>
|
|
1298
|
+
<span class="text-muted fw-medium">Sort:</span>
|
|
1299
|
+
</div>
|
|
1300
|
+
<button type="button" class="btn-sort-modern activity-sort-btn" data-sort="traversal" data-order="desc">
|
|
1301
|
+
<div class="btn-content">
|
|
1302
|
+
<i class="bi bi-eye btn-icon"></i>
|
|
1303
|
+
<span class="btn-text">Visit Count</span>
|
|
1304
|
+
<i class="bi bi-arrow-down sort-icon btn-arrow"></i>
|
|
1305
|
+
</div>
|
|
1306
|
+
</button>
|
|
1307
|
+
</div>
|
|
1308
|
+
</div>
|
|
1309
|
+
</div>
|
|
1310
|
+
|
|
1311
|
+
<div class="activities-container">
|
|
1312
|
+
<div class="activity-list">
|
|
764
1313
|
{% if total_activities|length > 0 %}
|
|
765
1314
|
<div id="all-activities-container">
|
|
766
1315
|
{% for activity in total_activities %}
|
|
767
1316
|
<div class="activity-item all-activity" data-page="1">
|
|
768
1317
|
<div class="activity-content">
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
1318
|
+
{% if activity in tested_activities %}
|
|
1319
|
+
<i class="bi bi-check-circle-fill text-success me-2"></i>
|
|
1320
|
+
{% else %}
|
|
1321
|
+
<i class="bi bi-dash-circle text-secondary me-2"></i>
|
|
1322
|
+
{% endif %}
|
|
774
1323
|
<span class="activity-name">{{ activity }}</span>
|
|
775
1324
|
</div>
|
|
776
1325
|
{% if activity in activity_count_history %}
|
|
@@ -833,6 +1382,140 @@
|
|
|
833
1382
|
</div>
|
|
834
1383
|
{% endif %}
|
|
835
1384
|
|
|
1385
|
+
<!-- Crash Analysis Section -->
|
|
1386
|
+
{% if crash_events or anr_events %}
|
|
1387
|
+
<div class="section-block">
|
|
1388
|
+
<h2 class="section-title">
|
|
1389
|
+
<i class="bi bi-exclamation-triangle text-danger"></i> Crash Analysis
|
|
1390
|
+
</h2>
|
|
1391
|
+
|
|
1392
|
+
<!-- Detailed Crash Information -->
|
|
1393
|
+
<div class="card">
|
|
1394
|
+
<div class="card-header bg-danger text-white">
|
|
1395
|
+
<div class="d-flex justify-content-between align-items-center">
|
|
1396
|
+
<span><i class="bi bi-bug"></i> Crash & ANR Events</span>
|
|
1397
|
+
<span class="badge bg-light text-dark" style="font-size: 1.1em; font-weight: 600;">{{ (crash_events|length) + (anr_events|length) }} events</span>
|
|
1398
|
+
</div>
|
|
1399
|
+
</div>
|
|
1400
|
+
<div class="card-body">
|
|
1401
|
+
<!-- Event Filter -->
|
|
1402
|
+
<div class="mb-3">
|
|
1403
|
+
<div class="btn-group" role="group" aria-label="Event filter">
|
|
1404
|
+
<input type="radio" class="btn-check" name="event-filter" id="all-events" autocomplete="off" checked>
|
|
1405
|
+
<label class="btn btn-outline-primary" for="all-events">All Events ({{ (crash_events|length) + (anr_events|length) }})</label>
|
|
1406
|
+
|
|
1407
|
+
<input type="radio" class="btn-check" name="event-filter" id="crashes-only" autocomplete="off">
|
|
1408
|
+
<label class="btn btn-outline-danger" for="crashes-only">Crashes Only ({{ crash_events|length }})</label>
|
|
1409
|
+
|
|
1410
|
+
<input type="radio" class="btn-check" name="event-filter" id="anr-only" autocomplete="off">
|
|
1411
|
+
<label class="btn btn-outline-warning" for="anr-only">ANR Only ({{ anr_events|length }})</label>
|
|
1412
|
+
</div>
|
|
1413
|
+
</div>
|
|
1414
|
+
|
|
1415
|
+
<!-- Events Table -->
|
|
1416
|
+
<div class="table-responsive">
|
|
1417
|
+
<table class="table table-custom">
|
|
1418
|
+
<thead>
|
|
1419
|
+
<tr>
|
|
1420
|
+
<th>Type</th>
|
|
1421
|
+
<th>Time</th>
|
|
1422
|
+
<th>Exception</th>
|
|
1423
|
+
<th>Process</th>
|
|
1424
|
+
<th>Details</th>
|
|
1425
|
+
</tr>
|
|
1426
|
+
</thead>
|
|
1427
|
+
<tbody id="crash-events-container">
|
|
1428
|
+
{% for crash in crash_events %}
|
|
1429
|
+
<tr class="event-row" data-type="crash" data-page="1">
|
|
1430
|
+
<td><span class="badge bg-danger">CRASH</span></td>
|
|
1431
|
+
<td>{{ crash.time }}</td>
|
|
1432
|
+
<td>{{ crash.exception_type }}</td>
|
|
1433
|
+
<td>{{ crash.process }}</td>
|
|
1434
|
+
<td>
|
|
1435
|
+
<button class="btn btn-sm btn-outline-primary" type="button"
|
|
1436
|
+
data-bs-toggle="collapse" data-bs-target="#crash-detail-{{ loop.index }}"
|
|
1437
|
+
aria-expanded="false" aria-controls="crash-detail-{{ loop.index }}">
|
|
1438
|
+
<i class="bi bi-eye"></i> Details
|
|
1439
|
+
</button>
|
|
1440
|
+
<button class="btn btn-sm btn-outline-secondary copy-stack-btn"
|
|
1441
|
+
data-stack-index="{{ loop.index }}">
|
|
1442
|
+
<i class="bi bi-clipboard"></i> Copy
|
|
1443
|
+
</button>
|
|
1444
|
+
</td>
|
|
1445
|
+
</tr>
|
|
1446
|
+
<tr class="collapse" id="crash-detail-{{ loop.index }}">
|
|
1447
|
+
<td colspan="5">
|
|
1448
|
+
<div class="bg-light p-3 rounded">
|
|
1449
|
+
<h6 class="text-danger">Stack Trace:</h6>
|
|
1450
|
+
<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>
|
|
1451
|
+
</div>
|
|
1452
|
+
</td>
|
|
1453
|
+
</tr>
|
|
1454
|
+
{% endfor %}
|
|
1455
|
+
|
|
1456
|
+
{% for anr in anr_events %}
|
|
1457
|
+
<tr class="event-row" data-type="anr" data-page="1">
|
|
1458
|
+
<td><span class="badge bg-warning text-dark">ANR</span></td>
|
|
1459
|
+
<td>{{ anr.time }}</td>
|
|
1460
|
+
<td>{{ anr.reason }}</td>
|
|
1461
|
+
<td>{{ anr.process }}</td>
|
|
1462
|
+
<td>
|
|
1463
|
+
<button class="btn btn-sm btn-outline-primary" type="button"
|
|
1464
|
+
data-bs-toggle="collapse" data-bs-target="#anr-detail-{{ loop.index }}"
|
|
1465
|
+
aria-expanded="false" aria-controls="anr-detail-{{ loop.index }}">
|
|
1466
|
+
<i class="bi bi-eye"></i> Details
|
|
1467
|
+
</button>
|
|
1468
|
+
<button class="btn btn-sm btn-outline-secondary copy-stack-btn"
|
|
1469
|
+
data-stack-index="anr-{{ loop.index }}">
|
|
1470
|
+
<i class="bi bi-clipboard"></i> Copy
|
|
1471
|
+
</button>
|
|
1472
|
+
</td>
|
|
1473
|
+
</tr>
|
|
1474
|
+
<tr class="collapse" id="anr-detail-{{ loop.index }}">
|
|
1475
|
+
<td colspan="5">
|
|
1476
|
+
<div class="bg-light p-3 rounded">
|
|
1477
|
+
<h6 class="text-dark">ANR Details:</h6>
|
|
1478
|
+
<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>
|
|
1479
|
+
</div>
|
|
1480
|
+
</td>
|
|
1481
|
+
</tr>
|
|
1482
|
+
{% endfor %}
|
|
1483
|
+
</tbody>
|
|
1484
|
+
</table>
|
|
1485
|
+
</div>
|
|
1486
|
+
|
|
1487
|
+
<!-- Pagination for Crash Events -->
|
|
1488
|
+
<div class="pagination-container d-flex justify-content-between align-items-center mt-3">
|
|
1489
|
+
<div class="d-flex align-items-center">
|
|
1490
|
+
<label for="events-page-size" class="form-label me-2 mb-0">Show:</label>
|
|
1491
|
+
<select class="form-select form-select-sm" id="events-page-size" style="width: auto;">
|
|
1492
|
+
<option value="5">5</option>
|
|
1493
|
+
<option value="10" selected>10</option>
|
|
1494
|
+
<option value="20">20</option>
|
|
1495
|
+
<option value="50">50</option>
|
|
1496
|
+
<option value="100">100</option>
|
|
1497
|
+
</select>
|
|
1498
|
+
</div>
|
|
1499
|
+
<nav aria-label="Crash Events Pagination">
|
|
1500
|
+
<ul class="pagination pagination-sm mb-0" id="events-pagination">
|
|
1501
|
+
<!-- Pagination will be generated by JavaScript -->
|
|
1502
|
+
</ul>
|
|
1503
|
+
</nav>
|
|
1504
|
+
</div>
|
|
1505
|
+
</div>
|
|
1506
|
+
</div>
|
|
1507
|
+
</div>
|
|
1508
|
+
{% else %}
|
|
1509
|
+
<div class="section-block">
|
|
1510
|
+
<h2 class="section-title">
|
|
1511
|
+
<i class="bi bi-exclamation-triangle text-danger"></i> Crash Analysis
|
|
1512
|
+
</h2>
|
|
1513
|
+
<div class="alert alert-info text-center">
|
|
1514
|
+
<i class="bi bi-info-circle"></i> No crash or ANR events detected in this test session.
|
|
1515
|
+
</div>
|
|
1516
|
+
</div>
|
|
1517
|
+
{% endif %}
|
|
1518
|
+
|
|
836
1519
|
<!-- Property Violations List -->
|
|
837
1520
|
{% if take_screenshots %}
|
|
838
1521
|
<div class="section-block">
|
|
@@ -887,6 +1570,35 @@
|
|
|
887
1570
|
<div class="section-block">
|
|
888
1571
|
<h2 class="section-title">Property Checking Statistics</h2>
|
|
889
1572
|
|
|
1573
|
+
<!-- Search Controls for Property Statistics -->
|
|
1574
|
+
<div class="search-controls-modern mb-4">
|
|
1575
|
+
<div class="d-flex align-items-center">
|
|
1576
|
+
<div class="search-icon-wrapper me-3">
|
|
1577
|
+
<i class="bi bi-search"></i>
|
|
1578
|
+
</div>
|
|
1579
|
+
<div class="flex-grow-1">
|
|
1580
|
+
<div class="input-group">
|
|
1581
|
+
<input type="text" class="form-control property-search-input"
|
|
1582
|
+
id="property-stats-search"
|
|
1583
|
+
placeholder="Search properties by name..."
|
|
1584
|
+
data-target="property-stats-container"
|
|
1585
|
+
data-item-class="property-stat-row"
|
|
1586
|
+
data-pagination="stats-pagination"
|
|
1587
|
+
data-page-size="stats-page-size">
|
|
1588
|
+
<button class="btn btn-primary search-btn" type="button"
|
|
1589
|
+
data-target="property-stats-search">
|
|
1590
|
+
<i class="bi bi-search"></i>
|
|
1591
|
+
</button>
|
|
1592
|
+
<button class="btn btn-outline-secondary search-clear-btn" type="button"
|
|
1593
|
+
data-target="property-stats-search">
|
|
1594
|
+
<i class="bi bi-x-lg"></i>
|
|
1595
|
+
</button>
|
|
1596
|
+
</div>
|
|
1597
|
+
<small class="text-muted search-results-count" id="property-search-results"></small>
|
|
1598
|
+
</div>
|
|
1599
|
+
</div>
|
|
1600
|
+
</div>
|
|
1601
|
+
|
|
890
1602
|
<div class="table-responsive">
|
|
891
1603
|
<table class="table table-custom">
|
|
892
1604
|
<thead>
|
|
@@ -1376,10 +2088,28 @@
|
|
|
1376
2088
|
}
|
|
1377
2089
|
});
|
|
1378
2090
|
|
|
2091
|
+
// Draw crash timeline chart
|
|
2092
|
+
var crashTimelineData = {{ crash_timeline_data|default('{}')|safe }};
|
|
2093
|
+
if (crashTimelineData && Object.keys(crashTimelineData).length > 0) {
|
|
2094
|
+
drawCrashTimelineChart(crashTimelineData);
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
// Initialize crash events functionality
|
|
2098
|
+
initCrashAnalysis();
|
|
2099
|
+
|
|
1379
2100
|
// Initialize pagination for Activities lists
|
|
1380
2101
|
initPagination('tested-activities-container', 'tested-activity', 'tested-pagination', 'tested-page-size');
|
|
1381
2102
|
initPagination('all-activities-container', 'all-activity', 'all-pagination', 'all-page-size');
|
|
1382
2103
|
|
|
2104
|
+
// Initialize activity sorting
|
|
2105
|
+
initActivitySorting();
|
|
2106
|
+
|
|
2107
|
+
// Initialize activity searching
|
|
2108
|
+
initActivitySearching();
|
|
2109
|
+
|
|
2110
|
+
// Initialize property statistics searching
|
|
2111
|
+
initPropertySearching();
|
|
2112
|
+
|
|
1383
2113
|
// Initialize pagination for Property tables
|
|
1384
2114
|
initPagination('property-violations-container', 'property-violation-row', 'violations-pagination', 'violations-page-size');
|
|
1385
2115
|
initPagination('property-stats-container', 'property-stat-row', 'stats-pagination', 'stats-page-size');
|
|
@@ -1387,6 +2117,77 @@
|
|
|
1387
2117
|
// Initialize sorting for Property Checking Statistics
|
|
1388
2118
|
initSorting();
|
|
1389
2119
|
|
|
2120
|
+
// Activity sorting function
|
|
2121
|
+
function initActivitySorting() {
|
|
2122
|
+
const sortButtons = document.querySelectorAll('.activity-sort-btn');
|
|
2123
|
+
|
|
2124
|
+
sortButtons.forEach(function(button) {
|
|
2125
|
+
button.addEventListener('click', function() {
|
|
2126
|
+
const sortType = this.dataset.sort;
|
|
2127
|
+
const currentOrder = this.dataset.order;
|
|
2128
|
+
const parentTab = this.closest('.tab-pane');
|
|
2129
|
+
const isTestedTab = parentTab.id === 'tested-activities';
|
|
2130
|
+
|
|
2131
|
+
// Toggle sort order
|
|
2132
|
+
const newOrder = currentOrder === 'asc' ? 'desc' : 'asc';
|
|
2133
|
+
|
|
2134
|
+
this.dataset.order = newOrder;
|
|
2135
|
+
const icon = this.querySelector('.sort-icon');
|
|
2136
|
+
|
|
2137
|
+
if (newOrder === 'asc') {
|
|
2138
|
+
icon.className = 'bi bi-arrow-up sort-icon btn-arrow';
|
|
2139
|
+
} else {
|
|
2140
|
+
icon.className = 'bi bi-arrow-down sort-icon btn-arrow';
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
// Sort activities
|
|
2144
|
+
sortActivities(sortType, newOrder, isTestedTab);
|
|
2145
|
+
});
|
|
2146
|
+
});
|
|
2147
|
+
|
|
2148
|
+
function sortActivities(sortType, order, isTestedTab) {
|
|
2149
|
+
const containerId = isTestedTab ? 'tested-activities-container' : 'all-activities-container';
|
|
2150
|
+
const itemClass = isTestedTab ? 'tested-activity' : 'all-activity';
|
|
2151
|
+
const paginationId = isTestedTab ? 'tested-pagination' : 'all-pagination';
|
|
2152
|
+
const pageSizeSelectId = isTestedTab ? 'tested-page-size' : 'all-page-size';
|
|
2153
|
+
|
|
2154
|
+
const container = document.getElementById(containerId);
|
|
2155
|
+
const items = Array.from(container.getElementsByClassName(itemClass));
|
|
2156
|
+
|
|
2157
|
+
items.sort(function(a, b) {
|
|
2158
|
+
const badgeA = a.querySelector('.traversal-badge');
|
|
2159
|
+
const badgeB = b.querySelector('.traversal-badge');
|
|
2160
|
+
|
|
2161
|
+
// Extract traversal count from badge text like "👁 5 times"
|
|
2162
|
+
const valueA = badgeA ? parseInt(badgeA.textContent.match(/\d+/)[0]) || 0 : 0;
|
|
2163
|
+
const valueB = badgeB ? parseInt(badgeB.textContent.match(/\d+/)[0]) || 0 : 0;
|
|
2164
|
+
|
|
2165
|
+
if (order === 'asc') {
|
|
2166
|
+
return valueA - valueB;
|
|
2167
|
+
} else {
|
|
2168
|
+
return valueB - valueA;
|
|
2169
|
+
}
|
|
2170
|
+
});
|
|
2171
|
+
|
|
2172
|
+
// Clear container and append sorted items
|
|
2173
|
+
container.innerHTML = '';
|
|
2174
|
+
items.forEach(function(item) {
|
|
2175
|
+
container.appendChild(item);
|
|
2176
|
+
});
|
|
2177
|
+
|
|
2178
|
+
// Check if there's an active search and reapply it
|
|
2179
|
+
const searchInputId = isTestedTab ? 'tested-activity-search' : 'all-activity-search';
|
|
2180
|
+
const searchInput = document.getElementById(searchInputId);
|
|
2181
|
+
if (searchInput && searchInput.value.trim() !== '') {
|
|
2182
|
+
// Reapply search filter after sorting
|
|
2183
|
+
performActivitySearch(searchInput);
|
|
2184
|
+
} else {
|
|
2185
|
+
// No active search, just re-initialize pagination
|
|
2186
|
+
initPagination(containerId, itemClass, paginationId, pageSizeSelectId);
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
|
|
1390
2191
|
// Simplified sorting function for Fails and Errors columns
|
|
1391
2192
|
function initSorting() {
|
|
1392
2193
|
const sortIcons = document.querySelectorAll('.sort-icon');
|
|
@@ -1458,9 +2259,24 @@
|
|
|
1458
2259
|
// Function to handle page navigation
|
|
1459
2260
|
function goToPage(pageNumber, containerId, itemClass, itemsPerPage, paginationId) {
|
|
1460
2261
|
const container = document.getElementById(containerId);
|
|
1461
|
-
const
|
|
2262
|
+
const allItems = Array.from(container.getElementsByClassName(itemClass));
|
|
1462
2263
|
const paginationElement = document.getElementById(paginationId);
|
|
1463
2264
|
|
|
2265
|
+
console.log('goToPage called with:', {pageNumber, containerId, itemClass, itemsPerPage, paginationId});
|
|
2266
|
+
console.log('Total items found:', allItems.length);
|
|
2267
|
+
|
|
2268
|
+
// Get items that should be visible based on search filter
|
|
2269
|
+
const filteredItems = allItems.filter(item => {
|
|
2270
|
+
const searchVisible = item.getAttribute('data-search-visible');
|
|
2271
|
+
const shouldShow = searchVisible === null || searchVisible === 'true';
|
|
2272
|
+
return shouldShow;
|
|
2273
|
+
});
|
|
2274
|
+
|
|
2275
|
+
console.log('Filtered items count:', filteredItems.length);
|
|
2276
|
+
console.log('Items with search-visible=true:', allItems.filter(item => item.getAttribute('data-search-visible') === 'true').length);
|
|
2277
|
+
console.log('Items with search-visible=false:', allItems.filter(item => item.getAttribute('data-search-visible') === 'false').length);
|
|
2278
|
+
console.log('Items with search-visible=null:', allItems.filter(item => item.getAttribute('data-search-visible') === null).length);
|
|
2279
|
+
|
|
1464
2280
|
// Update pagination active state
|
|
1465
2281
|
if (paginationElement) {
|
|
1466
2282
|
const pageItems = paginationElement.getElementsByClassName('page-item');
|
|
@@ -1471,33 +2287,28 @@
|
|
|
1471
2287
|
pageItems[i].className = 'page-item';
|
|
1472
2288
|
}
|
|
1473
2289
|
}
|
|
1474
|
-
|
|
1475
|
-
// Update prev/next buttons
|
|
1476
|
-
if (pageNumber === 1) {
|
|
1477
|
-
paginationElement.firstChild.className = 'page-item disabled';
|
|
1478
|
-
} else {
|
|
1479
|
-
paginationElement.firstChild.className = 'page-item';
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
const totalPages = Math.ceil(items.length / itemsPerPage);
|
|
1483
|
-
if (pageNumber === totalPages) {
|
|
1484
|
-
paginationElement.lastChild.className = 'page-item disabled';
|
|
1485
|
-
} else {
|
|
1486
|
-
paginationElement.lastChild.className = 'page-item';
|
|
1487
|
-
}
|
|
1488
2290
|
}
|
|
1489
2291
|
|
|
1490
|
-
//
|
|
2292
|
+
// Hide all items first
|
|
2293
|
+
console.log('Hiding all items...');
|
|
2294
|
+
allItems.forEach((item, index) => {
|
|
2295
|
+
item.style.display = 'none';
|
|
2296
|
+
});
|
|
2297
|
+
|
|
2298
|
+
// Show items for current page (only from filtered items)
|
|
1491
2299
|
const startIndex = (pageNumber - 1) * itemsPerPage;
|
|
1492
|
-
const endIndex = Math.min(startIndex + itemsPerPage,
|
|
2300
|
+
const endIndex = Math.min(startIndex + itemsPerPage, filteredItems.length);
|
|
1493
2301
|
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
2302
|
+
console.log('Showing items from index', startIndex, 'to', endIndex - 1);
|
|
2303
|
+
|
|
2304
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
2305
|
+
if (filteredItems[i]) {
|
|
2306
|
+
filteredItems[i].style.display = '';
|
|
2307
|
+
console.log('Showing item', i, ':', filteredItems[i].querySelector('.activity-name')?.textContent);
|
|
1499
2308
|
}
|
|
1500
2309
|
}
|
|
2310
|
+
|
|
2311
|
+
console.log('goToPage completed');
|
|
1501
2312
|
}
|
|
1502
2313
|
|
|
1503
2314
|
// Pagination function
|
|
@@ -1506,22 +2317,33 @@
|
|
|
1506
2317
|
const pageSizeSelect = document.getElementById(pageSizeSelectId);
|
|
1507
2318
|
if (!container) return;
|
|
1508
2319
|
|
|
1509
|
-
//
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
// Add event listener for page size changes
|
|
1513
|
-
if (pageSizeSelect) {
|
|
2320
|
+
// Remove existing event listener to prevent duplicate bindings
|
|
2321
|
+
if (pageSizeSelect && !pageSizeSelect.hasAttribute('data-listener-bound')) {
|
|
1514
2322
|
pageSizeSelect.addEventListener('change', function() {
|
|
1515
|
-
|
|
2323
|
+
const newItemsPerPage = parseInt(this.value);
|
|
1516
2324
|
renderPagination();
|
|
1517
|
-
goToPage(1, containerId, itemClass,
|
|
2325
|
+
goToPage(1, containerId, itemClass, newItemsPerPage, paginationId);
|
|
1518
2326
|
});
|
|
2327
|
+
// Mark as having listener bound
|
|
2328
|
+
pageSizeSelect.setAttribute('data-listener-bound', 'true');
|
|
1519
2329
|
}
|
|
1520
2330
|
|
|
1521
2331
|
function renderPagination() {
|
|
1522
|
-
const
|
|
1523
|
-
|
|
1524
|
-
|
|
2332
|
+
const allItems = Array.from(container.getElementsByClassName(itemClass));
|
|
2333
|
+
|
|
2334
|
+
// Always get current page size from select element
|
|
2335
|
+
const currentPageSizeSelect = document.getElementById(pageSizeSelectId);
|
|
2336
|
+
const currentItemsPerPage = currentPageSizeSelect ? parseInt(currentPageSizeSelect.value) : 10;
|
|
2337
|
+
|
|
2338
|
+
// Use same filtering logic as goToPage function
|
|
2339
|
+
const filteredItems = allItems.filter(item => {
|
|
2340
|
+
const searchVisible = item.getAttribute('data-search-visible');
|
|
2341
|
+
// If no search filter is applied, show all items
|
|
2342
|
+
return searchVisible === null || searchVisible === 'true';
|
|
2343
|
+
});
|
|
2344
|
+
|
|
2345
|
+
const totalItems = filteredItems.length;
|
|
2346
|
+
const totalPages = Math.max(1, Math.ceil(totalItems / currentItemsPerPage));
|
|
1525
2347
|
|
|
1526
2348
|
// Create pagination
|
|
1527
2349
|
const paginationElement = document.getElementById(paginationId);
|
|
@@ -1530,6 +2352,22 @@
|
|
|
1530
2352
|
// Clear pagination
|
|
1531
2353
|
paginationElement.innerHTML = '';
|
|
1532
2354
|
|
|
2355
|
+
// Don't show pagination if there's only one page or no items
|
|
2356
|
+
if (totalPages <= 1) {
|
|
2357
|
+
// Hide the entire pagination container when not needed
|
|
2358
|
+
const paginationContainer = paginationElement.closest('.pagination-container');
|
|
2359
|
+
if (paginationContainer) {
|
|
2360
|
+
paginationContainer.style.display = 'none';
|
|
2361
|
+
}
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
// Show the pagination container when needed
|
|
2366
|
+
const paginationContainer = paginationElement.closest('.pagination-container');
|
|
2367
|
+
if (paginationContainer) {
|
|
2368
|
+
paginationContainer.style.display = '';
|
|
2369
|
+
}
|
|
2370
|
+
|
|
1533
2371
|
// Previous button
|
|
1534
2372
|
const prevLi = document.createElement('li');
|
|
1535
2373
|
prevLi.className = 'page-item disabled';
|
|
@@ -1543,7 +2381,7 @@
|
|
|
1543
2381
|
pageLi.innerHTML = `<a class="page-link" href="#">${i}</a>`;
|
|
1544
2382
|
pageLi.addEventListener('click', function(e) {
|
|
1545
2383
|
e.preventDefault();
|
|
1546
|
-
goToPage(i, containerId, itemClass,
|
|
2384
|
+
goToPage(i, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
1547
2385
|
});
|
|
1548
2386
|
paginationElement.appendChild(pageLi);
|
|
1549
2387
|
}
|
|
@@ -1562,7 +2400,7 @@
|
|
|
1562
2400
|
if (activePage && activePage.previousElementSibling && activePage.previousElementSibling.previousElementSibling) {
|
|
1563
2401
|
const pageNum = parseInt(activePage.textContent) - 1;
|
|
1564
2402
|
if (pageNum >= 1) {
|
|
1565
|
-
goToPage(pageNum, containerId, itemClass,
|
|
2403
|
+
goToPage(pageNum, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
1566
2404
|
}
|
|
1567
2405
|
}
|
|
1568
2406
|
});
|
|
@@ -1574,9 +2412,8 @@
|
|
|
1574
2412
|
const activePage = paginationElement.querySelector('.active');
|
|
1575
2413
|
if (activePage && activePage.nextElementSibling && activePage.nextElementSibling.nextElementSibling) {
|
|
1576
2414
|
const pageNum = parseInt(activePage.textContent) + 1;
|
|
1577
|
-
const totalPages = Math.ceil(container.getElementsByClassName(itemClass).length / itemsPerPage);
|
|
1578
2415
|
if (pageNum <= totalPages) {
|
|
1579
|
-
goToPage(pageNum, containerId, itemClass,
|
|
2416
|
+
goToPage(pageNum, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
1580
2417
|
}
|
|
1581
2418
|
}
|
|
1582
2419
|
});
|
|
@@ -1585,7 +2422,9 @@
|
|
|
1585
2422
|
|
|
1586
2423
|
// Initial render
|
|
1587
2424
|
renderPagination();
|
|
1588
|
-
goToPage
|
|
2425
|
+
// Always call goToPage to ensure items are displayed correctly, even if no pagination is shown
|
|
2426
|
+
const currentItemsPerPage = pageSizeSelect ? parseInt(pageSizeSelect.value) : 10;
|
|
2427
|
+
goToPage(1, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
1589
2428
|
}
|
|
1590
2429
|
|
|
1591
2430
|
// Scroll functionality
|
|
@@ -1648,7 +2487,683 @@
|
|
|
1648
2487
|
|
|
1649
2488
|
// Call beautify function after DOM is ready
|
|
1650
2489
|
beautifyScreenshotCaptions();
|
|
2490
|
+
|
|
2491
|
+
// Crash analysis functions
|
|
2492
|
+
function initCrashAnalysis() {
|
|
2493
|
+
// Initialize event filtering
|
|
2494
|
+
var filterButtons = document.querySelectorAll('input[name="event-filter"]');
|
|
2495
|
+
filterButtons.forEach(function(button) {
|
|
2496
|
+
button.addEventListener('change', function() {
|
|
2497
|
+
filterCrashEvents(this.id);
|
|
2498
|
+
});
|
|
2499
|
+
});
|
|
2500
|
+
|
|
2501
|
+
// Initialize copy buttons for stack traces
|
|
2502
|
+
var copyButtons = document.querySelectorAll('.copy-stack-btn');
|
|
2503
|
+
copyButtons.forEach(function(button) {
|
|
2504
|
+
button.addEventListener('click', function() {
|
|
2505
|
+
var stackIndex = this.dataset.stackIndex;
|
|
2506
|
+
copyStackTrace(stackIndex);
|
|
2507
|
+
});
|
|
2508
|
+
});
|
|
2509
|
+
|
|
2510
|
+
// Initialize page size selector for crash events
|
|
2511
|
+
var pageSizeSelect = document.getElementById('events-page-size');
|
|
2512
|
+
if (pageSizeSelect) {
|
|
2513
|
+
pageSizeSelect.addEventListener('change', function() {
|
|
2514
|
+
updateCrashEventsPagination();
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
// Initialize pagination for crash events
|
|
2519
|
+
updateCrashEventsPagination();
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
function filterCrashEvents(filterType) {
|
|
2523
|
+
// Simply update pagination, which will handle filtering and display
|
|
2524
|
+
updateCrashEventsPagination();
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
function updateCrashEventsPagination() {
|
|
2528
|
+
var container = document.getElementById('crash-events-container');
|
|
2529
|
+
var pagination = document.getElementById('events-pagination');
|
|
2530
|
+
var pageSizeSelect = document.getElementById('events-page-size');
|
|
2531
|
+
|
|
2532
|
+
if (!container || !pagination || !pageSizeSelect) return;
|
|
2533
|
+
|
|
2534
|
+
// Get all rows and determine which should be visible based on current filter
|
|
2535
|
+
var allRows = Array.from(container.querySelectorAll('.event-row'));
|
|
2536
|
+
var currentFilter = getCurrentEventFilter();
|
|
2537
|
+
|
|
2538
|
+
var visibleRows = allRows.filter(function(row) {
|
|
2539
|
+
var rowType = row.dataset.type;
|
|
2540
|
+
switch(currentFilter) {
|
|
2541
|
+
case 'all-events':
|
|
2542
|
+
return true;
|
|
2543
|
+
case 'crashes-only':
|
|
2544
|
+
return rowType === 'crash';
|
|
2545
|
+
case 'anr-only':
|
|
2546
|
+
return rowType === 'anr';
|
|
2547
|
+
default:
|
|
2548
|
+
return true;
|
|
2549
|
+
}
|
|
2550
|
+
});
|
|
2551
|
+
|
|
2552
|
+
var pageSize = parseInt(pageSizeSelect.value) || 10;
|
|
2553
|
+
var totalPages = Math.ceil(visibleRows.length / pageSize);
|
|
2554
|
+
var currentPage = 1;
|
|
2555
|
+
|
|
2556
|
+
// Hide all rows first
|
|
2557
|
+
allRows.forEach(function(row) {
|
|
2558
|
+
row.style.display = 'none';
|
|
2559
|
+
var detailRow = row.nextElementSibling;
|
|
2560
|
+
if (detailRow && detailRow.classList.contains('collapse')) {
|
|
2561
|
+
detailRow.style.display = 'none';
|
|
2562
|
+
}
|
|
2563
|
+
});
|
|
2564
|
+
|
|
2565
|
+
// Show rows for current page
|
|
2566
|
+
var startIndex = (currentPage - 1) * pageSize;
|
|
2567
|
+
var endIndex = Math.min(startIndex + pageSize, visibleRows.length);
|
|
2568
|
+
|
|
2569
|
+
for (var i = startIndex; i < endIndex; i++) {
|
|
2570
|
+
visibleRows[i].style.display = '';
|
|
2571
|
+
var detailRow = visibleRows[i].nextElementSibling;
|
|
2572
|
+
if (detailRow && detailRow.classList.contains('collapse')) {
|
|
2573
|
+
detailRow.style.display = '';
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
|
|
2577
|
+
// Store current state for pagination callback
|
|
2578
|
+
window.crashEventsState = {
|
|
2579
|
+
visibleRows: visibleRows,
|
|
2580
|
+
pageSize: pageSize,
|
|
2581
|
+
totalPages: totalPages
|
|
2582
|
+
};
|
|
2583
|
+
|
|
2584
|
+
// Update pagination controls
|
|
2585
|
+
updatePaginationControls('events-pagination', currentPage, totalPages, function(page) {
|
|
2586
|
+
showCrashEventsPage(page, window.crashEventsState.visibleRows, window.crashEventsState.pageSize);
|
|
2587
|
+
});
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
function showCrashEventsPage(page, visibleRows, pageSize) {
|
|
2591
|
+
// Hide all visible rows
|
|
2592
|
+
visibleRows.forEach(function(row) {
|
|
2593
|
+
row.style.display = 'none';
|
|
2594
|
+
var detailRow = row.nextElementSibling;
|
|
2595
|
+
if (detailRow && detailRow.classList.contains('collapse')) {
|
|
2596
|
+
detailRow.style.display = 'none';
|
|
2597
|
+
}
|
|
2598
|
+
});
|
|
2599
|
+
|
|
2600
|
+
// Show rows for the specified page
|
|
2601
|
+
var startIndex = (page - 1) * pageSize;
|
|
2602
|
+
var endIndex = Math.min(startIndex + pageSize, visibleRows.length);
|
|
2603
|
+
|
|
2604
|
+
for (var i = startIndex; i < endIndex; i++) {
|
|
2605
|
+
visibleRows[i].style.display = '';
|
|
2606
|
+
var detailRow = visibleRows[i].nextElementSibling;
|
|
2607
|
+
if (detailRow && detailRow.classList.contains('collapse')) {
|
|
2608
|
+
detailRow.style.display = '';
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
// Update pagination controls to reflect current page
|
|
2613
|
+
var totalPages = Math.ceil(visibleRows.length / pageSize);
|
|
2614
|
+
var pagination = document.getElementById('events-pagination');
|
|
2615
|
+
if (pagination) {
|
|
2616
|
+
// Update active page
|
|
2617
|
+
var pageItems = pagination.querySelectorAll('.page-item');
|
|
2618
|
+
pageItems.forEach(function(item, index) {
|
|
2619
|
+
// Skip first (previous) and last (next) buttons
|
|
2620
|
+
if (index > 0 && index < pageItems.length - 1) {
|
|
2621
|
+
var pageNum = parseInt(item.textContent);
|
|
2622
|
+
if (pageNum === page) {
|
|
2623
|
+
item.classList.add('active');
|
|
2624
|
+
} else {
|
|
2625
|
+
item.classList.remove('active');
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
});
|
|
2629
|
+
|
|
2630
|
+
// Update previous button state
|
|
2631
|
+
if (pageItems.length > 0) {
|
|
2632
|
+
var prevButton = pageItems[0];
|
|
2633
|
+
if (page === 1) {
|
|
2634
|
+
prevButton.classList.add('disabled');
|
|
2635
|
+
} else {
|
|
2636
|
+
prevButton.classList.remove('disabled');
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
// Update next button state
|
|
2641
|
+
if (pageItems.length > 1) {
|
|
2642
|
+
var nextButton = pageItems[pageItems.length - 1];
|
|
2643
|
+
if (page === totalPages) {
|
|
2644
|
+
nextButton.classList.add('disabled');
|
|
2645
|
+
} else {
|
|
2646
|
+
nextButton.classList.remove('disabled');
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
|
|
2652
|
+
function getCurrentEventFilter() {
|
|
2653
|
+
var filterButtons = document.querySelectorAll('input[name="event-filter"]');
|
|
2654
|
+
for (var i = 0; i < filterButtons.length; i++) {
|
|
2655
|
+
if (filterButtons[i].checked) {
|
|
2656
|
+
return filterButtons[i].id;
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
return 'all-events'; // default
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
function updatePaginationControls(paginationId, currentPage, totalPages, onPageClick) {
|
|
2663
|
+
var pagination = document.getElementById(paginationId);
|
|
2664
|
+
if (!pagination) return;
|
|
2665
|
+
|
|
2666
|
+
pagination.innerHTML = '';
|
|
2667
|
+
|
|
2668
|
+
if (totalPages <= 1) {
|
|
2669
|
+
// Hide the entire pagination container when not needed
|
|
2670
|
+
var paginationContainer = pagination.closest('.pagination-container');
|
|
2671
|
+
if (paginationContainer) {
|
|
2672
|
+
paginationContainer.style.display = 'none';
|
|
2673
|
+
}
|
|
2674
|
+
return;
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
// Show the pagination container when needed
|
|
2678
|
+
var paginationContainer = pagination.closest('.pagination-container');
|
|
2679
|
+
if (paginationContainer) {
|
|
2680
|
+
paginationContainer.style.display = '';
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
// Previous button
|
|
2684
|
+
var prevLi = document.createElement('li');
|
|
2685
|
+
prevLi.className = 'page-item' + (currentPage === 1 ? ' disabled' : '');
|
|
2686
|
+
var prevLink = document.createElement('a');
|
|
2687
|
+
prevLink.className = 'page-link';
|
|
2688
|
+
prevLink.href = '#';
|
|
2689
|
+
prevLink.setAttribute('aria-label', 'Previous');
|
|
2690
|
+
prevLink.innerHTML = '<span aria-hidden="true">«</span>';
|
|
2691
|
+
|
|
2692
|
+
prevLink.addEventListener('click', function(e) {
|
|
2693
|
+
e.preventDefault();
|
|
2694
|
+
e.stopPropagation();
|
|
2695
|
+
// Get current page dynamically to avoid stale closure values
|
|
2696
|
+
var currentActivePage = getCurrentPageNumber(paginationId);
|
|
2697
|
+
if (currentActivePage > 1 && !prevLi.classList.contains('disabled')) {
|
|
2698
|
+
onPageClick(currentActivePage - 1);
|
|
2699
|
+
}
|
|
2700
|
+
});
|
|
2701
|
+
|
|
2702
|
+
prevLi.appendChild(prevLink);
|
|
2703
|
+
pagination.appendChild(prevLi);
|
|
2704
|
+
|
|
2705
|
+
// Page numbers
|
|
2706
|
+
for (var i = 1; i <= totalPages; i++) {
|
|
2707
|
+
var li = document.createElement('li');
|
|
2708
|
+
li.className = 'page-item' + (i === currentPage ? ' active' : '');
|
|
2709
|
+
var link = document.createElement('a');
|
|
2710
|
+
link.className = 'page-link';
|
|
2711
|
+
link.href = '#';
|
|
2712
|
+
link.textContent = i;
|
|
2713
|
+
link.addEventListener('click', (function(page) {
|
|
2714
|
+
return function(e) {
|
|
2715
|
+
e.preventDefault();
|
|
2716
|
+
e.stopPropagation();
|
|
2717
|
+
onPageClick(page);
|
|
2718
|
+
};
|
|
2719
|
+
})(i));
|
|
2720
|
+
li.appendChild(link);
|
|
2721
|
+
pagination.appendChild(li);
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
// Next button
|
|
2725
|
+
var nextLi = document.createElement('li');
|
|
2726
|
+
nextLi.className = 'page-item' + (currentPage === totalPages ? ' disabled' : '');
|
|
2727
|
+
var nextLink = document.createElement('a');
|
|
2728
|
+
nextLink.className = 'page-link';
|
|
2729
|
+
nextLink.href = '#';
|
|
2730
|
+
nextLink.setAttribute('aria-label', 'Next');
|
|
2731
|
+
nextLink.innerHTML = '<span aria-hidden="true">»</span>';
|
|
2732
|
+
|
|
2733
|
+
nextLink.addEventListener('click', function(e) {
|
|
2734
|
+
e.preventDefault();
|
|
2735
|
+
e.stopPropagation();
|
|
2736
|
+
// Get current page dynamically to avoid stale closure values
|
|
2737
|
+
var currentActivePage = getCurrentPageNumber(paginationId);
|
|
2738
|
+
if (currentActivePage < totalPages && !nextLi.classList.contains('disabled')) {
|
|
2739
|
+
onPageClick(currentActivePage + 1);
|
|
2740
|
+
}
|
|
2741
|
+
});
|
|
2742
|
+
|
|
2743
|
+
nextLi.appendChild(nextLink);
|
|
2744
|
+
pagination.appendChild(nextLi);
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
function getCurrentPageNumber(paginationId) {
|
|
2748
|
+
var pagination = document.getElementById(paginationId);
|
|
2749
|
+
if (!pagination) return 1;
|
|
2750
|
+
|
|
2751
|
+
var activeItem = pagination.querySelector('.page-item.active');
|
|
2752
|
+
if (activeItem) {
|
|
2753
|
+
var pageText = activeItem.textContent.trim();
|
|
2754
|
+
var pageNum = parseInt(pageText);
|
|
2755
|
+
return isNaN(pageNum) ? 1 : pageNum;
|
|
2756
|
+
}
|
|
2757
|
+
return 1;
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2760
|
+
function copyStackTrace(index) {
|
|
2761
|
+
var stackTraceElement = document.getElementById('stack-trace-' + index);
|
|
2762
|
+
if (!stackTraceElement) return;
|
|
2763
|
+
|
|
2764
|
+
var stackTrace = stackTraceElement.textContent;
|
|
2765
|
+
|
|
2766
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
2767
|
+
navigator.clipboard.writeText(stackTrace).then(function() {
|
|
2768
|
+
showCopyNotification('Stack trace copied to clipboard!');
|
|
2769
|
+
}).catch(function(err) {
|
|
2770
|
+
console.error('Failed to copy stack trace: ', err);
|
|
2771
|
+
showCopyNotification('Failed to copy stack trace', 'error');
|
|
2772
|
+
});
|
|
2773
|
+
} else {
|
|
2774
|
+
// Fallback for older browsers
|
|
2775
|
+
var textArea = document.createElement('textarea');
|
|
2776
|
+
textArea.value = stackTrace;
|
|
2777
|
+
document.body.appendChild(textArea);
|
|
2778
|
+
textArea.select();
|
|
2779
|
+
try {
|
|
2780
|
+
document.execCommand('copy');
|
|
2781
|
+
showCopyNotification('Stack trace copied to clipboard!');
|
|
2782
|
+
} catch (err) {
|
|
2783
|
+
console.error('Fallback copy failed: ', err);
|
|
2784
|
+
showCopyNotification('Failed to copy stack trace', 'error');
|
|
2785
|
+
}
|
|
2786
|
+
document.body.removeChild(textArea);
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2790
|
+
function showCopyNotification(message, type) {
|
|
2791
|
+
type = type || 'success';
|
|
2792
|
+
|
|
2793
|
+
// Create notification element
|
|
2794
|
+
var notification = document.createElement('div');
|
|
2795
|
+
notification.className = 'alert alert-' + (type === 'error' ? 'danger' : 'success') + ' position-fixed';
|
|
2796
|
+
notification.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
|
|
2797
|
+
notification.innerHTML = '<i class="bi bi-' + (type === 'error' ? 'exclamation-triangle' : 'check-circle') + '"></i> ' + message;
|
|
2798
|
+
|
|
2799
|
+
document.body.appendChild(notification);
|
|
2800
|
+
|
|
2801
|
+
// Auto remove after 3 seconds
|
|
2802
|
+
setTimeout(function() {
|
|
2803
|
+
if (notification.parentNode) {
|
|
2804
|
+
notification.parentNode.removeChild(notification);
|
|
2805
|
+
}
|
|
2806
|
+
}, 3000);
|
|
2807
|
+
}
|
|
1651
2808
|
});
|
|
2809
|
+
|
|
2810
|
+
// Global activity search functions
|
|
2811
|
+
function performActivitySearch(searchInput) {
|
|
2812
|
+
const searchTerm = searchInput.value.toLowerCase().trim();
|
|
2813
|
+
const containerId = searchInput.dataset.target;
|
|
2814
|
+
const itemClass = searchInput.dataset.itemClass;
|
|
2815
|
+
const paginationId = searchInput.dataset.pagination;
|
|
2816
|
+
const pageSizeSelectId = searchInput.dataset.pageSize;
|
|
2817
|
+
|
|
2818
|
+
const container = document.getElementById(containerId);
|
|
2819
|
+
const items = Array.from(container.getElementsByClassName(itemClass));
|
|
2820
|
+
|
|
2821
|
+
// Filter and count matching items
|
|
2822
|
+
let visibleCount = 0;
|
|
2823
|
+
let totalCount = items.length;
|
|
2824
|
+
|
|
2825
|
+
items.forEach(function(item, index) {
|
|
2826
|
+
const activityName = item.querySelector('.activity-name');
|
|
2827
|
+
if (activityName) {
|
|
2828
|
+
const text = activityName.textContent.toLowerCase();
|
|
2829
|
+
const matches = searchTerm === '' || text.includes(searchTerm);
|
|
2830
|
+
|
|
2831
|
+
if (matches) {
|
|
2832
|
+
item.setAttribute('data-search-visible', 'true');
|
|
2833
|
+
visibleCount++;
|
|
2834
|
+
} else {
|
|
2835
|
+
item.setAttribute('data-search-visible', 'false');
|
|
2836
|
+
}
|
|
2837
|
+
} else {
|
|
2838
|
+
// If no activity name found, hide the item
|
|
2839
|
+
item.setAttribute('data-search-visible', 'false');
|
|
2840
|
+
}
|
|
2841
|
+
});
|
|
2842
|
+
|
|
2843
|
+
// Update search results count
|
|
2844
|
+
updateSearchResultsCount(searchInput, visibleCount, totalCount, searchTerm);
|
|
2845
|
+
|
|
2846
|
+
// Re-initialize pagination and go to first page
|
|
2847
|
+
initPagination(containerId, itemClass, paginationId, pageSizeSelectId);
|
|
2848
|
+
|
|
2849
|
+
// Always go to page 1 after search
|
|
2850
|
+
const currentPageSize = document.getElementById(pageSizeSelectId) ?
|
|
2851
|
+
parseInt(document.getElementById(pageSizeSelectId).value) : 10;
|
|
2852
|
+
|
|
2853
|
+
goToPage(1, containerId, itemClass, currentPageSize, paginationId);
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2856
|
+
function updateSearchResultsCount(searchInput, visibleCount, totalCount, searchTerm) {
|
|
2857
|
+
const isTestedTab = searchInput.id.includes('tested');
|
|
2858
|
+
const resultsElementId = isTestedTab ? 'tested-search-results' : 'all-search-results';
|
|
2859
|
+
const resultsElement = document.getElementById(resultsElementId);
|
|
2860
|
+
|
|
2861
|
+
if (resultsElement) {
|
|
2862
|
+
if (searchTerm === '') {
|
|
2863
|
+
resultsElement.innerHTML = `<span class="text-muted">Showing all ${totalCount} activities - Type and click <i class="bi bi-search"></i> or press Enter to search</span>`;
|
|
2864
|
+
} else if (visibleCount === 0) {
|
|
2865
|
+
resultsElement.innerHTML = `<span class="text-danger">No activities found for "${searchTerm}"</span>`;
|
|
2866
|
+
} else if (visibleCount === totalCount) {
|
|
2867
|
+
resultsElement.innerHTML = `<span class="text-success">All ${totalCount} activities match "${searchTerm}"</span>`;
|
|
2868
|
+
} else {
|
|
2869
|
+
resultsElement.innerHTML = `<span class="text-info">Found ${visibleCount} of ${totalCount} activities for "${searchTerm}"</span>`;
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
// Activity searching function
|
|
2875
|
+
function initActivitySearching() {
|
|
2876
|
+
const searchInputs = document.querySelectorAll('.activity-search-input');
|
|
2877
|
+
const searchButtons = document.querySelectorAll('.search-btn');
|
|
2878
|
+
const clearButtons = document.querySelectorAll('.search-clear-btn');
|
|
2879
|
+
|
|
2880
|
+
// Initialize search functionality for each input
|
|
2881
|
+
searchInputs.forEach(function(input) {
|
|
2882
|
+
// Search on Enter key
|
|
2883
|
+
input.addEventListener('keydown', function(e) {
|
|
2884
|
+
if (e.key === 'Enter') {
|
|
2885
|
+
e.preventDefault();
|
|
2886
|
+
performActivitySearch(this);
|
|
2887
|
+
} else if (e.key === 'Escape') {
|
|
2888
|
+
clearActivitySearch(this);
|
|
2889
|
+
}
|
|
2890
|
+
});
|
|
2891
|
+
});
|
|
2892
|
+
|
|
2893
|
+
// Initialize search button functionality
|
|
2894
|
+
searchButtons.forEach(function(button) {
|
|
2895
|
+
button.addEventListener('click', function() {
|
|
2896
|
+
const targetInputId = this.dataset.target;
|
|
2897
|
+
const targetInput = document.getElementById(targetInputId);
|
|
2898
|
+
if (targetInput) {
|
|
2899
|
+
performActivitySearch(targetInput);
|
|
2900
|
+
}
|
|
2901
|
+
});
|
|
2902
|
+
});
|
|
2903
|
+
|
|
2904
|
+
// Initialize clear button functionality
|
|
2905
|
+
clearButtons.forEach(function(button) {
|
|
2906
|
+
button.addEventListener('click', function() {
|
|
2907
|
+
const targetInputId = this.dataset.target;
|
|
2908
|
+
const targetInput = document.getElementById(targetInputId);
|
|
2909
|
+
if (targetInput) {
|
|
2910
|
+
clearActivitySearch(targetInput);
|
|
2911
|
+
}
|
|
2912
|
+
});
|
|
2913
|
+
});
|
|
2914
|
+
|
|
2915
|
+
function clearActivitySearch(searchInput) {
|
|
2916
|
+
searchInput.value = '';
|
|
2917
|
+
performActivitySearch(searchInput);
|
|
2918
|
+
searchInput.focus();
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
// Property statistics searching function
|
|
2923
|
+
function initPropertySearching() {
|
|
2924
|
+
const searchInput = document.getElementById('property-stats-search');
|
|
2925
|
+
const searchButton = document.querySelector('.search-btn[data-target="property-stats-search"]');
|
|
2926
|
+
const clearButton = document.querySelector('[data-target="property-stats-search"].search-clear-btn');
|
|
2927
|
+
|
|
2928
|
+
if (!searchInput) return;
|
|
2929
|
+
|
|
2930
|
+
// Search on Enter key
|
|
2931
|
+
searchInput.addEventListener('keydown', function(e) {
|
|
2932
|
+
if (e.key === 'Enter') {
|
|
2933
|
+
e.preventDefault();
|
|
2934
|
+
performPropertySearch(this);
|
|
2935
|
+
} else if (e.key === 'Escape') {
|
|
2936
|
+
clearPropertySearch(this);
|
|
2937
|
+
}
|
|
2938
|
+
});
|
|
2939
|
+
|
|
2940
|
+
// Search button functionality
|
|
2941
|
+
if (searchButton) {
|
|
2942
|
+
searchButton.addEventListener('click', function() {
|
|
2943
|
+
performPropertySearch(searchInput);
|
|
2944
|
+
});
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
// Clear button functionality
|
|
2948
|
+
if (clearButton) {
|
|
2949
|
+
clearButton.addEventListener('click', function() {
|
|
2950
|
+
clearPropertySearch(searchInput);
|
|
2951
|
+
});
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2954
|
+
function performPropertySearch(searchInput) {
|
|
2955
|
+
const searchTerm = searchInput.value.toLowerCase().trim();
|
|
2956
|
+
const container = document.getElementById('property-stats-container');
|
|
2957
|
+
const items = Array.from(container.getElementsByClassName('property-stat-row'));
|
|
2958
|
+
|
|
2959
|
+
let visibleCount = 0;
|
|
2960
|
+
let totalCount = items.length;
|
|
2961
|
+
|
|
2962
|
+
// Filter items based on search term
|
|
2963
|
+
items.forEach(function(item) {
|
|
2964
|
+
const propertyNameElement = item.querySelector('.badge-custom');
|
|
2965
|
+
if (propertyNameElement) {
|
|
2966
|
+
const propertyName = propertyNameElement.textContent.toLowerCase();
|
|
2967
|
+
|
|
2968
|
+
if (searchTerm === '' || propertyName.includes(searchTerm)) {
|
|
2969
|
+
item.setAttribute('data-search-visible', 'true');
|
|
2970
|
+
visibleCount++;
|
|
2971
|
+
} else {
|
|
2972
|
+
item.setAttribute('data-search-visible', 'false');
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
});
|
|
2976
|
+
|
|
2977
|
+
// Update search results count
|
|
2978
|
+
updatePropertySearchResults(visibleCount, totalCount, searchTerm);
|
|
2979
|
+
|
|
2980
|
+
// Re-initialize pagination and go to first page
|
|
2981
|
+
initPagination('property-stats-container', 'property-stat-row', 'stats-pagination', 'stats-page-size');
|
|
2982
|
+
|
|
2983
|
+
// Always go to page 1 after search
|
|
2984
|
+
const currentPageSize = document.getElementById('stats-page-size') ?
|
|
2985
|
+
parseInt(document.getElementById('stats-page-size').value) : 10;
|
|
2986
|
+
goToPage(1, 'property-stats-container', 'property-stat-row', currentPageSize, 'stats-pagination');
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
function clearPropertySearch(searchInput) {
|
|
2990
|
+
searchInput.value = '';
|
|
2991
|
+
performPropertySearch(searchInput);
|
|
2992
|
+
searchInput.focus();
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
function updatePropertySearchResults(visibleCount, totalCount, searchTerm) {
|
|
2996
|
+
const resultsElement = document.getElementById('property-search-results');
|
|
2997
|
+
|
|
2998
|
+
if (resultsElement) {
|
|
2999
|
+
if (searchTerm === '') {
|
|
3000
|
+
resultsElement.innerHTML = `<span class="text-muted">Showing all ${totalCount} properties - Type and click <i class="bi bi-search"></i> or press Enter to search</span>`;
|
|
3001
|
+
} else if (visibleCount === 0) {
|
|
3002
|
+
resultsElement.innerHTML = `<span class="text-danger">No properties found for "${searchTerm}"</span>`;
|
|
3003
|
+
} else if (visibleCount === totalCount) {
|
|
3004
|
+
resultsElement.innerHTML = `<span class="text-success">All ${totalCount} properties match "${searchTerm}"</span>`;
|
|
3005
|
+
} else {
|
|
3006
|
+
resultsElement.innerHTML = `<span class="text-info">Found ${visibleCount} of ${totalCount} properties for "${searchTerm}"</span>`;
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
|
|
3012
|
+
// Global pagination and navigation functions
|
|
3013
|
+
function goToPage(pageNumber, containerId, itemClass, itemsPerPage, paginationId) {
|
|
3014
|
+
const container = document.getElementById(containerId);
|
|
3015
|
+
const allItems = Array.from(container.getElementsByClassName(itemClass));
|
|
3016
|
+
const paginationElement = document.getElementById(paginationId);
|
|
3017
|
+
|
|
3018
|
+
// Get items that should be visible based on search filter
|
|
3019
|
+
const filteredItems = allItems.filter(item => {
|
|
3020
|
+
const searchVisible = item.getAttribute('data-search-visible');
|
|
3021
|
+
const shouldShow = searchVisible === null || searchVisible === 'true';
|
|
3022
|
+
return shouldShow;
|
|
3023
|
+
});
|
|
3024
|
+
|
|
3025
|
+
// Update pagination active state
|
|
3026
|
+
if (paginationElement) {
|
|
3027
|
+
const pageItems = paginationElement.getElementsByClassName('page-item');
|
|
3028
|
+
for (let i = 0; i < pageItems.length; i++) {
|
|
3029
|
+
if (pageItems[i].textContent.trim() === pageNumber.toString()) {
|
|
3030
|
+
pageItems[i].className = 'page-item active';
|
|
3031
|
+
} else if (pageItems[i].textContent.trim() !== '«' && pageItems[i].textContent.trim() !== '»') {
|
|
3032
|
+
pageItems[i].className = 'page-item';
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
|
|
3037
|
+
// Hide all items first
|
|
3038
|
+
allItems.forEach((item, index) => {
|
|
3039
|
+
item.style.display = 'none';
|
|
3040
|
+
});
|
|
3041
|
+
|
|
3042
|
+
// Show items for current page (only from filtered items)
|
|
3043
|
+
const startIndex = (pageNumber - 1) * itemsPerPage;
|
|
3044
|
+
const endIndex = Math.min(startIndex + itemsPerPage, filteredItems.length);
|
|
3045
|
+
|
|
3046
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
3047
|
+
if (filteredItems[i]) {
|
|
3048
|
+
filteredItems[i].style.display = '';
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
function initPagination(containerId, itemClass, paginationId, pageSizeSelectId) {
|
|
3054
|
+
const container = document.getElementById(containerId);
|
|
3055
|
+
const pageSizeSelect = document.getElementById(pageSizeSelectId);
|
|
3056
|
+
if (!container) return;
|
|
3057
|
+
|
|
3058
|
+
// Remove existing event listener to prevent duplicate bindings
|
|
3059
|
+
if (pageSizeSelect && !pageSizeSelect.hasAttribute('data-listener-bound')) {
|
|
3060
|
+
pageSizeSelect.addEventListener('change', function() {
|
|
3061
|
+
const newItemsPerPage = parseInt(this.value);
|
|
3062
|
+
renderPagination();
|
|
3063
|
+
goToPage(1, containerId, itemClass, newItemsPerPage, paginationId);
|
|
3064
|
+
});
|
|
3065
|
+
// Mark as having listener bound
|
|
3066
|
+
pageSizeSelect.setAttribute('data-listener-bound', 'true');
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
function renderPagination() {
|
|
3070
|
+
const allItems = Array.from(container.getElementsByClassName(itemClass));
|
|
3071
|
+
|
|
3072
|
+
// Always get current page size from select element
|
|
3073
|
+
const currentPageSizeSelect = document.getElementById(pageSizeSelectId);
|
|
3074
|
+
const currentItemsPerPage = currentPageSizeSelect ? parseInt(currentPageSizeSelect.value) : 10;
|
|
3075
|
+
|
|
3076
|
+
// Use same filtering logic as goToPage function
|
|
3077
|
+
const filteredItems = allItems.filter(item => {
|
|
3078
|
+
const searchVisible = item.getAttribute('data-search-visible');
|
|
3079
|
+
// If no search filter is applied, show all items
|
|
3080
|
+
return searchVisible === null || searchVisible === 'true';
|
|
3081
|
+
});
|
|
3082
|
+
|
|
3083
|
+
const totalItems = filteredItems.length;
|
|
3084
|
+
const totalPages = Math.max(1, Math.ceil(totalItems / currentItemsPerPage));
|
|
3085
|
+
|
|
3086
|
+
// Create pagination
|
|
3087
|
+
const paginationElement = document.getElementById(paginationId);
|
|
3088
|
+
if (!paginationElement) return;
|
|
3089
|
+
|
|
3090
|
+
// Clear pagination
|
|
3091
|
+
paginationElement.innerHTML = '';
|
|
3092
|
+
|
|
3093
|
+
// Don't show pagination if there's only one page or no items
|
|
3094
|
+
if (totalPages <= 1) {
|
|
3095
|
+
// Hide the entire pagination container when not needed
|
|
3096
|
+
const paginationContainer = paginationElement.closest('.pagination-container');
|
|
3097
|
+
if (paginationContainer) {
|
|
3098
|
+
paginationContainer.style.display = 'none';
|
|
3099
|
+
}
|
|
3100
|
+
return;
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
// Show the pagination container when needed
|
|
3104
|
+
const paginationContainer = paginationElement.closest('.pagination-container');
|
|
3105
|
+
if (paginationContainer) {
|
|
3106
|
+
paginationContainer.style.display = '';
|
|
3107
|
+
}
|
|
3108
|
+
|
|
3109
|
+
// Previous button
|
|
3110
|
+
const prevLi = document.createElement('li');
|
|
3111
|
+
prevLi.className = 'page-item disabled';
|
|
3112
|
+
prevLi.innerHTML = '<a class="page-link" href="#" aria-label="Previous"><span aria-hidden="true">«</span></a>';
|
|
3113
|
+
paginationElement.appendChild(prevLi);
|
|
3114
|
+
|
|
3115
|
+
// Add page numbers
|
|
3116
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
3117
|
+
const pageLi = document.createElement('li');
|
|
3118
|
+
pageLi.className = i === 1 ? 'page-item active' : 'page-item';
|
|
3119
|
+
pageLi.innerHTML = `<a class="page-link" href="#">${i}</a>`;
|
|
3120
|
+
pageLi.addEventListener('click', function(e) {
|
|
3121
|
+
e.preventDefault();
|
|
3122
|
+
goToPage(i, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
3123
|
+
});
|
|
3124
|
+
paginationElement.appendChild(pageLi);
|
|
3125
|
+
}
|
|
3126
|
+
|
|
3127
|
+
// Next button
|
|
3128
|
+
const nextLi = document.createElement('li');
|
|
3129
|
+
nextLi.className = totalPages <= 1 ? 'page-item disabled' : 'page-item';
|
|
3130
|
+
nextLi.innerHTML = '<a class="page-link" href="#" aria-label="Next"><span aria-hidden="true">»</span></a>';
|
|
3131
|
+
paginationElement.appendChild(nextLi);
|
|
3132
|
+
|
|
3133
|
+
// Add event listeners to prev/next buttons
|
|
3134
|
+
if (paginationElement.firstChild) {
|
|
3135
|
+
paginationElement.firstChild.addEventListener('click', function(e) {
|
|
3136
|
+
e.preventDefault();
|
|
3137
|
+
const activePage = paginationElement.querySelector('.active');
|
|
3138
|
+
if (activePage && activePage.previousElementSibling && activePage.previousElementSibling.previousElementSibling) {
|
|
3139
|
+
const pageNum = parseInt(activePage.textContent) - 1;
|
|
3140
|
+
if (pageNum >= 1) {
|
|
3141
|
+
goToPage(pageNum, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
});
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
if (paginationElement.lastChild) {
|
|
3148
|
+
paginationElement.lastChild.addEventListener('click', function(e) {
|
|
3149
|
+
e.preventDefault();
|
|
3150
|
+
const activePage = paginationElement.querySelector('.active');
|
|
3151
|
+
if (activePage && activePage.nextElementSibling && activePage.nextElementSibling.nextElementSibling) {
|
|
3152
|
+
const pageNum = parseInt(activePage.textContent) + 1;
|
|
3153
|
+
if (pageNum <= totalPages) {
|
|
3154
|
+
goToPage(pageNum, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
});
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
// Initial render
|
|
3162
|
+
renderPagination();
|
|
3163
|
+
// Always call goToPage to ensure items are displayed correctly, even if no pagination is shown
|
|
3164
|
+
const currentItemsPerPage = pageSizeSelect ? parseInt(pageSizeSelect.value) : 10;
|
|
3165
|
+
goToPage(1, containerId, itemClass, currentItemsPerPage, paginationId);
|
|
3166
|
+
}
|
|
1652
3167
|
</script>
|
|
1653
3168
|
</body>
|
|
1654
3169
|
</html>
|