@@ -35,6 +35,9 @@ import { StatusCode } from '../common/status-code';
3535import { HEADER_FOOTER_HEIGHT } from './view-event-list-footer' ;
3636import { ViewEventContextMenuBuilder } from './view-context-menu-builder' ;
3737
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+
3841const SCROLL_BOTTOM_MARGIN = 5 ; // If you're in the last 5 pixels of the scroll area, we say you're at the bottom
3942
4043const EmptyStateOverlay = styled ( EmptyState ) `
@@ -52,6 +55,8 @@ interface ViewEventListProps {
5255 filteredEvents : CollectedEvent [ ] ;
5356 selectedEvent : CollectedEvent | undefined ;
5457 isPaused : boolean ;
58+ isMultiSelectEnabled : boolean ;
59+ onMultiSelectToggled : ( ) => void ;
5560
5661 contextMenuBuilder : ViewEventContextMenuBuilder ;
5762
@@ -156,6 +161,15 @@ const Status = styled(Column)`
156161 flex-shrink: 0;
157162 flex-grow: 0;
158163` ;
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+ ` ;
159173
160174const Source = styled ( Column ) `
161175 flex-basis: 49px;
@@ -229,6 +243,10 @@ const EventListRow = styled.div`
229243 user-select: none;
230244 cursor: pointer;
231245
246+ &.multiSelected {
247+ background-color: ${ p => p . theme . highlightBackground } ;
248+ color: ${ p => p . theme . highlightColor } ;
249+ }
232250 &.selected {
233251 background-color: ${ p => p . theme . highlightBackground } ;
234252 color: ${ p => p . theme . highlightColor } ;
@@ -322,6 +340,7 @@ interface EventRowProps extends ListChildComponentProps {
322340 selectedEvent : CollectedEvent | undefined ;
323341 events : CollectedEvent [ ] ;
324342 contextMenuBuilder : ViewEventContextMenuBuilder ;
343+ isMultiSelectEnabled : boolean ;
325344 }
326345}
327346
@@ -352,6 +371,7 @@ const EventRow = observer((props: EventRowProps) => {
352371 return < ExchangeRow
353372 index = { index }
354373 isSelected = { isSelected }
374+ isMultiSelectEnabled = { props . data . isMultiSelectEnabled }
355375 style = { style }
356376 exchange = { event }
357377 contextMenuBuilder = { contextMenuBuilder }
@@ -376,15 +396,31 @@ const EventRow = observer((props: EventRowProps) => {
376396 }
377397} ) ;
378398
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+
379413const ExchangeRow = inject ( 'uiStore' ) ( observer ( ( {
380414 index,
381415 isSelected,
382416 style,
383417 exchange,
384- contextMenuBuilder
418+ contextMenuBuilder,
419+ isMultiSelectEnabled
385420} : {
386421 index : number ,
387422 isSelected : boolean ,
423+ isMultiSelectEnabled : boolean ,
388424 style : { } ,
389425 exchange : HttpExchange ,
390426 contextMenuBuilder : ViewEventContextMenuBuilder
@@ -403,10 +439,11 @@ const ExchangeRow = inject('uiStore')(observer(({
403439 data-event-id = { exchange . id }
404440 tabIndex = { isSelected ? 0 : - 1 }
405441 onContextMenu = { contextMenuBuilder . getContextMenuCallback ( exchange ) }
406- className = { isSelected ? 'selected' : '' }
442+ className = { isSelected ? 'selected' : exchange . mulitSelected ? MULTI_SELECT_ROW_CLASSNAME : '' }
407443 style = { style }
408444 >
409445 < RowPin pinned = { pinned } />
446+ < RowCheckbox checked = { exchange . mulitSelected } whenChecked = { exchange . onMultiSelected } isMultiSelectEnabled = { isMultiSelectEnabled } />
410447 < RowMarker category = { category } title = { describeEventCategory ( category ) } />
411448 < Method pinned = { pinned } > { request . method } </ Method >
412449 < Status >
@@ -492,7 +529,7 @@ const RTCConnectionRow = observer(({
492529 data-event-id = { event . id }
493530 tabIndex = { isSelected ? 0 : - 1 }
494531
495- className = { isSelected ? 'selected' : '' }
532+ className = { isSelected ? 'selected' : event . mulitSelected ? MULTI_SELECT_ROW_CLASSNAME : '' }
496533 style = { style }
497534 >
498535 < RowPin pinned = { pinned } />
@@ -536,7 +573,7 @@ const RTCStreamRow = observer(({
536573 data-event-id = { event . id }
537574 tabIndex = { isSelected ? 0 : - 1 }
538575
539- className = { isSelected ? 'selected' : '' }
576+ className = { isSelected ? 'selected' : event . mulitSelected ? MULTI_SELECT_ROW_CLASSNAME : '' }
540577 style = { style }
541578 >
542579 < RowPin pinned = { pinned } />
@@ -604,7 +641,7 @@ const BuiltInApiRow = observer((p: {
604641 tabIndex = { p . isSelected ? 0 : - 1 }
605642
606643 onContextMenu = { p . contextMenuBuilder . getContextMenuCallback ( p . exchange ) }
607- className = { p . isSelected ? 'selected' : '' }
644+ className = { p . isSelected ? 'selected' : p . exchange . mulitSelected ? MULTI_SELECT_ROW_CLASSNAME : '' }
608645 style = { p . style }
609646 >
610647 < RowPin pinned = { pinned } />
@@ -659,7 +696,7 @@ const TlsRow = observer((p: {
659696 data-event-id = { tlsEvent . id }
660697 tabIndex = { p . isSelected ? 0 : - 1 }
661698
662- className = { p . isSelected ? 'selected' : '' }
699+ className = { p . isSelected ? 'selected' : tlsEvent . mulitSelected ? MULTI_SELECT_ROW_CLASSNAME : '' }
663700 style = { p . style }
664701 >
665702 {
@@ -686,12 +723,14 @@ export class ViewEventList extends React.Component<ViewEventListProps> {
686723 return {
687724 selectedEvent : this . props . selectedEvent ,
688725 events : this . props . filteredEvents ,
726+ isMultiSelectEnabled : this . props . isMultiSelectEnabled ,
689727 contextMenuBuilder : this . props . contextMenuBuilder
690728 } ;
691729 }
692730
693731 private listBodyRef = React . createRef < HTMLDivElement > ( ) ;
694732 private listRef = React . createRef < List > ( ) ;
733+ private AreMultipleEventsSelected = false ;
695734
696735 private KeyBoundListWindow = observer (
697736 React . forwardRef < HTMLDivElement > (
@@ -714,6 +753,7 @@ export class ViewEventList extends React.Component<ViewEventListProps> {
714753 return < ListContainer >
715754 < TableHeader >
716755 < MarkerHeader />
756+ < MultiSelect isMultiSelectEnabled = { this . props . isMultiSelectEnabled } > < input type = "Checkbox" onChange = { ( evt ) => this . props . onMultiSelectToggled ( ) } /> </ MultiSelect >
717757 < Method > Method</ Method >
718758 < Status > Status</ Status >
719759 < Source > Source</ Source >
@@ -876,20 +916,54 @@ export class ViewEventList extends React.Component<ViewEventListProps> {
876916 const eventIndex = parseInt ( ariaRowIndex , 10 ) - 1 ;
877917 const event = this . props . filteredEvents [ eventIndex ] ;
878918 if ( event !== this . props . selectedEvent ) {
879- this . onEventSelected ( eventIndex ) ;
919+ this . onEventSelected ( eventIndex , mouseEvent ) ;
880920 } else {
881921 // Clicking the selected row deselects it
882922 this . onEventDeselected ( ) ;
883923 }
884924 }
885925
886926 @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+ }
888959 this . props . onSelected ( this . props . filteredEvents [ index ] ) ;
889960 }
890961
891962 @action . bound
892963 onEventDeselected ( ) {
964+ if ( ! USE_MULTI_SELECT_CHECKBOXES && this . props . selectedEvent ) {
965+ this . props . selectedEvent . mulitSelected = false ;
966+ }
893967 this . props . onSelected ( undefined ) ;
894968 }
895969
0 commit comments