|
1 | 1 | import * as _ from 'lodash';
|
2 | 2 | import * as React from 'react';
|
3 | 3 | import { observer, Observer } from 'mobx-react';
|
4 |
| -import { action, computed } from 'mobx'; |
| 4 | +import { action, computed, runInAction } from 'mobx'; |
5 | 5 |
|
6 | 6 | import AutoSizer from 'react-virtualized-auto-sizer';
|
7 | 7 | import { FixedSizeList as List, ListChildComponentProps } from 'react-window';
|
@@ -33,6 +33,22 @@ import { StatusCode } from '../common/status-code';
|
33 | 33 |
|
34 | 34 | import { HEADER_FOOTER_HEIGHT } from './view-event-list-footer';
|
35 | 35 |
|
| 36 | +import { |
| 37 | + Menu, |
| 38 | + Item, |
| 39 | + Separator, |
| 40 | + Submenu, |
| 41 | + useContextMenu, |
| 42 | + ItemProps, |
| 43 | + ItemParams, |
| 44 | + } from "react-contexify"; |
| 45 | + const MENU_VIEW_EVENT_ID = "MENU_VIEW_EVENT_LIST"; |
| 46 | + |
| 47 | + |
| 48 | + const { show } = useContextMenu({ |
| 49 | + id: MENU_VIEW_EVENT_ID |
| 50 | +}); |
| 51 | +type ItemData = any; |
36 | 52 | const SCROLL_BOTTOM_MARGIN = 5; // If you're in the last 5 pixels of the scroll area, we say you're at the bottom
|
37 | 53 |
|
38 | 54 | const EmptyStateOverlay = styled(EmptyState)`
|
@@ -380,7 +396,7 @@ const ExchangeRow = observer(({
|
380 | 396 | aria-rowindex={index + 1}
|
381 | 397 | data-event-id={exchange.id}
|
382 | 398 | tabIndex={isSelected ? 0 : -1}
|
383 |
| - |
| 399 | + onContextMenu={e => displayMenu(e,exchange)} |
384 | 400 | className={isSelected ? 'selected' : ''}
|
385 | 401 | style={style}
|
386 | 402 | >
|
@@ -647,7 +663,47 @@ const TlsRow = observer((p: {
|
647 | 663 | } connection to { tlsEvent.upstreamHostname || 'unknown domain' }
|
648 | 664 | </TlsListRow>
|
649 | 665 | });
|
| 666 | +const UTF8Decoder = new TextDecoder('utf8', { fatal: true }); |
| 667 | + |
| 668 | +async function copyToClipboard(textToCopy: string) { |
| 669 | + try { |
| 670 | + if (navigator.clipboard && window.isSecureContext) |
| 671 | + await navigator.clipboard.writeText(textToCopy); |
| 672 | + else { |
| 673 | + const textArea = document.createElement("textarea"); |
| 674 | + textArea.value = textToCopy; |
| 675 | + textArea.style.position = "absolute"; |
| 676 | + textArea.style.left = "-9999px"; |
| 677 | + document.body.prepend(textArea); |
| 678 | + textArea.select(); |
| 679 | + try { |
| 680 | + document.execCommand('copy'); |
| 681 | + } catch (error) { |
| 682 | + console.error(error); |
| 683 | + } finally { |
| 684 | + textArea.remove(); |
| 685 | + } |
| 686 | + }; |
| 687 | + } catch (error) { |
| 688 | + console.error("Clipboard copy failure", error); |
| 689 | + } |
| 690 | +} |
| 691 | +const ContextMenuItemClicked = ( { id, event, props, data, triggerEvent }: ItemParams<ItemProps, ItemData> ) => { |
| 692 | + let exchange = (props as any).exchange as HttpExchange; |
| 693 | + switch(id) { |
| 694 | + case "TogglePin": |
| 695 | + runInAction(() => exchange.pinned = ! exchange.pinned ); |
| 696 | + break; |
| 697 | + case "DecodedBody": |
| 698 | + if (exchange && exchange.hasResponseBody() && exchange.response.body ) |
| 699 | + exchange.response.body.decodedPromise.then( val => { copyToClipboard(UTF8Decoder.decode(val)) }); |
| 700 | + break; |
| 701 | + } |
650 | 702 |
|
| 703 | +}; |
| 704 | +function displayMenu(e: React.MouseEvent, exchange : HttpExchange) { |
| 705 | + show({event: e, props: { exchange: exchange } }); |
| 706 | +} |
651 | 707 | @observer
|
652 | 708 | export class ViewEventList extends React.Component<ViewEventListProps> {
|
653 | 709 |
|
@@ -734,6 +790,14 @@ export class ViewEventList extends React.Component<ViewEventListProps> {
|
734 | 790 | }</Observer>
|
735 | 791 | }</AutoSizer>
|
736 | 792 | }
|
| 793 | + |
| 794 | +<Menu id={MENU_VIEW_EVENT_ID}> |
| 795 | + <Item id="TogglePin" onClick={ContextMenuItemClicked}>Toggle Pinned</Item> |
| 796 | + <Separator /> |
| 797 | + <Submenu label="Copy"> |
| 798 | + <Item id="DecodedBody" onClick={ContextMenuItemClicked}>Decoded Body</Item> |
| 799 | + </Submenu> |
| 800 | +</Menu> |
737 | 801 | </ListContainer>;
|
738 | 802 | }
|
739 | 803 |
|
|
0 commit comments