aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/components/panels
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components/panels')
-rw-r--r--frontend/src/components/panels/PcapPane.js289
-rw-r--r--frontend/src/components/panels/PcapPane.scss25
-rw-r--r--frontend/src/components/panels/RulePane.js6
-rw-r--r--frontend/src/components/panels/common.scss16
4 files changed, 204 insertions, 132 deletions
diff --git a/frontend/src/components/panels/PcapPane.js b/frontend/src/components/panels/PcapPane.js
index cfba037..e83e3da 100644
--- a/frontend/src/components/panels/PcapPane.js
+++ b/frontend/src/components/panels/PcapPane.js
@@ -1,14 +1,14 @@
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";
-import {Col, Container, Row} from "react-bootstrap";
+import {createCurlCommand, dateTimeToTime, durationBetween, formatSize} from "../../utils";
import InputField from "../fields/InputField";
import CheckField from "../fields/CheckField";
import TextField from "../fields/TextField";
import ButtonField from "../fields/ButtonField";
+import LinkPopover from "../objects/LinkPopover";
class PcapPane extends Component {
@@ -19,16 +19,11 @@ class PcapPane extends Component {
sessions: [],
isUploadFileValid: true,
isUploadFileFocused: false,
- uploadSelectedFile: null,
uploadFlushAll: false,
- uploadStatusCode: null,
- uploadOutput: null,
isFileValid: true,
isFileFocused: false,
fileValue: "",
- fileFlushAll: false,
- fileStatusCode: null,
- fileOutput: null,
+ processFlushAll: false,
deleteOriginalFile: false
};
}
@@ -38,46 +33,38 @@ class PcapPane extends Component {
}
loadSessions = () => {
- backend.getJson("/api/pcap/sessions").then(res => this.setState({sessions: res.json}));
+ backend.get("/api/pcap/sessions")
+ .then(res => this.setState({sessions: res.json, sessionsStatusCode: res.status}))
+ .catch(res => this.setState({
+ sessions: res.json, sessionsStatusCode: res.status,
+ sessionsResponse: JSON.stringify(res.json)
+ }));
};
- handleUploadFileChange = (file) => {
- this.setState({
- isUploadFileValid: file != null && file.type.endsWith("pcap"),
- isUploadFileFocused: false,
- uploadSelectedFile: file
- });
- };
-
- handleUploadPcap = () => {
+ uploadPcap = () => {
if (this.state.uploadSelectedFile == null || !this.state.isUploadFileValid) {
this.setState({isUploadFileFocused: true});
return;
}
const formData = new FormData();
- formData.append(
- "file",
- this.state.uploadSelectedFile
- );
-
- backend.postFile("/api/pcap/upload", formData).then(response =>
- response.json().then(result => this.setState({
- uploadStatusCode: response.status + " " + response.statusText,
- uploadOutput: JSON.stringify(result)
- }))
+ formData.append("file", this.state.uploadSelectedFile);
+ formData.append("flush_all", this.state.uploadFlushAll);
+ backend.postFile("/api/pcap/upload", formData).then(res => {
+ this.setState({
+ uploadStatusCode: res.status,
+ uploadResponse: JSON.stringify(res.json)
+ });
+ this.resetUpload();
+ this.loadSessions();
+ }).catch(res => this.setState({
+ uploadStatusCode: res.status,
+ uploadResponse: JSON.stringify(res.json)
+ })
);
};
- handleFileChange = (file) => {
- this.setState({
- isFileValid: file !== "" && file.endsWith("pcap"),
- isFileFocused: false,
- fileValue: file
- });
- };
-
- handleProcessPcap = () => {
+ processPcap = () => {
if (this.state.fileValue === "" || !this.state.isFileValid) {
this.setState({isFileFocused: true});
return;
@@ -85,123 +72,177 @@ class PcapPane extends Component {
backend.post("/api/pcap/file", {
file: this.state.fileValue,
- flush_all: this.state.fileFlushAll,
+ flush_all: this.state.processFlushAll,
delete_original_file: this.state.deleteOriginalFile
- }).then(response =>
- response.json().then(result => this.setState({
- fileStatusCode: response.status + " " + response.statusText,
- fileOutput: JSON.stringify(result)
- }))
+ }).then(res => {
+ this.setState({
+ processStatusCode: res.status,
+ processResponse: JSON.stringify(res.json)
+ });
+ this.resetProcess();
+ this.loadSessions();
+ }).catch(res => this.setState({
+ processStatusCode: res.status,
+ processResponse: JSON.stringify(res.json)
+ })
);
};
+ resetUpload = () => {
+ this.setState({
+ isUploadFileValid: true,
+ isUploadFileFocused: false,
+ uploadFlushAll: false,
+ uploadSelectedFile: null
+ });
+ };
+
+ resetProcess = () => {
+ this.setState({
+ isFileValid: true,
+ isFileFocused: false,
+ fileValue: "",
+ processFlushAll: false,
+ deleteOriginalFile: false,
+ });
+ };
+
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>{dateTimeToTime(s["started_at"])}</td>
+ <td>{durationBetween(s["started_at"], s["completed_at"])}</td>
<td>{formatSize(s["size"])}</td>
<td>{s["processed_packets"]}</td>
<td>{s["invalid_packets"]}</td>
- <td>undefined</td>
+ <td><LinkPopover text={Object.keys(s["packets_per_service"]).length + " services"}
+ content={JSON.stringify(s["packets_per_service"])}
+ placement="left"/></td>
<td className="table-cell-action"><a target="_blank" rel="noopener noreferrer"
href={"/api/pcap/sessions/" + s["id"] + "/download"}>download</a>
</td>
</tr>
);
- const uploadOutput = this.state.uploadOutput != null ? this.state.uploadOutput :
- createCurlCommand("pcap/upload", "POST", null, {
- file: "@" + ((this.state.uploadSelectedFile != null && this.state.isUploadFileValid) ? this.state.uploadSelectedFile.name :
- "invalid.pcap"),
- flush_all: this.state.uploadFlushAll
- })
- ;
+ const handleUploadFileChange = (file) => {
+ this.setState({
+ isUploadFileValid: file == null || (file.type.endsWith("pcap") || file.type.endsWith("pcapng")),
+ isUploadFileFocused: false,
+ uploadSelectedFile: file,
+ uploadStatusCode: null,
+ uploadResponse: null
+ });
+ };
+
+ const handleFileChange = (file) => {
+ this.setState({
+ isFileValid: (file.endsWith("pcap") || file.endsWith("pcapng")),
+ isFileFocused: false,
+ fileValue: file,
+ processStatusCode: null,
+ processResponse: null
+ });
+ };
+
+ const uploadCurlCommand = createCurlCommand("pcap/upload", "POST", null, {
+ file: "@" + ((this.state.uploadSelectedFile != null && this.state.isUploadFileValid) ?
+ this.state.uploadSelectedFile.name : "invalid.pcap"),
+ flush_all: this.state.uploadFlushAll
+ });
+
+ const fileCurlCommand = createCurlCommand("pcap/file", "POST", {
+ file: this.state.fileValue,
+ flush_all: this.state.processFlushAll,
+ delete_original_file: this.state.deleteOriginalFile
+ });
return (
- <div className="pane-container">
- <div className="pane-section">
+ <div className="pane-container pcap-pane">
+ <div className="pane-section pcap-list">
<div className="section-header">
<span className="api-request">GET /api/pcap/sessions</span>
- <span className="api-response">200 OK</span>
+ <span className="api-response"><LinkPopover text={this.state.sessionsStatusCode}
+ content={this.state.sessionsResponse}
+ placement="left"/></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 className="section-content">
+ <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>
- <div className="pane-section">
- <Container className="p-0">
- <Row>
- <Col style={{"paddingRight": "0"}}>
- <div className="section-header">
- <span className="api-request">POST /api/pcap/upload</span>
- <span className="api-response">{this.state.uploadStatusCode}</span>
+ <div className="double-pane-container">
+ <div className="pane-section">
+ <div className="section-header">
+ <span className="api-request">POST /api/pcap/upload</span>
+ <span className="api-response"><LinkPopover text={this.state.uploadStatusCode}
+ content={this.state.uploadResponse}
+ placement="left"/></span>
+ </div>
+
+ <div className="section-content">
+ <InputField type={"file"} name={"file"} invalid={!this.state.isUploadFileValid}
+ active={this.state.isUploadFileFocused}
+ onChange={handleUploadFileChange} value={this.state.uploadSelectedFile}
+ placeholder={"no .pcap[ng] selected"}/>
+ <div className="upload-actions">
+ <div className="upload-options">
+ <span>options:</span>
+ <CheckField name="flush_all" checked={this.state.uploadFlushAll}
+ onChange={v => this.setState({uploadFlushAll: v})}/>
</div>
+ <ButtonField variant="green" bordered onClick={this.uploadPcap} name="upload"/>
+ </div>
- <div className="section-content">
- <InputField type={"file"} name={"file"} invalid={!this.state.isUploadFileValid}
- active={this.state.isUploadFileFocused}
- onChange={this.handleUploadFileChange} value={this.state.uploadSelectedFile}
- defaultValue={"no .pcap[ng] selected"}/>
-
- <div className="upload-actions">
- <div className="upload-options">
- <span>options:</span>
- <CheckField name="flush_all" checked={this.state.uploadFlushAll}
- onChange={v => this.setState({uploadFlushAll: v})}/>
- </div>
- <ButtonField variant="green" bordered onClick={this.handleUploadPcap} name="upload" />
- </div>
-
- <TextField value={uploadOutput} rows={4} readonly small={true}/>
- </div>
- </Col>
+ <TextField value={uploadCurlCommand} rows={4} readonly small={true}/>
+ </div>
+ </div>
- <Col>
- <div className="section-header">
- <span className="api-request">POST /api/pcap/file</span>
- <span className="api-response">{this.state.fileStatusCode}</span>
+ <div className="pane-section">
+ <div className="section-header">
+ <span className="api-request">POST /api/pcap/file</span>
+ <span className="api-response"><LinkPopover text={this.state.processStatusCode}
+ content={this.state.processResponse}
+ placement="left"/></span>
+ </div>
+
+ <div className="section-content">
+ <InputField name="file" active={this.state.isFileFocused} invalid={!this.state.isFileValid}
+ onChange={handleFileChange} value={this.state.fileValue}
+ placeholder={"local .pcap[ng] path"} inline/>
+
+ <div className="upload-actions" style={{"marginTop": "11px"}}>
+ <div className="upload-options">
+ <CheckField name="flush_all" checked={this.state.processFlushAll}
+ onChange={v => this.setState({processFlushAll: v})}/>
+ <CheckField name="delete_original_file" checked={this.state.deleteOriginalFile}
+ onChange={v => this.setState({deleteOriginalFile: v})}/>
</div>
+ <ButtonField variant="blue" bordered onClick={this.processPcap} name="process"/>
+ </div>
- <div className="section-content">
- <InputField name="file" active={this.state.isUploadFileFocused}
- onChange={this.handleFileChange} value={this.state.uploadSelectedFile}
- defaultValue={"local .pcap[ng] path"} inline/>
-
- <div className="upload-actions" style={{"marginTop": "11px"}}>
- <div className="upload-options">
- <CheckField name="flush_all" checked={this.state.uploadFlushAll}
- onChange={v => this.setState({uploadFlushAll: v})}/>
- <CheckField name="delete_original_file" checked={this.state.uploadFlushAll}
- onChange={v => this.setState({uploadFlushAll: v})}/>
- </div>
- <ButtonField variant="blue" bordered onClick={this.handleUploadPcap} name="process" />
- </div>
-
- <TextField value={uploadOutput} rows={4} readonly small={true}/>
- </div>
- </Col>
- </Row>
- </Container>
+ <TextField value={fileCurlCommand} rows={4} readonly small={true}/>
+ </div>
+ </div>
</div>
</div>
);
diff --git a/frontend/src/components/panels/PcapPane.scss b/frontend/src/components/panels/PcapPane.scss
index 3c4d10b..721560a 100644
--- a/frontend/src/components/panels/PcapPane.scss
+++ b/frontend/src/components/panels/PcapPane.scss
@@ -1,10 +1,25 @@
@import '../../colors.scss';
-.pane-container {
+.pcap-pane {
+ display: flex;
+ flex-direction: column;
- .table-cell-action {
- font-size: 13px;
- font-weight: 600;
+ .pcap-list {
+ flex: 1;
+ overflow: hidden;
+
+ .section-content {
+ height: 100%;
+ }
+
+ .section-table {
+ height: calc(100% - 30px);
+ }
+
+ .table-cell-action {
+ font-size: 13px;
+ font-weight: 600;
+ }
}
.upload-actions {
@@ -21,4 +36,4 @@
}
}
-} \ No newline at end of file
+}
diff --git a/frontend/src/components/panels/RulePane.js b/frontend/src/components/panels/RulePane.js
index 01e37fa..d4c5460 100644
--- a/frontend/src/components/panels/RulePane.js
+++ b/frontend/src/components/panels/RulePane.js
@@ -73,13 +73,13 @@ class RulePane extends Component {
};
loadRules = () => {
- backend.getJson("/api/rules").then(res => this.setState({rules: res.json, rulesStatusCode: res.status}))
+ backend.get("/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 => {
+ backend.post("/api/rules", this.state.newRule).then(res => {
this.reset();
this.setState({ruleStatusCode: res.status});
this.loadRules();
@@ -92,7 +92,7 @@ class RulePane extends Component {
updateRule = () => {
const rule = this.state.selectedRule;
if (this.validateRule(rule)) {
- backend.putJson(`/api/rules/${rule.id}`, rule).then(res => {
+ backend.put(`/api/rules/${rule.id}`, rule).then(res => {
this.reset();
this.setState({ruleStatusCode: res.status});
this.loadRules();
diff --git a/frontend/src/components/panels/common.scss b/frontend/src/components/panels/common.scss
index cab0de1..ea8da94 100644
--- a/frontend/src/components/panels/common.scss
+++ b/frontend/src/components/panels/common.scss
@@ -82,4 +82,20 @@
margin-left: 10px;
}
}
+
+ .double-pane-container {
+ display: flex;
+
+ .pane-section {
+ flex: 1;
+ }
+
+ .pane-section:nth-child(1) {
+ margin-right: 5px;
+ }
+
+ .pane-section:nth-child(2) {
+ margin-left: 5px;
+ }
+ }
}