@@ -35,6 +35,9 @@ import { StatusCode } from '../common/status-code';
35
35
import { HEADER_FOOTER_HEIGHT } from './view-event-list-footer' ;
36
36
import { ViewEventContextMenuBuilder } from './view-context-menu-builder' ;
37
37
38
+ const USE_MULTI_SELECT_CHECKBOXES = false ; // if this is enabled then a checkbox is shown when multi-select is enabled to allow controlling the checked rows that way rather than using the list directly
39
+ const MULTI_SELECT_ROW_CLASSNAME = "multiSelected" ;
40
+
38
41
const SCROLL_BOTTOM_MARGIN = 5 ; // If you're in the last 5 pixels of the scroll area, we say you're at the bottom
39
42
40
43
const EmptyStateOverlay = styled ( EmptyState ) `
@@ -52,6 +55,8 @@ interface ViewEventListProps {
52
55
filteredEvents : CollectedEvent [ ] ;
53
56
selectedEvent : CollectedEvent | undefined ;
54
57
isPaused : boolean ;
58
+ isMultiSelectEnabled : boolean ;
59
+ onMultiSelectToggled : ( ) => void ;
55
60
56
61
contextMenuBuilder : ViewEventContextMenuBuilder ;
57
62
@@ -156,6 +161,15 @@ const Status = styled(Column)`
156
161
flex-shrink: 0;
157
162
flex-grow: 0;
158
163
` ;
164
+ const MultiSelect = styled ( Column ) `
165
+ flex-basis: 20px;
166
+ ${ ( p : { isMultiSelectEnabled : boolean } ) => p . isMultiSelectEnabled && USE_MULTI_SELECT_CHECKBOXES ? "margin-right: 25px !important;" : "margin-right: 15px !important;" }
167
+ flex-shrink: 0;
168
+ margin-left: -20px !important;
169
+
170
+ title: "Multi-select events";
171
+ flex-grow: 0;
172
+ ` ;
159
173
160
174
const Source = styled ( Column ) `
161
175
flex-basis: 49px;
@@ -229,6 +243,10 @@ const EventListRow = styled.div`
229
243
user-select: none;
230
244
cursor: pointer;
231
245
246
+ &.multiSelected {
247
+ background-color: ${ p => p . theme . highlightBackground } ;
248
+ color: ${ p => p . theme . highlightColor } ;
249
+ }
232
250
&.selected {
233
251
background-color: ${ p => p . theme . highlightBackground } ;
234
252
color: ${ p => p . theme . highlightColor } ;
@@ -322,6 +340,7 @@ interface EventRowProps extends ListChildComponentProps {
322
340
selectedEvent : CollectedEvent | undefined ;
323
341
events : CollectedEvent [ ] ;
324
342
contextMenuBuilder : ViewEventContextMenuBuilder ;
343
+ isMultiSelectEnabled : boolean ;
325
344
}
326
345
}
327
346
@@ -352,6 +371,7 @@ const EventRow = observer((props: EventRowProps) => {
352
371
return < ExchangeRow
353
372
index = { index }
354
373
isSelected = { isSelected }
374
+ isMultiSelectEnabled = { props . data . isMultiSelectEnabled }
355
375
style = { style }
356
376
exchange = { event }
357
377
contextMenuBuilder = { contextMenuBuilder }
@@ -376,15 +396,31 @@ const EventRow = observer((props: EventRowProps) => {
376
396
}
377
397
} ) ;
378
398
399
+ interface RowCheckboxProps {
400
+ checked :boolean ;
401
+ whenChecked : React . ChangeEventHandler < HTMLInputElement > ;
402
+ isMultiSelectEnabled : boolean ;
403
+ }
404
+
405
+
406
+ const RowCheckbox = styled . input . attrs ( ( props : RowCheckboxProps ) => ( {
407
+ type : "checkbox" , checked : props . checked , onChange : props . whenChecked
408
+
409
+ } ) ) < RowCheckboxProps > `
410
+ ${ props => props . isMultiSelectEnabled && USE_MULTI_SELECT_CHECKBOXES ? `` : `width: 0 !important;` }
411
+ ` ;
412
+
379
413
const ExchangeRow = inject ( 'uiStore' ) ( observer ( ( {
380
414
index,
381
415
isSelected,
382
416
style,
383
417
exchange,
384
- contextMenuBuilder
418
+ contextMenuBuilder,
419
+ isMultiSelectEnabled
385
420
} : {
386
421
index : number ,
387
422
isSelected : boolean ,
423
+ isMultiSelectEnabled : boolean ,
388
424
style : { } ,
389
425
exchange : HttpExchange ,
390
426
contextMenuBuilder : ViewEventContextMenuBuilder
@@ -403,10 +439,11 @@ const ExchangeRow = inject('uiStore')(observer(({
403
439
data-event-id = { exchange . id }
404
440
tabIndex = { isSelected ? 0 : - 1 }
405
441
onContextMenu = { contextMenuBuilder . getContextMenuCallback ( exchange ) }
406
- className = { isSelected ? 'selected' : '' }
442
+ className = { isSelected ? 'selected' : exchange . mulitSelected ? MULTI_SELECT_ROW_CLASSNAME : '' }
407
443
style = { style }
408
444
>
409
445
< RowPin pinned = { pinned } />
446
+ < RowCheckbox checked = { exchange . mulitSelected } whenChecked = { exchange . onMultiSelected } isMultiSelectEnabled = { isMultiSelectEnabled } />
410
447
< RowMarker category = { category } title = { describeEventCategory ( category ) } />
411
448
< Method pinned = { pinned } > { request . method } </ Method >
412
449
< Status >
@@ -492,7 +529,7 @@ const RTCConnectionRow = observer(({
492
529
data-event-id = { event . id }
493
530
tabIndex = { isSelected ? 0 : - 1 }
494
531
495
- className = { isSelected ? 'selected' : '' }
532
+ className = { isSelected ? 'selected' : event . mulitSelected ? MULTI_SELECT_ROW_CLASSNAME : '' }
496
533
style = { style }
497
534
>
498
535
< RowPin pinned = { pinned } />
@@ -536,7 +573,7 @@ const RTCStreamRow = observer(({
536
573
data-event-id = { event . id }
537
574
tabIndex = { isSelected ? 0 : - 1 }
538
575
539
- className = { isSelected ? 'selected' : '' }
576
+ className = { isSelected ? 'selected' : event . mulitSelected ? MULTI_SELECT_ROW_CLASSNAME : '' }
540
577
style = { style }
541
578
>
542
579
< RowPin pinned = { pinned } />
@@ -604,7 +641,7 @@ const BuiltInApiRow = observer((p: {
604
641
tabIndex = { p . isSelected ? 0 : - 1 }
605
642
606
643
onContextMenu = { p . contextMenuBuilder . getContextMenuCallback ( p . exchange ) }
607
- className = { p . isSelected ? 'selected' : '' }
644
+ className = { p . isSelected ? 'selected' : p . exchange . mulitSelected ? MULTI_SELECT_ROW_CLASSNAME : '' }
608
645
style = { p . style }
609
646
>
610
647
< RowPin pinned = { pinned } />
@@ -659,7 +696,7 @@ const TlsRow = observer((p: {
659
696
data-event-id = { tlsEvent . id }
660
697
tabIndex = { p . isSelected ? 0 : - 1 }
661
698
662
- className = { p . isSelected ? 'selected' : '' }
699
+ className = { p . isSelected ? 'selected' : tlsEvent . mulitSelected ? MULTI_SELECT_ROW_CLASSNAME : '' }
663
700
style = { p . style }
664
701
>
665
702
{
@@ -686,12 +723,14 @@ export class ViewEventList extends React.Component<ViewEventListProps> {
686
723
return {
687
724
selectedEvent : this . props . selectedEvent ,
688
725
events : this . props . filteredEvents ,
726
+ isMultiSelectEnabled : this . props . isMultiSelectEnabled ,
689
727
contextMenuBuilder : this . props . contextMenuBuilder
690
728
} ;
691
729
}
692
730
693
731
private listBodyRef = React . createRef < HTMLDivElement > ( ) ;
694
732
private listRef = React . createRef < List > ( ) ;
733
+ private AreMultipleEventsSelected = false ;
695
734
696
735
private KeyBoundListWindow = observer (
697
736
React . forwardRef < HTMLDivElement > (
@@ -714,6 +753,7 @@ export class ViewEventList extends React.Component<ViewEventListProps> {
714
753
return < ListContainer >
715
754
< TableHeader >
716
755
< MarkerHeader />
756
+ < MultiSelect isMultiSelectEnabled = { this . props . isMultiSelectEnabled } > < input type = "Checkbox" onChange = { ( evt ) => this . props . onMultiSelectToggled ( ) } /> </ MultiSelect >
717
757
< Method > Method</ Method >
718
758
< Status > Status</ Status >
719
759
< Source > Source</ Source >
@@ -876,20 +916,54 @@ export class ViewEventList extends React.Component<ViewEventListProps> {
876
916
const eventIndex = parseInt ( ariaRowIndex , 10 ) - 1 ;
877
917
const event = this . props . filteredEvents [ eventIndex ] ;
878
918
if ( event !== this . props . selectedEvent ) {
879
- this . onEventSelected ( eventIndex ) ;
919
+ this . onEventSelected ( eventIndex , mouseEvent ) ;
880
920
} else {
881
921
// Clicking the selected row deselects it
882
922
this . onEventDeselected ( ) ;
883
923
}
884
924
}
885
925
886
926
@action . bound
887
- onEventSelected ( index : number ) {
927
+ onEventSelected ( index : number , mouseEvent : React . MouseEvent ) {
928
+ if ( this . props . isMultiSelectEnabled ) {
929
+ const eventIndex = index ;
930
+ const event = this . props . filteredEvents [ eventIndex ] ;
931
+ if ( ( ! USE_MULTI_SELECT_CHECKBOXES || mouseEvent . shiftKey ) && ! mouseEvent . ctrlKey && this . AreMultipleEventsSelected ) { //if using the checkboxes then only clear otehr checkboxes when shift key is hit
932
+ this . props . filteredEvents . forEach ( evt => evt . mulitSelected = false ) ; //to increase the perf here we should cache the selected events in a list, then we can uncheck them quickly and clear the list rather than doing this every click
933
+ this . AreMultipleEventsSelected = false ;
934
+ }
935
+ if ( ! USE_MULTI_SELECT_CHECKBOXES ) {
936
+ if ( ! mouseEvent . ctrlKey ) {
937
+ if ( this . props . selectedEvent ) {
938
+ this . props . selectedEvent . mulitSelected = false ;
939
+ }
940
+ event . mulitSelected = true ;
941
+ }
942
+ }
943
+
944
+
945
+ if ( mouseEvent . ctrlKey ) {
946
+ event . mulitSelected = ! event . mulitSelected ;
947
+ this . AreMultipleEventsSelected = true ; //even if technically only one is selected we are safe to set this to true it just does the above reset first
948
+ }
949
+ if ( mouseEvent . shiftKey ) {
950
+ this . AreMultipleEventsSelected = true ; //even if technically only one is selected we are safe to set this to true it just does the above reset first
951
+ if ( this . props . selectedEvent ) {
952
+ let curIndex = this . props . filteredEvents . indexOf ( this . props . selectedEvent ) ;
953
+ for ( let x = curIndex < eventIndex ? curIndex : eventIndex ; x <= ( curIndex < eventIndex ? eventIndex : curIndex ) ; x ++ ) {
954
+ this . props . filteredEvents [ x ] . mulitSelected = true ;
955
+ }
956
+ }
957
+ }
958
+ }
888
959
this . props . onSelected ( this . props . filteredEvents [ index ] ) ;
889
960
}
890
961
891
962
@action . bound
892
963
onEventDeselected ( ) {
964
+ if ( ! USE_MULTI_SELECT_CHECKBOXES && this . props . selectedEvent ) {
965
+ this . props . selectedEvent . mulitSelected = false ;
966
+ }
893
967
this . props . onSelected ( undefined ) ;
894
968
}
895
969
0 commit comments