install forms
This commit is contained in:
@@ -1,30 +1,65 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { Field, reduxForm, formValueSelector } from 'redux-form';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import flow from 'lodash/flow';
|
||||
import i18n, { TFunction } from 'i18next';
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import i18n from 'i18next';
|
||||
|
||||
import i18next from 'i18next';
|
||||
import Controls from './Controls';
|
||||
|
||||
import AddressList from './AddressList';
|
||||
|
||||
import { getInterfaceIp } from '../../helpers/helpers';
|
||||
import {
|
||||
ALL_INTERFACES_IP,
|
||||
FORM_NAME,
|
||||
ADDRESS_IN_USE_TEXT,
|
||||
PORT_53_FAQ_LINK,
|
||||
STATUS_RESPONSE,
|
||||
STANDARD_DNS_PORT,
|
||||
STANDARD_WEB_PORT,
|
||||
MAX_PORT,
|
||||
} from '../../helpers/constants';
|
||||
|
||||
import { renderInputField, toNumber } from '../../helpers/form';
|
||||
import { validateRequiredValue, validateInstallPort } from '../../helpers/validators';
|
||||
import { toNumber } from '../../helpers/form';
|
||||
import { validateRequiredValue } from '../../helpers/validators';
|
||||
import { DhcpInterface } from '../../initialState';
|
||||
|
||||
const validateInstallPort = (value: any) => {
|
||||
if (value < 1 || value > MAX_PORT) {
|
||||
return i18next.t('form_error_port');
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
type StaticIpType = {
|
||||
ip: string;
|
||||
static: string;
|
||||
};
|
||||
|
||||
type ConfigType = {
|
||||
web: {
|
||||
ip: string;
|
||||
port?: number;
|
||||
status: string;
|
||||
can_autofix: boolean;
|
||||
};
|
||||
dns: {
|
||||
ip: string;
|
||||
port?: number;
|
||||
status: string;
|
||||
can_autofix: boolean;
|
||||
};
|
||||
staticIp: StaticIpType;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
handleSubmit: (data: any) => void;
|
||||
handleChange?: (...args: unknown[]) => unknown;
|
||||
handleFix: (web: any, dns: any, set_static_ip: boolean) => void;
|
||||
validateForm: (data: any) => void;
|
||||
config: ConfigType;
|
||||
interfaces: DhcpInterface[];
|
||||
initialValues?: object;
|
||||
};
|
||||
|
||||
const renderInterfaces = (interfaces: DhcpInterface[]) =>
|
||||
Object.values(interfaces).map((option: DhcpInterface) => {
|
||||
const { name, ip_addresses, flags } = option;
|
||||
@@ -43,113 +78,69 @@ const renderInterfaces = (interfaces: DhcpInterface[]) =>
|
||||
return null;
|
||||
});
|
||||
|
||||
type Props = {
|
||||
handleSubmit: (...args: unknown[]) => string;
|
||||
handleChange?: (...args: unknown[]) => unknown;
|
||||
handleFix: (...args: unknown[]) => unknown;
|
||||
validateForm?: (...args: unknown[]) => unknown;
|
||||
webIp: string;
|
||||
dnsIp: string;
|
||||
config: {
|
||||
const Settings: React.FC<Props> = ({
|
||||
handleSubmit,
|
||||
handleFix,
|
||||
validateForm,
|
||||
config,
|
||||
interfaces,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaultValues = {
|
||||
web: {
|
||||
status: string;
|
||||
can_autofix: boolean;
|
||||
};
|
||||
ip: config.web.ip || ALL_INTERFACES_IP,
|
||||
port: config.web.port || STANDARD_WEB_PORT,
|
||||
},
|
||||
dns: {
|
||||
status: string;
|
||||
can_autofix: boolean;
|
||||
};
|
||||
staticIp: {
|
||||
ip: string;
|
||||
static: string;
|
||||
};
|
||||
ip: config.dns.ip || ALL_INTERFACES_IP,
|
||||
port: config.dns.port || STANDARD_DNS_PORT,
|
||||
},
|
||||
};
|
||||
webPort?: number;
|
||||
dnsPort?: number;
|
||||
interfaces: DhcpInterface[];
|
||||
invalid: boolean;
|
||||
initialValues?: object;
|
||||
t: TFunction;
|
||||
};
|
||||
|
||||
class Settings extends Component<Props> {
|
||||
componentDidMount() {
|
||||
const { webIp, webPort, dnsIp, dnsPort } = this.props;
|
||||
const {
|
||||
control,
|
||||
watch,
|
||||
handleSubmit: reactHookFormSubmit,
|
||||
formState: { isValid, errors },
|
||||
} = useForm({
|
||||
defaultValues,
|
||||
mode: 'onChange',
|
||||
});
|
||||
|
||||
this.props.validateForm({
|
||||
const watchFields = watch();
|
||||
|
||||
const { status: webStatus, can_autofix: isWebFixAvailable } = config.web;
|
||||
const { status: dnsStatus, can_autofix: isDnsFixAvailable } = config.dns;
|
||||
const { staticIp } = config;
|
||||
|
||||
const webIpVal = watch("web.ip");
|
||||
const webPortVal = watch("web.port");
|
||||
const dnsIpVal = watch("dns.ip");
|
||||
const dnsPortVal = watch("dns.port");
|
||||
|
||||
useEffect(() => {
|
||||
validateForm({
|
||||
web: {
|
||||
ip: webIp,
|
||||
port: webPort,
|
||||
ip: webIpVal,
|
||||
port: webPortVal,
|
||||
},
|
||||
dns: {
|
||||
ip: dnsIp,
|
||||
port: dnsPort,
|
||||
ip: dnsIpVal,
|
||||
port: dnsPortVal,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getStaticIpMessage = (staticIp: { ip: string; static: string }) => {
|
||||
const { static: status, ip } = staticIp;
|
||||
|
||||
switch (status) {
|
||||
case STATUS_RESPONSE.NO: {
|
||||
return (
|
||||
<>
|
||||
<div className="mb-2">
|
||||
<Trans values={{ ip }} components={[<strong key="0">text</strong>]}>
|
||||
install_static_configure
|
||||
</Trans>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-primary btn-sm"
|
||||
onClick={() => this.handleStaticIp(ip)}>
|
||||
<Trans>set_static_ip</Trans>
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
case STATUS_RESPONSE.ERROR: {
|
||||
return (
|
||||
<div className="text-danger">
|
||||
<Trans>install_static_error</Trans>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
case STATUS_RESPONSE.YES: {
|
||||
return (
|
||||
<div className="text-success">
|
||||
<Trans>install_static_ok</Trans>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
handleAutofix = (type: any) => {
|
||||
const {
|
||||
webIp,
|
||||
|
||||
webPort,
|
||||
|
||||
dnsIp,
|
||||
|
||||
dnsPort,
|
||||
|
||||
handleFix,
|
||||
} = this.props;
|
||||
}, [webIpVal, webPortVal, dnsIpVal, dnsPortVal]);
|
||||
|
||||
const handleAutofix = (type: string) => {
|
||||
const web = {
|
||||
ip: webIp,
|
||||
port: webPort,
|
||||
ip: watchFields.web?.ip,
|
||||
port: watchFields.web?.port,
|
||||
autofix: false,
|
||||
};
|
||||
const dns = {
|
||||
ip: dnsIp,
|
||||
port: dnsPort,
|
||||
ip: watchFields.dns?.ip,
|
||||
port: watchFields.dns?.port,
|
||||
autofix: false,
|
||||
};
|
||||
const set_static_ip = false;
|
||||
@@ -163,276 +154,315 @@ class Settings extends Component<Props> {
|
||||
handleFix(web, dns, set_static_ip);
|
||||
};
|
||||
|
||||
handleStaticIp = (ip: any) => {
|
||||
const {
|
||||
webIp,
|
||||
|
||||
webPort,
|
||||
|
||||
dnsIp,
|
||||
|
||||
dnsPort,
|
||||
|
||||
handleFix,
|
||||
} = this.props;
|
||||
|
||||
const handleStaticIp = (ip: string) => {
|
||||
const web = {
|
||||
ip: webIp,
|
||||
port: webPort,
|
||||
ip: watchFields.web?.ip,
|
||||
port: watchFields.web?.port,
|
||||
autofix: false,
|
||||
};
|
||||
const dns = {
|
||||
ip: dnsIp,
|
||||
port: dnsPort,
|
||||
ip: watchFields.dns?.ip,
|
||||
port: watchFields.dns?.port,
|
||||
autofix: false,
|
||||
};
|
||||
const set_static_ip = true;
|
||||
|
||||
if (window.confirm(this.props.t('confirm_static_ip', { ip }))) {
|
||||
if (window.confirm(t('confirm_static_ip', { ip }))) {
|
||||
handleFix(web, dns, set_static_ip);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
handleSubmit,
|
||||
const getStaticIpMessage = useCallback((staticIp: StaticIpType) => {
|
||||
const { static: status, ip } = staticIp;
|
||||
|
||||
handleChange,
|
||||
switch (status) {
|
||||
case STATUS_RESPONSE.NO:
|
||||
return (
|
||||
<>
|
||||
<div className="mb-2">
|
||||
<Trans values={{ ip }} components={[<strong key="0">text</strong>]}>
|
||||
install_static_configure
|
||||
</Trans>
|
||||
</div>
|
||||
|
||||
webIp,
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-primary btn-sm"
|
||||
onClick={() => handleStaticIp(ip)}
|
||||
>
|
||||
<Trans>set_static_ip</Trans>
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
case STATUS_RESPONSE.ERROR:
|
||||
return (
|
||||
<div className="text-danger">
|
||||
<Trans>install_static_error</Trans>
|
||||
</div>
|
||||
);
|
||||
case STATUS_RESPONSE.YES:
|
||||
return (
|
||||
<div className="text-success">
|
||||
<Trans>install_static_ok</Trans>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}, [handleStaticIp]);
|
||||
|
||||
webPort,
|
||||
const onSubmit = (data: any) => {
|
||||
validateForm(data);
|
||||
handleSubmit(data);
|
||||
};
|
||||
|
||||
dnsIp,
|
||||
return (
|
||||
<form className="setup__step" onSubmit={reactHookFormSubmit(onSubmit)}>
|
||||
<div className="setup__group">
|
||||
<div className="setup__subtitle">
|
||||
<Trans>install_settings_title</Trans>
|
||||
</div>
|
||||
|
||||
dnsPort,
|
||||
|
||||
interfaces,
|
||||
|
||||
invalid,
|
||||
|
||||
config,
|
||||
|
||||
t,
|
||||
} = this.props;
|
||||
const { status: webStatus, can_autofix: isWebFixAvailable } = config.web;
|
||||
const { status: dnsStatus, can_autofix: isDnsFixAvailable } = config.dns;
|
||||
const { staticIp } = config;
|
||||
|
||||
return (
|
||||
<form className="setup__step" onSubmit={handleSubmit}>
|
||||
<div className="setup__group">
|
||||
<div className="setup__subtitle">
|
||||
<Trans>install_settings_title</Trans>
|
||||
<div className="row">
|
||||
<div className="col-8">
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<Trans>install_settings_listen</Trans>
|
||||
</label>
|
||||
<Controller
|
||||
name="web.ip"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<select
|
||||
{...field}
|
||||
className="form-control custom-select"
|
||||
onChange={(e) => {
|
||||
field.onChange(e);
|
||||
}}>
|
||||
<option value={ALL_INTERFACES_IP}>
|
||||
{t('install_settings_all_interfaces')}
|
||||
</option>
|
||||
{renderInterfaces(interfaces)}
|
||||
</select>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-8">
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<Trans>install_settings_listen</Trans>
|
||||
</label>
|
||||
|
||||
<Field
|
||||
name="web.ip"
|
||||
component="select"
|
||||
className="form-control custom-select"
|
||||
onChange={handleChange}>
|
||||
<option value={ALL_INTERFACES_IP}>
|
||||
{this.props.t('install_settings_all_interfaces')}
|
||||
</option>
|
||||
{renderInterfaces(interfaces)}
|
||||
</Field>
|
||||
</div>
|
||||
<div className="col-4">
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<Trans>install_settings_port</Trans>
|
||||
</label>
|
||||
<Controller
|
||||
name="web.port"
|
||||
control={control}
|
||||
rules={{
|
||||
required: t('form_error_required'),
|
||||
validate: {
|
||||
installPort: validateInstallPort,
|
||||
},
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<input
|
||||
{...field}
|
||||
type="number"
|
||||
className="form-control"
|
||||
placeholder={STANDARD_WEB_PORT.toString()}
|
||||
onChange={(e) => {
|
||||
const val = toNumber(e.target.value);
|
||||
field.onChange(val);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.web?.port && (
|
||||
<div className="text-danger">
|
||||
{errors.web.port.message}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-4">
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<Trans>install_settings_port</Trans>
|
||||
</label>
|
||||
|
||||
<Field
|
||||
name="web.port"
|
||||
component={renderInputField}
|
||||
type="number"
|
||||
className="form-control"
|
||||
placeholder={STANDARD_WEB_PORT.toString()}
|
||||
validate={[validateInstallPort, validateRequiredValue]}
|
||||
normalize={toNumber}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<div className="col-12">
|
||||
{webStatus && (
|
||||
<div className="setup__error text-danger">
|
||||
{webStatus}
|
||||
{isWebFixAvailable && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary btn-sm ml-2"
|
||||
onClick={() => handleAutofix('web')}
|
||||
>
|
||||
<Trans>fix</Trans>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="col-12">
|
||||
{webStatus && (
|
||||
<hr className="divider--small" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="setup__desc">
|
||||
<Trans>install_settings_interface_link</Trans>
|
||||
|
||||
<div className="mt-1">
|
||||
<AddressList
|
||||
interfaces={interfaces}
|
||||
address={watchFields.web?.ip}
|
||||
port={watchFields.web?.port}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="setup__group">
|
||||
<div className="setup__subtitle">
|
||||
<Trans>install_settings_dns</Trans>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-8">
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<Trans>install_settings_listen</Trans>
|
||||
</label>
|
||||
<Controller
|
||||
name="dns.ip"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<select
|
||||
{...field}
|
||||
className="form-control custom-select"
|
||||
onChange={(e) => {
|
||||
field.onChange(e);
|
||||
}}>
|
||||
<option value={ALL_INTERFACES_IP}>
|
||||
{t('install_settings_all_interfaces')}
|
||||
</option>
|
||||
{renderInterfaces(interfaces)}
|
||||
</select>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-4">
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<Trans>install_settings_port</Trans>
|
||||
</label>
|
||||
<Controller
|
||||
name="dns.port"
|
||||
control={control}
|
||||
rules={{
|
||||
required: t('form_error_required'),
|
||||
validate: {
|
||||
required: validateRequiredValue,
|
||||
installPort: validateInstallPort,
|
||||
},
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<input
|
||||
{...field}
|
||||
type="number"
|
||||
className="form-control"
|
||||
placeholder={STANDARD_WEB_PORT.toString()}
|
||||
onChange={(e) => {
|
||||
const val = toNumber(e.target.value);
|
||||
field.onChange(val);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.dns?.port.message && (
|
||||
<div className="text-danger">
|
||||
{t(errors.dns.port.message)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-12">
|
||||
{dnsStatus && (
|
||||
<>
|
||||
<div className="setup__error text-danger">
|
||||
{webStatus}
|
||||
{isWebFixAvailable && (
|
||||
{dnsStatus}
|
||||
{isDnsFixAvailable && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary btn-sm ml-2"
|
||||
onClick={() => this.handleAutofix('web')}>
|
||||
onClick={() => handleAutofix('dns')}>
|
||||
<Trans>fix</Trans>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<hr className="divider--small" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="setup__desc">
|
||||
<Trans>install_settings_interface_link</Trans>
|
||||
|
||||
<div className="mt-1">
|
||||
<AddressList interfaces={interfaces} address={webIp} port={webPort} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="setup__group">
|
||||
<div className="setup__subtitle">
|
||||
<Trans>install_settings_dns</Trans>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-8">
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<Trans>install_settings_listen</Trans>
|
||||
</label>
|
||||
|
||||
<Field
|
||||
name="dns.ip"
|
||||
component="select"
|
||||
className="form-control custom-select"
|
||||
onChange={handleChange}>
|
||||
<option value={ALL_INTERFACES_IP}>{t('install_settings_all_interfaces')}</option>
|
||||
{renderInterfaces(interfaces)}
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-4">
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<Trans>install_settings_port</Trans>
|
||||
</label>
|
||||
|
||||
<Field
|
||||
name="dns.port"
|
||||
component={renderInputField}
|
||||
type="number"
|
||||
className="form-control"
|
||||
placeholder={STANDARD_WEB_PORT.toString()}
|
||||
validate={[validateInstallPort, validateRequiredValue]}
|
||||
normalize={toNumber}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-12">
|
||||
{dnsStatus && (
|
||||
<>
|
||||
<div className="setup__error text-danger">
|
||||
{dnsStatus}
|
||||
{isDnsFixAvailable && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary btn-sm ml-2"
|
||||
onClick={() => this.handleAutofix('dns')}>
|
||||
<Trans>fix</Trans>
|
||||
</button>
|
||||
)}
|
||||
{isDnsFixAvailable && (
|
||||
<div className="text-muted mb-2">
|
||||
<p className="mb-1">
|
||||
<Trans>autofix_warning_text</Trans>
|
||||
</p>
|
||||
<Trans components={[<li key="0">text</li>]}>autofix_warning_list</Trans>
|
||||
<p className="mb-1">
|
||||
<Trans>autofix_warning_result</Trans>
|
||||
</p>
|
||||
</div>
|
||||
{isDnsFixAvailable && (
|
||||
<div className="text-muted mb-2">
|
||||
<p className="mb-1">
|
||||
<Trans>autofix_warning_text</Trans>
|
||||
</p>
|
||||
|
||||
<Trans components={[<li key="0">text</li>]}>autofix_warning_list</Trans>
|
||||
|
||||
<p className="mb-1">
|
||||
<Trans>autofix_warning_result</Trans>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{dnsPort === STANDARD_DNS_PORT &&
|
||||
!isDnsFixAvailable &&
|
||||
dnsStatus.includes(ADDRESS_IN_USE_TEXT) && (
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href={PORT_53_FAQ_LINK}
|
||||
key="0"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
link
|
||||
</a>,
|
||||
]}>
|
||||
port_53_faq_link
|
||||
</Trans>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{watchFields.dns?.port === STANDARD_DNS_PORT &&
|
||||
!isDnsFixAvailable &&
|
||||
dnsStatus?.includes(ADDRESS_IN_USE_TEXT) && (
|
||||
<Trans
|
||||
components={[
|
||||
<a
|
||||
href={PORT_53_FAQ_LINK}
|
||||
key="0"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
]}
|
||||
>
|
||||
port_53_faq_link
|
||||
</Trans>
|
||||
)}
|
||||
|
||||
<hr className="divider--small" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="setup__desc">
|
||||
<Trans>install_settings_dns_desc</Trans>
|
||||
|
||||
<div className="mt-1">
|
||||
<AddressList interfaces={interfaces} address={dnsIp} port={dnsPort} isDns={true} />
|
||||
</div>
|
||||
<hr className="divider--small" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="setup__group">
|
||||
<div className="setup__subtitle">
|
||||
<Trans>static_ip</Trans>
|
||||
</div>
|
||||
<div className="setup__desc">
|
||||
<Trans>install_settings_dns_desc</Trans>
|
||||
|
||||
<div className="mb-2">
|
||||
<Trans>static_ip_desc</Trans>
|
||||
<div className="mt-1">
|
||||
<AddressList
|
||||
interfaces={interfaces}
|
||||
address={watchFields.dns?.ip}
|
||||
port={watchFields.dns?.port}
|
||||
isDns={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.getStaticIpMessage(staticIp)}
|
||||
<div className="setup__group">
|
||||
<div className="setup__subtitle">
|
||||
<Trans>static_ip</Trans>
|
||||
</div>
|
||||
|
||||
<Controls invalid={invalid} />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
<div className="mb-2">
|
||||
<Trans>static_ip_desc</Trans>
|
||||
</div>
|
||||
|
||||
const selector = formValueSelector(FORM_NAME.INSTALL);
|
||||
{getStaticIpMessage(staticIp)}
|
||||
</div>
|
||||
|
||||
const SettingsForm = connect((state) => {
|
||||
const webIp = selector(state, 'web.ip');
|
||||
const webPort = selector(state, 'web.port');
|
||||
const dnsIp = selector(state, 'dns.ip');
|
||||
const dnsPort = selector(state, 'dns.port');
|
||||
<Controls invalid={!isValid} />
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
webIp,
|
||||
webPort,
|
||||
dnsIp,
|
||||
dnsPort,
|
||||
};
|
||||
})(Settings);
|
||||
|
||||
export default flow([
|
||||
withTranslation(),
|
||||
reduxForm({
|
||||
form: FORM_NAME.INSTALL,
|
||||
destroyOnUnmount: false,
|
||||
forceUnregisterOnUnmount: true,
|
||||
}),
|
||||
])(SettingsForm);
|
||||
export default Settings;
|
||||
|
||||
Reference in New Issue
Block a user