diff options
Diffstat (limited to 'frontend/src/components/Connection.js')
-rw-r--r-- | frontend/src/components/Connection.js | 104 |
1 files changed, 91 insertions, 13 deletions
diff --git a/frontend/src/components/Connection.js b/frontend/src/components/Connection.js index 13b394a..8121d51 100644 --- a/frontend/src/components/Connection.js +++ b/frontend/src/components/Connection.js @@ -1,8 +1,50 @@ import React, {Component} from 'react'; import './Connection.scss'; -import {Button, OverlayTrigger, Tooltip} from "react-bootstrap"; +import axios from 'axios' +import {Button, Form, OverlayTrigger, Popover} from "react-bootstrap"; class Connection extends Component { + + constructor(props) { + super(props); + this.state = { + update: false, + copiedMessage: false + }; + + this.copyTextarea = React.createRef(); + this.handleAction = this.handleAction.bind(this); + } + + handleAction(name) { + if (name === "hide") { + const enabled = !this.props.data.hidden; + axios.post(`/api/connections/${this.props.data.id}/${enabled ? "hide" : "show"}`) + .then(res => { + if (res.status === 202) { + this.props.onEnabled(!enabled); + this.setState({update: true}); + } + }); + } + if (name === "mark") { + const marked = this.props.data.marked; + axios.post(`/api/connections/${this.props.data.id}/${marked ? "unmark" : "mark"}`) + .then(res => { + if (res.status === 202) { + this.props.onMarked(!marked); + this.setState({update: true}); + } + }); + } + if (name === "copy") { + this.copyTextarea.current.select(); + document.execCommand('copy'); + this.setState({copiedMessage: true}); + setTimeout(() => this.setState({copiedMessage: false}), 3000); + } + } + render() { let conn = this.props.data; let serviceName = "/dev/null"; @@ -13,16 +55,37 @@ class Connection extends Component { } let startedAt = new Date(conn.started_at); let closedAt = new Date(conn.closed_at); + let processedAt = new Date(conn.processed_at); let duration = ((closedAt - startedAt) / 1000).toFixed(3); - let timeInfo = `Started at ${startedAt}\nClosed at ${closedAt}\nProcessed at ${new Date(conn.processed_at)}`; + let timeInfo = <div> + <span>Started at {startedAt.toLocaleDateString() + " " + startedAt.toLocaleTimeString()}</span><br/> + <span>Processed at {processedAt.toLocaleDateString() + " " + processedAt.toLocaleTimeString()}</span><br/> + <span>Closed at {closedAt.toLocaleDateString() + " " + closedAt.toLocaleTimeString()}</span> + </div>; let classes = "connection"; if (this.props.selected) { classes += " connection-selected"; } - if (conn.marked){ - classes += " connection-marked"; - } + + const popoverFor = function (name, content) { + return <Popover id={`popover-${name}-${conn.id}`} className="connection-popover"> + <Popover.Content> + {content} + </Popover.Content> + </Popover>; + }; + + const commentPopoverContent = <div> + <span>Click to <strong>{conn.comment.length > 0 ? "edit" : "add"}</strong> comment</span> + {conn.comment && <Form.Control as="textarea" readOnly={true} rows={2} defaultValue={conn.comment}/>} + </div>; + + const copyPopoverContent = <div> + {this.state.copiedMessage ? <span><strong>Copied!</strong></span> : + <span>Click to <strong>copy</strong> the connection id</span>} + <Form.Control as="textarea" readOnly={true} rows={1} defaultValue={conn.id} ref={this.copyTextarea}/> + </div>; return ( <tr className={classes}> @@ -38,24 +101,39 @@ class Connection extends Component { <td className="clickable" onClick={() => this.props.onSelected()}>{conn.ip_dst}</td> <td className="clickable" onClick={() => this.props.onSelected()}>{conn.port_dst}</td> <td className="clickable" onClick={() => this.props.onSelected()}> - {/*<OverlayTrigger placement="top" overlay={<Tooltip id={`tooltip-${conn.id}`}>{timeInfo}</Tooltip>}>*/} + <OverlayTrigger trigger={["focus", "hover"]} placement="right" + overlay={popoverFor("duration", timeInfo)}> <span className="test-tooltip">{duration}s</span> - {/*</OverlayTrigger>*/} + </OverlayTrigger> </td> <td className="clickable" onClick={() => this.props.onSelected()}>{conn.client_bytes}</td> <td className="clickable" onClick={() => this.props.onSelected()}>{conn.server_bytes}</td> <td> - <span className="connection-icon connection-hide">%</span> - <span className="connection-icon connection-mark">!!</span> - <span className="connection-icon connection-comment">@</span> - <span className="connection-icon connection-link">#</span> + <OverlayTrigger trigger={["focus", "hover"]} placement="right" + overlay={popoverFor("hide", <span>Hide this connection from the list</span>)}> + <span className={"connection-icon" + (conn.hidden ? " icon-enabled" : "")} + onClick={() => this.handleAction("hide")}>%</span> + </OverlayTrigger> + <OverlayTrigger trigger={["focus", "hover"]} placement="right" + overlay={popoverFor("hide", <span>Mark this connection</span>)}> + <span className={"connection-icon" + (conn.marked ? " icon-enabled" : "")} + onClick={() => this.handleAction("mark")}>!!</span> + </OverlayTrigger> + <OverlayTrigger trigger={["focus", "hover"]} placement="right" + overlay={popoverFor("comment", commentPopoverContent)}> + <span className={"connection-icon" + (conn.comment ? " icon-enabled" : "")} + onClick={() => this.handleAction("comment")}>@</span> + </OverlayTrigger> + <OverlayTrigger trigger={["focus", "hover"]} placement="right" + overlay={popoverFor("copy", copyPopoverContent)}> + <span className="connection-icon" + onClick={() => this.handleAction("copy")}>#</span> + </OverlayTrigger> </td> - </tr> ); } } - export default Connection; |