From 8db3b3b43bec6170a7f1db21772c48c5e270c97b Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Thu, 30 Apr 2020 20:16:13 +0200 Subject: Add services dialog --- frontend/src/colors.scss | 8 ++ frontend/src/components/Connection.js | 78 +++++++-------- frontend/src/components/Connection.scss | 49 ++++----- frontend/src/components/ConnectionContent.js | 2 - frontend/src/index.scss | 114 +++++++++++++++++---- frontend/src/utils.js | 5 + frontend/src/views/App.js | 19 +++- frontend/src/views/Connections.js | 61 +++--------- frontend/src/views/Connections.scss | 32 +++++- frontend/src/views/Header.js | 22 +++-- frontend/src/views/MainPane.js | 10 ++ frontend/src/views/Services.js | 142 +++++++++++++++++++++++++++ frontend/src/views/Services.scss | 16 +++ 13 files changed, 400 insertions(+), 158 deletions(-) create mode 100644 frontend/src/utils.js create mode 100644 frontend/src/views/Services.js create mode 100644 frontend/src/views/Services.scss (limited to 'frontend') diff --git a/frontend/src/colors.scss b/frontend/src/colors.scss index 290a0cd..75f1828 100644 --- a/frontend/src/colors.scss +++ b/frontend/src/colors.scss @@ -9,3 +9,11 @@ $color-secondary-1: #A20A0A; $color-secondary-2: #DF3030; $color-secondary-3: #FF9D9D; $color-secondary-4: #FFDFDF; + +$color-blue: #247085; +$color-blue-light: #A5B8BE; +$color-blue-dark: #013B4C; + +$color-green: #25965D; +$color-green-light: #CDE4D8; +$color-green-dark: #004321; \ No newline at end of file diff --git a/frontend/src/components/Connection.js b/frontend/src/components/Connection.js index 4bdc8cd..ce2b173 100644 --- a/frontend/src/components/Connection.js +++ b/frontend/src/components/Connection.js @@ -1,24 +1,13 @@ import React, {Component} from 'react'; import './Connection.scss'; -import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; -import { - faCloudDownloadAlt, - faCloudUploadAlt, - faComment, - faEyeSlash, - faHourglassHalf, - faLaptop, - faLink, - faServer, - faThumbtack, -} from '@fortawesome/free-solid-svg-icons' +import {Button, OverlayTrigger, Tooltip} from "react-bootstrap"; class Connection extends Component { render() { let conn = this.props.data - let serviceName = "assign" - let serviceColor = "#fff" - if (conn.service != null) { + let serviceName = "/dev/null" + let serviceColor = "#0F192E" + if (conn.service.port !== 0) { serviceName = conn.service.name serviceColor = conn.service.color } @@ -27,41 +16,40 @@ class Connection extends Component { let duration = ((closedAt - startedAt) / 1000).toFixed(3) let timeInfo = `Started at ${startedAt}\nClosed at ${closedAt}\nProcessed at ${new Date(conn.processed_at)}` + let classes = "connection" + if (this.props.selected) { + classes += " connection-selected" + } + if (conn.marked){ + classes += " connection-marked" + } return ( - -
+ + - - - - - {conn.ip_src}:{conn.port_src} - - {"->"} - - - {conn.ip_dst}:{conn.port_dst} + }}>{serviceName} - - - - {duration}s - - - - {conn.client_bytes} - - {conn.server_bytes} - - - - - -
- + + this.props.onSelected()}>{conn.ip_src} + this.props.onSelected()}>{conn.port_src} + this.props.onSelected()}>{conn.ip_dst} + this.props.onSelected()}>{conn.port_dst} + this.props.onSelected()}> + {/*{timeInfo}}>*/} + {duration}s + {/**/} + + this.props.onSelected()}>{conn.client_bytes} + this.props.onSelected()}>{conn.server_bytes} + + % + !! + @ + # + ); diff --git a/frontend/src/components/Connection.scss b/frontend/src/components/Connection.scss index 8910cb4..d27ebc8 100644 --- a/frontend/src/components/Connection.scss +++ b/frontend/src/components/Connection.scss @@ -2,52 +2,41 @@ .connection { background-color: $color-primary-0; - margin-bottom: 5px; + border-top: 3px solid $color-primary-3; + border-bottom: 3px solid $color-primary-3; + td { + vertical-align: middle; + } &.connection-marked { border-right: 5px solid $color-secondary-2; } .connection-service { - padding: 0 12px 0 0; - .btn { - font-size: 12px; - width: 120px; + width: 100%; } - } - - .connection-separator { - margin: 0 10px; - } - - .connection-duration { - margin-left: 15px; - //.connection-seconds { - // width: 75px; - // display: inline-block; - // text-align: right; - //} - } - - .connection-bytes { - margin-left: 10px; - margin-right: 10px; - - .connection-bytes-count { - margin-right: 5px; + .btn:hover { + background-color: $color-primary-1 !important; + color: $color-primary-4; } } - .connection-hide, .connection-mark, .connection-comment, .connection-link { - margin-left: 5px; + .connection-icon { + font-weight: 600; + font-size: 18px; + margin-right: 6px; + cursor: pointer; } + &:hover { + background-color: $color-primary-2; + } - svg { - margin-right: 6px; + &.connection-selected { + background-color: $color-primary-2; } } diff --git a/frontend/src/components/ConnectionContent.js b/frontend/src/components/ConnectionContent.js index 061282c..bd35b5c 100644 --- a/frontend/src/components/ConnectionContent.js +++ b/frontend/src/components/ConnectionContent.js @@ -11,8 +11,6 @@ class ConnectionContent extends Component { render() { let content = this.props.connectionPayload - console.log(content) - if (content === undefined) { return
nope
} diff --git a/frontend/src/index.scss b/frontend/src/index.scss index 5c18095..def3fdf 100644 --- a/frontend/src/index.scss +++ b/frontend/src/index.scss @@ -21,41 +21,64 @@ pre { font-size: 14px; } -button { - :focus { - outline: none; - box-shadow: none; - } -} .btn { border-radius: 0; + background-color: $color-primary-2; + border: none; + border-bottom: 5px solid $color-primary-1; color: $color-primary-4; + outline: none; + padding: 5px 12px; + font-weight: 500; + + &:hover, &:active { + background-color: $color-primary-1; + color: $color-primary-4; + } + + &:focus, &:active { + outline: none !important; + box-shadow: none !important; + } } -.btn-primary { - margin-left: 20px; - padding: 5px 12px; +.btn-sm { + border: none; + font-size: 12px; +} + +.btn-red { + color: $color-secondary-4; background-color: $color-secondary-2; - font-weight: 500; - border: 0; border-bottom: 5px solid $color-secondary-1; - color: $color-secondary-4; - outline:none; + &:hover, &:active { + color: $color-secondary-4; + background-color: $color-secondary-1; + } +} +.btn-blue { + color: $color-blue-light; + background-color: $color-blue; + border-bottom: 5px solid $color-blue-dark; - :focus, :active { - outline: none; - box-shadow: none; + &:hover, &:active { + color: $color-blue-light; + background-color: $color-blue-dark; } - } -.btn-primary:hover { - background-color: $color-secondary-1; - border-color: $color-secondary-1; - outline: none; +.btn-green { + color: $color-green-light; + background-color: $color-green; + border-bottom: 5px solid $color-green-dark; + + &:hover, &:active { + color: $color-green-light; + background-color: $color-green-dark; + } } a { @@ -85,4 +108,53 @@ a { /* Handle on hover */ ::-webkit-scrollbar-thumb:hover { background: $color-secondary-2; +} + +.clickable { + cursor: pointer; +} + +.modal-content { + background-color: $color-primary-0; + + .modal-header { + background-color: $color-primary-2; + border: none; + } + + .modal-footer { + border: none; + } +} + +input.form-control, textarea.form-control { + background-color: $color-primary-2; + border: none; + color: $color-primary-4; + + &:focus { + background-color: $color-primary-1; + color: $color-primary-4; + box-shadow: none; + } + + &[readonly] { + background-color: $color-primary-2; + border: none; + color: $color-primary-4; + } + + &[readonly]:focus { + background-color: $color-primary-1; + color: $color-primary-4; + box-shadow: none; + } +} + +textarea.form-control { + resize: none; +} + +.table { + color: $color-primary-4; } \ No newline at end of file diff --git a/frontend/src/utils.js b/frontend/src/utils.js new file mode 100644 index 0000000..2487f09 --- /dev/null +++ b/frontend/src/utils.js @@ -0,0 +1,5 @@ + +export function createCurlCommand(subCommand, data) { + return `curl --request PUT \\\n --url ${window.location.hostname}/api${subCommand} \\\n ` + + `--header 'content-type: application/json' \\\n --data '${JSON.stringify(data)}'` +} diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js index 4d80da5..2b444a2 100644 --- a/frontend/src/views/App.js +++ b/frontend/src/views/App.js @@ -4,20 +4,35 @@ import './App.scss'; import MainPane from "./MainPane"; import Footer from "./Footer"; import {Route, BrowserRouter as Router, Switch} from "react-router-dom"; +import Services from "./Services"; class App extends Component { + constructor(props) { + super(props); + this.state = { + servicesShow: false + }; + } + render() { + let modal = "" + if (this.state.servicesShow) { + modal = this.setState({servicesShow: false})} /> + } + return (
-
+
this.setState({servicesShow: true})}/> + } /> } /> - } /> + {modal}
+
); } diff --git a/frontend/src/views/Connections.js b/frontend/src/views/Connections.js index 5876a40..fa7798e 100644 --- a/frontend/src/views/Connections.js +++ b/frontend/src/views/Connections.js @@ -2,8 +2,8 @@ import React, {Component} from 'react'; import './Connections.scss'; import axios from 'axios' import Connection from "../components/Connection"; -import {Link} from "react-router-dom"; import Table from 'react-bootstrap/Table'; +import {Redirect} from 'react-router'; class Connections extends Component { constructor(props) { @@ -19,34 +19,16 @@ class Connections extends Component { } render() { - let connection = { - "id": "5dd95ff0fe7ae01ae7f419c2", - "ip_src": "10.62.82.1", - "ip_dst": "10.62.82.2", - "port_src": 59113, - "port_dst": 23179, - "started_at": "2019-11-23T16:36:00.1Z", - "closed_at": "2019-11-23T16:36:00.971Z", - "client_bytes": 331, - "server_bytes": 85, - "client_documents": 1, - "server_documents": 1, - "processed_at": "2020-04-21T17:10:29.532Z", - "matched_rules": [], - "hidden": false, - "marked": true, - "comment": "", - "service": { - "port": 23179, - "name": "kaboom", - "color": "#3C6D3C", - "notes": "wdddoddddddw" - } + let redirect = "" + if (this.state.selected) { + redirect = ; } return ( +
- +
+
@@ -61,31 +43,16 @@ class Connections extends Component { - - - - - - - - - - - - - - - - - + { + this.state.connections.map(c => + this.setState({selected: c.id})} + selected={this.state.selected === c.id}/> + ) + }
service
1MarkOtto@mdo
2JacobThornton@fat
3Larry the Bird@twitter
- { - this.state.connections.map(c => - - ) - } + {redirect}
); } diff --git a/frontend/src/views/Connections.scss b/frontend/src/views/Connections.scss index da74e11..6d2de3f 100644 --- a/frontend/src/views/Connections.scss +++ b/frontend/src/views/Connections.scss @@ -2,12 +2,40 @@ .connections { background-color: $color-primary-3; - padding: 10px 10px 10px 10px; + padding: 0 10px; + position: relative; height: 100%; overflow: auto; .table { - color: $color-primary-4; + margin-top: 10px; } + + .connections-header-padding { + position: sticky; + height: 10px; + background-color: $color-primary-3; + top: 0; + left: 0; + right: 0; + margin-bottom: -10px; + } + + th { + background-color: $color-primary-2; + border-top: 3px solid $color-primary-3; + border-bottom: 3px solid $color-primary-3; + font-size: 13.5px; + + position: sticky; + top: 10px; + padding: 5px; + } + + &:hover::-webkit-scrollbar-thumb { + background: $color-secondary-2; + } + + } \ No newline at end of file diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js index b3f919b..ac272e6 100644 --- a/frontend/src/views/Header.js +++ b/frontend/src/views/Header.js @@ -1,9 +1,17 @@ import React, {Component} from 'react'; import Typed from 'typed.js'; import './Header.scss'; +import {Button} from "react-bootstrap"; class Header extends Component { + constructor(props) { + super(props); + this.state = { + servicesShow: false + }; + } + componentDidMount() { const options = { strings: ["caronte$ "], @@ -28,15 +36,11 @@ class Header extends Component {
- - - + + +
diff --git a/frontend/src/views/MainPane.js b/frontend/src/views/MainPane.js index 88b5376..0fc083e 100644 --- a/frontend/src/views/MainPane.js +++ b/frontend/src/views/MainPane.js @@ -26,6 +26,16 @@ class MainPane extends Component { } componentDidMount() { + if (this.props.match.params.id !== this.state.id) { + const id = this.props.match.params.id; + this.setState({id: id}); + + axios.get(`/api/streams/${id}`).then(res => this.setState({connectionContent: res.data})) + + + } + + } render() { diff --git a/frontend/src/views/Services.js b/frontend/src/views/Services.js new file mode 100644 index 0000000..1b3789d --- /dev/null +++ b/frontend/src/views/Services.js @@ -0,0 +1,142 @@ +import React, {Component} from 'react'; +import './Services.scss'; +import {Button, ButtonGroup, Col, Container, Form, FormControl, InputGroup, Modal, Row, Table} from "react-bootstrap"; +import axios from 'axios' +import {createCurlCommand} from '../utils'; + +class Services extends Component { + + constructor(props) { + super(props); + this.state = { + services: {}, + port: "", + portValid: false + } + + this.portChanged = this.portChanged.bind(this); + } + + componentDidMount() { + axios.get("/api/services").then(res => this.setState({services: res.data})) + } + + portChanged(event) { + let value = event.target.value.replace(/[^\d]/gi, '') + let intValue = parseInt(value) + this.setState({port: value, portValid: intValue > 0 && intValue <= 65565}) + + + } + + + render() { + let curl = createCurlCommand("/services", { + "port": this.state.port, + "name": "aaaaa", + "color": "#fff", + "notes": "aaa" + }) + + let rows = Object.values(this.state.services).map(s => + + + {s.port} + {s.name} + + ) + + + + + return ( + + + + ~/services + + + + + + + + + + + + + + + + {rows} + +
nameport
+ + +
+ + port: + + + {!this.state.portValid ? "assert(1 <= port <= 65565)" : ""} + + + + + name: + + + {"assert(len(name) >= 3)"} + + + + + color: + + + + + + + + + notes: + + +
+ + + + +
+ + + + + {curl} + + + + + +
+
+ + + + +
+ ); + } +} + +export default Services; diff --git a/frontend/src/views/Services.scss b/frontend/src/views/Services.scss new file mode 100644 index 0000000..fd65beb --- /dev/null +++ b/frontend/src/views/Services.scss @@ -0,0 +1,16 @@ +.curl-output { + width: 100%; + font-size: 13px; +} + +.services-list { + .btn { + width: 150px; + } +} + +.dialog-footer { + .btn { + width: 80px; + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2