From 042cd78894b7c9ce622715e86cb52e203dbe4b34 Mon Sep 17 00:00:00 2001 From: therealbobo Date: Sun, 13 Sep 2020 00:51:55 +0200 Subject: added config menu --- frontend/src/views/App.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'frontend/src/views/App.js') diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js index 6c101fa..229eaed 100644 --- a/frontend/src/views/App.js +++ b/frontend/src/views/App.js @@ -6,6 +6,7 @@ import {BrowserRouter as Router, Route, Switch} from "react-router-dom"; import Services from "./Services"; import Filters from "./Filters"; import Rules from "./Rules"; +import Config from "./Config"; class App extends Component { @@ -14,7 +15,8 @@ class App extends Component { this.state = { servicesWindowOpen: false, filterWindowOpen: false, - rulesWindowOpen: false + rulesWindowOpen: false, + configWindowOpen: false }; } @@ -29,13 +31,18 @@ class App extends Component { if (this.state.rulesWindowOpen) { modal = this.setState({rulesWindowOpen: false})}/>; } + if (this.state.configWindowOpen) { + modal = this.setState({configWindowOpen: false})}/>; + } return (
this.setState({servicesWindowOpen: true})} onOpenFilters={() => this.setState({filterWindowOpen: true})} - onOpenRules={() => this.setState({rulesWindowOpen: true})} /> + onOpenRules={() => this.setState({rulesWindowOpen: true})} + onOpenConfig={() => this.setState({configWindowOpen: true})} + /> }/> }/> -- cgit v1.2.3-70-g09d2 From b5f3cd7accf3699fd7ed3053d671a4c254dfeaa3 Mon Sep 17 00:00:00 2001 From: therealbobo Date: Mon, 14 Sep 2020 09:45:18 +0200 Subject: auto startup configuration --- frontend/src/views/App.js | 9 +++++++++ frontend/src/views/Config.js | 9 +++++---- frontend/src/views/Services.js | 10 ---------- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'frontend/src/views/App.js') diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js index 229eaed..5b49045 100644 --- a/frontend/src/views/App.js +++ b/frontend/src/views/App.js @@ -18,6 +18,15 @@ class App extends Component { rulesWindowOpen: false, configWindowOpen: false }; + + fetch('/api/services') + .then(response => { + if( response.status === 503){ + this.setState({configWindowOpen: true}); + } + }); + + } render() { diff --git a/frontend/src/views/Config.js b/frontend/src/views/Config.js index 438e2d6..9b220d9 100644 --- a/frontend/src/views/Config.js +++ b/frontend/src/views/Config.js @@ -4,7 +4,6 @@ import { import React, {Component, useState} from 'react'; import './Config.scss'; import {Button, ButtonGroup, ToggleButton, Col, Container, Form, FormControl, InputGroup, Modal, Row, Table} from "react-bootstrap"; -import axios from 'axios' import {createCurlCommand} from '../utils'; class Config extends Component { @@ -74,9 +73,11 @@ class Config extends Component { fetch('/setup', requestOptions) - .then(function(response){ - console.log(response.status); - console.log(response); + .then(response => { + if (response.status === 202 ){ + //this.setState({showConfig:false}); + this.props.onHide(); + } } ); diff --git a/frontend/src/views/Services.js b/frontend/src/views/Services.js index 9f0fbd2..0de021f 100644 --- a/frontend/src/views/Services.js +++ b/frontend/src/views/Services.js @@ -82,16 +82,6 @@ class Services extends Component { } ); - /* - axios.put("/api/services", { - name: this.state.name, - port: this.state.port, - color: this.state.color, - notes: this.state.notes - }); - */ - - this.newService(); this.loadServices(); } -- cgit v1.2.3-70-g09d2 From e1ce4fefede7f956e4b7ae9bc602b4f49fbfad69 Mon Sep 17 00:00:00 2001 From: therealbobo Date: Mon, 14 Sep 2020 11:32:57 +0200 Subject: auto disabling config button --- frontend/src/views/App.js | 9 +++++++-- frontend/src/views/Config.js | 4 ++++ frontend/src/views/Config.scss | 13 +++++++++++++ frontend/src/views/Header.js | 3 ++- 4 files changed, 26 insertions(+), 3 deletions(-) (limited to 'frontend/src/views/App.js') diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js index 5b49045..5a2d913 100644 --- a/frontend/src/views/App.js +++ b/frontend/src/views/App.js @@ -16,13 +16,16 @@ class App extends Component { servicesWindowOpen: false, filterWindowOpen: false, rulesWindowOpen: false, - configWindowOpen: false + configWindowOpen: false, + configDone: false }; fetch('/api/services') .then(response => { if( response.status === 503){ this.setState({configWindowOpen: true}); + } else if (response.status === 200){ + this.setState({configDone: true}); } }); @@ -41,7 +44,8 @@ class App extends Component { modal = this.setState({rulesWindowOpen: false})}/>; } if (this.state.configWindowOpen) { - modal = this.setState({configWindowOpen: false})}/>; + modal = this.setState({configWindowOpen: false})} + onDone={() => this.setState({configDone: true})}/>; } return ( @@ -51,6 +55,7 @@ class App extends Component { onOpenFilters={() => this.setState({filterWindowOpen: true})} onOpenRules={() => this.setState({rulesWindowOpen: true})} onOpenConfig={() => this.setState({configWindowOpen: true})} + onConfigDone={this.state.configDone} /> }/> diff --git a/frontend/src/views/Config.js b/frontend/src/views/Config.js index 9b220d9..1468b1b 100644 --- a/frontend/src/views/Config.js +++ b/frontend/src/views/Config.js @@ -77,6 +77,8 @@ class Config extends Component { if (response.status === 202 ){ //this.setState({showConfig:false}); this.props.onHide(); + this.props.onDone(); + console.log(this.props.disabled); } } ); @@ -158,6 +160,8 @@ class Config extends Component { + +
diff --git a/frontend/src/views/Config.scss b/frontend/src/views/Config.scss index 9946ce9..b0b899f 100644 --- a/frontend/src/views/Config.scss +++ b/frontend/src/views/Config.scss @@ -36,3 +36,16 @@ width: 80px; } } + +.blink{ + + span{ + animation: blink 1s linear infinite; + } + @keyframes blink{ + 0%{opacity: 0;} + 50%{opacity: .5;} + 100%{opacity: 1;} + } + +} diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js index 03e4e5c..3f95bcd 100644 --- a/frontend/src/views/Header.js +++ b/frontend/src/views/Header.js @@ -73,7 +73,8 @@ class Header extends Component { - +
-- cgit v1.2.3-70-g09d2 From 81e22267dfddca85e9e515ce7683efa9c8541ac8 Mon Sep 17 00:00:00 2001 From: therealbobo Date: Mon, 14 Sep 2020 18:49:09 +0200 Subject: initial upload support --- frontend/src/views/App.js | 6 +++ frontend/src/views/Header.js | 2 +- frontend/src/views/Upload.js | 106 +++++++++++++++++++++++++++++++++++++++++ frontend/src/views/Upload.scss | 21 ++++++++ 4 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 frontend/src/views/Upload.js create mode 100644 frontend/src/views/Upload.scss (limited to 'frontend/src/views/App.js') diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js index 5a2d913..ebead2f 100644 --- a/frontend/src/views/App.js +++ b/frontend/src/views/App.js @@ -7,6 +7,7 @@ import Services from "./Services"; import Filters from "./Filters"; import Rules from "./Rules"; import Config from "./Config"; +import Upload from "./Upload"; class App extends Component { @@ -17,6 +18,7 @@ class App extends Component { filterWindowOpen: false, rulesWindowOpen: false, configWindowOpen: false, + uploadWindowOpen: false, configDone: false }; @@ -47,6 +49,9 @@ class App extends Component { modal = this.setState({configWindowOpen: false})} onDone={() => this.setState({configDone: true})}/>; } + if (this.state.uploadWindowOpen) { + modal = this.setState({uploadWindowOpen: false}) }/>; + } return (
@@ -55,6 +60,7 @@ class App extends Component { 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/Header.js b/frontend/src/views/Header.js index 3f95bcd..0af7abf 100644 --- a/frontend/src/views/Header.js +++ b/frontend/src/views/Header.js @@ -70,7 +70,7 @@ class Header extends Component {
- + + + + + ); + } +} + +export default Upload; diff --git a/frontend/src/views/Upload.scss b/frontend/src/views/Upload.scss new file mode 100644 index 0000000..e327b8c --- /dev/null +++ b/frontend/src/views/Upload.scss @@ -0,0 +1,21 @@ +@import '../colors.scss'; + +.curl-output { + width: 100%; + font-size: 13px; +} + +#pcap-upload{ + align: center; + width: 100%; +} + +.btn-color { + border: 3px solid #fff; +} + +.dialog-footer { + .btn { + width: 80px; + } +} -- cgit v1.2.3-70-g09d2 From 44af615b32faf53c04cd38cb63782cf1b1332c94 Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Sat, 26 Sep 2020 12:05:27 +0200 Subject: General refactor --- frontend/package.json | 1 - frontend/src/backend.js | 38 ++-- frontend/src/components/fields/BooleanField.js | 37 ---- frontend/src/components/fields/BooleanField.scss | 34 ---- frontend/src/components/fields/CheckField.js | 36 ++++ frontend/src/components/fields/CheckField.scss | 35 ++++ frontend/src/components/fields/InputField.js | 75 +++++++ frontend/src/components/fields/InputField.scss | 147 ++++++++++++++ frontend/src/components/fields/StringField.js | 66 ------- frontend/src/components/fields/StringField.scss | 117 ----------- frontend/src/components/fields/TextField.js | 42 ++++ frontend/src/components/fields/TextField.scss | 79 ++++++++ .../components/filters/BooleanConnectionsFilter.js | 6 +- .../components/filters/StringConnectionsFilter.js | 8 +- frontend/src/components/panels/PcapPane.js | 86 ++++++-- frontend/src/components/panels/PcapPane.scss | 14 +- frontend/src/utils.js | 18 +- frontend/src/views/App.js | 12 +- frontend/src/views/Header.js | 5 +- frontend/src/views/Header.scss | 2 +- frontend/src/views/MainPane.js | 8 +- frontend/src/views/Services.js | 2 +- frontend/src/views/Upload.js | 218 --------------------- frontend/src/views/Upload.scss | 21 -- 24 files changed, 555 insertions(+), 552 deletions(-) delete mode 100644 frontend/src/components/fields/BooleanField.js delete mode 100644 frontend/src/components/fields/BooleanField.scss create mode 100644 frontend/src/components/fields/CheckField.js create mode 100644 frontend/src/components/fields/CheckField.scss create mode 100644 frontend/src/components/fields/InputField.js create mode 100644 frontend/src/components/fields/InputField.scss delete mode 100644 frontend/src/components/fields/StringField.js delete mode 100644 frontend/src/components/fields/StringField.scss create mode 100644 frontend/src/components/fields/TextField.js create mode 100644 frontend/src/components/fields/TextField.scss delete mode 100644 frontend/src/views/Upload.js delete mode 100644 frontend/src/views/Upload.scss (limited to 'frontend/src/views/App.js') diff --git a/frontend/package.json b/frontend/package.json index bf995c5..3629e70 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,7 +9,6 @@ "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", - "axios": "^0.19.2", "bootstrap": "^4.4.1", "bs-custom-file-input": "^1.3.4", "classnames": "^2.2.6", diff --git a/frontend/src/backend.js b/frontend/src/backend.js index 35ae6e3..5eb0e40 100644 --- a/frontend/src/backend.js +++ b/frontend/src/backend.js @@ -1,11 +1,11 @@ -async function request(method, url, data) { +async function json(method, url, data, headers) { const options = { method: method, mode: "cors", cache: "no-cache", credentials: "same-origin", - headers: { + headers: headers || { "Content-Type": "application/json" }, redirect: "follow", @@ -18,19 +18,35 @@ async function request(method, url, data) { return result.json(); } +async function file(url, data, headers) { + const options = { + method: "POST", + mode: "cors", + cache: "no-cache", + credentials: "same-origin", + body: data, + redirect: "follow", + referrerPolicy: "no-referrer", + }; + return await fetch(url, options); +} + const backend = { - get: (url = "") => { - return request("GET", url, null); + get: (url = "", headers = null) => { + return json("GET", url, null, headers); }, - post: (url = "", data = null) => { - return request("POST", url, data); + post: (url = "", data = null, headers = null) => { + return json("POST", url, data, headers); }, - put: (url = "", data = null) => { - return request("PUT", url, data); + put: (url = "", data = null, headers = null) => { + return json("PUT", url, data, headers); + }, + delete: (url = "", data = null, headers = null) => { + return json("DELETE", url, data, headers); + }, + postFile: (url = "", data = null, headers = null) => { + return file(url, data, headers); }, - delete: (url = "", data = null) => { - return request("DELETE", url, data); - } }; export default backend; diff --git a/frontend/src/components/fields/BooleanField.js b/frontend/src/components/fields/BooleanField.js deleted file mode 100644 index 06a6da7..0000000 --- a/frontend/src/components/fields/BooleanField.js +++ /dev/null @@ -1,37 +0,0 @@ -import React, {Component} from 'react'; -import './BooleanField.scss'; -import {randomClassName} from "../../utils"; - -const classNames = require('classnames'); - -class BooleanField extends Component { - - constructor(props) { - super(props); - - this.id = `field-${this.props.name || "noname"}-${randomClassName()}`; - } - - render() { - - const checked = this.props.checked || false; - const small = this.props.small || false; - const name = this.props.name || null; - const handler = () => { - if (this.props.onChange) { - this.props.onChange(!checked); - } - }; - - return ( -
-
- - -
-
- ); - } -} - -export default BooleanField; diff --git a/frontend/src/components/fields/BooleanField.scss b/frontend/src/components/fields/BooleanField.scss deleted file mode 100644 index 6ec25f7..0000000 --- a/frontend/src/components/fields/BooleanField.scss +++ /dev/null @@ -1,34 +0,0 @@ -@import '../../colors.scss'; - -.boolean-field { - font-size: 0.9em; - - .field-input { - border-radius: 5px; - width: fit-content; - background-color: $color-primary-2; - - input { - display: none; - } - - label { - margin: 0; - padding: 6px 15px; - cursor: pointer; - } - - &:hover { - background-color: $color-primary-1; - } - } - - &.field-checked .field-input { - background-color: $color-primary-4 !important; - color: $color-primary-3; - } - - &.field-small { - font-size: 0.8em; - } -} diff --git a/frontend/src/components/fields/CheckField.js b/frontend/src/components/fields/CheckField.js new file mode 100644 index 0000000..5cceac4 --- /dev/null +++ b/frontend/src/components/fields/CheckField.js @@ -0,0 +1,36 @@ +import React, {Component} from 'react'; +import './CheckField.scss'; +import {randomClassName} from "../../utils"; + +const classNames = require('classnames'); + +class CheckField extends Component { + + constructor(props) { + super(props); + + this.id = `field-${this.props.name || "noname"}-${randomClassName()}`; + } + + render() { + const checked = this.props.checked || false; + const small = this.props.small || false; + const name = this.props.name || null; + const handler = () => { + if (this.props.onChange) { + this.props.onChange(!checked); + } + }; + + return ( +
+
+ + +
+
+ ); + } +} + +export default CheckField; diff --git a/frontend/src/components/fields/CheckField.scss b/frontend/src/components/fields/CheckField.scss new file mode 100644 index 0000000..7b0ac5f --- /dev/null +++ b/frontend/src/components/fields/CheckField.scss @@ -0,0 +1,35 @@ +@import '../../colors.scss'; + +.check-field { + font-size: 0.9em; + margin: 5px 0; + + .field-input { + border-radius: 5px; + width: fit-content; + background-color: $color-primary-2; + + input { + display: none; + } + + label { + margin: 0; + padding: 6px 15px; + cursor: pointer; + } + + &:hover { + background-color: $color-primary-1; + } + } + + &.field-checked .field-input { + background-color: $color-primary-4 !important; + color: $color-primary-3; + } + + &.field-small { + font-size: 0.8em; + } +} diff --git a/frontend/src/components/fields/InputField.js b/frontend/src/components/fields/InputField.js new file mode 100644 index 0000000..af3b3df --- /dev/null +++ b/frontend/src/components/fields/InputField.js @@ -0,0 +1,75 @@ +import React, {Component} from 'react'; +import './InputField.scss'; +import {randomClassName} from "../../utils"; + +const classNames = require('classnames'); + +class InputField extends Component { + + constructor(props) { + super(props); + + this.id = `field-${this.props.name || "noname"}-${randomClassName()}`; + } + + render() { + const active = this.props.active || false; + const invalid = this.props.invalid || false; + const small = this.props.small || false; + const inline = this.props.inline || false; + const name = this.props.name || null; + const value = this.props.value || ""; + const type = this.props.type || "text"; + const error = this.props.error || null; + const defaultValue = this.props.defaultValue || null; + const handler = (e) => { + if (this.props.onChange) { + if (type === "file") { + let file = e.target.files[0]; + this.props.onChange(file); + } else if (e == null) { + this.props.onChange(""); + } else { + this.props.onChange(e.target.value); + } + } + }; + let inputProps = {}; + if (type !== "file") { + inputProps["value"] = value; + } + + return ( +
+
+ { name && +
+ +
+ } +
+
+ { type === "file" && } + +
+ { type !== "file" && value !== "" && +
+ handler(null)}>del +
+ } +
+
+ {error && +
+ error: {error} +
+ } +
+ ); + } +} + +export default InputField; diff --git a/frontend/src/components/fields/InputField.scss b/frontend/src/components/fields/InputField.scss new file mode 100644 index 0000000..cdb8c9f --- /dev/null +++ b/frontend/src/components/fields/InputField.scss @@ -0,0 +1,147 @@ +@import '../../colors.scss'; + +.input-field { + font-size: 0.9em; + margin: 5px 0; + + .field-name { + label { + margin: 0; + } + } + + .field-input { + position: relative; + + .field-value { + input, .file-label { + background-color: $color-primary-2; + width: 100%; + border: none; + color: $color-primary-4; + border-radius: 5px; + padding: 7px 10px; + + &:focus { + background-color: $color-primary-1; + color: $color-primary-4; + box-shadow: none; + outline: none; + } + + &[readonly] { + background-color: $color-primary-2; + border: none; + color: $color-primary-4; + } + + &[readonly]:focus { + background-color: $color-primary-1; + color: $color-primary-4; + box-shadow: none; + } + } + + input[type="file"] { + display: none; + } + + .file-label { + margin: 0; + } + + .file-label:after { + content: "Browse"; + position: absolute; + right: 0; + top: 0; + padding: 7px 10px 7px 12px; + background-color: $color-primary-1; + border-bottom-right-radius: 5px; + border-top-right-radius: 5px; + } + } + } + + &.field-active { + &.field-inline .field-name { + background-color: $color-primary-4 !important; + color: $color-primary-3 !important; + } + + .field-value input, .field-value .file-label { + background-color: $color-primary-4 !important; + color: $color-primary-3 !important; + } + + .file-label:after { + background-color: $color-secondary-4 !important; + } + } + + &.field-invalid { + &.field-inline .field-name { + background-color: $color-secondary-2 !important; + color: $color-primary-4 !important; + } + + .field-value input, .field-value .file-label { + background-color: $color-secondary-2 !important; + color: $color-primary-4 !important; + } + + .file-label:after { + background-color: $color-secondary-1 !important; + } + } + + &.field-small { + font-size: 0.8em; + } + + &.field-inline .field-wrapper { + display: flex; + + .field-name { + background-color: $color-primary-2; + padding: 6px 7px; + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + } + + .field-input { + width: 100%; + + input, .file-label { + border-bottom-left-radius: 0; + border-top-left-radius: 0; + padding-left: 3px; + } + } + + &:focus-within .field-name { + background-color: $color-primary-1; + } + } + + .field-clear { + position: absolute; + right: 8px; + top: 8px; + z-index: 10; + font-size: 0.9em; + font-weight: 600; + letter-spacing: -0.5px; + cursor: pointer; + } + + &.field-active .field-clear { + color: $color-primary-2; + } + + .field-error { + padding: 5px 10px; + font-size: 0.9em; + color: $color-secondary-0; + } +} diff --git a/frontend/src/components/fields/StringField.js b/frontend/src/components/fields/StringField.js deleted file mode 100644 index 7781b2d..0000000 --- a/frontend/src/components/fields/StringField.js +++ /dev/null @@ -1,66 +0,0 @@ -import React, {Component} from 'react'; -import './StringField.scss'; -import {randomClassName} from "../../utils"; - -const classNames = require('classnames'); - -class StringField extends Component { - - constructor(props) { - super(props); - - this.id = `field-${this.props.name || "noname"}-${randomClassName()}`; - } - - render() { - - const active = this.props.active || false; - const invalid = this.props.invalid || false; - const small = this.props.small || false; - const inline = this.props.inline || false; - const name = this.props.name || null; - const value = this.props.value || ""; - const type = this.props.type || "text"; - const error = this.props.error || null; - const handler = (e) => { - if (this.props.onChange) { - if (e == null) { - this.props.onChange(""); - } else { - this.props.onChange(e.target.value); - } - } - }; - - return ( -
-
- { name && -
- -
- } -
-
- -
- { value !== "" && -
- handler(null)}>del -
- } -
-
- {error && -
- error: {error} -
- } -
- ); - } -} - -export default StringField; diff --git a/frontend/src/components/fields/StringField.scss b/frontend/src/components/fields/StringField.scss deleted file mode 100644 index 2523c8d..0000000 --- a/frontend/src/components/fields/StringField.scss +++ /dev/null @@ -1,117 +0,0 @@ -@import '../../colors.scss'; - -.string-field { - font-size: 0.9em; - - .field-name { - label { - margin: 0; - } - } - - .field-input { - position: relative; - - .field-value input { - background-color: $color-primary-2; - width: 100%; - border: none; - color: $color-primary-4; - border-radius: 5px; - padding: 7px 10px; - - &:focus { - background-color: $color-primary-1; - color: $color-primary-4; - box-shadow: none; - outline: none; - } - - &[readonly] { - background-color: $color-primary-2; - border: none; - color: $color-primary-4; - } - - &[readonly]:focus { - background-color: $color-primary-1; - color: $color-primary-4; - box-shadow: none; - } - } - } - - &.field-active { - &.field-inline .field-name { - background-color: $color-primary-4 !important; - color: $color-primary-3 !important; - } - - .field-value input { - background-color: $color-primary-4 !important; - color: $color-primary-3 !important; - } - } - - &.field-invalid { - &.field-inline .field-name { - background-color: $color-secondary-2 !important; - color: $color-primary-4 !important; - } - - .field-value input { - background-color: $color-secondary-2 !important; - color: $color-primary-4 !important; - } - } - - &.field-small { - font-size: 0.8em; - } - - &.field-inline .field-wrapper { - display: flex; - - .field-name { - background-color: $color-primary-2; - padding: 6px 7px; - border-top-left-radius: 5px; - border-bottom-left-radius: 5px; - } - - .field-input { - width: 100%; - - input { - border-bottom-left-radius: 0; - border-top-left-radius: 0; - padding-left: 3px; - } - } - - &:focus-within .field-name { - background-color: $color-primary-1; - } - } - - .field-clear { - position: absolute; - right: 8px; - top: 8px; - z-index: 10; - font-size: 0.9em; - font-weight: 600; - letter-spacing: -0.5px; - cursor: pointer; - } - - &.field-active .field-clear { - color: $color-primary-2; - } - - .field-error { - padding: 5px 10px; - font-size: 0.9em; - color: $color-secondary-0; - } -} diff --git a/frontend/src/components/fields/TextField.js b/frontend/src/components/fields/TextField.js new file mode 100644 index 0000000..86b98ed --- /dev/null +++ b/frontend/src/components/fields/TextField.js @@ -0,0 +1,42 @@ +import React, {Component} from 'react'; +import './TextField.scss'; +import {randomClassName} from "../../utils"; + +const classNames = require('classnames'); + +class TextField extends Component { + + constructor(props) { + super(props); + + this.id = `field-${this.props.name || "noname"}-${randomClassName()}`; + } + + render() { + const name = this.props.name || null; + const error = this.props.error || null; + const rows = this.props.rows || 3; + + const handler = (e) => { + if (this.props.onChange) { + if (e == null) { + this.props.onChange(""); + } else { + this.props.onChange(e.target.value); + } + } + }; + + return ( +
+ {name && } +