aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/views
diff options
context:
space:
mode:
authorEmiliano Ciavatta2020-05-09 12:34:08 +0000
committerEmiliano Ciavatta2020-05-09 12:34:08 +0000
commit6006d47c1f3397862bb13c782d66689067135bdb (patch)
treea86e5a275063485cc93a5d8b7077ec119900037d /frontend/src/views
parentdee7d7dfcbec7ef4475896935873f04d4df0d40f (diff)
Add infinite scroll to connections, implement connection actions
Diffstat (limited to 'frontend/src/views')
-rw-r--r--frontend/src/views/App.js10
-rw-r--r--frontend/src/views/Connections.js94
-rw-r--r--frontend/src/views/Footer.scss2
-rw-r--r--frontend/src/views/Header.js6
-rw-r--r--frontend/src/views/Header.scss2
-rw-r--r--frontend/src/views/MainPane.js10
-rw-r--r--frontend/src/views/MainPane.scss3
-rw-r--r--frontend/src/views/Services.js16
8 files changed, 110 insertions, 33 deletions
diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js
index 2b444a2..e3119aa 100644
--- a/frontend/src/views/App.js
+++ b/frontend/src/views/App.js
@@ -3,7 +3,7 @@ import Header from "./Header";
import './App.scss';
import MainPane from "./MainPane";
import Footer from "./Footer";
-import {Route, BrowserRouter as Router, Switch} from "react-router-dom";
+import {BrowserRouter as Router, Route, Switch} from "react-router-dom";
import Services from "./Services";
class App extends Component {
@@ -16,9 +16,9 @@ class App extends Component {
}
render() {
- let modal = ""
+ let modal = "";
if (this.state.servicesShow) {
- modal = <Services onHide={() => this.setState({servicesShow: false})} />
+ modal = <Services onHide={() => this.setState({servicesShow: false})}/>;
}
return (
@@ -26,8 +26,8 @@ class App extends Component {
<Router>
<Header onOpenServices={() => this.setState({servicesShow: true})}/>
<Switch>
- <Route path="/connections/:id" children={<MainPane/>} />
- <Route path="/" children={<MainPane/>} />
+ <Route path="/connections/:id" children={<MainPane/>}/>
+ <Route path="/" children={<MainPane/>}/>
</Switch>
{modal}
<Footer/>
diff --git a/frontend/src/views/Connections.js b/frontend/src/views/Connections.js
index fa7798e..400f4e0 100644
--- a/frontend/src/views/Connections.js
+++ b/frontend/src/views/Connections.js
@@ -4,29 +4,107 @@ import axios from 'axios'
import Connection from "../components/Connection";
import Table from 'react-bootstrap/Table';
import {Redirect} from 'react-router';
+import {objectToQueryString} from "../utils";
class Connections extends Component {
+
constructor(props) {
super(props);
this.state = {
+ loading: false,
connections: [],
+ firstConnection: null,
+ lastConnection: null,
+ showHidden: false
};
- }
+ this.scrollTopThreashold = 0.00001;
+ this.scrollBottomThreashold = 0.99999;
+ this.maxConnections = 500;
+ this.queryLimit = 50;
+ this.handleScroll = this.handleScroll.bind(this);
+ }
+
componentDidMount() {
- axios.get("/api/connections").then(res => this.setState({connections: res.data}))
+ this.loadConnections({limit: this.queryLimit, hidden: this.state.showHidden});
+ }
+
+ 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,
+ hidden: this.state.showHidden
+ });
+ }
+ if (!this.state.loading && relativeScroll < this.scrollTopThreashold) {
+ this.loadConnections({
+ to: this.state.firstConnection.id, limit: this.queryLimit,
+ hidden: this.state.showHidden
+ });
+ }
+
+ }
+
+ async loadConnections(params) {
+ let url = "/api/connections";
+ if (params !== undefined) {
+ url += "?" + objectToQueryString(params);
+ }
+ this.setState({loading: true});
+ let res = await axios.get(url);
+
+ let connections = this.state.connections;
+ let firstConnection = this.state.firstConnection;
+ let lastConnection = this.state.lastConnection;
+ if (res.data.length > 0) {
+ if (params !== undefined && params.from !== undefined) {
+ connections = this.state.connections.concat(res.data);
+ lastConnection = connections[connections.length - 1];
+ if (connections.length > this.maxConnections) {
+ connections = connections.slice(connections.length - this.maxConnections,
+ connections.length - 1);
+ firstConnection = connections[0];
+ }
+ } else if (params !== undefined && params.to !== undefined) {
+ connections = res.data.concat(this.state.connections);
+ firstConnection = connections[0];
+ if (connections.length > this.maxConnections) {
+ connections = connections.slice(0, this.maxConnections);
+ lastConnection = connections[this.maxConnections - 1];
+ }
+ } else {
+ connections = res.data;
+ firstConnection = connections[0];
+ lastConnection = connections[connections.length - 1];
+ }
+ }
+
+ this.setState({
+ loading: false,
+ connections: connections,
+ firstConnection: firstConnection,
+ lastConnection: lastConnection
+ });
}
+
render() {
- let redirect = ""
+ let redirect = "";
if (this.state.selected) {
- redirect = <Redirect push to={"/connections/" + this.state.selected} />;
+ redirect = <Redirect push to={"/connections/" + this.state.selected}/>;
}
- return (
+ let loading = null;
+ if (this.state.loading) {
+ loading = <tr>
+ <td colSpan={9}>Loading...</td>
+ </tr>;
+ }
- <div className="connections">
+ return (
+ <div className="connections" onScroll={this.handleScroll}>
<div className="connections-header-padding"/>
<Table borderless size="sm">
<thead>
@@ -46,9 +124,11 @@ class Connections extends Component {
{
this.state.connections.map(c =>
<Connection key={c.id} data={c} onSelected={() => this.setState({selected: c.id})}
- selected={this.state.selected === c.id}/>
+ selected={this.state.selected === c.id} onMarked={marked => c.marked = marked}
+ onEnabled={enabled => c.hidden = !enabled}/>
)
}
+ {loading}
</tbody>
</Table>
diff --git a/frontend/src/views/Footer.scss b/frontend/src/views/Footer.scss
index 9a8cacb..c89f971 100644
--- a/frontend/src/views/Footer.scss
+++ b/frontend/src/views/Footer.scss
@@ -3,7 +3,7 @@
.footer {
padding: 15px 30px;
- >.row {
+ > .row {
background-color: $color-primary-0;
}
diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js
index ac272e6..f96b036 100644
--- a/frontend/src/views/Header.js
+++ b/frontend/src/views/Header.js
@@ -31,7 +31,9 @@ class Header extends Component {
<div className="row">
<div className="col">
<h1 className="header-title type-wrap">
- <span style={{ whiteSpace: 'pre' }} ref={(el) => { this.el = el; }} />
+ <span style={{whiteSpace: 'pre'}} ref={(el) => {
+ this.el = el;
+ }}/>
</h1>
</div>
<div className="col">
@@ -45,7 +47,7 @@ class Header extends Component {
</div>
</div>
</header>
- )
+ );
}
}
diff --git a/frontend/src/views/Header.scss b/frontend/src/views/Header.scss
index 16c2dbd..0c524e6 100644
--- a/frontend/src/views/Header.scss
+++ b/frontend/src/views/Header.scss
@@ -3,7 +3,7 @@
.header {
padding: 15px 30px;
- >.row {
+ > .row {
background-color: $color-primary-0;
}
diff --git a/frontend/src/views/MainPane.js b/frontend/src/views/MainPane.js
index 0fc083e..e84f94c 100644
--- a/frontend/src/views/MainPane.js
+++ b/frontend/src/views/MainPane.js
@@ -19,9 +19,7 @@ class MainPane extends Component {
const id = this.props.match.params.id;
this.setState({id: id});
- axios.get(`/api/streams/${id}`).then(res => this.setState({connectionContent: res.data}))
-
-
+ axios.get(`/api/streams/${id}`).then(res => this.setState({connectionContent: res.data}));
}
}
@@ -30,12 +28,8 @@ class MainPane extends Component {
const id = this.props.match.params.id;
this.setState({id: id});
- axios.get(`/api/streams/${id}`).then(res => this.setState({connectionContent: res.data}))
-
-
+ axios.get(`/api/streams/${id}`).then(res => this.setState({connectionContent: res.data}));
}
-
-
}
render() {
diff --git a/frontend/src/views/MainPane.scss b/frontend/src/views/MainPane.scss
index c1a2f7f..d0d25b1 100644
--- a/frontend/src/views/MainPane.scss
+++ b/frontend/src/views/MainPane.scss
@@ -5,5 +5,4 @@
position: relative;
}
-
-} \ No newline at end of file
+}
diff --git a/frontend/src/views/Services.js b/frontend/src/views/Services.js
index 66d99c6..b95b01c 100644
--- a/frontend/src/views/Services.js
+++ b/frontend/src/views/Services.js
@@ -112,7 +112,7 @@ class Services extends Component {
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>
+ onClick={() => this.editService(s)} style={{"backgroundColor": s.color}}>edit</Button></td>
<td>{s.port}</td>
<td>{s.name}</td>
</tr>
@@ -149,7 +149,7 @@ class Services extends Component {
</tr>
</thead>
<tbody>
- {rows}
+ {rows}
</tbody>
</Table>
</Col>
@@ -157,7 +157,7 @@ class Services extends Component {
<Form>
<Form.Group controlId="servicePort">
<Form.Label>port:</Form.Label>
- <Form.Control type="text" onChange={this.portChanged} value={this.state.port} />
+ <Form.Control type="text" onChange={this.portChanged} value={this.state.port}/>
</Form.Group>
<Form.Group controlId="serviceName">
@@ -168,16 +168,17 @@ class Services extends Component {
<Form.Group controlId="serviceColor">
<Form.Label>color:</Form.Label>
<ButtonGroup aria-label="Basic example">
- {colorButtons.slice(0,8)}
+ {colorButtons.slice(0, 8)}
</ButtonGroup>
<ButtonGroup aria-label="Basic example">
- {colorButtons.slice(8,18)}
+ {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.Control as="textarea" rows={3} onChange={this.notesChanged}
+ value={this.state.notes}/>
</Form.Group>
</Form>
@@ -189,7 +190,8 @@ class Services extends Component {
<Row>
<Col md={12}>
<InputGroup>
- <FormControl as="textarea" rows={4} className="curl-output" readOnly={true} value={output}/>
+ <FormControl as="textarea" rows={4} className="curl-output" readOnly={true}
+ value={output}/>
</InputGroup>
</Col>