aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/views
diff options
context:
space:
mode:
authorEmiliano Ciavatta2020-09-30 20:58:05 +0000
committerEmiliano Ciavatta2020-09-30 20:58:05 +0000
commit55afd62a8cfe2cde6e627f1905ab8fe77965afd6 (patch)
tree57545a722a62d2279bfcd2e36f1cbd1da5a5736a /frontend/src/views
parent4cfdf6e2dfe9184e988a145495e072571d512cdc (diff)
parentd6e2aaad41f916c2080c59cf7b4e42bf87a1a03f (diff)
Merge branch 'feature/frontend' into develop
Diffstat (limited to 'frontend/src/views')
-rw-r--r--frontend/src/views/App.js51
-rw-r--r--frontend/src/views/App.scss15
-rw-r--r--frontend/src/views/Connections.js83
-rw-r--r--frontend/src/views/Filters.js6
-rw-r--r--frontend/src/views/Footer.js4
-rw-r--r--frontend/src/views/Header.js30
-rw-r--r--frontend/src/views/Header.scss19
-rw-r--r--frontend/src/views/MainPane.js46
-rw-r--r--frontend/src/views/MainPane.scss6
-rw-r--r--frontend/src/views/Rules.js118
-rw-r--r--frontend/src/views/Services.js210
-rw-r--r--frontend/src/views/Services.scss32
12 files changed, 123 insertions, 497 deletions
diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js
index 6c101fa..fb4454c 100644
--- a/frontend/src/views/App.js
+++ b/frontend/src/views/App.js
@@ -1,49 +1,46 @@
import React, {Component} from 'react';
+import './App.scss';
import Header from "./Header";
-import MainPane from "./MainPane";
+import MainPane from "../components/panels/MainPane";
import Footer from "./Footer";
-import {BrowserRouter as Router, Route, Switch} from "react-router-dom";
-import Services from "./Services";
+import {BrowserRouter as Router} from "react-router-dom";
import Filters from "./Filters";
-import Rules from "./Rules";
+import backend from "../backend";
+import ConfigurationPane from "../components/panels/ConfigurationPane";
class App extends Component {
constructor(props) {
super(props);
- this.state = {
- servicesWindowOpen: false,
- filterWindowOpen: false,
- rulesWindowOpen: false
- };
+
+ this.state = {};
+ }
+
+ componentDidMount() {
+ backend.get("/api/services").then(_ => this.setState({configured: true}));
}
render() {
let modal;
- if (this.state.servicesWindowOpen) {
- modal = <Services onHide={() => this.setState({servicesWindowOpen: false})}/>;
- }
- if (this.state.filterWindowOpen) {
+ if (this.state.filterWindowOpen && this.state.configured) {
modal = <Filters onHide={() => this.setState({filterWindowOpen: false})}/>;
}
- if (this.state.rulesWindowOpen) {
- modal = <Rules onHide={() => this.setState({rulesWindowOpen: false})}/>;
- }
return (
- <div className="app">
+ <div className="main">
<Router>
- <Header onOpenServices={() => this.setState({servicesWindowOpen: true})}
- onOpenFilters={() => this.setState({filterWindowOpen: true})}
- onOpenRules={() => this.setState({rulesWindowOpen: true})} />
- <Switch>
- <Route path="/connections/:id" children={<MainPane/>}/>
- <Route path="/" children={<MainPane/>}/>
- </Switch>
- {modal}
- <Footer/>
+ <div className="main-header">
+ <Header onOpenFilters={() => this.setState({filterWindowOpen: true})} />
+ </div>
+ <div className="main-content">
+ {this.state.configured ? <MainPane /> :
+ <ConfigurationPane onConfigured={() => this.setState({configured: true})} />}
+ {modal}
+ </div>
+ <div className="main-footer">
+ {this.state.configured && <Footer/>}
+ </div>
</Router>
-
</div>
);
}
diff --git a/frontend/src/views/App.scss b/frontend/src/views/App.scss
new file mode 100644
index 0000000..b25d4c9
--- /dev/null
+++ b/frontend/src/views/App.scss
@@ -0,0 +1,15 @@
+
+.main {
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+
+ .main-content {
+ flex: 1 1;
+ overflow: hidden;
+ }
+
+ .main-header, .main-footer {
+ flex: 0 0;
+ }
+}
diff --git a/frontend/src/views/Connections.js b/frontend/src/views/Connections.js
index 62733d7..73979c4 100644
--- a/frontend/src/views/Connections.js
+++ b/frontend/src/views/Connections.js
@@ -1,10 +1,11 @@
import React, {Component} from 'react';
import './Connections.scss';
-import axios from 'axios';
import Connection from "../components/Connection";
import Table from 'react-bootstrap/Table';
import {Redirect} from 'react-router';
import {withRouter} from "react-router-dom";
+import backend from "../backend";
+import ConnectionMatchedRules from "../components/ConnectionMatchedRules";
class Connections extends Component {
@@ -25,21 +26,21 @@ class Connections extends Component {
this.scrollBottomThreashold = 0.99999;
this.maxConnections = 500;
this.queryLimit = 50;
-
- this.handleScroll = this.handleScroll.bind(this);
- this.connectionSelected = this.connectionSelected.bind(this);
- this.addServicePortFilter = this.addServicePortFilter.bind(this);
}
componentDidMount() {
this.loadConnections({limit: this.queryLimit})
.then(() => this.setState({loaded: true}));
+ if (this.props.initialConnection != null) {
+ this.setState({selected: this.props.initialConnection.id});
+ // TODO: scroll to initial connection
+ }
}
- connectionSelected(c) {
+ connectionSelected = (c) => {
this.setState({selected: c.id});
this.props.onSelected(c);
- }
+ };
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.state.loaded && prevProps.location.search !== this.props.location.search) {
@@ -49,7 +50,7 @@ class Connections extends Component {
}
}
- handleScroll(e) {
+ handleScroll = (e) => {
let relativeScroll = e.currentTarget.scrollTop / (e.currentTarget.scrollHeight - e.currentTarget.clientHeight);
if (!this.state.loading && relativeScroll > this.scrollBottomThreashold) {
this.loadConnections({from: this.state.lastConnection.id, limit: this.queryLimit,})
@@ -59,13 +60,23 @@ class Connections extends Component {
this.loadConnections({to: this.state.firstConnection.id, limit: this.queryLimit,})
.then(() => console.log("Previous connections loaded"));
}
- }
+ };
- addServicePortFilter(port) {
- let urlParams = new URLSearchParams(this.props.location.search);
+ addServicePortFilter = (port) => {
+ const urlParams = new URLSearchParams(this.props.location.search);
urlParams.set("service_port", port);
this.setState({queryString: "?" + urlParams});
- }
+ };
+
+ addMatchedRulesFilter = (matchedRule) => {
+ const urlParams = new URLSearchParams(this.props.location.search);
+ const oldMatchedRules = urlParams.getAll("matched_rules") || [];
+
+ if (!oldMatchedRules.includes(matchedRule)) {
+ urlParams.append("matched_rules", matchedRule);
+ this.setState({queryString: "?" + urlParams});
+ }
+ };
async loadConnections(params) {
let url = "/api/connections";
@@ -75,15 +86,15 @@ class Connections extends Component {
}
this.setState({loading: true, prevParams: params});
- let res = await axios.get(`${url}?${urlParams}`);
+ let res = (await backend.get(`${url}?${urlParams}`)).json;
let connections = this.state.connections;
let firstConnection = this.state.firstConnection;
let lastConnection = this.state.lastConnection;
if (params !== undefined && params.from !== undefined) {
- if (res.data.length > 0) {
- connections = this.state.connections.concat(res.data);
+ if (res.length > 0) {
+ connections = this.state.connections.concat(res);
lastConnection = connections[connections.length - 1];
if (connections.length > this.maxConnections) {
connections = connections.slice(connections.length - this.maxConnections,
@@ -92,8 +103,8 @@ class Connections extends Component {
}
}
} else if (params !== undefined && params.to !== undefined) {
- if (res.data.length > 0) {
- connections = res.data.concat(this.state.connections);
+ if (res.length > 0) {
+ connections = res.concat(this.state.connections);
firstConnection = connections[0];
if (connections.length > this.maxConnections) {
connections = connections.slice(0, this.maxConnections);
@@ -101,8 +112,8 @@ class Connections extends Component {
}
}
} else {
- if (res.data.length > 0) {
- connections = res.data;
+ if (res.length > 0) {
+ connections = res;
firstConnection = connections[0];
lastConnection = connections[connections.length - 1];
} else {
@@ -112,21 +123,15 @@ class Connections extends Component {
}
}
- let flagRule = this.state.flagRule;
let rules = this.state.rules;
- if (flagRule === null) {
- let res = await axios.get("/api/rules");
- rules = res.data;
- flagRule = rules.filter(rule => {
- return rule.name === "flag";
- })[0];
+ if (rules === null) {
+ rules = (await backend.get("/api/rules")).json;
}
this.setState({
loading: false,
connections: connections,
- rules: res.data,
- flagRule: flagRule,
+ rules: rules,
firstConnection: firstConnection,
lastConnection: lastConnection
});
@@ -134,7 +139,7 @@ class Connections extends Component {
render() {
let redirect;
- let queryString = this.state.queryString !== null ? this.state.queryString : ""
+ let queryString = this.state.queryString !== null ? this.state.queryString : "";
if (this.state.selected) {
let format = this.props.match.params.format;
format = format !== undefined ? "/" + format : "";
@@ -159,6 +164,7 @@ class Connections extends Component {
<th>srcport</th>
<th>dstip</th>
<th>dstport</th>
+ <th>started_at</th>
<th>duration</th>
<th>up</th>
<th>down</th>
@@ -167,13 +173,18 @@ class Connections extends Component {
</thead>
<tbody>
{
- this.state.connections.map(c =>
- <Connection key={c.id} data={c} onSelected={() => this.connectionSelected(c)}
- selected={this.state.selected === c.id} onMarked={marked => c.marked = marked}
- onEnabled={enabled => c.hidden = !enabled}
- containsFlag={c.matched_rules.includes(this.state.flagRule.id)}
- addServicePortFilter={this.addServicePortFilter}/>
- )
+ this.state.connections.flatMap(c => {
+ return [<Connection key={c.id} data={c} onSelected={() => this.connectionSelected(c)}
+ selected={this.state.selected === c.id}
+ onMarked={marked => c.marked = marked}
+ onEnabled={enabled => c.hidden = !enabled}
+ addServicePortFilter={this.addServicePortFilter} />,
+ c.matched_rules.length > 0 &&
+ <ConnectionMatchedRules key={c.id + "_m"} matchedRules={c.matched_rules}
+ rules={this.state.rules}
+ addMatchedRulesFilter={this.addMatchedRulesFilter} />
+ ];
+ })
}
{loading}
</tbody>
diff --git a/frontend/src/views/Filters.js b/frontend/src/views/Filters.js
index 78f0342..ba7d467 100644
--- a/frontend/src/views/Filters.js
+++ b/frontend/src/views/Filters.js
@@ -1,7 +1,7 @@
import React, {Component} from 'react';
-import './Services.scss';
-import {Button, Col, Container, Modal, Row, Table} from "react-bootstrap";
+import {Col, Container, Modal, Row, Table} from "react-bootstrap";
import {filtersDefinitions, filtersNames} from "../components/filters/FiltersDefinitions";
+import ButtonField from "../components/fields/ButtonField";
class Filters extends Component {
@@ -89,7 +89,7 @@ class Filters extends Component {
</Container>
</Modal.Body>
<Modal.Footer className="dialog-footer">
- <Button variant="red" onClick={this.props.onHide}>close</Button>
+ <ButtonField variant="red" bordered onClick={this.props.onHide} name="close" />
</Modal.Footer>
</Modal>
);
diff --git a/frontend/src/views/Footer.js b/frontend/src/views/Footer.js
index b6ffd9d..0a3c5a3 100644
--- a/frontend/src/views/Footer.js
+++ b/frontend/src/views/Footer.js
@@ -8,11 +8,11 @@ class Footer extends Component {
<footer className="footer container-fluid">
<div className="row">
<div className="col-12">
- <div className="footer-timeline">timeline</div>
+ <div className="footer-timeline">timeline - <a href="https://github.com/eciavatta/caronte/issues/12">to be implemented</a></div>
</div>
</div>
</footer>
- )
+ );
}
}
diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js
index 5d0f690..944f1d5 100644
--- a/frontend/src/views/Header.js
+++ b/frontend/src/views/Header.js
@@ -1,8 +1,9 @@
import React, {Component} from 'react';
import Typed from 'typed.js';
import './Header.scss';
-import {Button} from "react-bootstrap";
import {filtersDefinitions, filtersNames} from "../components/filters/FiltersDefinitions";
+import {Link} from "react-router-dom";
+import ButtonField from "../components/fields/ButtonField";
class Header extends Component {
@@ -45,7 +46,7 @@ class Header extends Component {
render() {
let quickFilters = filtersNames.filter(name => this.state[`${name}_active`])
- .map(name => filtersDefinitions[name])
+ .map(name => <React.Fragment key={name} >{filtersDefinitions[name]}</React.Fragment>)
.slice(0, 5);
return (
@@ -60,21 +61,26 @@ class Header extends Component {
</div>
<div className="col-auto">
- <div className="filters-bar-wrapper">
- <div className="filters-bar">
- {quickFilters}
- </div>
+ <div className="filters-bar">
+ {quickFilters}
</div>
</div>
<div className="col">
<div className="header-buttons">
- <Button onClick={this.props.onOpenFilters}>filters</Button>
- <Button variant="yellow" size="sm">pcaps</Button>
- <Button variant="blue" onClick={this.props.onOpenRules}>rules</Button>
- <Button variant="red" onClick={this.props.onOpenServices}>
- services
- </Button>
+ <ButtonField variant="pink" onClick={this.props.onOpenFilters} name="filters" bordered />
+ <Link to="/pcaps">
+ <ButtonField variant="purple" name="pcaps" bordered />
+ </Link>
+ <Link to="/rules">
+ <ButtonField variant="deep-purple" name="rules" bordered />
+ </Link>
+ <Link to="/services">
+ <ButtonField variant="indigo" name="services" bordered />
+ </Link>
+ <Link to="/config">
+ <ButtonField variant="blue" name="config" bordered />
+ </Link>
</div>
</div>
</div>
diff --git a/frontend/src/views/Header.scss b/frontend/src/views/Header.scss
index e84e758..15d1375 100644
--- a/frontend/src/views/Header.scss
+++ b/frontend/src/views/Header.scss
@@ -14,12 +14,21 @@
}
.header-buttons {
- margin: 5px 0;
- text-align: right;
+ margin: 7px 0;
+ display: flex;
+ justify-content: flex-end;
+
+ .button-field {
+ margin-left: 7px;
+ }
}
- .filters-bar-wrapper {
- height: 50px;
- padding: 8px 0;
+ .filters-bar {
+ padding: 3px 0;
+
+ .filter {
+ display: inline-block;
+ margin-right: 10px;
+ }
}
}
diff --git a/frontend/src/views/MainPane.js b/frontend/src/views/MainPane.js
deleted file mode 100644
index 69de725..0000000
--- a/frontend/src/views/MainPane.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import React, {Component} from 'react';
-import './MainPane.scss';
-import Connections from "./Connections";
-import ConnectionContent from "../components/ConnectionContent";
-import {withRouter} from "react-router-dom";
-import axios from 'axios';
-
-class MainPane extends Component {
-
- constructor(props) {
- super(props);
- this.state = {
- selectedConnection: null
- };
- }
-
- componentDidMount() {
- if ('id' in this.props.match.params) {
- const id = this.props.match.params.id;
- axios.get(`/api/connections/${id}`).then(res => {
- if (res.status === 200) {
- this.setState({selectedConnection: res.data});
- }
- });
- }
- }
-
- render() {
- return (
- <div className="main-pane">
- <div className="container-fluid">
- <div className="row">
- <div className="col-md-6 pane">
- <Connections onSelected={(c) => this.setState({selectedConnection: c})} />
- </div>
- <div className="col-md-6 pl-0 pane">
- <ConnectionContent connection={this.state.selectedConnection}/>
- </div>
- </div>
- </div>
- </div>
- );
- }
-}
-
-export default withRouter(MainPane);
diff --git a/frontend/src/views/MainPane.scss b/frontend/src/views/MainPane.scss
deleted file mode 100644
index 20720ba..0000000
--- a/frontend/src/views/MainPane.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-.main-pane {
- .pane {
- height: calc(100vh - 210px);
- position: relative;
- }
-}
diff --git a/frontend/src/views/Rules.js b/frontend/src/views/Rules.js
deleted file mode 100644
index 3424410..0000000
--- a/frontend/src/views/Rules.js
+++ /dev/null
@@ -1,118 +0,0 @@
-import React, {Component} from 'react';
-import './Services.scss';
-import {Button, ButtonGroup, Col, Container, Form, FormControl, InputGroup, Modal, Row, Table} from "react-bootstrap";
-import axios from "axios";
-
-class Rules extends Component {
-
- constructor(props) {
- super(props);
-
- this.state = {
- rules: []
- };
- }
-
- componentDidMount() {
- this.loadRules();
- }
-
- loadRules() {
- axios.get("/api/rules").then(res => this.setState({rules: res.data}));
- }
-
- render() {
- let rulesRows = this.state.rules.map(rule =>
- <tr key={rule.id}>
- <td><Button variant="btn-edit" size="sm"
- style={{"backgroundColor": rule.color}}>edit</Button></td>
- <td>{rule.name}</td>
- </tr>
- );
-
-
- return (
- <Modal
- {...this.props}
- show="true"
- size="lg"
- aria-labelledby="rules-dialog"
- centered
- >
- <Modal.Header>
- <Modal.Title id="rules-dialog">
- ~/rules
- </Modal.Title>
- </Modal.Header>
- <Modal.Body>
- <Container>
- <Row>
- <Col md={7}>
- <Table borderless size="sm" className="rules-list">
- <thead>
- <tr>
- <th><Button size="sm" >new</Button></th>
- <th>name</th>
- </tr>
- </thead>
- <tbody>
- {rulesRows}
-
- </tbody>
- </Table>
- </Col>
- <Col md={5}>
- <Form>
- <Form.Group controlId="servicePort">
- <Form.Label>port:</Form.Label>
- <Form.Control type="text" />
- </Form.Group>
-
- <Form.Group controlId="serviceName">
- <Form.Label>name:</Form.Label>
- <Form.Control type="text" />
- </Form.Group>
-
- <Form.Group controlId="serviceColor">
- <Form.Label>color:</Form.Label>
- <ButtonGroup aria-label="Basic example">
-
- </ButtonGroup>
- <ButtonGroup aria-label="Basic example">
-
- </ButtonGroup>
- </Form.Group>
-
- <Form.Group controlId="serviceNotes">
- <Form.Label>notes:</Form.Label>
- <Form.Control as="textarea" rows={3} />
- </Form.Group>
- </Form>
-
-
- </Col>
-
- </Row>
-
- <Row>
- <Col md={12}>
- <InputGroup>
- <FormControl as="textarea" rows={4} className="curl-output" readOnly={true}
- />
- </InputGroup>
-
- </Col>
- </Row>
-
-
- </Container>
- </Modal.Body>
- <Modal.Footer className="dialog-footer">
- <Button variant="red" onClick={this.props.onHide}>close</Button>
- </Modal.Footer>
- </Modal>
- );
- }
-}
-
-export default Rules;
diff --git a/frontend/src/views/Services.js b/frontend/src/views/Services.js
deleted file mode 100644
index b95b01c..0000000
--- a/frontend/src/views/Services.js
+++ /dev/null
@@ -1,210 +0,0 @@
-import React, {Component} from 'react';
-import './Services.scss';
-import {Button, ButtonGroup, Col, Container, Form, FormControl, InputGroup, Modal, Row, Table} from "react-bootstrap";
-import axios from 'axios'
-import {createCurlCommand} from '../utils';
-
-class Services extends Component {
-
- constructor(props) {
- super(props);
- this.alphabet = 'abcdefghijklmnopqrstuvwxyz';
- this.colors = ["#E53935", "#D81B60", "#8E24AA", "#5E35B1", "#3949AB", "#1E88E5", "#039BE5", "#00ACC1",
- "#00897B", "#43A047", "#7CB342", "#9E9D24", "#F9A825", "#FB8C00", "#F4511E", "#6D4C41"];
-
- this.state = {
- services: {},
- port: 0,
- portValid: false,
- name: "",
- nameValid: false,
- color: this.colors[0],
- colorValid: false,
- notes: ""
- };
-
- this.portChanged = this.portChanged.bind(this);
- this.nameChanged = this.nameChanged.bind(this);
- this.notesChanged = this.notesChanged.bind(this);
- this.newService = this.newService.bind(this);
- this.editService = this.editService.bind(this);
- this.saveService = this.saveService.bind(this);
- this.loadServices = this.loadServices.bind(this);
- }
-
- componentDidMount() {
- this.loadServices();
- }
-
- portChanged(event) {
- let value = event.target.value.replace(/[^\d]/gi, '');
- let port = 0;
- if (value !== "") {
- port = parseInt(value);
- }
- this.setState({port: port});
- }
-
- nameChanged(event) {
- let value = event.target.value.replace(/[\s]/gi, '_').replace(/[^\w]/gi, '').toLowerCase();
- this.setState({name: value});
- }
-
- notesChanged(event) {
- this.setState({notes: event.target.value});
- }
-
- newService() {
- this.setState({name: "", port: 0, notes: ""});
- }
-
- editService(service) {
- this.setState({name: service.name, port: service.port, color: service.color, notes: service.notes});
- }
-
- saveService() {
- if (this.state.portValid && this.state.nameValid) {
- axios.put("/api/services", {
- name: this.state.name,
- port: this.state.port,
- color: this.state.color,
- notes: this.state.notes
- });
-
- this.newService();
- this.loadServices();
- }
- }
-
- loadServices() {
- axios.get("/api/services").then(res => this.setState({services: res.data}));
- }
-
- componentDidUpdate(prevProps, prevState, snapshot) {
- if (this.state.name != null && prevState.name !== this.state.name) {
- this.setState({
- nameValid: this.state.name.length >= 3
- });
- }
- if (prevState.port !== this.state.port) {
- this.setState({
- portValid: this.state.port > 0 && this.state.port <= 65565
- });
- }
- }
-
- render() {
- let output = "";
- if (!this.state.portValid) {
- output += "assert(1 <= port <= 65565)\n";
- }
- if (!this.state.nameValid) {
- output += "assert(len(name) >= 3)\n";
- }
- if (output === "") {
- output = createCurlCommand("/services", {
- "port": this.state.port,
- "name": this.state.name,
- "color": this.state.color,
- "notes": this.state.notes
- });
- }
- let rows = Object.values(this.state.services).map(s =>
- <tr>
- <td><Button variant="btn-edit" size="sm"
- onClick={() => this.editService(s)} style={{"backgroundColor": s.color}}>edit</Button></td>
- <td>{s.port}</td>
- <td>{s.name}</td>
- </tr>
- );
-
- let colorButtons = this.colors.map((color, i) =>
- <Button size="sm" className="btn-color" key={"button" + this.alphabet[i]}
- style={{"backgroundColor": color, "borderColor": this.state.color === color ? "#fff" : color}}
- onClick={() => this.setState({color: color})}>{this.alphabet[i]}</Button>);
-
- return (
- <Modal
- {...this.props}
- show="true"
- size="lg"
- aria-labelledby="services-dialog"
- centered
- >
- <Modal.Header>
- <Modal.Title id="services-dialog">
- ~/services
- </Modal.Title>
- </Modal.Header>
- <Modal.Body>
- <Container>
- <Row>
- <Col md={7}>
- <Table borderless size="sm" className="services-list">
- <thead>
- <tr>
- <th><Button size="sm" onClick={this.newService}>new</Button></th>
- <th>port</th>
- <th>name</th>
- </tr>
- </thead>
- <tbody>
- {rows}
- </tbody>
- </Table>
- </Col>
- <Col md={5}>
- <Form>
- <Form.Group controlId="servicePort">
- <Form.Label>port:</Form.Label>
- <Form.Control type="text" onChange={this.portChanged} value={this.state.port}/>
- </Form.Group>
-
- <Form.Group controlId="serviceName">
- <Form.Label>name:</Form.Label>
- <Form.Control type="text" onChange={this.nameChanged} value={this.state.name}/>
- </Form.Group>
-
- <Form.Group controlId="serviceColor">
- <Form.Label>color:</Form.Label>
- <ButtonGroup aria-label="Basic example">
- {colorButtons.slice(0, 8)}
- </ButtonGroup>
- <ButtonGroup aria-label="Basic example">
- {colorButtons.slice(8, 18)}
- </ButtonGroup>
- </Form.Group>
-
- <Form.Group controlId="serviceNotes">
- <Form.Label>notes:</Form.Label>
- <Form.Control as="textarea" rows={3} onChange={this.notesChanged}
- value={this.state.notes}/>
- </Form.Group>
- </Form>
-
-
- </Col>
-
- </Row>
-
- <Row>
- <Col md={12}>
- <InputGroup>
- <FormControl as="textarea" rows={4} className="curl-output" readOnly={true}
- value={output}/>
- </InputGroup>
-
- </Col>
- </Row>
- </Container>
- </Modal.Body>
- <Modal.Footer className="dialog-footer">
- <Button variant="green" onClick={this.saveService}>save</Button>
- <Button variant="red" onClick={this.props.onHide}>close</Button>
- </Modal.Footer>
- </Modal>
- );
- }
-}
-
-export default Services;
diff --git a/frontend/src/views/Services.scss b/frontend/src/views/Services.scss
deleted file mode 100644
index 2abb55e..0000000
--- a/frontend/src/views/Services.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-@import '../colors.scss';
-
-.curl-output {
- width: 100%;
- font-size: 13px;
-}
-
-.services-list {
- .btn {
- width: 70px;
- }
-
- td {
- background-color: $color-primary-2;
- border-top: 2px solid $color-primary-0;
- vertical-align: middle;
- }
-
- th {
- background-color: $color-primary-1;
- }
-}
-
-.btn-color {
- border: 3px solid #fff;
-}
-
-.dialog-footer {
- .btn {
- width: 80px;
- }
-}