From 8d07bfe5f17534b7301a064aeaf8ed8071f10a40 Mon Sep 17 00:00:00 2001
From: Emiliano Ciavatta
Date: Wed, 23 Sep 2020 20:19:09 +0200
Subject: Frontend refactor: checkpoint
---
frontend/src/components/Connection.js | 27 ++---
frontend/src/components/ConnectionContent.js | 6 +-
frontend/src/components/fields/StringField.js | 31 ++++++
frontend/src/components/fields/StringField.scss | 66 +++++++++++
.../src/components/filters/FiltersDefinitions.js | 33 ++++--
.../components/filters/RulesConnectionsFilter.js | 6 +-
frontend/src/components/panels/PcapPane.js | 121 +++++++++++++++++++++
frontend/src/components/panels/PcapPane.scss | 55 ++++++++++
8 files changed, 313 insertions(+), 32 deletions(-)
create mode 100644 frontend/src/components/fields/StringField.js
create mode 100644 frontend/src/components/fields/StringField.scss
create mode 100644 frontend/src/components/panels/PcapPane.js
create mode 100644 frontend/src/components/panels/PcapPane.scss
(limited to 'frontend/src/components')
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 {
{duration}
-
{conn.client_bytes} |
- {conn.server_bytes} |
+ {formatSize(conn.client_bytes)} |
+ {formatSize(conn.server_bytes)} |
{/*Hide this connection from the list)}>*/}
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 (
+
+
+
+ {this.props.name}:
+
+
+
+
+ { this.props.active &&
+
+ this.props.onValueChanged("")}>del
+
+ }
+
+ );
+ }
+}
+
+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: ,
+ validateFunc={validatePort}
+ key="service_port_filter" />,
matched_rules: ,
client_address: ,
+ validateFunc={validateIpAddress}
+ key="client_address_filter" />,
client_port: ,
+ validateFunc={validatePort}
+ key="client_port_filter" />,
min_duration: ,
+ validateFunc={validateMin(0)}
+ key="min_duration_filter" />,
max_duration: ,
+ replaceFunc={cleanNumber}
+ key="max_duration_filter" />,
min_bytes: ,
+ validateFunc={validateMin(0)}
+ key="min_bytes_filter" />,
max_bytes: ,
+ replaceFunc={cleanNumber}
+ key="max_bytes_filter" />,
started_after: ,
+ decodeFunc={timestampToTime}
+ key="started_after_filter" />,
started_before: ,
+ decodeFunc={timestampToTime}
+ key="started_before_filter" />,
closed_after: ,
+ decodeFunc={timestampToTime}
+ key="closed_after_filter" />,
closed_before: ,
+ decodeFunc={timestampToTime}
+ key="closed_before_filter" />,
marked: ,
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 =>
+
+ {s["id"].substring(0, 8)} |
+ {timestampToTime2(s["started_at"])} |
+ {((new Date(s["completed_at"]) - new Date(s["started_at"])) / 1000).toFixed(3)}s |
+ {formatSize(s["size"])} |
+ {s["processed_packets"]} |
+ {s["invalid_packets"]} |
+ undefined |
+ download |
+
+ );
+
+ return (
+
+
+
+ GET /api/pcap/sessions
+ 200 OK
+
+
+
+
+
+
+ id |
+ started_at |
+ duration |
+ size |
+ processed_packets |
+ invalid_packets |
+ packets_per_service |
+ actions |
+
+
+
+ {sessions}
+
+
+
+
+
+
+
+
+
+
+ POST /api/pcap/upload
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ POST /api/pcap/file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+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
--
cgit v1.2.3-70-g09d2
|