From 8c39914f46aac4b2c4d11a5581b772e7007379fb Mon Sep 17 00:00:00 2001 From: Mcat12 Date: Thu, 8 Nov 2018 12:10:44 -0500 Subject: [PATCH 01/11] Don't refresh DHCP settings after page load Signed-off-by: Mcat12 --- src/components/settings/DHCPInfo.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/settings/DHCPInfo.js b/src/components/settings/DHCPInfo.js index c5a345c..82b01f4 100644 --- a/src/components/settings/DHCPInfo.js +++ b/src/components/settings/DHCPInfo.js @@ -40,10 +40,7 @@ class DHCPInfo extends Component { } updateDHCPInfo() { - this.updateHandler = makeCancelable(api.getDHCPInfo(), { - repeat: this.updateDHCPInfo, - interval: 600000 - }); + this.updateHandler = makeCancelable(api.getDHCPInfo()); this.updateHandler.promise .then(res => { this.setState({ From 07c37b2a8a9ddd5a0167b4bcb588ee47449533d9 Mon Sep 17 00:00:00 2001 From: Mcat12 Date: Thu, 8 Nov 2018 15:48:54 -0500 Subject: [PATCH 02/11] Handle API errors better by handling rejected promises from fetch Some statuses (such as 500) are returned as rejected promises by fetch. These responses are now caught and handled as normal API responses (checking for errors later). If fetch returns an Error, that is kept as a rejected promise. Signed-off-by: Mcat12 --- src/utils.js | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/utils.js b/src/utils.js index d53e52c..4757430 100644 --- a/src/utils.js +++ b/src/utils.js @@ -127,6 +127,7 @@ export const api = { }) .then(api.checkIfLoggedOut) .then(api.convertJSON) + .catch(api.convertJSON) .then(api.checkForErrors); }, post(url, data) { @@ -138,6 +139,7 @@ export const api = { }) .then(api.checkIfLoggedOut) .then(api.convertJSON) + .catch(api.convertJSON) .then(api.checkForErrors); }, delete(url) { @@ -167,6 +169,9 @@ export const api = { /** * If the user is logged in, check if the user's session has lapsed. * If so, log them out and refresh the page. + * + * @param response the Response from fetch + * @return {Promise} if logged in, the response, otherwise a canceled promise */ checkIfLoggedOut(response) { if (api.loggedIn && response.status === 401) { @@ -179,14 +184,32 @@ export const api = { return Promise.resolve(response); }, - async convertJSON(data) { - if (!data.ok) return Promise.reject({ data, json: await data.json() }); - else return data.json(); + /** + * If the input is a Response, return a promise for parsing the JSON. + * If the input is an Error, return a rejecting promise with error. + * + * @param data a Response or Error + * @returns {*} a promise with the parsed JSON, or the error + */ + convertJSON(data) { + if (data instanceof Error) { + return Promise.reject(data); + } + + return data.json(); }, + /** + * Check for an error returned by the API + * + * @param data the parsed JSON body of the response + * @returns {*} a resolving promise with the data if no error, otherwise a + * rejecting promise with the error + */ checkForErrors(data) { if (data.error) { return Promise.reject(data.error); } + return Promise.resolve(data); }, urlFor(endpoint) { From aadadca1b22d3c1776e784c3c93840451b621340 Mon Sep 17 00:00:00 2001 From: Mcat12 Date: Thu, 8 Nov 2018 15:50:06 -0500 Subject: [PATCH 03/11] Add updateDHCPInfo to the api endpoints Required adding a `put` method for making PUT requests Signed-off-by: Mcat12 --- src/utils.js | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/utils.js b/src/utils.js index 4757430..9a8ea69 100644 --- a/src/utils.js +++ b/src/utils.js @@ -121,6 +121,24 @@ export const api = { getStatus() { return api.get("dns/status"); }, + getNetworkInfo() { + return api.get("settings/network"); + }, + getVersion() { + return api.get("version"); + }, + getFTLdb() { + return api.get("settings/ftldb"); + }, + getDNSInfo() { + return api.get("settings/dns"); + }, + getDHCPInfo() { + return api.get("settings/dhcp"); + }, + updateDHCPInfo(settings) { + return api.put("settings/dhcp", settings); + }, get(url) { return fetch(api.urlFor(url), { credentials: this.credentialType() @@ -142,6 +160,18 @@ export const api = { .catch(api.convertJSON) .then(api.checkForErrors); }, + put(url, data) { + return fetch(api.urlFor(url), { + method: "PUT", + body: JSON.stringify(data), + headers: new Headers({ "Content-Type": "application/json" }), + credentials: this.credentialType() + }) + .then(api.checkIfLoggedOut) + .then(api.convertJSON) + .catch(api.convertJSON) + .then(api.checkForErrors); + }, delete(url) { return fetch(api.urlFor(url), { method: "DELETE", @@ -149,23 +179,9 @@ export const api = { }) .then(api.checkIfLoggedOut) .then(api.convertJSON) + .catch(api.convertJSON) .then(api.checkForErrors); }, - getNetworkInfo() { - return api.get("settings/network"); - }, - getVersion() { - return api.get("version"); - }, - getFTLdb() { - return api.get("settings/ftldb"); - }, - getDNSInfo() { - return api.get("settings/dns"); - }, - getDHCPInfo() { - return api.get("settings/dhcp"); - }, /** * If the user is logged in, check if the user's session has lapsed. * If so, log them out and refresh the page. From 1c2d881ae1809f9d6645df3f171eb256b139b929 Mon Sep 17 00:00:00 2001 From: Mcat12 Date: Thu, 8 Nov 2018 15:53:00 -0500 Subject: [PATCH 04/11] Send a DHCP settings update request when DHCP settings are applied If an error is returned, it is shown at the top of the form. Signed-off-by: Mcat12 --- src/components/settings/DHCPInfo.js | 105 ++++++++++++++++++---------- 1 file changed, 67 insertions(+), 38 deletions(-) diff --git a/src/components/settings/DHCPInfo.js b/src/components/settings/DHCPInfo.js index 82b01f4..83b57d7 100644 --- a/src/components/settings/DHCPInfo.js +++ b/src/components/settings/DHCPInfo.js @@ -22,16 +22,20 @@ import { Label } from "reactstrap"; import { isPositiveNumber, isValidHostname, isValidIpv4 } from "../../validate"; +import Alert from "../common/Alert"; class DHCPInfo extends Component { state = { - active: false, - ip_start: "", - ip_end: "", - router_ip: "", - lease_time: "", - domain: "", - ipv6_support: false + errorMessage: "", + settings: { + active: false, + ip_start: "", + ip_end: "", + router_ip: "", + lease_time: "", + domain: "", + ipv6_support: false + } }; constructor(props) { @@ -44,13 +48,15 @@ class DHCPInfo extends Component { this.updateHandler.promise .then(res => { this.setState({ - active: res.active, - ip_start: res.ip_start, - ip_end: res.ip_end, - router_ip: res.router_ip, - lease_time: res.lease_time, - domain: res.domain, - ipv6_support: res.ipv6_support + settings: { + active: res.active, + ip_start: res.ip_start, + ip_end: res.ip_end, + router_ip: res.router_ip, + lease_time: res.lease_time, + domain: res.domain, + ipv6_support: res.ipv6_support + } }); }) .catch(ignoreCancel); @@ -73,10 +79,16 @@ class DHCPInfo extends Component { * @returns {function(Event)} */ onChange = (key, attr) => { - return e => - this.setState({ - [key]: e.target[attr] - }); + return e => { + const value = e.target[attr]; + + this.setState(oldState => ({ + settings: { + ...oldState.settings, + [key]: value + } + })); + }; }; /** @@ -87,7 +99,9 @@ class DHCPInfo extends Component { saveSettings = e => { e.preventDefault(); - // TODO: send settings to API + api.updateDHCPInfo(this.state.settings).catch(error => { + this.setState({ errorMessage: error.message }); + }); }; /** @@ -97,37 +111,52 @@ class DHCPInfo extends Component { * @param validator the validation function */ isSettingValid = (value, validator) => { - return (!this.state.active && value.length === 0) || validator(value); + return ( + (!this.state.settings.active && value.length === 0) || validator(value) + ); }; render() { const { t } = this.props; const isIpStartValid = this.isSettingValid( - this.state.ip_start, + this.state.settings.ip_start, + isValidIpv4 + ); + const isIpEndValid = this.isSettingValid( + this.state.settings.ip_end, isValidIpv4 ); - const isIpEndValid = this.isSettingValid(this.state.ip_end, isValidIpv4); const isRouterIpValid = this.isSettingValid( - this.state.router_ip, + this.state.settings.router_ip, isValidIpv4 ); const isLeaseTimeValid = this.isSettingValid( - this.state.lease_time, + this.state.settings.lease_time, isPositiveNumber ); const isDomainValid = this.isSettingValid( - this.state.domain, + this.state.settings.domain, isValidHostname ); + const errorAlert = + this.state.errorMessage.length > 0 ? ( + this.setState({ errorMessage: "" })} + /> + ) : null; + return (
+ {errorAlert} @@ -258,6 +290,7 @@ class DHCPInfo extends Component {