diff options
author | Emiliano Ciavatta | 2020-09-23 18:19:09 +0000 |
---|---|---|
committer | Emiliano Ciavatta | 2020-09-23 18:19:09 +0000 |
commit | 8d07bfe5f17534b7301a064aeaf8ed8071f10a40 (patch) | |
tree | f645b9f033d878d54175705c1d1909e0420c54f4 | |
parent | 8c8487b79300342b4c6dafe9c3691d43b8dc8e37 (diff) |
Frontend refactor: checkpoint
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | frontend/src/backend.js | 36 | ||||
-rw-r--r-- | frontend/src/colors.scss | 32 | ||||
-rw-r--r-- | frontend/src/components/Connection.js | 27 | ||||
-rw-r--r-- | frontend/src/components/ConnectionContent.js | 6 | ||||
-rw-r--r-- | frontend/src/components/fields/StringField.js | 31 | ||||
-rw-r--r-- | frontend/src/components/fields/StringField.scss | 66 | ||||
-rw-r--r-- | frontend/src/components/filters/FiltersDefinitions.js | 33 | ||||
-rw-r--r-- | frontend/src/components/filters/RulesConnectionsFilter.js | 6 | ||||
-rw-r--r-- | frontend/src/components/panels/PcapPane.js | 121 | ||||
-rw-r--r-- | frontend/src/components/panels/PcapPane.scss | 55 | ||||
-rw-r--r-- | frontend/src/index.scss | 58 | ||||
-rw-r--r-- | frontend/src/utils.js | 18 | ||||
-rw-r--r-- | frontend/src/views/Config.js | 8 | ||||
-rw-r--r-- | frontend/src/views/Connections.js | 23 | ||||
-rw-r--r-- | frontend/src/views/Footer.js | 4 | ||||
-rw-r--r-- | frontend/src/views/Header.js | 12 | ||||
-rw-r--r-- | frontend/src/views/Header.scss | 4 | ||||
-rw-r--r-- | frontend/src/views/MainPane.js | 8 | ||||
-rw-r--r-- | frontend/src/views/Rules.js | 4 | ||||
-rw-r--r-- | frontend/src/views/Services.js | 33 |
21 files changed, 489 insertions, 97 deletions
diff --git a/.travis.yml b/.travis.yml index 1d66f6e..b59b12f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ services: - docker before_script: - - docker pull eciavatta/caronte-env - docker pull mongo:4 - docker-compose -f docker-compose.testing.yml up -d --build diff --git a/frontend/src/backend.js b/frontend/src/backend.js new file mode 100644 index 0000000..35ae6e3 --- /dev/null +++ b/frontend/src/backend.js @@ -0,0 +1,36 @@ + +async function request(method, url, data) { + const options = { + method: method, + mode: "cors", + cache: "no-cache", + credentials: "same-origin", + headers: { + "Content-Type": "application/json" + }, + redirect: "follow", + referrerPolicy: "no-referrer", + }; + if (data != null) { + options.body = JSON.stringify(data); + } + const result = await fetch(url, options); + return result.json(); +} + +const backend = { + get: (url = "") => { + return request("GET", url, null); + }, + post: (url = "", data = null) => { + return request("POST", url, data); + }, + put: (url = "", data = null) => { + return request("PUT", url, data); + }, + delete: (url = "", data = null) => { + return request("DELETE", url, data); + } +}; + +export default backend; diff --git a/frontend/src/colors.scss b/frontend/src/colors.scss index 064f9f5..d982f03 100644 --- a/frontend/src/colors.scss +++ b/frontend/src/colors.scss @@ -10,10 +10,30 @@ $color-secondary-2: #df3030; $color-secondary-3: #ff9d9d; $color-secondary-4: #ffdfdf; -$color-blue: #247085; -$color-blue-light: #a5b8be; -$color-blue-dark: #013b4c; +$color-red: #E53935; +$color-red-light: #FFEBEE; +$color-red-dark: #B71C1C; -$color-green: #25965d; -$color-green-light: #cde4d8; -$color-green-dark: #004321; +$color-pink: #D81B60; +$color-pink-light: #FCE4EC; +$color-pink-dark: #880E4F; + +$color-purple: #8E24AA; +$color-purple-light: #F3E5F5; +$color-purple-dark: #4A148C; + +$color-deep-purple: #5E35B1; +$color-deep-purple-light: #EDE7F6; +$color-deep-purple-dark: #311B92; + +$color-indigo: #3949AB; +$color-indigo-light: #E8EAF6; +$color-indigo-dark: #1A237E; + +$color-green: #43A047; +$color-green-light: #E8F5E9; +$color-green-dark: #1B5E20; + +$color-blue: #1E88E5; +$color-blue-light: #E3F2FD; +$color-blue-dark: #0D47A1; diff --git a/frontend/src/components/Connection.js b/frontend/src/components/Connection.js index 93c6438..1149584 100644 --- a/frontend/src/components/Connection.js +++ b/frontend/src/components/Connection.js @@ -1,7 +1,8 @@ import React, {Component} from 'react'; import './Connection.scss'; -import axios from 'axios' import {Button, Form, OverlayTrigger, Popover} from "react-bootstrap"; +import backend from "../backend"; +import {formatSize} from "../utils"; class Connection extends Component { @@ -19,22 +20,18 @@ class Connection extends Component { 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}); - } + backend.post(`/api/connections/${this.props.data.id}/${enabled ? "hide" : "show"}`) + .then(_ => { + 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}); - } + backend.post(`/api/connections/${this.props.data.id}/${marked ? "unmark" : "mark"}`) + .then(_ => { + this.props.onMarked(!marked); + this.setState({update: true}); }); } if (name === "copy") { @@ -114,8 +111,8 @@ class Connection extends Component { <span className="test-tooltip">{duration}</span> </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 className="clickable" onClick={this.props.onSelected}>{formatSize(conn.client_bytes)}</td> + <td className="clickable" onClick={this.props.onSelected}>{formatSize(conn.server_bytes)}</td> <td className="contains-flag"> {/*<OverlayTrigger trigger={["focus", "hover"]} placement="right"*/} {/* overlay={popoverFor("hide", <span>Hide this connection from the list</span>)}>*/} diff --git a/frontend/src/components/ConnectionContent.js b/frontend/src/components/ConnectionContent.js index 20ec92b..0c00e8e 100644 --- a/frontend/src/components/ConnectionContent.js +++ b/frontend/src/components/ConnectionContent.js @@ -1,8 +1,8 @@ import React, {Component} from 'react'; import './ConnectionContent.scss'; import {Button, Dropdown, Row} from 'react-bootstrap'; -import axios from 'axios'; import MessageAction from "./MessageAction"; +import backend from "../backend"; const classNames = require('classnames'); @@ -27,9 +27,9 @@ class ConnectionContent extends Component { this.props.connection !== prevProps.connection || this.state.format !== prevState.format)) { this.setState({loading: true}); // TODO: limit workaround. - axios.get(`/api/streams/${this.props.connection.id}?format=${this.state.format}&limit=999999`).then(res => { + backend.get(`/api/streams/${this.props.connection.id}?format=${this.state.format}&limit=999999`).then(res => { this.setState({ - connectionContent: res.data, + connectionContent: res, loading: false }); }); diff --git a/frontend/src/components/fields/StringField.js b/frontend/src/components/fields/StringField.js new file mode 100644 index 0000000..09fe24d --- /dev/null +++ b/frontend/src/components/fields/StringField.js @@ -0,0 +1,31 @@ +import React, {Component} from 'react'; +import './StringField.scss'; + +const classNames = require('classnames'); + +class StringField extends Component { + + render() { + return ( + <div className={classNames("field", "d-inline-block", {"field-active" : this.props.isActive}, + {"field-invalid": this.props.isInvalid})}> + <div className="input-group"> + <div className="field-name-wrapper"> + <span className="field-name" id={`field-${this.props.name}`}>{this.props.name}:</span> + </div> + <input placeholder={this.props.defaultValue} aria-label={this.props.name} + aria-describedby={`filter-${this.props.name}`} className="field-value" + onChange={this.props.onValueChanged} value={this.props.value} /> + </div> + + { this.props.active && + <div className="field-clear"> + <span className="filter-delete-icon" onClick={() => this.props.onValueChanged("")}>del</span> + </div> + } + </div> + ); + } +} + +export default StringField; diff --git a/frontend/src/components/fields/StringField.scss b/frontend/src/components/fields/StringField.scss new file mode 100644 index 0000000..7efac56 --- /dev/null +++ b/frontend/src/components/fields/StringField.scss @@ -0,0 +1,66 @@ +@import '../../colors.scss'; + +.field { + margin: 0 10px; + position: relative; + + .field-name-wrapper { + background-color: $color-primary-2; + padding: 3px 7px; + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + } + + .field-name { + font-size: 13px; + } + + .field-value { + font-size: 13px; + padding-left: 0; + border-radius: 5px; + + &:focus { + background-color: $color-primary-2; + } + } + + &.field-active { + .field-name-wrapper { + background-color: $color-primary-4; + color: $color-primary-3; + } + + .field-value { + background-color: $color-primary-4; + color: $color-primary-3; + } + } + + &.field-invalid { + .field-name-wrapper { + background-color: $color-secondary-2; + color: $color-primary-4; + } + + .field-value { + background-color: $color-secondary-2; + color: $color-primary-4; + } + } + + .field-delete { + position: absolute; + right: 10px; + top: 10px; + z-index: 10; + font-size: 11px; + letter-spacing: -0.5px; + color: $color-primary-2; + cursor: pointer; + + .field-delete-icon { + font-weight: 800; + } + } +} diff --git a/frontend/src/components/filters/FiltersDefinitions.js b/frontend/src/components/filters/FiltersDefinitions.js index a582d02..d36792e 100644 --- a/frontend/src/components/filters/FiltersDefinitions.js +++ b/frontend/src/components/filters/FiltersDefinitions.js @@ -21,49 +21,60 @@ export const filtersDefinitions = { service_port: <StringConnectionsFilter filterName="service_port" defaultFilterValue="all_ports" replaceFunc={cleanNumber} - validateFunc={validatePort}/>, + validateFunc={validatePort} + key="service_port_filter" />, matched_rules: <RulesConnectionsFilter />, client_address: <StringConnectionsFilter filterName="client_address" defaultFilterValue="all_addresses" - validateFunc={validateIpAddress} />, + validateFunc={validateIpAddress} + key="client_address_filter" />, client_port: <StringConnectionsFilter filterName="client_port" defaultFilterValue="all_ports" replaceFunc={cleanNumber} - validateFunc={validatePort}/>, + validateFunc={validatePort} + key="client_port_filter" />, min_duration: <StringConnectionsFilter filterName="min_duration" defaultFilterValue="0" replaceFunc={cleanNumber} - validateFunc={validateMin(0)}/>, + validateFunc={validateMin(0)} + key="min_duration_filter" />, max_duration: <StringConnectionsFilter filterName="max_duration" defaultFilterValue="∞" - replaceFunc={cleanNumber} />, + replaceFunc={cleanNumber} + key="max_duration_filter" />, min_bytes: <StringConnectionsFilter filterName="min_bytes" defaultFilterValue="0" replaceFunc={cleanNumber} - validateFunc={validateMin(0)} />, + validateFunc={validateMin(0)} + key="min_bytes_filter" />, max_bytes: <StringConnectionsFilter filterName="max_bytes" defaultFilterValue="∞" - replaceFunc={cleanNumber} />, + replaceFunc={cleanNumber} + key="max_bytes_filter" />, started_after: <StringConnectionsFilter filterName="started_after" defaultFilterValue="00:00:00" validateFunc={validate24HourTime} encodeFunc={timeToTimestamp} - decodeFunc={timestampToTime} />, + decodeFunc={timestampToTime} + key="started_after_filter" />, started_before: <StringConnectionsFilter filterName="started_before" defaultFilterValue="00:00:00" validateFunc={validate24HourTime} encodeFunc={timeToTimestamp} - decodeFunc={timestampToTime} />, + decodeFunc={timestampToTime} + key="started_before_filter" />, closed_after: <StringConnectionsFilter filterName="closed_after" defaultFilterValue="00:00:00" validateFunc={validate24HourTime} encodeFunc={timeToTimestamp} - decodeFunc={timestampToTime} />, + decodeFunc={timestampToTime} + key="closed_after_filter" />, closed_before: <StringConnectionsFilter filterName="closed_before" defaultFilterValue="00:00:00" validateFunc={validate24HourTime} encodeFunc={timeToTimestamp} - decodeFunc={timestampToTime} />, + decodeFunc={timestampToTime} + key="closed_before_filter" />, marked: <BooleanConnectionsFilter filterName={"marked"} />, hidden: <BooleanConnectionsFilter filterName={"hidden"} /> }; diff --git a/frontend/src/components/filters/RulesConnectionsFilter.js b/frontend/src/components/filters/RulesConnectionsFilter.js index 358085f..621b6d6 100644 --- a/frontend/src/components/filters/RulesConnectionsFilter.js +++ b/frontend/src/components/filters/RulesConnectionsFilter.js @@ -3,7 +3,7 @@ import {withRouter} from "react-router-dom"; import {Redirect} from "react-router"; import './RulesConnectionsFilter.scss'; import ReactTags from 'react-tag-autocomplete'; -import axios from 'axios'; +import backend from "../../backend"; const classNames = require('classnames'); @@ -24,8 +24,8 @@ class RulesConnectionsFilter extends Component { let params = new URLSearchParams(this.props.location.search); let activeRules = params.getAll("matched_rules") || []; - axios.get("/api/rules").then(res => { - let rules = res.data.flatMap(rule => rule.enabled ? [{id: rule.id, name: rule.name}] : []); + backend.get("/api/rules").then(res => { + let rules = res.flatMap(rule => rule.enabled ? [{id: rule.id, name: rule.name}] : []); activeRules = rules.filter(rule => activeRules.some(id => rule.id === id)); this.setState({rules, activeRules, mounted: true}); }); diff --git a/frontend/src/components/panels/PcapPane.js b/frontend/src/components/panels/PcapPane.js new file mode 100644 index 0000000..817c7b5 --- /dev/null +++ b/frontend/src/components/panels/PcapPane.js @@ -0,0 +1,121 @@ +import React, {Component} from 'react'; +import './PcapPane.scss'; +import Table from "react-bootstrap/Table"; +import backend from "../../backend"; +import {formatSize, timestampToTime2} from "../../utils"; +import {Container, Row, Col, Form} from "react-bootstrap"; +import StringField from "../fields/StringField"; + +class PcapPane extends Component { + + constructor(props) { + super(props); + + this.state = { + sessions: [], + }; + + this.loadSessions = this.loadSessions.bind(this); + } + + componentDidMount() { + this.loadSessions(); + } + + loadSessions() { + backend.get("/api/pcap/sessions").then(res => this.setState({sessions: res})); + } + + render() { + let sessions = this.state.sessions.map(s => + <tr className="table-row"> + <td>{s["id"].substring(0, 8)}</td> + <td>{timestampToTime2(s["started_at"])}</td> + <td>{((new Date(s["completed_at"]) - new Date(s["started_at"])) / 1000).toFixed(3)}s</td> + <td>{formatSize(s["size"])}</td> + <td>{s["processed_packets"]}</td> + <td>{s["invalid_packets"]}</td> + <td>undefined</td> + <td className="table-cell-action"><a target="_blank" href={"/api/pcap/sessions/" + s["id"] + "/download"}>download</a></td> + </tr> + ); + + return ( + <div className="pane-container"> + <div className="pane-section"> + <div className="section-header"> + <span className="api-request">GET /api/pcap/sessions</span> + <span className="api-response">200 OK</span> + </div> + + <div className="section-table"> + <Table borderless size="sm"> + <thead> + <tr> + <th>id</th> + <th>started_at</th> + <th>duration</th> + <th>size</th> + <th>processed_packets</th> + <th>invalid_packets</th> + <th>packets_per_service</th> + <th>actions</th> + </tr> + </thead> + <tbody> + {sessions} + </tbody> + </Table> + </div> + </div> + + <div className="pane-section"> + <Container className="p-0"> + <Row> + <Col> + <div className="section-header"> + <span className="api-request">POST /api/pcap/upload</span> + <span className="api-response"></span> + </div> + + <div className="section-content"> + <Form.File className="custom-file" onChange={this.onFileChange} + label=".pcap/.pcapng" id="custom-file" + custom={true} + /> + + + <br/><br/><br/><br/> + <StringField /> + + </div> + </Col> + + <Col> + <div className="section-header"> + <span className="api-request">POST /api/pcap/file</span> + <span className="api-response"></span> + </div> + + <div className="section-content"> + <Form.Control type="text" id="pcap-upload" className="custom-file" + onChange={this.onLocalFileChange} placeholder="local .pcap/.pcapng" + custom + /> + </div> + </Col> + </Row> + </Container> + + + + + </div> + + </div> + + ); + } +} + +export default PcapPane; diff --git a/frontend/src/components/panels/PcapPane.scss b/frontend/src/components/panels/PcapPane.scss new file mode 100644 index 0000000..3df87f5 --- /dev/null +++ b/frontend/src/components/panels/PcapPane.scss @@ -0,0 +1,55 @@ +@import '../../colors.scss'; + +.pane-container { + background-color: $color-primary-3; + padding: 10px 10px 0; + height: 100%; + + .section-header { + background-color: $color-primary-2; + padding: 5px 10px; + height: 31px; + + font-weight: 500; + font-size: 14px; + + .api-response { + float: right; + } + } + + .section-table { + margin-top: 10px; + + .table-row { + background-color: $color-primary-0; + border-top: 3px solid $color-primary-3; + border-bottom: 3px solid $color-primary-3; + } + + .table-cell-action { + font-size: 13px; + font-weight: 600; + } + } + + .section-content { + background-color: $color-primary-0; + padding: 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; + } + + + +}
\ No newline at end of file diff --git a/frontend/src/index.scss b/frontend/src/index.scss index 53ce4dd..358fd70 100644 --- a/frontend/src/index.scss +++ b/frontend/src/index.scss @@ -49,14 +49,62 @@ pre { } .btn-red { - color: $color-secondary-4; - background-color: $color-secondary-2; - border-bottom: 5px solid $color-secondary-1; + color: $color-red-light; + background-color: $color-red; + border-bottom: 5px solid $color-red-dark; &:hover, &:active { - color: $color-secondary-4; - background-color: $color-secondary-1; + color: $color-red-light; + background-color: $color-red-dark; + } +} + +.btn-pink { + color: $color-pink-light; + background-color: $color-pink; + border-bottom: 5px solid $color-pink-dark; + + &:hover, + &:active { + color: $color-pink-light; + background-color: $color-pink-dark; + } +} + +.btn-purple { + color: $color-purple-light; + background-color: $color-purple; + border-bottom: 5px solid $color-purple-dark; + + &:hover, + &:active { + color: $color-purple-light; + background-color: $color-purple-dark; + } +} + +.btn-deep-purple { + color: $color-deep-purple-light; + background-color: $color-deep-purple; + border-bottom: 5px solid $color-deep-purple-dark; + + &:hover, + &:active { + color: $color-deep-purple-light; + background-color: $color-deep-purple-dark; + } +} + +.btn-indigo { + color: $color-indigo-light; + background-color: $color-indigo; + border-bottom: 5px solid $color-indigo-dark; + + &:hover, + &:active { + color: $color-indigo-light; + background-color: $color-indigo-dark; } } diff --git a/frontend/src/utils.js b/frontend/src/utils.js index 7381f69..4991755 100644 --- a/frontend/src/utils.js +++ b/frontend/src/utils.js @@ -64,3 +64,21 @@ export function timestampToDateTime(timestamp) { let d = new Date(timestamp); return d.toLocaleDateString() + " " + d.toLocaleTimeString(); } + +export function timestampToTime2(timestamp) { + let d = new Date(timestamp); + let hours = d.getHours(); + let minutes = "0" + d.getMinutes(); + let seconds = "0" + d.getSeconds(); + return hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2); +} + +export function formatSize(size) { + if (size < 1000) { + return `${size}`; + } else if (size < 1000000) { + return `${(size / 1000).toFixed(1)}K`; + } else { + return `${(size / 1000000).toFixed(1)}M`; + } +} diff --git a/frontend/src/views/Config.js b/frontend/src/views/Config.js index f5766eb..a770378 100644 --- a/frontend/src/views/Config.js +++ b/frontend/src/views/Config.js @@ -1,10 +1,6 @@ -import { - validateIpAddress, -} from "../utils"; -import React, {Component, useState} from 'react'; +import React, {Component} from 'react'; import './Config.scss'; -import {Button, ButtonGroup, ToggleButton, Col, Container, Form, FormControl, InputGroup, Modal, Row, Table} from "react-bootstrap"; -import {createCurlCommand} from '../utils'; +import {Button, ButtonGroup, Col, Container, Form, Modal, Row, Table, ToggleButton} from "react-bootstrap"; class Config extends Component { diff --git a/frontend/src/views/Connections.js b/frontend/src/views/Connections.js index 62733d7..da8958b 100644 --- a/frontend/src/views/Connections.js +++ b/frontend/src/views/Connections.js @@ -1,10 +1,10 @@ import React, {Component} from 'react'; import './Connections.scss'; -import axios from 'axios'; import Connection from "../components/Connection"; import Table from 'react-bootstrap/Table'; import {Redirect} from 'react-router'; import {withRouter} from "react-router-dom"; +import backend from "../backend"; class Connections extends Component { @@ -75,15 +75,15 @@ class Connections extends Component { } this.setState({loading: true, prevParams: params}); - let res = await axios.get(`${url}?${urlParams}`); + let res = await backend.get(`${url}?${urlParams}`); let connections = this.state.connections; let firstConnection = this.state.firstConnection; let lastConnection = this.state.lastConnection; if (params !== undefined && params.from !== undefined) { - if (res.data.length > 0) { - connections = this.state.connections.concat(res.data); + if (res.length > 0) { + connections = this.state.connections.concat(res); lastConnection = connections[connections.length - 1]; if (connections.length > this.maxConnections) { connections = connections.slice(connections.length - this.maxConnections, @@ -92,8 +92,8 @@ class Connections extends Component { } } } else if (params !== undefined && params.to !== undefined) { - if (res.data.length > 0) { - connections = res.data.concat(this.state.connections); + if (res.length > 0) { + connections = res.concat(this.state.connections); firstConnection = connections[0]; if (connections.length > this.maxConnections) { connections = connections.slice(0, this.maxConnections); @@ -101,8 +101,8 @@ class Connections extends Component { } } } else { - if (res.data.length > 0) { - connections = res.data; + if (res.length > 0) { + connections = res; firstConnection = connections[0]; lastConnection = connections[connections.length - 1]; } else { @@ -115,8 +115,7 @@ class Connections extends Component { let flagRule = this.state.flagRule; let rules = this.state.rules; if (flagRule === null) { - let res = await axios.get("/api/rules"); - rules = res.data; + rules = await backend.get("/api/rules"); flagRule = rules.filter(rule => { return rule.name === "flag"; })[0]; @@ -125,7 +124,7 @@ class Connections extends Component { this.setState({ loading: false, connections: connections, - rules: res.data, + rules: res, flagRule: flagRule, firstConnection: firstConnection, lastConnection: lastConnection @@ -134,7 +133,7 @@ class Connections extends Component { render() { let redirect; - let queryString = this.state.queryString !== null ? this.state.queryString : "" + let queryString = this.state.queryString !== null ? this.state.queryString : ""; if (this.state.selected) { let format = this.props.match.params.format; format = format !== undefined ? "/" + format : ""; diff --git a/frontend/src/views/Footer.js b/frontend/src/views/Footer.js index b6ffd9d..0a3c5a3 100644 --- a/frontend/src/views/Footer.js +++ b/frontend/src/views/Footer.js @@ -8,11 +8,11 @@ class Footer extends Component { <footer className="footer container-fluid"> <div className="row"> <div className="col-12"> - <div className="footer-timeline">timeline</div> + <div className="footer-timeline">timeline - <a href="https://github.com/eciavatta/caronte/issues/12">to be implemented</a></div> </div> </div> </footer> - ) + ); } } diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js index 0af7abf..5860d80 100644 --- a/frontend/src/views/Header.js +++ b/frontend/src/views/Header.js @@ -69,12 +69,12 @@ class Header extends Component { <div className="col"> <div className="header-buttons"> - <Button onClick={this.props.onOpenFilters}>filters</Button> - <Button variant="warning" onClick={this.props.onOpenUpload}>pcaps</Button> - <Button variant="blue" onClick={this.props.onOpenRules}>rules</Button> - <Button variant="red" onClick={this.props.onOpenServices}>services</Button> - <Button variant="green" onClick={this.props.onOpenConfig} - disabled={this.props.onConfigDone}>config</Button> + <Button variant="pink" onClick={this.props.onOpenFilters}>filters</Button> + <Button variant="purple" onClick={this.props.onOpenUpload}>pcaps</Button> + <Button variant="deep-purple" onClick={this.props.onOpenRules}>rules</Button> + <Button variant="indigo" onClick={this.props.onOpenServices}>services</Button> + <Button variant="blue" onClick={this.props.onOpenConfig} + disabled={false}>config</Button> </div> </div> </div> diff --git a/frontend/src/views/Header.scss b/frontend/src/views/Header.scss index e84e758..e36b2d6 100644 --- a/frontend/src/views/Header.scss +++ b/frontend/src/views/Header.scss @@ -16,6 +16,10 @@ .header-buttons { margin: 5px 0; text-align: right; + + button { + margin-left: 10px; + } } .filters-bar-wrapper { diff --git a/frontend/src/views/MainPane.js b/frontend/src/views/MainPane.js index 69de725..3c0d795 100644 --- a/frontend/src/views/MainPane.js +++ b/frontend/src/views/MainPane.js @@ -3,7 +3,8 @@ import './MainPane.scss'; import Connections from "./Connections"; import ConnectionContent from "../components/ConnectionContent"; import {withRouter} from "react-router-dom"; -import axios from 'axios'; +import PcapPane from "../components/panels/PcapPane"; +import backend from "../backend"; class MainPane extends Component { @@ -17,9 +18,9 @@ class MainPane extends Component { componentDidMount() { if ('id' in this.props.match.params) { const id = this.props.match.params.id; - axios.get(`/api/connections/${id}`).then(res => { + backend.get(`/api/connections/${id}`).then(res => { if (res.status === 200) { - this.setState({selectedConnection: res.data}); + this.setState({selectedConnection: res}); } }); } @@ -34,6 +35,7 @@ class MainPane extends Component { <Connections onSelected={(c) => this.setState({selectedConnection: c})} /> </div> <div className="col-md-6 pl-0 pane"> + {/*<PcapPane />*/} <ConnectionContent connection={this.state.selectedConnection}/> </div> </div> diff --git a/frontend/src/views/Rules.js b/frontend/src/views/Rules.js index 3424410..bbc3bb6 100644 --- a/frontend/src/views/Rules.js +++ b/frontend/src/views/Rules.js @@ -1,7 +1,7 @@ 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 backend from "../backend"; class Rules extends Component { @@ -18,7 +18,7 @@ class Rules extends Component { } loadRules() { - axios.get("/api/rules").then(res => this.setState({rules: res.data})); + backend.get("/api/rules").then(res => this.setState({rules: res.data})); } render() { diff --git a/frontend/src/views/Services.js b/frontend/src/views/Services.js index 0de021f..22d61b3 100644 --- a/frontend/src/views/Services.js +++ b/frontend/src/views/Services.js @@ -1,8 +1,8 @@ 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'; +import backend from "../backend"; class Services extends Component { @@ -64,31 +64,20 @@ class Services extends Component { saveService() { if (this.state.portValid && this.state.nameValid) { - const requestOptions = { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - color: this.state.color, - name: this.state.name, - notes: this.state.notes, - port: this.state.port, - }) - }; - - - fetch('/api/services', requestOptions) - .then(function(response){ - console.log(response); - } - ); - - this.newService(); - this.loadServices(); + backend.put("/api/services", { + color: this.state.color, + name: this.state.name, + notes: this.state.notes, + port: this.state.port, + }).then(_ => { + this.newService(); + this.loadServices(); + }); } } loadServices() { - axios.get("/api/services").then(res => this.setState({services: res.data})); + backend.get("/api/services").then(res => this.setState({services: res})); } componentDidUpdate(prevProps, prevState, snapshot) { |