From 8d07bfe5f17534b7301a064aeaf8ed8071f10a40 Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Wed, 23 Sep 2020 20:19:09 +0200 Subject: Frontend refactor: checkpoint --- frontend/src/components/fields/StringField.js | 31 ++++++++++++ frontend/src/components/fields/StringField.scss | 66 +++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 frontend/src/components/fields/StringField.js create mode 100644 frontend/src/components/fields/StringField.scss (limited to 'frontend/src/components/fields') diff --git a/frontend/src/components/fields/StringField.js b/frontend/src/components/fields/StringField.js new file mode 100644 index 0000000..09fe24d --- /dev/null +++ b/frontend/src/components/fields/StringField.js @@ -0,0 +1,31 @@ +import React, {Component} from 'react'; +import './StringField.scss'; + +const classNames = require('classnames'); + +class StringField extends Component { + + render() { + return ( +
+
+
+ {this.props.name}: +
+ +
+ + { this.props.active && +
+ this.props.onValueChanged("")}>del +
+ } +
+ ); + } +} + +export default StringField; diff --git a/frontend/src/components/fields/StringField.scss b/frontend/src/components/fields/StringField.scss new file mode 100644 index 0000000..7efac56 --- /dev/null +++ b/frontend/src/components/fields/StringField.scss @@ -0,0 +1,66 @@ +@import '../../colors.scss'; + +.field { + margin: 0 10px; + position: relative; + + .field-name-wrapper { + background-color: $color-primary-2; + padding: 3px 7px; + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + } + + .field-name { + font-size: 13px; + } + + .field-value { + font-size: 13px; + padding-left: 0; + border-radius: 5px; + + &:focus { + background-color: $color-primary-2; + } + } + + &.field-active { + .field-name-wrapper { + background-color: $color-primary-4; + color: $color-primary-3; + } + + .field-value { + background-color: $color-primary-4; + color: $color-primary-3; + } + } + + &.field-invalid { + .field-name-wrapper { + background-color: $color-secondary-2; + color: $color-primary-4; + } + + .field-value { + background-color: $color-secondary-2; + color: $color-primary-4; + } + } + + .field-delete { + position: absolute; + right: 10px; + top: 10px; + z-index: 10; + font-size: 11px; + letter-spacing: -0.5px; + color: $color-primary-2; + cursor: pointer; + + .field-delete-icon { + font-weight: 800; + } + } +} -- cgit v1.2.3-70-g09d2 From 04ee54be31931111bf89e50e4e54ac92b9a19d7a Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Wed, 23 Sep 2020 22:00:56 +0200 Subject: Add StringField --- frontend/src/components/fields/StringField.js | 53 ++++++++--- frontend/src/components/fields/StringField.scss | 121 +++++++++++++++++------- frontend/src/utils.js | 4 + 3 files changed, 131 insertions(+), 47 deletions(-) (limited to 'frontend/src/components/fields') diff --git a/frontend/src/components/fields/StringField.js b/frontend/src/components/fields/StringField.js index 09fe24d..aa23fe8 100644 --- a/frontend/src/components/fields/StringField.js +++ b/frontend/src/components/fields/StringField.js @@ -1,26 +1,55 @@ import React, {Component} from 'react'; import './StringField.scss'; +import {randomClassName} from "../../utils"; const classNames = require('classnames'); class StringField extends Component { render() { + const id = `field-${this.props.name || "noname"}-${randomClassName()}`; + 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 ( -
-
-
- {this.props.name}: +
+
+ { name && +
+ +
+ } +
+
+ +
+ { value !== "" && +
+ handler(null)}>del +
+ }
-
- - { this.props.active && -
- this.props.onValueChanged("")}>del + {error && +
+ error: {error}
}
diff --git a/frontend/src/components/fields/StringField.scss b/frontend/src/components/fields/StringField.scss index 7efac56..674815f 100644 --- a/frontend/src/components/fields/StringField.scss +++ b/frontend/src/components/fields/StringField.scss @@ -1,66 +1,117 @@ @import '../../colors.scss'; .field { - margin: 0 10px; - position: relative; - - .field-name-wrapper { - background-color: $color-primary-2; - padding: 3px 7px; - border-top-left-radius: 5px; - border-bottom-left-radius: 5px; - } + font-size: 0.9em; .field-name { - font-size: 13px; + label { + margin: 0; + } } - .field-value { - font-size: 13px; - padding-left: 0; - border-radius: 5px; + .field-input { + position: relative; - &:focus { + .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-name-wrapper { - background-color: $color-primary-4; - color: $color-primary-3; + &.field-inline .field-name { + background-color: $color-primary-4 !important; + color: $color-primary-3 !important; } - .field-value { - background-color: $color-primary-4; - color: $color-primary-3; + .field-value input { + background-color: $color-primary-4 !important; + color: $color-primary-3 !important; } } &.field-invalid { - .field-name-wrapper { - background-color: $color-secondary-2; - color: $color-primary-4; + &.field-inline .field-name { + background-color: $color-secondary-2 !important; + color: $color-primary-4 !important; } - .field-value { - background-color: $color-secondary-2; - color: $color-primary-4; + .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-delete { + .field-clear { position: absolute; - right: 10px; - top: 10px; + right: 8px; + top: 8px; z-index: 10; - font-size: 11px; + font-size: 0.9em; + font-weight: 600; letter-spacing: -0.5px; - color: $color-primary-2; cursor: pointer; + } - .field-delete-icon { - font-weight: 800; - } + &.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/utils.js b/frontend/src/utils.js index 4991755..c81cdfc 100644 --- a/frontend/src/utils.js +++ b/frontend/src/utils.js @@ -82,3 +82,7 @@ export function formatSize(size) { return `${(size / 1000000).toFixed(1)}M`; } } + +export function randomClassName(size = 10) { + return Math.random().toString(36).substring(size); +} -- cgit v1.2.3-70-g09d2 From 05678b74d98247c957faa1ca3d0bafc5f68974d1 Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Wed, 23 Sep 2020 23:16:58 +0200 Subject: Add BooleanField --- frontend/src/components/fields/BooleanField.js | 37 +++++++++++ frontend/src/components/fields/BooleanField.scss | 34 ++++++++++ frontend/src/components/fields/StringField.js | 16 +++-- frontend/src/components/fields/StringField.scss | 2 +- .../components/filters/BooleanConnectionsFilter.js | 12 ++-- .../filters/BooleanConnectionsFilter.scss | 24 ------- .../src/components/filters/FiltersDefinitions.js | 34 ++++++---- .../components/filters/StringConnectionsFilter.js | 31 ++------- .../filters/StringConnectionsFilter.scss | 66 ------------------- frontend/src/components/panels/PcapPane.js | 4 +- frontend/src/index.scss | 27 +------- frontend/src/utils.js | 4 +- frontend/src/views/Header.js | 6 +- frontend/src/views/Header.scss | 8 ++- frontend/src/views/MainPane.js | 4 +- frontend/yarn.lock | 74 +++++++++++----------- 16 files changed, 168 insertions(+), 215 deletions(-) create mode 100644 frontend/src/components/fields/BooleanField.js create mode 100644 frontend/src/components/fields/BooleanField.scss delete mode 100644 frontend/src/components/filters/BooleanConnectionsFilter.scss delete mode 100644 frontend/src/components/filters/StringConnectionsFilter.scss (limited to 'frontend/src/components/fields') diff --git a/frontend/src/components/fields/BooleanField.js b/frontend/src/components/fields/BooleanField.js new file mode 100644 index 0000000..06a6da7 --- /dev/null +++ b/frontend/src/components/fields/BooleanField.js @@ -0,0 +1,37 @@ +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 new file mode 100644 index 0000000..6ec25f7 --- /dev/null +++ b/frontend/src/components/fields/BooleanField.scss @@ -0,0 +1,34 @@ +@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/StringField.js b/frontend/src/components/fields/StringField.js index aa23fe8..7781b2d 100644 --- a/frontend/src/components/fields/StringField.js +++ b/frontend/src/components/fields/StringField.js @@ -6,8 +6,14 @@ const classNames = require('classnames'); class StringField extends Component { + constructor(props) { + super(props); + + this.id = `field-${this.props.name || "noname"}-${randomClassName()}`; + } + render() { - const id = `field-${this.props.name || "noname"}-${randomClassName()}`; + const active = this.props.active || false; const invalid = this.props.invalid || false; const small = this.props.small || false; @@ -27,18 +33,18 @@ class StringField extends Component { }; return ( -
+
{ name &&
- +
}
+ aria-describedby={this.id} onChange={handler} value={value} />
{ value !== "" &&
diff --git a/frontend/src/components/fields/StringField.scss b/frontend/src/components/fields/StringField.scss index 674815f..2523c8d 100644 --- a/frontend/src/components/fields/StringField.scss +++ b/frontend/src/components/fields/StringField.scss @@ -1,6 +1,6 @@ @import '../../colors.scss'; -.field { +.string-field { font-size: 0.9em; .field-name { diff --git a/frontend/src/components/filters/BooleanConnectionsFilter.js b/frontend/src/components/filters/BooleanConnectionsFilter.js index 7dea7cf..490d185 100644 --- a/frontend/src/components/filters/BooleanConnectionsFilter.js +++ b/frontend/src/components/filters/BooleanConnectionsFilter.js @@ -1,9 +1,7 @@ import React, {Component} from 'react'; import {withRouter} from "react-router-dom"; import {Redirect} from "react-router"; -import './BooleanConnectionsFilter.scss'; - -const classNames = require('classnames'); +import BooleanField from "../fields/BooleanField"; class BooleanConnectionsFilter extends Component { @@ -57,11 +55,9 @@ class BooleanConnectionsFilter extends Component { } return ( -
-
- {this.props.filterName} -
- +
+ {redirect}
); diff --git a/frontend/src/components/filters/BooleanConnectionsFilter.scss b/frontend/src/components/filters/BooleanConnectionsFilter.scss deleted file mode 100644 index 941b967..0000000 --- a/frontend/src/components/filters/BooleanConnectionsFilter.scss +++ /dev/null @@ -1,24 +0,0 @@ -@import '../../colors'; - -.filter { - .filter-boolean { - padding: 0 10px; - background-color: $color-primary-2; - border-radius: 5px; - cursor: pointer; - height: 34px; - - span { - display: block; - font-size: 13px; - padding: 6px 5px; - } - } - - &.filter-active { - .filter-boolean { - background-color: $color-primary-4; - color: $color-primary-3; - } - } -} diff --git a/frontend/src/components/filters/FiltersDefinitions.js b/frontend/src/components/filters/FiltersDefinitions.js index d36792e..02ccb42 100644 --- a/frontend/src/components/filters/FiltersDefinitions.js +++ b/frontend/src/components/filters/FiltersDefinitions.js @@ -12,7 +12,6 @@ import React from "react"; import RulesConnectionsFilter from "./RulesConnectionsFilter"; import BooleanConnectionsFilter from "./BooleanConnectionsFilter"; - export const filtersNames = ["service_port", "matched_rules", "client_address", "client_port", "min_duration", "max_duration", "min_bytes", "max_bytes", "started_after", "started_before", "closed_after", "closed_before", "marked", "hidden"]; @@ -22,59 +21,70 @@ export const filtersDefinitions = { defaultFilterValue="all_ports" replaceFunc={cleanNumber} validateFunc={validatePort} - key="service_port_filter" />, + key="service_port_filter" + width={200} />, matched_rules: , client_address: , + key="client_address_filter" + width={320} />, client_port: , + key="client_port_filter" + width={200} />, min_duration: , + key="min_duration_filter" + width={200} />, max_duration: , + key="max_duration_filter" + width={200} />, min_bytes: , + key="min_bytes_filter" + width={200} />, max_bytes: , + key="max_bytes_filter" + width={200} />, started_after: , + key="started_after_filter" + width={200} />, started_before: , + key="started_before_filter" + width={200} />, closed_after: , + key="closed_after_filter" + width={200} />, closed_before: , + key="closed_before_filter" + width={200} />, marked: , hidden: }; diff --git a/frontend/src/components/filters/StringConnectionsFilter.js b/frontend/src/components/filters/StringConnectionsFilter.js index 490a569..0d7f063 100644 --- a/frontend/src/components/filters/StringConnectionsFilter.js +++ b/frontend/src/components/filters/StringConnectionsFilter.js @@ -1,9 +1,7 @@ import React, {Component} from 'react'; import {withRouter} from "react-router-dom"; import {Redirect} from "react-router"; -import './StringConnectionsFilter.scss'; - -const classNames = require('classnames'); +import StringField from "../fields/StringField"; class StringConnectionsFilter extends Component { @@ -62,8 +60,7 @@ class StringConnectionsFilter extends Component { (typeof this.props.validateFunc === "function" && this.props.validateFunc(value)); } - filterChanged(event) { - let fieldValue = event.target.value; + filterChanged(fieldValue) { if (this.state.timeoutHandle !== null) { clearTimeout(this.state.timeoutHandle); } @@ -116,26 +113,10 @@ class StringConnectionsFilter extends Component { let active = this.state.filterValue !== null; return ( -
-
-
- {this.props.filterName}: -
- -
- - { active && -
- { - this.needRedirect = true; - this.setState({fieldValue: "", filterValue: null}); - }}>del -
- } - +
+ {redirect}
); diff --git a/frontend/src/components/filters/StringConnectionsFilter.scss b/frontend/src/components/filters/StringConnectionsFilter.scss deleted file mode 100644 index 1476616..0000000 --- a/frontend/src/components/filters/StringConnectionsFilter.scss +++ /dev/null @@ -1,66 +0,0 @@ -@import '../../colors'; - -.filter { - margin: 0 10px; - position: relative; - - .filter-name-wrapper { - background-color: $color-primary-2; - padding: 3px 7px; - border-top-left-radius: 5px; - border-bottom-left-radius: 5px; - } - - .filter-name { - font-size: 13px; - } - - .filter-value { - font-size: 13px; - padding-left: 0; - border-radius: 5px; - - &:focus { - background-color: $color-primary-2; - } - } - - &.filter-active { - .filter-name-wrapper { - background-color: $color-primary-4; - color: $color-primary-3; - } - - .filter-value { - background-color: $color-primary-4; - color: $color-primary-3; - } - } - - &.filter-invalid { - .filter-name-wrapper { - background-color: $color-secondary-2; - color: $color-primary-4; - } - - .filter-value { - background-color: $color-secondary-2; - color: $color-primary-4; - } - } - - .filter-delete { - position: absolute; - right: 10px; - top: 10px; - z-index: 10; - font-size: 11px; - letter-spacing: -0.5px; - color: $color-primary-2; - cursor: pointer; - - .filter-delete-icon { - font-weight: 800; - } - } -} diff --git a/frontend/src/components/panels/PcapPane.js b/frontend/src/components/panels/PcapPane.js index 817c7b5..9f3bc19 100644 --- a/frontend/src/components/panels/PcapPane.js +++ b/frontend/src/components/panels/PcapPane.js @@ -5,6 +5,7 @@ import backend from "../../backend"; import {formatSize, timestampToTime2} from "../../utils"; import {Container, Row, Col, Form} from "react-bootstrap"; import StringField from "../fields/StringField"; +import BooleanField from "../fields/BooleanField"; class PcapPane extends Component { @@ -13,6 +14,7 @@ class PcapPane extends Component { this.state = { sessions: [], + test: false }; this.loadSessions = this.loadSessions.bind(this); @@ -86,7 +88,7 @@ class PcapPane extends Component {



- + this.setState({test: v})} />
diff --git a/frontend/src/index.scss b/frontend/src/index.scss index 358fd70..5d1bbfa 100644 --- a/frontend/src/index.scss +++ b/frontend/src/index.scss @@ -13,6 +13,7 @@ body { color: $color-primary-4; height: 100%; max-height: 100%; + font-size: 100%; } pre { @@ -182,32 +183,6 @@ textarea.form-control { resize: none; } -input.form-control, -textarea.form-control { - background-color: $color-primary-2; - border: none; - color: $color-primary-4; - font-family: 'Fira Code', monospace; - - &:focus { - background-color: $color-primary-1; - color: $color-primary-4; - box-shadow: 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; - } -} - .table { color: $color-primary-4; } diff --git a/frontend/src/utils.js b/frontend/src/utils.js index c81cdfc..46667d6 100644 --- a/frontend/src/utils.js +++ b/frontend/src/utils.js @@ -83,6 +83,6 @@ export function formatSize(size) { } } -export function randomClassName(size = 10) { - return Math.random().toString(36).substring(size); +export function randomClassName() { + return Math.random().toString(36).slice(2) } diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js index 5860d80..deb3ab7 100644 --- a/frontend/src/views/Header.js +++ b/frontend/src/views/Header.js @@ -60,10 +60,8 @@ class Header extends Component {
-
-
- {quickFilters} -
+
+ {quickFilters}
diff --git a/frontend/src/views/Header.scss b/frontend/src/views/Header.scss index e36b2d6..f3bfec1 100644 --- a/frontend/src/views/Header.scss +++ b/frontend/src/views/Header.scss @@ -22,8 +22,12 @@ } } - .filters-bar-wrapper { - height: 50px; + .filters-bar { padding: 8px 0; + + .filter { + display: inline-block; + margin-right: 10px; + } } } diff --git a/frontend/src/views/MainPane.js b/frontend/src/views/MainPane.js index 3c0d795..88af4a7 100644 --- a/frontend/src/views/MainPane.js +++ b/frontend/src/views/MainPane.js @@ -35,8 +35,8 @@ class MainPane extends Component { this.setState({selectedConnection: c})} />
- {/**/} - + + {/**/}
diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 39d346b..c5f59cb 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1691,9 +1691,9 @@ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== "@types/node@*": - version "14.10.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.10.2.tgz#9b47a2c8e4dabd4db73b57e750b24af689600514" - integrity sha512-IzMhbDYCpv26pC2wboJ4MMOa9GKtjplXfcAqrMeNJpUUwpM/2ATt2w1JPUXwS6spu856TvKZL2AOmeU2rAxskw== + version "14.11.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.1.tgz#56af902ad157e763f9ba63d671c39cda3193c835" + integrity sha512-oTQgnd0hblfLsJ6BvJzzSL+Inogp3lq9fGgqRkMB/ziKMgEUaFl801OncOzUmalfzt14N0oPHMK47ipl+wbTIw== "@types/parse-json@^4.0.0": version "4.0.0" @@ -2792,20 +2792,19 @@ browserslist@4.10.0: pkg-up "^3.1.0" browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.6.2, browserslist@^4.6.4, browserslist@^4.8.5, browserslist@^4.9.1: - version "4.14.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.2.tgz#1b3cec458a1ba87588cc5e9be62f19b6d48813ce" - integrity sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw== + version "4.14.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.3.tgz#381f9e7f13794b2eb17e1761b4f118e8ae665a53" + integrity sha512-GcZPC5+YqyPO4SFnz48/B0YaCwS47Q9iPChRGi6t7HhflKBcINzFrJvRfC+jp30sRMKxF+d4EHGs27Z0XP1NaQ== dependencies: - caniuse-lite "^1.0.30001125" - electron-to-chromium "^1.3.564" - escalade "^3.0.2" + caniuse-lite "^1.0.30001131" + electron-to-chromium "^1.3.570" + escalade "^3.1.0" node-releases "^1.1.61" bs-custom-file-input@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/bs-custom-file-input/-/bs-custom-file-input-1.3.4.tgz#c275cb8d4f1c02ba026324292509fa9a747dbda8" integrity sha512-NBsQzTnef3OW1MvdKBbMHAYHssCd613MSeJV7z2McXznWtVMnJCy7Ckyc+PwxV6Pk16cu6YBcYWh/ZE0XWNKCA== ->>>>>>> 98355cdf838d8c18e9a28176ae7a847770545395 bser@2.1.1: version "2.1.1" @@ -2983,10 +2982,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125: - version "1.0.30001131" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001131.tgz#afad8a28fc2b7a0d3ae9407e71085a0ead905d54" - integrity sha512-4QYi6Mal4MMfQMSqGIRPGbKIbZygeN83QsWq1ixpUwvtfgAZot5BrCKzGygvZaV+CnELdTwD0S4cqUNozq7/Cw== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001131: + version "1.0.30001133" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001133.tgz#ec564c5495311299eb05245e252d589a84acd95e" + integrity sha512-s3XAUFaC/ntDb1O3lcw9K8MPeOW7KO3z9+GzAoBxfz1B0VdacXPMKgFUtG4KIsgmnbexmi013s9miVu4h+qMHw== capture-exit@^2.0.0: version "2.0.0" @@ -3828,11 +3827,11 @@ debug@^3.1.1, debug@^3.2.5: ms "^2.1.1" debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + version "4.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" + integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== dependencies: - ms "^2.1.1" + ms "2.1.2" decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" @@ -4152,7 +4151,7 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.564: +electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.570: version "1.3.570" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.570.tgz#3f5141cc39b4e3892a276b4889980dabf1d29c7f" integrity sha512-Y6OCoVQgFQBP5py6A/06+yWxUZHDlNr/gNDGatjH8AZqXl8X0tE4LfjLJsXGz/JmWJz8a6K7bR1k+QzZ+k//fg== @@ -4305,7 +4304,7 @@ es6-symbol@^3.1.1, es6-symbol@~3.1.3: d "^1.0.1" ext "^1.1.2" -escalade@^3.0.2: +escalade@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig== @@ -7377,7 +7376,7 @@ ms@2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -ms@^2.1.1: +ms@2.1.2, ms@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -8470,9 +8469,9 @@ postcss-lab-function@^2.0.1: postcss-values-parser "^2.0.0" postcss-load-config@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.0.tgz#c84d692b7bb7b41ddced94ee62e8ab31b417b003" - integrity sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q== + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.1.tgz#0a684bb8beb05e55baf922f7ab44c3edb17cf78e" + integrity sha512-D2ENobdoZsW0+BHy4x1CAkXtbXtYWYRIxL/JbtRBqrRGOPtJ2zoga/bEZWhV/ShWB5saVxJMzbMdSyA/vv4tXw== dependencies: cosmiconfig "^5.0.0" import-cwd "^2.0.0" @@ -8846,13 +8845,14 @@ postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: uniq "^1.0.1" postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" - integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== + version "6.0.3" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.3.tgz#766d77728728817cc140fa1ac6da5e77f9fada98" + integrity sha512-0ClFaY4X1ra21LRqbW6y3rUbWcxnSVkDFG57R7Nxus9J9myPFlv+jYDMohzpkBx0RrjjiqjtycpchQ+PLGmZ9w== dependencies: cssesc "^3.0.0" indexes-of "^1.0.1" uniq "^1.0.1" + util-deprecate "^1.0.2" postcss-svgo@^4.0.2: version "4.0.2" @@ -8902,9 +8902,9 @@ postcss@7.0.21: supports-color "^6.1.0" postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.23, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.32" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" - integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw== + version "7.0.34" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.34.tgz#f2baf57c36010df7de4009940f21532c16d65c20" + integrity sha512-H/7V2VeNScX9KE83GDrDZNiGT1m2H+UTnlinIzhjlLX9hfMUn1mHNnGeX81a1c8JSBdBvqk7c2ZOG6ZPn5itGw== dependencies: chalk "^2.4.2" source-map "^0.6.1" @@ -9572,9 +9572,9 @@ regexpp@^3.0.0: integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== regexpu-core@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" - integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== + version "4.7.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" + integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== dependencies: regenerate "^1.4.0" regenerate-unicode-properties "^8.2.0" @@ -10307,9 +10307,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.5" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" - integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + version "3.0.6" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz#c80757383c28abf7296744998cbc106ae8b854ce" + integrity sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw== spdy-transport@^3.0.0: version "3.0.0" @@ -11124,7 +11124,7 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -util-deprecate@^1.0.1, util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -- 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/components/fields') 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 && } +