diff options
author | Emiliano Ciavatta | 2020-09-30 13:58:16 +0000 |
---|---|---|
committer | Emiliano Ciavatta | 2020-09-30 13:58:16 +0000 |
commit | d5ed31be3b6c97f92be4e94b70d32d1b89932ae9 (patch) | |
tree | 0deffc50058f731c51ba4b804c9db7eaff1c94a0 /frontend/src/components/panels | |
parent | 43135c255d82aa7c54ea83b14369c93425ae75f6 (diff) |
Complete services page
Diffstat (limited to 'frontend/src/components/panels')
-rw-r--r-- | frontend/src/components/panels/RulePane.js | 16 | ||||
-rw-r--r-- | frontend/src/components/panels/ServicePane.js | 190 | ||||
-rw-r--r-- | frontend/src/components/panels/ServicePane.scss | 22 |
3 files changed, 221 insertions, 7 deletions
diff --git a/frontend/src/components/panels/RulePane.js b/frontend/src/components/panels/RulePane.js index d4c5460..7cb849c 100644 --- a/frontend/src/components/panels/RulePane.js +++ b/frontend/src/components/panels/RulePane.js @@ -344,27 +344,29 @@ class RulePane extends Component { <span>filters:</span> <NumericField name="service_port" inline value={rule.filter.service_port} onChange={(v) => this.updateParam((r) => r.filter.service_port = v)} - min={0} max={65565} error={this.state.ruleServicePortError} /> + min={0} max={65565} error={this.state.ruleServicePortError} + readonly={isUpdate} /> <NumericField name="client_port" inline value={rule.filter.client_port} onChange={(v) => this.updateParam((r) => r.filter.client_port = v)} - min={0} max={65565} error={this.state.ruleClientPortError} /> + min={0} max={65565} error={this.state.ruleClientPortError} + readonly={isUpdate} /> <InputField name="client_address" value={rule.filter.client_address} - error={this.state.ruleClientAddressError} + error={this.state.ruleClientAddressError} readonly={isUpdate} onChange={(v) => this.updateParam((r) => r.filter.client_address = v)} /> </Col> <Col style={{"paddingTop": "11px"}}> <NumericField name="min_duration" inline value={rule.filter.min_duration} - error={this.state.ruleDurationError} + error={this.state.ruleDurationError} readonly={isUpdate} onChange={(v) => this.updateParam((r) => r.filter.min_duration = v)} /> <NumericField name="max_duration" inline value={rule.filter.max_duration} - error={this.state.ruleDurationError} + error={this.state.ruleDurationError} readonly={isUpdate} onChange={(v) => this.updateParam((r) => r.filter.max_duration = v)} /> <NumericField name="min_bytes" inline value={rule.filter.min_bytes} - error={this.state.ruleBytesError} + error={this.state.ruleBytesError} readonly={isUpdate} onChange={(v) => this.updateParam((r) => r.filter.min_bytes = v)} /> <NumericField name="max_bytes" inline value={rule.filter.max_bytes} - error={this.state.ruleBytesError} + error={this.state.ruleBytesError} readonly={isUpdate} onChange={(v) => this.updateParam((r) => r.filter.max_bytes = v)} /> </Col> </Row> diff --git a/frontend/src/components/panels/ServicePane.js b/frontend/src/components/panels/ServicePane.js new file mode 100644 index 0000000..b21ad6c --- /dev/null +++ b/frontend/src/components/panels/ServicePane.js @@ -0,0 +1,190 @@ +import React, {Component} from 'react'; +import './common.scss'; +import './ServicePane.scss'; +import Table from "react-bootstrap/Table"; +import {Col, Container, Row} from "react-bootstrap"; +import InputField from "../fields/InputField"; +import TextField from "../fields/TextField"; +import backend from "../../backend"; +import NumericField from "../fields/extensions/NumericField"; +import ColorField from "../fields/extensions/ColorField"; +import ButtonField from "../fields/ButtonField"; +import validation from "../../validation"; +import LinkPopover from "../objects/LinkPopover"; +import {createCurlCommand} from "../../utils"; + +const classNames = require('classnames'); +const _ = require('lodash'); + +class ServicePane extends Component { + + constructor(props) { + super(props); + + this.state = { + services: [], + currentService: this.emptyService, + }; + } + + componentDidMount() { + this.reset(); + this.loadServices(); + } + + emptyService = { + "port": 0, + "name": "", + "color": "", + "notes": "" + }; + + loadServices = () => { + backend.get("/api/services") + .then(res => this.setState({services: Object.values(res.json), servicesStatusCode: res.status})) + .catch(res => this.setState({servicesStatusCode: res.status, servicesResponse: JSON.stringify(res.json)})); + }; + + updateService = () => { + const service = this.state.currentService; + if (this.validateService(service)) { + backend.put("/api/services", service).then(res => { + this.reset(); + this.setState({serviceStatusCode: res.status}); + this.loadServices(); + }).catch(res => { + this.setState({serviceStatusCode: res.status, serviceResponse: JSON.stringify(res.json)}); + }); + } + }; + + validateService = (service) => { + let valid = true; + if (!validation.isValidPort(service.port, true)) { + this.setState({servicePortError: "port < 0 || port > 65565"}); + valid = false; + } + if (service.name.length < 3) { + this.setState({serviceNameError: "name.length < 3"}); + valid = false; + } + if (!validation.isValidColor(service.color)) { + this.setState({serviceColorError: "color is not hexcolor"}); + valid = false; + } + + return valid; + }; + + reset = () => { + this.setState({ + isUpdate: false, + currentService: _.cloneDeep(this.emptyService), + servicePortError: null, + serviceNameError: null, + serviceColorError: null, + serviceStatusCode: null, + servicesStatusCode: null, + serviceResponse: null, + servicesResponse: null + }); + }; + + updateParam = (callback) => { + callback(this.state.currentService); + this.setState({currentService: this.state.currentService}); + }; + + render() { + const isUpdate = this.state.isUpdate; + const service = this.state.currentService; + + let services = this.state.services.map(s => + <tr onClick={() => { + this.reset(); + this.setState({isUpdate: true, currentService: _.cloneDeep(s)}); + }} className={classNames("row-small", "row-clickable", {"row-selected": service.port === s.port })}> + <td>{s["port"]}</td> + <td>{s["name"]}</td> + <td><ButtonField name={s["color"]} color={s["color"]} small /></td> + <td>{s["notes"]}</td> + </tr> + ); + + const curlCommand = createCurlCommand("/services", "PUT", service); + + return ( + <div className="pane-container service-pane"> + <div className="pane-section services-list"> + <div className="section-header"> + <span className="api-request">GET /api/services</span> + {this.state.servicesStatusCode && + <span className="api-response"><LinkPopover text={this.state.servicesStatusCode} + content={this.state.servicesResponse} + placement="left" /></span>} + </div> + + <div className="section-content"> + <div className="section-table"> + <Table borderless size="sm"> + <thead> + <tr> + <th>port</th> + <th>name</th> + <th>color</th> + <th>notes</th> + </tr> + </thead> + <tbody> + {services} + </tbody> + </Table> + </div> + </div> + </div> + + <div className="pane-section service-edit"> + <div className="section-header"> + <span className="api-request">PUT /api/services</span> + <span className="api-response"><LinkPopover text={this.state.serviceStatusCode} + content={this.state.serviceResponse} + placement="left" /></span> + </div> + + <div className="section-content"> + <Container className="p-0"> + <Row> + <Col> + <NumericField name="port" value={service.port} + onChange={(v) => this.updateParam((s) => s.port = v)} + min={0} max={65565} error={this.state.servicePortError} /> + <InputField name="name" value={service.name} + onChange={(v) => this.updateParam((s) => s.name = v)} + error={this.state.serviceNameError} /> + <ColorField value={service.color} error={this.state.serviceColorError} + onChange={(v) => this.updateParam((s) => s.color = v)} /> + </Col> + + <Col> + <TextField name="notes" rows={7} value={service.notes} + onChange={(v) => this.updateParam((s) => s.notes = v)} /> + </Col> + </Row> + </Container> + + <TextField value={curlCommand} rows={3} readonly small={true}/> + </div> + + <div className="section-footer"> + {<ButtonField variant="red" name="cancel" bordered onClick={this.reset}/>} + <ButtonField variant={isUpdate ? "blue" : "green"} name={isUpdate ? "update_service" : "add_service"} + bordered onClick={this.updateService} /> + </div> + </div> + </div> + ); + } + +} + +export default ServicePane; diff --git a/frontend/src/components/panels/ServicePane.scss b/frontend/src/components/panels/ServicePane.scss new file mode 100644 index 0000000..0b154e6 --- /dev/null +++ b/frontend/src/components/panels/ServicePane.scss @@ -0,0 +1,22 @@ + +.service-pane { + display: flex; + flex-direction: column; + + .services-list { + flex: 1; + overflow: hidden; + + .section-content { + height: 100%; + } + + .section-table { + height: calc(100% - 30px); + } + } + + .service-edit { + flex: 0; + } +} |