From 6006d47c1f3397862bb13c782d66689067135bdb Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Sat, 9 May 2020 14:34:08 +0200 Subject: Add infinite scroll to connections, implement connection actions --- frontend/src/views/App.js | 10 ++--- frontend/src/views/Connections.js | 94 ++++++++++++++++++++++++++++++++++++--- frontend/src/views/Footer.scss | 2 +- frontend/src/views/Header.js | 6 ++- frontend/src/views/Header.scss | 2 +- frontend/src/views/MainPane.js | 10 +---- frontend/src/views/MainPane.scss | 3 +- frontend/src/views/Services.js | 16 ++++--- 8 files changed, 110 insertions(+), 33 deletions(-) (limited to 'frontend/src/views') 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 = this.setState({servicesShow: false})} /> + modal = this.setState({servicesShow: false})}/>; } return ( @@ -26,8 +26,8 @@ class App extends Component {
this.setState({servicesShow: true})}/> - } /> - } /> + }/> + }/> {modal}
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 = ; } - return ( + let loading = null; + if (this.state.loading) { + loading = + Loading... + ; + } -
+ return ( +
@@ -46,9 +124,11 @@ class Connections extends Component { { this.state.connections.map(c => 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}
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 {

- { this.el = el; }} /> + { + this.el = el; + }}/>

@@ -45,7 +47,7 @@ class Header extends Component {
- ) + ); } } 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 => + onClick={() => this.editService(s)} style={{"backgroundColor": s.color}}>edit {s.port} {s.name} @@ -149,7 +149,7 @@ class Services extends Component { - {rows} + {rows} @@ -157,7 +157,7 @@ class Services extends Component {
port: - + @@ -168,16 +168,17 @@ class Services extends Component { color: - {colorButtons.slice(0,8)} + {colorButtons.slice(0, 8)} - {colorButtons.slice(8,18)} + {colorButtons.slice(8, 18)} notes: - + @@ -189,7 +190,8 @@ class Services extends Component { - + -- cgit v1.2.3-70-g09d2