From 08456e7f2e1c1af6fc8fdbf580c0178a25b93f8b Mon Sep 17 00:00:00 2001 From: Emiliano Ciavatta Date: Thu, 15 Oct 2020 08:53:09 +0200 Subject: General improvements --- .../components/filters/BooleanConnectionsFilter.js | 64 +++++++---------- .../src/components/filters/ExitSearchFilter.js | 9 ++- .../src/components/filters/FiltersDispatcher.js | 57 --------------- .../components/filters/RulesConnectionsFilter.js | 81 +++++++++------------- .../components/filters/StringConnectionsFilter.js | 77 ++++++++++---------- 5 files changed, 100 insertions(+), 188 deletions(-) delete mode 100644 frontend/src/components/filters/FiltersDispatcher.js (limited to 'frontend/src/components/filters') diff --git a/frontend/src/components/filters/BooleanConnectionsFilter.js b/frontend/src/components/filters/BooleanConnectionsFilter.js index a9a420e..c611a0d 100644 --- a/frontend/src/components/filters/BooleanConnectionsFilter.js +++ b/frontend/src/components/filters/BooleanConnectionsFilter.js @@ -17,65 +17,49 @@ import React, {Component} from 'react'; import {withRouter} from "react-router-dom"; -import {Redirect} from "react-router"; import CheckField from "../fields/CheckField"; +import dispatcher from "../../dispatcher"; class BooleanConnectionsFilter extends Component { - constructor(props) { - super(props); - this.state = { - filterActive: "false" - }; - - this.filterChanged = this.filterChanged.bind(this); - this.needRedirect = false; - } + state = { + filterActive: "false" + }; componentDidMount() { let params = new URLSearchParams(this.props.location.search); this.setState({filterActive: this.toBoolean(params.get(this.props.filterName)).toString()}); + + this.connectionsFiltersCallback = payload => { + const name = this.props.filterName; + if (name in payload && this.state.filterActive !== payload[name]) { + this.setState({filterActive: payload[name]}); + } + }; + dispatcher.register("connections_filters", this.connectionsFiltersCallback); } - componentDidUpdate(prevProps, prevState, snapshot) { - let urlParams = new URLSearchParams(this.props.location.search); - let externalActive = this.toBoolean(urlParams.get(this.props.filterName)); - let filterActive = this.toBoolean(this.state.filterActive); - // if the filterActive state is changed by another component (and not by filterChanged func) and - // the query string is not equals at the filterActive state, update the state of the component - if (this.toBoolean(prevState.filterActive) === filterActive && filterActive !== externalActive) { - this.setState({filterActive: externalActive.toString()}); - } + componentWillUnmount() { + dispatcher.unregister(this.connectionsFiltersCallback); } - toBoolean(value) { + toBoolean = (value) => { return value !== null && value.toLowerCase() === "true"; - } + }; - filterChanged() { - this.needRedirect = true; - this.setState({filterActive: (!this.toBoolean(this.state.filterActive)).toString()}); - } + filterChanged = () => { + const newValue = (!this.toBoolean(this.state.filterActive)).toString(); + const urlParams = {}; + urlParams[this.props.filterName] = newValue === "true" ? "true" : null; + dispatcher.dispatch("connections_filters", urlParams); + this.setState({filterActive: newValue}); + }; render() { - let redirect = null; - if (this.needRedirect) { - let urlParams = new URLSearchParams(this.props.location.search); - if (this.toBoolean(this.state.filterActive)) { - urlParams.set(this.props.filterName, "true"); - } else { - urlParams.delete(this.props.filterName); - } - redirect = ; - - this.needRedirect = false; - } - return (
- {redirect} + onChange={this.filterChanged}/>
); } diff --git a/frontend/src/components/filters/ExitSearchFilter.js b/frontend/src/components/filters/ExitSearchFilter.js index cfee298..68ca686 100644 --- a/frontend/src/components/filters/ExitSearchFilter.js +++ b/frontend/src/components/filters/ExitSearchFilter.js @@ -28,11 +28,16 @@ class ExitSearchFilter extends Component { let params = new URLSearchParams(this.props.location.search); this.setState({performedSearch: params.get("performed_search")}); - dispatcher.register("connections_filters", payload => { + this.connectionsFiltersCallback = payload => { if (this.state.performedSearch !== payload["performed_search"]) { this.setState({performedSearch: payload["performed_search"]}); } - }); + }; + dispatcher.register("connections_filters", this.connectionsFiltersCallback); + } + + componentWillUnmount() { + dispatcher.unregister(this.connectionsFiltersCallback); } render() { diff --git a/frontend/src/components/filters/FiltersDispatcher.js b/frontend/src/components/filters/FiltersDispatcher.js deleted file mode 100644 index 3769055..0000000 --- a/frontend/src/components/filters/FiltersDispatcher.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is part of caronte (https://github.com/eciavatta/caronte). - * Copyright (c) 2020 Emiliano Ciavatta. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import React, {Component} from 'react'; -import {withRouter} from "react-router-dom"; -import {Redirect} from "react-router"; -import dispatcher from "../../dispatcher"; - -class FiltersDispatcher extends Component { - - state = {}; - - componentDidMount() { - let params = new URLSearchParams(this.props.location.search); - this.setState({params}); - - dispatcher.register("connections_filters", payload => { - const params = this.state.params; - - Object.entries(payload).forEach(([key, value]) => { - if (value == null) { - params.delete(key); - } else { - params.set(key, value); - } - }); - - this.needRedirect = true; - this.setState({params}); - }); - } - - render() { - if (this.needRedirect) { - this.needRedirect = false; - return ; - } - - return null; - } -} - -export default withRouter(FiltersDispatcher); diff --git a/frontend/src/components/filters/RulesConnectionsFilter.js b/frontend/src/components/filters/RulesConnectionsFilter.js index fc0ad4d..4c993dc 100644 --- a/frontend/src/components/filters/RulesConnectionsFilter.js +++ b/frontend/src/components/filters/RulesConnectionsFilter.js @@ -17,87 +17,74 @@ import React, {Component} from 'react'; import {withRouter} from "react-router-dom"; -import {Redirect} from "react-router"; import './RulesConnectionsFilter.scss'; import ReactTags from 'react-tag-autocomplete'; import backend from "../../backend"; +import dispatcher from "../../dispatcher"; const classNames = require('classnames'); +const _ = require('lodash'); class RulesConnectionsFilter extends Component { - constructor(props) { - super(props); - this.state = { - mounted: false, - rules: [], - activeRules: [] - }; - - this.needRedirect = false; - } + state = { + rules: [], + activeRules: [] + }; componentDidMount() { - let params = new URLSearchParams(this.props.location.search); + const params = new URLSearchParams(this.props.location.search); let activeRules = params.getAll("matched_rules") || []; backend.get("/api/rules").then(res => { let rules = res.json.flatMap(rule => rule.enabled ? [{id: rule.id, name: rule.name}] : []); activeRules = rules.filter(rule => activeRules.some(id => rule.id === id)); - this.setState({rules, activeRules, mounted: true}); + this.setState({rules, activeRules}); }); + + this.connectionsFiltersCallback = payload => { + if ("matched_rules" in payload && !_.isEqual(payload["matched_rules"].sort(), this.state.activeRules.sort())) { + const newRules = this.state.rules.filter(r => payload["matched_rules"].includes(r.id)); + this.setState({ + activeRules: newRules.map(r => { + return {id: r.id, name: r.name}; + }) + }); + } + }; + dispatcher.register("connections_filters", this.connectionsFiltersCallback); } - componentDidUpdate(prevProps, prevState, snapshot) { - let urlParams = new URLSearchParams(this.props.location.search); - let externalRules = urlParams.getAll("matched_rules") || []; - let activeRules = this.state.activeRules.map(r => r.id); - let compareRules = (first, second) => first.sort().join(",") === second.sort().join(","); - if (this.state.mounted && - compareRules(prevState.activeRules.map(r => r.id), activeRules) && - !compareRules(externalRules, activeRules)) { - this.setState({activeRules: externalRules.map(id => this.state.rules.find(r => r.id === id))}); - } + componentWillUnmount() { + dispatcher.unregister(this.connectionsFiltersCallback); } - onDelete(i) { - const activeRules = this.state.activeRules.slice(0); + onDelete = (i) => { + const activeRules = _.clone(this.state.activeRules); activeRules.splice(i, 1); - this.needRedirect = true; - this.setState({ activeRules }); - } + this.setState({activeRules}); + dispatcher.dispatch("connections_filters", {"matched_rules": activeRules.map(r => r.id)}); + }; - onAddition(rule) { + onAddition = (rule) => { if (!this.state.activeRules.includes(rule)) { const activeRules = [].concat(this.state.activeRules, rule); - this.needRedirect = true; this.setState({activeRules}); + dispatcher.dispatch("connections_filters", {"matched_rules": activeRules.map(r => r.id)}); } - } + }; render() { - let redirect = null; - - if (this.needRedirect) { - let urlParams = new URLSearchParams(this.props.location.search); - urlParams.delete("matched_rules"); - this.state.activeRules.forEach(rule => urlParams.append("matched_rules", rule.id)); - redirect = ; - - this.needRedirect = false; - } - return ( -
+
- suggestion.name.startsWith(query) && !this.state.activeRules.includes(suggestion)} /> + suggestion.name.startsWith(query) && !this.state.activeRules.includes(suggestion)}/>
- - {redirect}
); } diff --git a/frontend/src/components/filters/StringConnectionsFilter.js b/frontend/src/components/filters/StringConnectionsFilter.js index a3b45dc..c833220 100644 --- a/frontend/src/components/filters/StringConnectionsFilter.js +++ b/frontend/src/components/filters/StringConnectionsFilter.js @@ -17,37 +17,36 @@ import React, {Component} from 'react'; import {withRouter} from "react-router-dom"; -import {Redirect} from "react-router"; import InputField from "../fields/InputField"; +import dispatcher from "../../dispatcher"; class StringConnectionsFilter extends Component { - constructor(props) { - super(props); - this.state = { - fieldValue: "", - filterValue: null, - timeoutHandle: null, - invalidValue: false - }; - this.needRedirect = false; - this.filterChanged = this.filterChanged.bind(this); - } + state = { + fieldValue: "", + filterValue: null, + timeoutHandle: null, + invalidValue: false + }; componentDidMount() { let params = new URLSearchParams(this.props.location.search); this.updateStateFromFilterValue(params.get(this.props.filterName)); + + this.connectionsFiltersCallback = payload => { + const name = this.props.filterName; + if (name in payload && this.state.filterValue !== payload[name]) { + this.updateStateFromFilterValue(payload[name]); + } + }; + dispatcher.register("connections_filters", this.connectionsFiltersCallback); } - componentDidUpdate(prevProps, prevState, snapshot) { - let urlParams = new URLSearchParams(this.props.location.search); - let filterValue = urlParams.get(this.props.filterName); - if (prevState.filterValue === this.state.filterValue && this.state.filterValue !== filterValue) { - this.updateStateFromFilterValue(filterValue); - } + componentWillUnmount() { + dispatcher.unregister(this.connectionsFiltersCallback); } - updateStateFromFilterValue(filterValue) { + updateStateFromFilterValue = (filterValue) => { if (filterValue !== null) { let fieldValue = filterValue; if (typeof this.props.decodeFunc === "function") { @@ -70,15 +69,21 @@ class StringConnectionsFilter extends Component { } else { this.setState({fieldValue: "", filterValue: null}); } - } + }; - isValueValid(value) { + isValueValid = (value) => { return typeof this.props.validateFunc !== "function" || (typeof this.props.validateFunc === "function" && this.props.validateFunc(value)); - } + }; - filterChanged(fieldValue) { - if (this.state.timeoutHandle !== null) { + changeFilterValue = (value) => { + const urlParams = {}; + urlParams[this.props.filterName] = value; + dispatcher.dispatch("connections_filters", urlParams); + }; + + filterChanged = (fieldValue) => { + if (this.state.timeoutHandle) { clearTimeout(this.state.timeoutHandle); } @@ -87,11 +92,12 @@ class StringConnectionsFilter extends Component { } if (fieldValue === "") { - this.needRedirect = true; this.setState({fieldValue: "", filterValue: null, invalidValue: false}); - return; + return this.changeFilterValue(null); } + + if (this.isValueValid(fieldValue)) { let filterValue = fieldValue; if (filterValue !== "" && typeof this.props.encodeFunc === "function") { @@ -101,40 +107,27 @@ class StringConnectionsFilter extends Component { this.setState({ fieldValue: fieldValue, timeoutHandle: setTimeout(() => { - this.needRedirect = true; this.setState({filterValue: filterValue}); + this.changeFilterValue(filterValue); }, 500), invalidValue: false }); } else { - this.needRedirect = true; this.setState({ fieldValue: fieldValue, invalidValue: true }); } - } + }; render() { - let redirect = null; - if (this.needRedirect) { - let urlParams = new URLSearchParams(this.props.location.search); - if (this.state.filterValue !== null) { - urlParams.set(this.props.filterName, this.state.filterValue); - } else { - urlParams.delete(this.props.filterName); - } - redirect = ; - this.needRedirect = false; - } let active = this.state.filterValue !== null; return (
- {redirect} + value={this.state.fieldValue} inline={true} small={true}/>
); } -- cgit v1.2.3-70-g09d2