MessagesView.js (5046B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { 8 Component, 9 createRef, 10 createFactory, 11 } = require("resource://devtools/client/shared/vendor/react.mjs"); 12 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); 13 const { div } = dom; 14 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs"); 15 const { 16 connect, 17 } = require("resource://devtools/client/shared/vendor/react-redux.js"); 18 const Actions = require("resource://devtools/client/netmonitor/src/actions/index.js"); 19 const { 20 findDOMNode, 21 } = require("resource://devtools/client/shared/vendor/react-dom.mjs"); 22 const { 23 getSelectedMessage, 24 isSelectedMessageVisible, 25 } = require("resource://devtools/client/netmonitor/src/selectors/index.js"); 26 27 // Components 28 const SplitBox = createFactory( 29 require("resource://devtools/client/shared/components/splitter/SplitBox.js") 30 ); 31 const MessageListContent = createFactory( 32 require("resource://devtools/client/netmonitor/src/components/messages/MessageListContent.js") 33 ); 34 const Toolbar = createFactory( 35 require("resource://devtools/client/netmonitor/src/components/messages/Toolbar.js") 36 ); 37 const StatusBar = createFactory( 38 require("resource://devtools/client/netmonitor/src/components/messages/StatusBar.js") 39 ); 40 41 loader.lazyGetter(this, "MessagePayload", function () { 42 return createFactory( 43 require("resource://devtools/client/netmonitor/src/components/messages/MessagePayload.js") 44 ); 45 }); 46 47 /** 48 * Renders a list of messages in table view. 49 * Full payload is separated using a SplitBox. 50 */ 51 class MessagesView extends Component { 52 static get propTypes() { 53 return { 54 connector: PropTypes.object.isRequired, 55 selectedMessage: PropTypes.object, 56 messageDetailsOpen: PropTypes.bool.isRequired, 57 openMessageDetailsTab: PropTypes.func.isRequired, 58 selectedMessageVisible: PropTypes.bool.isRequired, 59 channelId: PropTypes.number, 60 }; 61 } 62 63 constructor(props) { 64 super(props); 65 66 this.searchboxRef = createRef(); 67 this.clearFilterText = this.clearFilterText.bind(this); 68 this.handleContainerElement = this.handleContainerElement.bind(this); 69 this.state = { 70 startPanelContainer: null, 71 }; 72 } 73 74 componentDidUpdate(prevProps) { 75 const { channelId, openMessageDetailsTab, selectedMessageVisible } = 76 this.props; 77 78 // If a new connection is selected, clear the filter text 79 if (channelId !== prevProps.channelId) { 80 this.clearFilterText(); 81 } 82 83 if (!selectedMessageVisible) { 84 openMessageDetailsTab(false); 85 } 86 } 87 88 componentWillUnmount() { 89 const { openMessageDetailsTab } = this.props; 90 openMessageDetailsTab(false); 91 92 const { clientHeight } = findDOMNode(this.refs.endPanel) || {}; 93 94 if (clientHeight) { 95 Services.prefs.setIntPref( 96 "devtools.netmonitor.msg.payload-preview-height", 97 clientHeight 98 ); 99 } 100 } 101 102 /* Store the parent DOM element of the SplitBox startPanel's element. 103 We need this element for as an option for the IntersectionObserver */ 104 handleContainerElement(element) { 105 if (!this.state.startPanelContainer) { 106 this.setState({ 107 startPanelContainer: element, 108 }); 109 } 110 } 111 112 // Reset the filter text 113 clearFilterText() { 114 if (this.searchboxRef) { 115 this.searchboxRef.current.onClearButtonClick(); 116 } 117 } 118 119 render() { 120 const { messageDetailsOpen, connector, selectedMessage, channelId } = 121 this.props; 122 123 const { searchboxRef } = this; 124 const { startPanelContainer } = this.state; 125 126 const initialHeight = Services.prefs.getIntPref( 127 "devtools.netmonitor.msg.payload-preview-height" 128 ); 129 130 return div( 131 { id: "messages-view", className: "monitor-panel" }, 132 Toolbar({ 133 searchboxRef, 134 }), 135 SplitBox({ 136 className: "devtools-responsive-container", 137 initialHeight, 138 minSize: "50px", 139 maxSize: "80%", 140 splitterSize: messageDetailsOpen ? 1 : 0, 141 onSelectContainerElement: this.handleContainerElement, 142 startPanel: MessageListContent({ 143 connector, 144 startPanelContainer, 145 channelId, 146 }), 147 endPanel: 148 messageDetailsOpen && 149 MessagePayload({ 150 ref: "endPanel", 151 connector, 152 selectedMessage, 153 }), 154 endPanelCollapsed: !messageDetailsOpen, 155 endPanelControl: true, 156 vert: false, 157 }), 158 StatusBar() 159 ); 160 } 161 } 162 163 module.exports = connect( 164 state => ({ 165 channelId: state.messages.currentChannelId, 166 messageDetailsOpen: state.messages.messageDetailsOpen, 167 selectedMessage: getSelectedMessage(state), 168 selectedMessageVisible: isSelectedMessageVisible(state), 169 }), 170 dispatch => ({ 171 openMessageDetailsTab: open => dispatch(Actions.openMessageDetails(open)), 172 }) 173 )(MessagesView);