From 1412a34f64e234dbc7d4e6815b841699f4dd104a Mon Sep 17 00:00:00 2001
From: Emiliano Ciavatta
Date: Sun, 27 Sep 2020 17:48:38 +0200
Subject: Add other custom fields
---
frontend/src/components/fields/ButtonField.scss | 119 ++++++++++++++++++++++++
1 file changed, 119 insertions(+)
create mode 100644 frontend/src/components/fields/ButtonField.scss
(limited to 'frontend/src/components/fields/ButtonField.scss')
diff --git a/frontend/src/components/fields/ButtonField.scss b/frontend/src/components/fields/ButtonField.scss
new file mode 100644
index 0000000..933279e
--- /dev/null
+++ b/frontend/src/components/fields/ButtonField.scss
@@ -0,0 +1,119 @@
+@import '../../colors.scss';
+
+.button-field {
+ font-size: 0.9em;
+
+ .button-bordered {
+ border-bottom: 5px solid $color-primary-1;
+ }
+
+ &.field-small {
+ font-size: 0.8em;
+ }
+
+ .button-variant-red {
+ color: $color-red-light;
+ background-color: $color-red;
+
+ &.button-bordered {
+ border-bottom: 5px solid $color-red-dark;
+ }
+
+ &:hover,
+ &:active {
+ color: $color-red-light;
+ background-color: $color-red-dark;
+ }
+ }
+
+ .button-variant-pink {
+ color: $color-pink-light;
+ background-color: $color-pink;
+
+ &.button-bordered {
+ border-bottom: 5px solid $color-pink-dark;
+ }
+
+ &:hover,
+ &:active {
+ color: $color-pink-light;
+ background-color: $color-pink-dark;
+ }
+ }
+
+ .button-variant-purple {
+ color: $color-purple-light;
+ background-color: $color-purple;
+
+ &.button-bordered {
+ border-bottom: 5px solid $color-purple-dark;
+ }
+
+ &:hover,
+ &:active {
+ color: $color-purple-light;
+ background-color: $color-purple-dark;
+ }
+ }
+
+ .button-variant-deep-purple {
+ color: $color-deep-purple-light;
+ background-color: $color-deep-purple;
+
+ &.button-bordered {
+ border-bottom: 5px solid $color-deep-purple-dark;
+ }
+
+ &:hover,
+ &:active {
+ color: $color-deep-purple-light;
+ background-color: $color-deep-purple-dark;
+ }
+ }
+
+ .button-variant-indigo {
+ color: $color-indigo-light;
+ background-color: $color-indigo;
+
+ &.button-bordered {
+ border-bottom: 5px solid $color-indigo-dark;
+ }
+
+ &:hover,
+ &:active {
+ color: $color-indigo-light;
+ background-color: $color-indigo-dark;
+ }
+ }
+
+ .button-variant-blue {
+ color: $color-blue-light;
+ background-color: $color-blue;
+
+ &.button-bordered {
+ border-bottom: 5px solid $color-blue-dark;
+ }
+
+ &:hover,
+ &:active {
+ color: $color-blue-light;
+ background-color: $color-blue-dark;
+ }
+ }
+
+ .button-variant-green {
+ color: $color-green-light;
+ background-color: $color-green;
+
+ &.button-bordered {
+ border-bottom: 5px solid $color-green-dark;
+ }
+
+ &:hover,
+ &:active {
+ color: $color-green-light;
+ background-color: $color-green-dark;
+ }
+ }
+
+}
--
cgit v1.2.3-70-g09d2
From 7f4cc5d3f3f92338a464853c182b9d6a3ea850eb Mon Sep 17 00:00:00 2001
From: Emiliano Ciavatta
Date: Sun, 27 Sep 2020 18:43:27 +0200
Subject: Replaced the old fields with the new ones
---
frontend/src/components/Connection.js | 8 +--
frontend/src/components/ConnectionContent.js | 68 +++++-----------------
frontend/src/components/ConnectionContent.scss | 12 ++--
frontend/src/components/MessageAction.js | 4 +-
frontend/src/components/fields/ButtonField.js | 9 +++
frontend/src/components/fields/ButtonField.scss | 4 ++
frontend/src/components/fields/CheckField.scss | 4 ++
frontend/src/components/fields/ChoiceField.js | 15 ++++-
frontend/src/components/fields/ChoiceField.scss | 2 +-
.../src/components/fields/extensions/ColorField.js | 17 +++---
.../components/fields/extensions/ColorField.scss | 9 ++-
frontend/src/components/panels/PcapPane.js | 7 ++-
frontend/src/components/panels/RulePane.js | 12 +---
frontend/src/views/Filters.js | 5 +-
frontend/src/views/Header.js | 13 +++--
frontend/src/views/Header.scss | 9 +--
16 files changed, 93 insertions(+), 105 deletions(-)
(limited to 'frontend/src/components/fields/ButtonField.scss')
diff --git a/frontend/src/components/Connection.js b/frontend/src/components/Connection.js
index 1149584..7887185 100644
--- a/frontend/src/components/Connection.js
+++ b/frontend/src/components/Connection.js
@@ -1,8 +1,9 @@
import React, {Component} from 'react';
import './Connection.scss';
-import {Button, Form, OverlayTrigger, Popover} from "react-bootstrap";
+import {Form, OverlayTrigger, Popover} from "react-bootstrap";
import backend from "../backend";
import {formatSize} from "../utils";
+import ButtonField from "./fields/ButtonField";
class Connection extends Component {
@@ -96,9 +97,8 @@ class Connection extends Component {
{ type === "file" && }
- }
+
{ type !== "file" && value !== "" &&
diff --git a/frontend/src/components/fields/extensions/NumericField.js b/frontend/src/components/fields/extensions/NumericField.js
index 8823c42..ed81ed7 100644
--- a/frontend/src/components/fields/extensions/NumericField.js
+++ b/frontend/src/components/fields/extensions/NumericField.js
@@ -11,25 +11,31 @@ class NumericField extends Component {
};
}
- render() {
- const handler = (value) => {
- value = value.replace(/[^\d]/gi, '');
- let intValue = 0;
- if (value !== "") {
- intValue = parseInt(value);
- }
- const valid =
- (!this.props.validate || (typeof this.props.validate === "function" && this.props.validate(intValue))) &&
- (!this.props.min || (typeof this.props.min === "number" && intValue >= this.props.min)) &&
- (!this.props.max || (typeof this.props.max === "number" && intValue <= this.props.max));
- this.setState({invalid: !valid});
- if (this.props.onChange) {
- this.props.onChange(intValue);
- }
- };
+ componentDidUpdate(prevProps, prevState, snapshot) {
+ if (prevProps.value !== this.props.value) {
+ this.onChange(this.props.value);
+ }
+ }
+ onChange = (value) => {
+ value = value.toString().replace(/[^\d]/gi, '');
+ let intValue = 0;
+ if (value !== "") {
+ intValue = parseInt(value);
+ }
+ const valid =
+ (!this.props.validate || (typeof this.props.validate === "function" && this.props.validate(intValue))) &&
+ (!this.props.min || (typeof this.props.min === "number" && intValue >= this.props.min)) &&
+ (!this.props.max || (typeof this.props.max === "number" && intValue <= this.props.max));
+ this.setState({invalid: !valid});
+ if (typeof this.props.onChange === "function") {
+ this.props.onChange(intValue);
+ }
+ };
+
+ render() {
return (
-
);
}
diff --git a/frontend/src/components/filters/RulesConnectionsFilter.js b/frontend/src/components/filters/RulesConnectionsFilter.js
index 0741bea..f4d0b1c 100644
--- a/frontend/src/components/filters/RulesConnectionsFilter.js
+++ b/frontend/src/components/filters/RulesConnectionsFilter.js
@@ -25,7 +25,7 @@ class RulesConnectionsFilter extends Component {
let activeRules = params.getAll("matched_rules") || [];
backend.getJson("/api/rules").then(res => {
- let rules = res.flatMap(rule => rule.enabled ? [{id: rule.id, name: rule.name}] : []);
+ let rules = res.json.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/filters/StringConnectionsFilter.js b/frontend/src/components/filters/StringConnectionsFilter.js
index a304198..f463593 100644
--- a/frontend/src/components/filters/StringConnectionsFilter.js
+++ b/frontend/src/components/filters/StringConnectionsFilter.js
@@ -115,7 +115,7 @@ class StringConnectionsFilter extends Component {
return (
{redirect}
diff --git a/frontend/src/components/objects/LinkPopover.js b/frontend/src/components/objects/LinkPopover.js
new file mode 100644
index 0000000..58b2f6a
--- /dev/null
+++ b/frontend/src/components/objects/LinkPopover.js
@@ -0,0 +1,33 @@
+import React, {Component} from 'react';
+import {randomClassName} from "../../utils";
+import {OverlayTrigger, Popover} from "react-bootstrap";
+import './LinkPopover.scss';
+
+class LinkPopover extends Component {
+
+ constructor(props) {
+ super(props);
+
+ this.id = `link-overlay-${randomClassName()}`;
+ }
+
+ render() {
+ const popover = (
+
+ {this.props.title && {this.props.title}}
+
+ {this.props.content}
+
+
+ );
+
+ return (this.props.content ?
+
+ {this.props.text}
+ :
+
{this.props.text}
+ );
+ }
+}
+
+export default LinkPopover;
diff --git a/frontend/src/components/objects/LinkPopover.scss b/frontend/src/components/objects/LinkPopover.scss
new file mode 100644
index 0000000..d5f4879
--- /dev/null
+++ b/frontend/src/components/objects/LinkPopover.scss
@@ -0,0 +1,7 @@
+@import '../../colors.scss';
+
+.link-popover {
+ text-decoration: underline;
+ font-weight: 500;
+ cursor: pointer;
+}
\ No newline at end of file
diff --git a/frontend/src/components/panels/PcapPane.js b/frontend/src/components/panels/PcapPane.js
index a491dff..cfba037 100644
--- a/frontend/src/components/panels/PcapPane.js
+++ b/frontend/src/components/panels/PcapPane.js
@@ -1,5 +1,6 @@
import React, {Component} from 'react';
-import './PcapPane.scss';
+// import './PcapPane.scss';
+import './common.scss';
import Table from "react-bootstrap/Table";
import backend from "../../backend";
import {createCurlCommand, formatSize, timestampToTime2} from "../../utils";
@@ -37,7 +38,7 @@ class PcapPane extends Component {
}
loadSessions = () => {
- backend.getJson("/api/pcap/sessions").then(res => this.setState({sessions: res}));
+ backend.getJson("/api/pcap/sessions").then(res => this.setState({sessions: res.json}));
};
handleUploadFileChange = (file) => {
@@ -104,7 +105,7 @@ class PcapPane extends Component {
{s["processed_packets"]} |
{s["invalid_packets"]} |
undefined |
-
download
|
diff --git a/frontend/src/components/panels/PcapPane.scss b/frontend/src/components/panels/PcapPane.scss
index ce28227..3c4d10b 100644
--- a/frontend/src/components/panels/PcapPane.scss
+++ b/frontend/src/components/panels/PcapPane.scss
@@ -1,51 +1,10 @@
@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;
+ .table-cell-action {
+ font-size: 13px;
+ font-weight: 600;
}
.upload-actions {
diff --git a/frontend/src/components/panels/RulePane.js b/frontend/src/components/panels/RulePane.js
index 2e91d91..01e37fa 100644
--- a/frontend/src/components/panels/RulePane.js
+++ b/frontend/src/components/panels/RulePane.js
@@ -1,4 +1,5 @@
import React, {Component} from 'react';
+import './common.scss';
import './RulePane.scss';
import Table from "react-bootstrap/Table";
import {Col, Container, Row} from "react-bootstrap";
@@ -10,6 +11,11 @@ import NumericField from "../fields/extensions/NumericField";
import ColorField from "../fields/extensions/ColorField";
import ChoiceField from "../fields/ChoiceField";
import ButtonField from "../fields/ButtonField";
+import validation from "../../validation";
+import LinkPopover from "../objects/LinkPopover";
+
+const classNames = require('classnames');
+const _ = require('lodash');
class RulePane extends Component {
@@ -18,103 +24,352 @@ class RulePane extends Component {
this.state = {
rules: [],
+ newRule: this.emptyRule,
+ newPattern: this.emptyPattern
+ };
+
+ this.directions = {
+ 0: "both",
+ 1: "c->s",
+ 2: "s->c"
};
}
componentDidMount() {
+ this.reset();
this.loadRules();
}
+ emptyRule = {
+ "name": "",
+ "color": "",
+ "notes": "",
+ "enabled": true,
+ "patterns": [],
+ "filter": {
+ "service_port": 0,
+ "client_address": "",
+ "client_port": 0,
+ "min_duration": 0,
+ "max_duration": 0,
+ "min_bytes": 0,
+ "max_bytes": 0
+ },
+ "version": 0
+ };
+
+ emptyPattern = {
+ "regex": "",
+ "flags": {
+ "caseless": false,
+ "dot_all": false,
+ "multi_line": false,
+ "utf_8_mode": false,
+ "unicode_property": false
+ },
+ "min_occurrences": 0,
+ "max_occurrences": 0,
+ "direction": 0
+ };
+
loadRules = () => {
- backend.getJson("/api/rules").then(res => this.setState({rules: res}));
+ backend.getJson("/api/rules").then(res => this.setState({rules: res.json, rulesStatusCode: res.status}))
+ .catch(res => this.setState({rulesStatusCode: res.status, rulesResponse: JSON.stringify(res.json)}));
+ };
+
+ addRule = () => {
+ if (this.validateRule(this.state.newRule)) {
+ backend.postJson("/api/rules", this.state.newRule).then(res => {
+ this.reset();
+ this.setState({ruleStatusCode: res.status});
+ this.loadRules();
+ }).catch(res => {
+ this.setState({ruleStatusCode: res.status, ruleResponse: JSON.stringify(res.json)});
+ });
+ }
+ };
+
+ updateRule = () => {
+ const rule = this.state.selectedRule;
+ if (this.validateRule(rule)) {
+ backend.putJson(`/api/rules/${rule.id}`, rule).then(res => {
+ this.reset();
+ this.setState({ruleStatusCode: res.status});
+ this.loadRules();
+ }).catch(res => {
+ this.setState({ruleStatusCode: res.status, ruleResponse: JSON.stringify(res.json)});
+ });
+ }
+ };
+
+ validateRule = (rule) => {
+ let valid = true;
+ if (rule.name.length < 3) {
+ this.setState({ruleNameError: "name.length < 3"});
+ valid = false;
+ }
+ if (!validation.isValidColor(rule.color)) {
+ this.setState({ruleColorError: "color is not hexcolor"});
+ valid = false;
+ }
+ if (!validation.isValidPort(rule.filter.service_port)) {
+ this.setState({ruleServicePortError: "service_port > 65565"});
+ valid = false;
+ }
+ if (!validation.isValidPort(rule.filter.client_port)) {
+ this.setState({ruleClientPortError: "client_port > 65565"});
+ valid = false;
+ }
+ if (!validation.isValidAddress(rule.filter.client_address)) {
+ this.setState({ruleClientAddressError: "client_address is not ip_address"});
+ valid = false;
+ }
+ if (rule.filter.min_duration > rule.filter.max_duration) {
+ this.setState({ruleDurationError: "min_duration > max_dur."});
+ valid = false;
+ }
+ if (rule.filter.min_bytes > rule.filter.max_bytes) {
+ this.setState({ruleBytesError: "min_bytes > max_bytes"});
+ valid = false;
+ }
+ if (rule.patterns.length < 1) {
+ this.setState({rulePatternsError: "patterns.length < 1"});
+ valid = false;
+ }
+
+ return valid;
};
+ reset = () => {
+ const newRule = _.cloneDeep(this.emptyRule);
+ const newPattern = _.cloneDeep(this.emptyPattern);
+ this.setState({
+ selectedRule: null,
+ newRule: newRule,
+ selectedPattern: null,
+ newPattern: newPattern,
+ patternRegexFocused: false,
+ patternOccurrencesFocused: false,
+ ruleNameError: null,
+ ruleColorError: null,
+ ruleServicePortError: null,
+ ruleClientPortError: null,
+ ruleClientAddressError: null,
+ ruleDurationError: null,
+ ruleBytesError: null,
+ rulePatternsError: null,
+ ruleStatusCode: null,
+ rulesStatusCode: null,
+ ruleResponse: null,
+ rulesResponse: null
+ });
+ };
+
+ updateParam = (callback) => {
+ const updatedRule = this.currentRule();
+ callback(updatedRule);
+ this.setState({newRule: updatedRule});
+ };
+
+ currentRule = () => this.state.selectedRule != null ? this.state.selectedRule : this.state.newRule;
+
+ addPattern = (pattern) => {
+ if (!this.validatePattern(pattern)) {
+ return;
+ }
+
+ const newPattern = _.cloneDeep(this.emptyPattern);
+ this.currentRule().patterns.push(pattern);
+ this.setState({
+ newPattern: newPattern
+ });
+ };
+
+ editPattern = (pattern) => {
+ this.setState({
+ selectedPattern: pattern
+ });
+ };
+
+ updatePattern = (pattern) => {
+ if (!this.validatePattern(pattern)) {
+ return;
+ }
+
+ this.setState({
+ selectedPattern: null
+ });
+ };
+
+ validatePattern = (pattern) => {
+ let valid = true;
+ if (pattern.regex === "") {
+ valid = false;
+ this.setState({patternRegexFocused: true});
+ }
+ if (pattern.min_occurrences > pattern.max_occurrences) {
+ valid = false;
+ this.setState({patternOccurrencesFocused: true});
+ }
+ return valid;
+ };
render() {
+ const isUpdate = this.state.selectedRule != null;
+ const rule = this.currentRule();
+ const pattern = this.state.selectedPattern || this.state.newPattern;
+
let rules = this.state.rules.map(r =>
-
+
{
+ this.reset();
+ this.setState({selectedRule: _.cloneDeep(r)});
+ }} className={classNames("row-small", "row-clickable", {"row-selected": rule.id === r.id })}>
{r["id"].substring(0, 8)} |
{r["name"]} |
+ |
{r["notes"]} |
- {/*{((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*/}
- {/* | */}
+
+ );
+
+ let patterns = (this.state.selectedPattern == null && !isUpdate ?
+ rule.patterns.concat(this.state.newPattern) :
+ rule.patterns
+ ).map(p => p === pattern ?
+
+
+ {
+ this.updateParam(() => pattern.regex = v);
+ this.setState({patternRegexFocused: pattern.regex === ""});
+ }} />
+ |
+ this.updateParam(() => pattern.flags.caseless = v)}/> |
+ this.updateParam(() => pattern.flags.dot_all = v)}/> |
+ this.updateParam(() => pattern.flags.multi_line = v)}/> |
+ this.updateParam(() => pattern.flags.utf_8_mode = v)}/> |
+ this.updateParam(() => pattern.flags.unicode_property = v)}/> |
+
+ this.updateParam(() => pattern.min_occurrences = v)} />
+ |
+
+ this.updateParam(() => pattern.max_occurrences = v)} />
+ |
+ s", "s->c"]}
+ value={this.directions[pattern.direction]}
+ onChange={(v) => this.updateParam(() => pattern.direction = v)} /> |
+ {this.state.selectedPattern == null ?
+ this.addPattern(p)}/> :
+ this.updatePattern(p)}/>}
+ |
+
+ :
+
+ {p.regex} |
+ {p.flags.caseless ? "yes": "no"} |
+ {p.flags.dot_all ? "yes": "no"} |
+ {p.flags.multi_line ? "yes": "no"} |
+ {p.flags.utf_8_mode ? "yes": "no"} |
+ {p.flags.unicode_property ? "yes": "no"} |
+ {p.min_occurrences} |
+ {p.max_occurrences} |
+ {this.directions[p.direction]} |
+ {!isUpdate && this.editPattern(p) }/> | }
);
return (
-
+
GET /api/rules
- 200 OK
+ {this.state.rulesStatusCode &&
+ }
-
-
-
-
- id |
- name |
- notes |
-
-
-
- {rules}
-
-
+
+
+
+
+
+ id |
+ name |
+ color |
+ notes |
+
+
+
+ {rules}
+
+
+
-
+
- POST /api/rules
-
+
+ {isUpdate ? `PUT /api/rules/${this.state.selectedRule.id}` : "POST /api/rules"}
+
+
-
- this.setState({test1: e})} inline />
-
+ this.updateParam((r) => r.name = v)}
+ error={this.state.ruleNameError} />
+ this.updateParam((r) => r.color = v)} />
+ this.updateParam((r) => r.notes = v)} />
-
- filters:
- this.setState({test: e})} validate={(e) => e%2 === 0} />
-
-
-
+
+ filters:
+ this.updateParam((r) => r.filter.service_port = v)}
+ min={0} max={65565} error={this.state.ruleServicePortError} />
+ this.updateParam((r) => r.filter.client_port = v)}
+ min={0} max={65565} error={this.state.ruleClientPortError} />
+ this.updateParam((r) => r.filter.client_address = v)} />
-
-
-
-
-
-
+
+ this.updateParam((r) => r.filter.min_duration = v)} />
+ this.updateParam((r) => r.filter.max_duration = v)} />
+ this.updateParam((r) => r.filter.min_bytes = v)} />
+ this.updateParam((r) => r.filter.max_bytes = v)} />
-
-
- patterns:
@@ -128,29 +383,24 @@ class RulePane extends Component {
min |
max |
direction |
- actions |
+ {!isUpdate && actions | }
-
- |
- |
- |
- |
- |
- |
- |
- |
- s", "s->c"]} value="both" /> |
- |
-
+ {patterns}
+ {this.state.rulePatternsError != null &&
+
error: {this.state.rulePatternsError}}
-
-
+
+ {}
+
+
+
);
}
diff --git a/frontend/src/components/panels/RulePane.scss b/frontend/src/components/panels/RulePane.scss
index b030c6a..d45c366 100644
--- a/frontend/src/components/panels/RulePane.scss
+++ b/frontend/src/components/panels/RulePane.scss
@@ -1,16 +1,32 @@
.rule-pane {
- .post-rules-actions {
- display: flex;
+ display: flex;
+ flex-direction: column;
- .rules-options {
- flex: 1;
+ .rules-list {
+ flex: 2 1;
+ overflow: hidden;
+
+ .section-content {
+ height: 100%;
}
- button {
- margin-left: 10px;
+ .section-table {
+ height: calc(100% - 30px);
}
}
+ .rule-edit {
+ flex: 3 0;
+ display: flex;
+ flex-direction: column;
-}
\ No newline at end of file
+ .section-content {
+ flex: 1;
+ }
+
+ .section-table {
+ max-height: 150px;
+ }
+ }
+}
diff --git a/frontend/src/components/panels/common.scss b/frontend/src/components/panels/common.scss
new file mode 100644
index 0000000..cab0de1
--- /dev/null
+++ b/frontend/src/components/panels/common.scss
@@ -0,0 +1,85 @@
+@import '../../colors.scss';
+
+.pane-container {
+ background-color: $color-primary-3;
+ padding: 10px 10px 0;
+ height: 100%;
+
+ .pane-section {
+ margin-bottom: 10px;
+ background-color: $color-primary-0;
+
+ .section-header {
+ background-color: $color-primary-2;
+ padding: 5px 10px;
+ font-weight: 500;
+ font-size: 0.9em;
+ display: flex;
+
+ .api-request {
+ flex: 1;
+ }
+ }
+
+ .section-content {
+ padding: 10px;
+ }
+
+ .section-table {
+ position: relative;
+ overflow-y: scroll;
+
+ .table-error {
+ font-size: 0.8em;
+ color: $color-secondary-0;
+ margin-left: 10px;
+ }
+ }
+
+ table {
+ margin-bottom: 0;
+
+ tbody tr {
+ background-color: $color-primary-3;
+ border-top: 3px solid $color-primary-0;
+ border-bottom: 3px solid $color-primary-0;
+ }
+
+ th {
+ background-color: $color-primary-2;
+ font-size: 0.8em;
+ position: sticky;
+ top: 0;
+ padding: 2px 5px;
+ border: none;
+ }
+
+ .row-small {
+ font-size: 0.9em;
+ }
+
+ .row-clickable {
+ cursor: pointer;
+
+ &:hover {
+ background-color: $color-primary-0;
+ }
+ }
+
+ .row-selected {
+ background-color: $color-primary-0;
+ }
+ }
+ }
+
+ .section-footer {
+ display: flex;
+ padding: 10px;
+ background-color: $color-primary-0;
+ justify-content: flex-end;
+
+ .button-field {
+ margin-left: 10px;
+ }
+ }
+}
diff --git a/frontend/src/validation.js b/frontend/src/validation.js
new file mode 100644
index 0000000..eac8774
--- /dev/null
+++ b/frontend/src/validation.js
@@ -0,0 +1,8 @@
+
+const validation = {
+ isValidColor: (color) => true, // TODO
+ isValidPort: (port, required) => parseInt(port) > (required ? 0 : -1) && parseInt(port) <= 65565,
+ isValidAddress: (address) => true // TODO
+};
+
+export default validation;
diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js
index ccfdb3a..8bd5e46 100644
--- a/frontend/src/views/App.js
+++ b/frontend/src/views/App.js
@@ -5,7 +5,6 @@ import Footer from "./Footer";
import {BrowserRouter as Router} from "react-router-dom";
import Services from "./Services";
import Filters from "./Filters";
-import Rules from "./Rules";
import Config from "./Config";
class App extends Component {
@@ -15,7 +14,6 @@ class App extends Component {
this.state = {
servicesWindowOpen: false,
filterWindowOpen: false,
- rulesWindowOpen: false,
configWindowOpen: false,
configDone: false
};
@@ -40,9 +38,6 @@ class App extends Component {
if (this.state.filterWindowOpen) {
modal =
this.setState({filterWindowOpen: false})}/>;
}
- if (this.state.rulesWindowOpen) {
- modal = this.setState({rulesWindowOpen: false})}/>;
- }
if (this.state.configWindowOpen) {
modal = this.setState({configWindowOpen: false})}
onDone={() => this.setState({configDone: true})}/>;
@@ -53,7 +48,6 @@ class App extends Component {
this.setState({servicesWindowOpen: true})}
onOpenFilters={() => this.setState({filterWindowOpen: true})}
- onOpenRules={() => this.setState({rulesWindowOpen: true})}
onOpenConfig={() => this.setState({configWindowOpen: true})}
onOpenUpload={() => this.setState({uploadWindowOpen: true})}
onConfigDone={this.state.configDone}
diff --git a/frontend/src/views/Config.js b/frontend/src/views/Config.js
index a770378..b11f827 100644
--- a/frontend/src/views/Config.js
+++ b/frontend/src/views/Config.js
@@ -68,8 +68,6 @@ class Config extends Component {
})
};
- let msg = "";
-
fetch('/setup', requestOptions)
.then(response => {
if (response.status === 202 ){
diff --git a/frontend/src/views/Connections.js b/frontend/src/views/Connections.js
index f3fec64..64068c5 100644
--- a/frontend/src/views/Connections.js
+++ b/frontend/src/views/Connections.js
@@ -75,7 +75,7 @@ class Connections extends Component {
}
this.setState({loading: true, prevParams: params});
- let res = await backend.getJson(`${url}?${urlParams}`);
+ let res = (await backend.getJson(`${url}?${urlParams}`)).json;
let connections = this.state.connections;
let firstConnection = this.state.firstConnection;
@@ -115,7 +115,7 @@ class Connections extends Component {
let flagRule = this.state.flagRule;
let rules = this.state.rules;
if (flagRule === null) {
- rules = await backend.getJson("/api/rules");
+ rules = (await backend.getJson("/api/rules")).json;
flagRule = rules.filter(rule => {
return rule.name === "flag";
})[0];
diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js
index 0b82011..06cb20e 100644
--- a/frontend/src/views/Header.js
+++ b/frontend/src/views/Header.js
@@ -1,7 +1,6 @@
import React, {Component} from 'react';
import Typed from 'typed.js';
import './Header.scss';
-import {Button} from "react-bootstrap";
import {filtersDefinitions, filtersNames} from "../components/filters/FiltersDefinitions";
import {Link} from "react-router-dom";
import ButtonField from "../components/fields/ButtonField";
diff --git a/frontend/src/views/MainPane.js b/frontend/src/views/MainPane.js
index 9d3f7b7..6f4e3cd 100644
--- a/frontend/src/views/MainPane.js
+++ b/frontend/src/views/MainPane.js
@@ -22,7 +22,7 @@ class MainPane extends Component {
if (match != null) {
this.setState({loading: true});
backend.getJson(`/api/connections/${match[1]}`)
- .then(connection => this.setState({selectedConnection: connection, loading: false}))
+ .then(res => this.setState({selectedConnection: res.json, loading: false}))
.catch(error => console.log(error));
}
}
diff --git a/frontend/src/views/Rules.js b/frontend/src/views/Rules.js
deleted file mode 100644
index bbc3bb6..0000000
--- a/frontend/src/views/Rules.js
+++ /dev/null
@@ -1,118 +0,0 @@
-import React, {Component} from 'react';
-import './Services.scss';
-import {Button, ButtonGroup, Col, Container, Form, FormControl, InputGroup, Modal, Row, Table} from "react-bootstrap";
-import backend from "../backend";
-
-class Rules extends Component {
-
- constructor(props) {
- super(props);
-
- this.state = {
- rules: []
- };
- }
-
- componentDidMount() {
- this.loadRules();
- }
-
- loadRules() {
- backend.get("/api/rules").then(res => this.setState({rules: res.data}));
- }
-
- render() {
- let rulesRows = this.state.rules.map(rule =>
-
- |
- {rule.name} |
-
- );
-
-
- return (
-
-
-
- ~/rules
-
-
-
-
-
-
-
-
-
- |
- name |
-
-
-
- {rulesRows}
-
-
-
-
-
-
- port:
-
-
-
-
- name:
-
-
-
-
- color:
-
-
-
-
-
-
-
-
-
- notes:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
-
-export default Rules;
--
cgit v1.2.3-70-g09d2