From 0af3e21ab2e4b2004d92b8167c0f46c35a7ffedc Mon Sep 17 00:00:00 2001 From: Mcat12 Date: Wed, 23 Jan 2019 22:06:38 -0800 Subject: [PATCH] Convert settings components to TypeScript Signed-off-by: Mcat12 --- package-lock.json | 10 +++ package.json | 1 + ...s.js => ConditionalForwardingSettings.tsx} | 26 +++--- .../settings/{DHCPInfo.js => DHCPInfo.tsx} | 87 +++++++++--------- .../settings/{DNSInfo.js => DNSInfo.tsx} | 51 +++++++---- .../settings/{DnsList.js => DnsList.tsx} | 19 ++-- .../{DnsListItem.js => DnsListItem.tsx} | 13 ++- .../{DnsListNewItem.js => DnsListNewItem.tsx} | 35 +++++--- ...ptionSettings.js => DnsOptionSettings.tsx} | 20 ++++- .../settings/{FTLInfo.js => FTLInfo.tsx} | 24 ++--- .../{NetworkInfo.js => NetworkInfo.tsx} | 25 +++--- ...enceSettings.js => PreferenceSettings.tsx} | 63 +++++++------ .../{VersionCard.js => VersionCard.tsx} | 24 ++--- .../{VersionInfo.js => VersionInfo.tsx} | 26 ++---- .../{DHCPInfo.test.js => DHCPInfo.test.tsx} | 23 +++-- ...pstreams.js => preconfiguredUpstreams.tsx} | 19 +++- src/util/api.tsx | 90 ++++++++++++++----- 17 files changed, 337 insertions(+), 219 deletions(-) rename src/components/settings/{ConditionalForwardingSettings.js => ConditionalForwardingSettings.tsx} (79%) rename src/components/settings/{DHCPInfo.js => DHCPInfo.tsx} (80%) rename src/components/settings/{DNSInfo.js => DNSInfo.tsx} (79%) rename src/components/settings/{DnsList.js => DnsList.tsx} (76%) rename src/components/settings/{DnsListItem.js => DnsListItem.tsx} (76%) rename src/components/settings/{DnsListNewItem.js => DnsListNewItem.tsx} (76%) rename src/components/settings/{DnsOptionSettings.js => DnsOptionSettings.tsx} (83%) rename src/components/settings/{FTLInfo.js => FTLInfo.tsx} (74%) rename src/components/settings/{NetworkInfo.js => NetworkInfo.tsx} (84%) rename src/components/settings/{PreferenceSettings.js => PreferenceSettings.tsx} (79%) rename src/components/settings/{VersionCard.js => VersionCard.tsx} (84%) rename src/components/settings/{VersionInfo.js => VersionInfo.tsx} (79%) rename src/components/settings/__tests__/{DHCPInfo.test.js => DHCPInfo.test.tsx} (85%) rename src/components/settings/{preconfiguredUpstreams.js => preconfiguredUpstreams.tsx} (87%) diff --git a/package-lock.json b/package-lock.json index da88342..e13e0a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1505,6 +1505,16 @@ "@types/react": "*" } }, + "@types/react-bootstrap-typeahead": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@types/react-bootstrap-typeahead/-/react-bootstrap-typeahead-3.4.0.tgz", + "integrity": "sha512-J2JFcXWoY4234vnBGGh41PdTLMLQT9tZzkn1iBzuf/lRJv+tnGX2BtmbFUmKhwFzGFbjHqKubUvtHnFsYNohRQ==", + "dev": true, + "requires": { + "@types/react": "*", + "csstype": "^2.2.0" + } + }, "@types/react-dom": { "version": "16.0.11", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.0.11.tgz", diff --git a/package.json b/package.json index af45a0b..e8e5d45 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@types/node": "^10.12.18", "@types/react": "^16.7.20", "@types/react-bootstrap-daterangepicker": "0.0.26", + "@types/react-bootstrap-typeahead": "^3.4.0", "@types/react-dom": "^16.0.11", "@types/react-router-dom": "^4.3.1", "@types/react-table": "^6.7.21", diff --git a/src/components/settings/ConditionalForwardingSettings.js b/src/components/settings/ConditionalForwardingSettings.tsx similarity index 79% rename from src/components/settings/ConditionalForwardingSettings.js rename to src/components/settings/ConditionalForwardingSettings.tsx index 326cbaf..0361e06 100644 --- a/src/components/settings/ConditionalForwardingSettings.js +++ b/src/components/settings/ConditionalForwardingSettings.tsx @@ -9,8 +9,22 @@ * Please see LICENSE file for your rights under this license. */ import React, { Fragment } from "react"; -import PropTypes from "prop-types"; import { Col, FormGroup, Input, Label } from "reactstrap"; +import i18next from "i18next"; + +export interface ConditionalForwardingObject { + enabled: boolean, + routerIp: string, + domain: string +} + +export interface ConditionalForwardingSettingsProps { + settings: ConditionalForwardingObject, + onUpdate: (settings: ConditionalForwardingObject) => void, + isRouterIpValid: boolean; + isDomainValid: boolean; + t: i18next.TranslationFunction +} const ConditionalForwardingSettings = ({ settings, @@ -18,7 +32,7 @@ const ConditionalForwardingSettings = ({ isRouterIpValid, isDomainValid, t -}) => ( +}: ConditionalForwardingSettingsProps) => ( ); -ConditionalForwardingSettings.propTypes = { - settings: PropTypes.object.isRequired, - onUpdate: PropTypes.func.isRequired, - isRouterIpValid: PropTypes.bool.isRequired, - isDomainValid: PropTypes.bool.isRequired, - t: PropTypes.func.isRequired -}; - export default ConditionalForwardingSettings; diff --git a/src/components/settings/DHCPInfo.js b/src/components/settings/DHCPInfo.tsx similarity index 80% rename from src/components/settings/DHCPInfo.js rename to src/components/settings/DHCPInfo.tsx index 4e15ae7..922b120 100644 --- a/src/components/settings/DHCPInfo.js +++ b/src/components/settings/DHCPInfo.tsx @@ -8,31 +8,26 @@ * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ -import React, { Component } from "react"; -import { withNamespaces } from "react-i18next"; -import { ignoreCancel, makeCancelable } from "../../util"; -import api from "../../util/api"; -import { - Button, - Col, - Form, - FormGroup, - Input, - InputGroup, - InputGroupAddon, - Label -} from "reactstrap"; -import { - isPositiveNumber, - isValidHostname, - isValidIpv4 -} from "../../util/validate"; -import Alert from "../common/Alert"; +import React, { ChangeEvent, Component, FormEvent } from "react"; +import { WithNamespaces, withNamespaces } from "react-i18next"; +import { CancelablePromise, ignoreCancel, makeCancelable } from "../../util"; +import api, { ApiDhcpSettings, ApiResultResponse } from "../../util/api"; +import { Button, Col, Form, FormGroup, Input, InputGroup, InputGroupAddon, Label } from "reactstrap"; +import { isValidHostname, isValidIpv4 } from "../../util/validate"; +import Alert, { AlertType } from "../common/Alert"; -class DHCPInfo extends Component { - state = { +export interface DHCPInfoState { + alertMessage: string; + alertType: AlertType; + showAlert: boolean; + processing: boolean; + settings: ApiDhcpSettings; +} + +class DHCPInfo extends Component { + state: DHCPInfoState = { alertMessage: "", - alertType: "", + alertType: "info", showAlert: false, processing: false, settings: { @@ -40,27 +35,20 @@ class DHCPInfo extends Component { ip_start: "", ip_end: "", router_ip: "", - lease_time: "", + lease_time: 0, domain: "", ipv6_support: false } }; + private loadHandler: undefined | CancelablePromise; + private updateHandler: undefined | CancelablePromise; + loadDHCPInfo = () => { this.loadHandler = makeCancelable(api.getDHCPInfo()); this.loadHandler.promise .then(res => { - this.setState({ - 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 - } - }); + this.setState({ settings: res }); }) .catch(ignoreCancel); }; @@ -70,7 +58,9 @@ class DHCPInfo extends Component { } componentWillUnmount() { - this.loadHandler.cancel(); + if (this.loadHandler) { + this.loadHandler.cancel(); + } if (this.updateHandler) { this.updateHandler.cancel(); @@ -85,9 +75,10 @@ class DHCPInfo extends Component { * @param attr {string} the event target attribute to use * @returns {function(Event)} */ - onChange = (key, attr) => { - return e => { - const value = e.target[attr]; + onChange = (key: string, attr: string) => { + return (e: ChangeEvent) => { + // @ts-ignore + const value: string = e.target[attr]; this.setState(oldState => ({ settings: { @@ -103,7 +94,7 @@ class DHCPInfo extends Component { * * @param e the submit event */ - saveSettings = e => { + saveSettings = (e: FormEvent) => { e.preventDefault(); const { t } = this.props; @@ -155,7 +146,7 @@ class DHCPInfo extends Component { * @param value the value to check * @param validator the validation function */ - isSettingValid = (value, validator) => { + isSettingValid = (value: string, validator: (value: string) => boolean) => { return ( (!this.state.settings.active && value.length === 0) || validator(value) ); @@ -180,10 +171,7 @@ class DHCPInfo extends Component { this.state.settings.router_ip, isValidIpv4 ); - const isLeaseTimeValid = this.isSettingValid( - this.state.settings.lease_time, - isPositiveNumber - ); + const isLeaseTimeValid = this.state.settings.lease_time >= 0; const isDomainValid = this.isSettingValid( this.state.settings.domain, isValidHostname @@ -262,7 +250,14 @@ class DHCPInfo extends Component { id="leaseTime" disabled={!this.state.settings.active} value={this.state.settings.lease_time} - onChange={this.onChange("lease_time", "value")} + onChange={(e: ChangeEvent) => + this.setState(oldState => ({ + settings: { + ...oldState.settings, + lease_time: parseInt(e.target.value) + } + })) + } invalid={!isLeaseTimeValid} /> Hours diff --git a/src/components/settings/DNSInfo.js b/src/components/settings/DNSInfo.tsx similarity index 79% rename from src/components/settings/DNSInfo.js rename to src/components/settings/DNSInfo.tsx index 78a8fab..3a77b00 100644 --- a/src/components/settings/DNSInfo.js +++ b/src/components/settings/DNSInfo.tsx @@ -8,21 +8,31 @@ * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ -import React, { Component } from "react"; -import { withNamespaces } from "react-i18next"; -import { ignoreCancel, makeCancelable } from "../../util"; -import api from "../../util/api"; +import React, { Component, FormEvent } from "react"; +import { WithNamespaces, withNamespaces } from "react-i18next"; +import { CancelablePromise, ignoreCancel, makeCancelable } from "../../util"; +import api, { ApiDnsSettings, ApiResultResponse } from "../../util/api"; import DnsList from "./DnsList"; import { Button, Col, Form, FormGroup } from "reactstrap"; -import ConditionalForwardingSettings from "./ConditionalForwardingSettings"; -import DnsOptionSettings from "./DnsOptionSettings"; -import Alert from "../common/Alert"; +import ConditionalForwardingSettings, { ConditionalForwardingObject } from "./ConditionalForwardingSettings"; +import DnsOptionSettings, { DnsOptionsObject } from "./DnsOptionSettings"; +import Alert, { AlertType } from "../common/Alert"; import { isValidHostname, isValidIpv4 } from "../../util/validate"; -class DNSInfo extends Component { - state = { +export interface DNSInfoState { + alertMessage: string; + alertType: AlertType; + showAlert: boolean; + processing: boolean; + upstreamDns: Array; + conditionalForwarding: ConditionalForwardingObject; + options: DnsOptionsObject; +} + +class DNSInfo extends Component { + state: DNSInfoState = { alertMessage: "", - alertType: "", + alertType: "info", showAlert: false, processing: false, upstreamDns: [], @@ -39,6 +49,9 @@ class DNSInfo extends Component { } }; + private loadHandler: undefined | CancelablePromise; + private updateHandler: undefined | CancelablePromise; + loadDNSInfo = () => { this.loadHandler = makeCancelable(api.getDNSInfo()); this.loadHandler.promise @@ -70,26 +83,30 @@ class DNSInfo extends Component { } componentWillUnmount() { - this.loadHandler.cancel(); + if (this.loadHandler) { + this.loadHandler.cancel(); + } } - handleUpstreamAdd = upstream => { + handleUpstreamAdd = (upstream: string) => { this.setState({ upstreamDns: this.state.upstreamDns.concat(upstream) }); }; - handleUpstreamRemove = upstream => { + handleUpstreamRemove = (upstream: string) => { this.setState({ upstreamDns: this.state.upstreamDns.filter(item => item !== upstream) }); }; - handleConditionalForwardingUpdate = conditionalForwarding => { + handleConditionalForwardingUpdate = ( + conditionalForwarding: ConditionalForwardingObject + ) => { this.setState({ conditionalForwarding }); }; - handleDnsOptionsUpdate = options => { + handleDnsOptionsUpdate = (options: DnsOptionsObject) => { this.setState({ options }); }; @@ -98,7 +115,7 @@ class DNSInfo extends Component { * * @param e the submit event */ - saveSettings = e => { + saveSettings = (e: FormEvent) => { e.preventDefault(); const { t } = this.props; @@ -157,7 +174,7 @@ class DNSInfo extends Component { }); }; - isCFSettingValid = (value, validator) => { + isCFSettingValid = (value: string, validator: (value: string) => boolean) => { return ( (!this.state.conditionalForwarding.enabled && value.length === 0) || validator(value) diff --git a/src/components/settings/DnsList.js b/src/components/settings/DnsList.tsx similarity index 76% rename from src/components/settings/DnsList.js rename to src/components/settings/DnsList.tsx index dd3b8d3..5668536 100644 --- a/src/components/settings/DnsList.js +++ b/src/components/settings/DnsList.tsx @@ -9,12 +9,17 @@ * Please see LICENSE file for your rights under this license. */ import React from "react"; -import PropTypes from "prop-types"; import { ListGroup } from "reactstrap"; import DnsListItem from "./DnsListItem"; import DnsListNewItem from "./DnsListNewItem"; import { isValidIpv4OptionalPort } from "../../util/validate"; +export interface DnsListProps { + upstreams: Array; + onAdd: (upstream: string) => void; + onRemove: (upstream: string) => void; +} + /** * Check if an upstream address is unique and valid * @@ -22,10 +27,10 @@ import { isValidIpv4OptionalPort } from "../../util/validate"; * @param upstreams the list of current upstreams * @returns {boolean} if the upstream address is unique and valid */ -export const isAddressValid = (address, upstreams) => +export const isAddressValid = (address: string, upstreams: Array) => !upstreams.includes(address) && isValidIpv4OptionalPort(address); -const DnsList = ({ upstreams, onAdd, onRemove }) => ( +const DnsList = ({ upstreams, onAdd, onRemove }: DnsListProps) => ( {upstreams.map(upstream => ( ( ))} isAddressValid(address, upstreams)} + isValid={(address: string) => isAddressValid(address, upstreams)} upstreams={upstreams} /> ); -DnsList.propTypes = { - upstreams: PropTypes.arrayOf(PropTypes.string).isRequired, - onAdd: PropTypes.func.isRequired, - onRemove: PropTypes.func.isRequired -}; - export default DnsList; diff --git a/src/components/settings/DnsListItem.js b/src/components/settings/DnsListItem.tsx similarity index 76% rename from src/components/settings/DnsListItem.js rename to src/components/settings/DnsListItem.tsx index fecf7b2..d99ae9d 100644 --- a/src/components/settings/DnsListItem.js +++ b/src/components/settings/DnsListItem.tsx @@ -9,10 +9,14 @@ * Please see LICENSE file for your rights under this license. */ import React from "react"; -import PropTypes from "prop-types"; import { Button, ListGroupItem } from "reactstrap"; -const DnsListItem = ({ address, onRemove }) => ( +export interface DnsListItemProps { + address: string, + onRemove: () => void; +} + +const DnsListItem = ({ address, onRemove }: DnsListItemProps) => ( {address}