diff options
Diffstat (limited to 'frontend/src/components/panels')
-rw-r--r-- | frontend/src/components/panels/PcapPane.js | 289 | ||||
-rw-r--r-- | frontend/src/components/panels/PcapPane.scss | 25 | ||||
-rw-r--r-- | frontend/src/components/panels/RulePane.js | 6 | ||||
-rw-r--r-- | frontend/src/components/panels/common.scss | 16 |
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; + } + } } |