Pull request: beta client squashed
Merge in DNS/adguard-home from beta-client-2 to master
Squashed commit of the following:
commit b2640cc49a6c5484d730b534dcf5a8013d7fa478
Merge: 659def862 aef4659e9
Author: Eugene Burkov <e.burkov@adguard.com>
Date: Tue Dec 29 19:23:09 2020 +0300
Merge branch 'master' into beta-client-2
commit 659def8626467949c35b7a6a0c99ffafb07b4385
Author: Eugene Burkov <e.burkov@adguard.com>
Date: Tue Dec 29 17:25:14 2020 +0300
all: upgrade github actions node version
commit b4b8cf8dd75672e9155da5d111ac66e8f5ba1535
Author: Vladislav Abdulmyanov <v.abdulmyanov@adguard.com>
Date: Tue Dec 29 16:57:14 2020 +0300
all: beta client squashed
This commit is contained in:
14
client2/src/components/Install/Install.module.pcss
Normal file
14
client2/src/components/Install/Install.module.pcss
Normal file
@@ -0,0 +1,14 @@
|
||||
.layout {
|
||||
background-image: url('../../assets/img/background_min.png');
|
||||
background-repeat: no-repeat;
|
||||
min-height: 100vh;
|
||||
background-color: #f1f3f7;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 40px;
|
||||
}
|
||||
.content {
|
||||
max-width: 404px;
|
||||
}
|
||||
122
client2/src/components/Install/Install.tsx
Normal file
122
client2/src/components/Install/Install.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
import React, { FC } from 'react';
|
||||
import { Layout } from 'antd';
|
||||
import { Formik, FormikHelpers } from 'formik';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import { IInitialConfigurationBeta } from 'Entities/InitialConfigurationBeta';
|
||||
import Icons from 'Lib/theme/Icons';
|
||||
import {
|
||||
DEFAULT_DNS_ADDRESS,
|
||||
DEFAULT_DNS_PORT,
|
||||
DEFAULT_IP_ADDRESS,
|
||||
DEFAULT_IP_PORT,
|
||||
} from 'Consts/install';
|
||||
import { notifyError } from 'Common/ui';
|
||||
import InstallStore from 'Store/stores/Install';
|
||||
|
||||
import AdminInterface from './components/AdminInterface';
|
||||
import Auth from './components/Auth';
|
||||
import DnsServer from './components/DnsServer';
|
||||
import Stepper from './components/Stepper';
|
||||
import Welcome from './components/Welcome';
|
||||
import ConfigureDevices from './components/ConfigureDevices';
|
||||
|
||||
import s from './Install.module.pcss';
|
||||
|
||||
const { Content } = Layout;
|
||||
|
||||
export type FormValues = IInitialConfigurationBeta & { step: number };
|
||||
|
||||
const InstallForm: FC = observer(() => {
|
||||
const initialValues: FormValues = {
|
||||
step: 0,
|
||||
web: {
|
||||
ip: [DEFAULT_IP_ADDRESS],
|
||||
port: DEFAULT_IP_PORT,
|
||||
},
|
||||
dns: {
|
||||
ip: [DEFAULT_DNS_ADDRESS],
|
||||
port: DEFAULT_DNS_PORT,
|
||||
},
|
||||
password: '',
|
||||
username: '',
|
||||
};
|
||||
|
||||
const onNext = async (values: FormValues, { setFieldValue }: FormikHelpers<FormValues>) => {
|
||||
const currentStep = values.step;
|
||||
const checker = (condition: boolean, message: string) => {
|
||||
if (condition) {
|
||||
setFieldValue('step', currentStep + 1);
|
||||
} else {
|
||||
notifyError(message);
|
||||
}
|
||||
};
|
||||
switch (currentStep) {
|
||||
case 1: {
|
||||
// web
|
||||
const check = await InstallStore.checkConfig(values);
|
||||
checker(check?.web?.status === '', check?.web?.status || '');
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
// dns
|
||||
const check = await InstallStore.checkConfig(values);
|
||||
checker(check?.dns?.status === '', check?.dns?.status || '');
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
// configure
|
||||
const config = await InstallStore.configure(values);
|
||||
if (config) {
|
||||
const { web } = values;
|
||||
window.location.href = `http://${web.ip[0]}:${web.port}`;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
setFieldValue('step', currentStep + 1);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
onSubmit={onNext}
|
||||
>
|
||||
{({ values, handleSubmit, setFieldValue }) => (
|
||||
<form noValidate className={s.content} onSubmit={handleSubmit}>
|
||||
<Stepper currentStep={values.step} />
|
||||
{values.step === 0 && (
|
||||
<Welcome onNext={() => setFieldValue('step', 1)}/>
|
||||
)}
|
||||
{values.step === 1 && (
|
||||
<AdminInterface values={values} setFieldValue={setFieldValue} />
|
||||
)}
|
||||
{values.step === 2 && (
|
||||
<Auth values={values} setFieldValue={setFieldValue} />
|
||||
)}
|
||||
{values.step === 3 && (
|
||||
<DnsServer values={values} setFieldValue={setFieldValue} />
|
||||
)}
|
||||
{values.step === 4 && (
|
||||
<ConfigureDevices values={values} setFieldValue={setFieldValue} />
|
||||
)}
|
||||
</form>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
});
|
||||
|
||||
const Install: FC = () => {
|
||||
return (
|
||||
<Layout className={s.layout}>
|
||||
<Content className={s.container}>
|
||||
<InstallForm />
|
||||
</Content>
|
||||
<Icons/>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Install;
|
||||
@@ -0,0 +1,17 @@
|
||||
.manualOptions {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.name {
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid var(--gray300);
|
||||
margin-bottom: 16px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.manualOption {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
import React, { FC, useContext } from 'react';
|
||||
import cn from 'classnames';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { FormikHelpers } from 'formik';
|
||||
|
||||
import { Input, Radio, Switch } from 'Common/controls';
|
||||
import { DEFAULT_IP_ADDRESS } from 'Consts/install';
|
||||
import { chechNetworkType, NETWORK_TYPE } from 'Helpers/installHelpers';
|
||||
import theme from 'Lib/theme';
|
||||
import Store from 'Store/installStore';
|
||||
|
||||
import s from './AdminInterface.module.pcss';
|
||||
import { FormValues } from '../../Install';
|
||||
import StepButtons from '../StepButtons';
|
||||
|
||||
enum NETWORK_OPTIONS {
|
||||
ALL = 'all',
|
||||
CUSTOM = 'custom',
|
||||
}
|
||||
|
||||
interface AdminInterfaceProps {
|
||||
values: FormValues;
|
||||
setFieldValue: FormikHelpers<FormValues>['setFieldValue'];
|
||||
}
|
||||
|
||||
const AdminInterface: FC<AdminInterfaceProps> = observer(({
|
||||
values,
|
||||
setFieldValue,
|
||||
}) => {
|
||||
const { ui: { intl }, install: { addresses } } = useContext(Store);
|
||||
const { web: { ip } } = values;
|
||||
const radioValue = ip.length === 1 && ip[0] === DEFAULT_IP_ADDRESS
|
||||
? NETWORK_OPTIONS.ALL : NETWORK_OPTIONS.CUSTOM;
|
||||
|
||||
const onSelectRadio = (v: string | number) => {
|
||||
const value = v === NETWORK_OPTIONS.ALL
|
||||
? [DEFAULT_IP_ADDRESS] : [];
|
||||
setFieldValue('web.ip', value);
|
||||
};
|
||||
|
||||
const getManualBlock = () => (
|
||||
<div className={s.manualOptions}>
|
||||
{addresses?.interfaces.map((a) => {
|
||||
let name = '';
|
||||
const type = chechNetworkType(a.name);
|
||||
switch (type) {
|
||||
case NETWORK_TYPE.ETHERNET:
|
||||
name = `${intl.getMessage('ethernet')} (${a.name}) `;
|
||||
break;
|
||||
case NETWORK_TYPE.LOCAL:
|
||||
name = `${intl.getMessage('localhost')} (${a.name}) `;
|
||||
break;
|
||||
default:
|
||||
name = a.name || '';
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<div key={a.name}>
|
||||
<div>
|
||||
<div className={s.name}>
|
||||
{name}
|
||||
</div>
|
||||
{a.ipAddresses?.map((addrIp) => (
|
||||
<div key={addrIp} className={s.manualOption}>
|
||||
<div className={theme.typography.subtext}>
|
||||
http://{addrIp}
|
||||
</div>
|
||||
<Switch
|
||||
checked={values.web.ip.includes(addrIp)}
|
||||
onChange={() => {
|
||||
const temp = new Set(ip);
|
||||
if (temp.has(addrIp)) {
|
||||
temp.delete(addrIp);
|
||||
} else {
|
||||
temp.add(addrIp);
|
||||
}
|
||||
setFieldValue('web.ip', Array.from(temp.values()));
|
||||
}}/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={s.content}>
|
||||
<div className={theme.typography.title}>
|
||||
{intl.getMessage('install_admin_interface_title')}
|
||||
</div>
|
||||
<div className={cn(theme.typography.text, theme.typography.text_block)}>
|
||||
{intl.getMessage('install_admin_interface_title_decs')}
|
||||
</div>
|
||||
<div className={theme.typography.subTitle}>
|
||||
{intl.getMessage('install_admin_interface_where_interface')}
|
||||
</div>
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
{intl.getMessage('install_admin_interface_where_interface_desc')}
|
||||
</div>
|
||||
<Radio
|
||||
value={radioValue}
|
||||
onSelect={onSelectRadio}
|
||||
options={[
|
||||
{
|
||||
value: NETWORK_OPTIONS.ALL,
|
||||
label: intl.getMessage('install_all_networks'),
|
||||
desc: intl.getMessage('install_all_networks_description'),
|
||||
},
|
||||
{
|
||||
value: NETWORK_OPTIONS.CUSTOM,
|
||||
label: intl.getMessage('install_choose_networks'),
|
||||
desc: intl.getMessage('install_choose_networks_desc'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{ radioValue !== NETWORK_OPTIONS.ALL && getManualBlock()}
|
||||
<div className={theme.typography.subTitle}>
|
||||
{intl.getMessage('install_admin_interface_port')}
|
||||
</div>
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
{intl.getMessage('install_admin_interface_port_desc')}
|
||||
</div>
|
||||
<Input
|
||||
label={`${intl.getMessage('port')}:`}
|
||||
placeholder={intl.getMessage('port')}
|
||||
type="number"
|
||||
name="webPort"
|
||||
value={values.web.port}
|
||||
onChange={(v) => {
|
||||
const port = v === '' ? '' : parseInt(v, 10);
|
||||
setFieldValue('web.port', port);
|
||||
}}
|
||||
/>
|
||||
<StepButtons
|
||||
setFieldValue={setFieldValue}
|
||||
currentStep={1}
|
||||
values={values}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default AdminInterface;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './AdminInterface';
|
||||
55
client2/src/components/Install/components/Auth/Auth.tsx
Normal file
55
client2/src/components/Install/components/Auth/Auth.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import React, { FC, useContext } from 'react';
|
||||
import cn from 'classnames';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { FormikHelpers } from 'formik';
|
||||
|
||||
import { Input } from 'Common/controls';
|
||||
import theme from 'Lib/theme';
|
||||
import Store from 'Store/installStore';
|
||||
|
||||
import StepButtons from '../StepButtons';
|
||||
import { FormValues } from '../../Install';
|
||||
|
||||
interface AuthProps {
|
||||
values: FormValues;
|
||||
setFieldValue: FormikHelpers<FormValues>['setFieldValue'];
|
||||
}
|
||||
|
||||
const Auth: FC<AuthProps> = observer(({
|
||||
values,
|
||||
setFieldValue,
|
||||
}) => {
|
||||
const { ui: { intl } } = useContext(Store);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={theme.typography.title}>
|
||||
{intl.getMessage('install_auth_title')}
|
||||
</div>
|
||||
<div className={cn(theme.typography.text, theme.typography.text_block)}>
|
||||
{intl.getMessage('install_auth_description')}
|
||||
</div>
|
||||
<Input
|
||||
placeholder={intl.getMessage('login')}
|
||||
type="username"
|
||||
name="username"
|
||||
value={values.username}
|
||||
onChange={(v) => setFieldValue('username', v)}
|
||||
/>
|
||||
<Input
|
||||
placeholder={intl.getMessage('password')}
|
||||
type="password"
|
||||
name="password"
|
||||
value={values.password}
|
||||
onChange={(v) => setFieldValue('password', v)}
|
||||
/>
|
||||
<StepButtons
|
||||
setFieldValue={setFieldValue}
|
||||
currentStep={2}
|
||||
values={values}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default Auth;
|
||||
1
client2/src/components/Install/components/Auth/index.ts
Normal file
1
client2/src/components/Install/components/Auth/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './Auth';
|
||||
@@ -0,0 +1,4 @@
|
||||
.tabs {
|
||||
width: 505px;
|
||||
margin-left: -131px;
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import React, { FC, useContext } from 'react';
|
||||
import { Tabs } from 'antd';
|
||||
import cn from 'classnames';
|
||||
import { FormikHelpers } from 'formik';
|
||||
|
||||
import Store from 'Store/installStore';
|
||||
import theme from 'Lib/theme';
|
||||
import { danger, p } from 'Common/formating';
|
||||
import { DEFAULT_DNS_PORT, DEFAULT_IP_ADDRESS, DEFAULT_IP_PORT } from 'Consts/install';
|
||||
|
||||
import { FormValues } from '../../Install';
|
||||
import StepButtons from '../StepButtons';
|
||||
import s from './ConfigureDevices.module.pcss';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
interface ConfigureDevicesProps {
|
||||
values: FormValues;
|
||||
setFieldValue: FormikHelpers<FormValues>['setFieldValue'];
|
||||
}
|
||||
|
||||
const ConfigureDevices: FC<ConfigureDevicesProps> = ({
|
||||
values, setFieldValue,
|
||||
}) => {
|
||||
const { ui: { intl }, install: { addresses } } = useContext(Store);
|
||||
|
||||
const dhcp = (e: string) => (
|
||||
// TODO: link to dhcp
|
||||
<a href="http://" target="_blank" rel="noopener noreferrer">{e}</a>
|
||||
);
|
||||
|
||||
const allIps = addresses?.interfaces.reduce<string[]>((all, data) => {
|
||||
const { ipAddresses } = data;
|
||||
if (ipAddresses) {
|
||||
all.push(...ipAddresses);
|
||||
}
|
||||
return all;
|
||||
}, [] as string[]);
|
||||
|
||||
const { web: { ip: webIp }, dns: { ip: dnsIp } } = values;
|
||||
const selectedWebIps = webIp.length === 1 && webIp[0] === DEFAULT_IP_ADDRESS
|
||||
? allIps : webIp;
|
||||
const selectedDnsIps = dnsIp.length === 1 && dnsIp[0] === DEFAULT_IP_ADDRESS
|
||||
? allIps : dnsIp;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={theme.typography.title}>
|
||||
{intl.getMessage('install_configure_title')}
|
||||
</div>
|
||||
<div className={cn(theme.typography.text, theme.typography.text_block)}>
|
||||
{intl.getMessage('install_configure_danger_notice', { danger })}
|
||||
</div>
|
||||
<div className={theme.typography.subTitle}>
|
||||
{intl.getMessage('install_configure_how_to_title')}
|
||||
</div>
|
||||
<Tabs defaultActiveKey="1" tabPosition="left" className={s.tabs}>
|
||||
<TabPane tab="Router" key="1">
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
{intl.getMessage('install_configure_router', { p })}
|
||||
</div>
|
||||
</TabPane>
|
||||
<TabPane tab="Windows" key="2">
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
{intl.getMessage('install_configure_windows', { p })}
|
||||
</div>
|
||||
</TabPane>
|
||||
<TabPane tab="Macos" key="3">
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
{intl.getMessage('install_configure_macos', { p })}
|
||||
</div>
|
||||
</TabPane>
|
||||
<TabPane tab="Linux" key="4">
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
{/* TODO: add linux setup */}
|
||||
{intl.getMessage('install_configure_router', { p })}
|
||||
</div>
|
||||
</TabPane>
|
||||
<TabPane tab="Android" key="5">
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
{intl.getMessage('install_configure_android', { p })}
|
||||
</div>
|
||||
</TabPane>
|
||||
<TabPane tab="iOs" key="6">
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
{intl.getMessage('install_configure_ios', { p })}
|
||||
</div>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
|
||||
<div className={theme.typography.subTitle}>
|
||||
{intl.getMessage('install_configure_adresses')}
|
||||
</div>
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
<p>
|
||||
{intl.getMessage('install_admin_interface_title')}
|
||||
</p>
|
||||
<p>
|
||||
{selectedWebIps?.map((ip) => (
|
||||
<div key={ip}>
|
||||
{ip}{values.web.port !== DEFAULT_IP_PORT && `:${values.web.port}`}
|
||||
</div>
|
||||
))}
|
||||
</p>
|
||||
<p>
|
||||
{intl.getMessage('install_dns_server_title')}
|
||||
</p>
|
||||
<div>
|
||||
{selectedDnsIps?.map((ip) => (
|
||||
<div key={ip}>
|
||||
{ip}{values.dns.port !== DEFAULT_DNS_PORT && `:${values.dns.port}`}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
{intl.getMessage('install_configure_dhcp', { dhcp })}
|
||||
</div>
|
||||
<StepButtons
|
||||
setFieldValue={setFieldValue}
|
||||
currentStep={4}
|
||||
values={values}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfigureDevices;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './ConfigureDevices';
|
||||
@@ -0,0 +1,12 @@
|
||||
.manualOptions {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.manualOption {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid var(--gray300);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
import React, { FC, useContext } from 'react';
|
||||
import cn from 'classnames';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { FormikHelpers } from 'formik';
|
||||
|
||||
import { Input, Radio, Switch } from 'Common/controls';
|
||||
import { DEFAULT_IP_ADDRESS } from 'Consts/install';
|
||||
import { chechNetworkType, NETWORK_TYPE } from 'Helpers/installHelpers';
|
||||
import theme from 'Lib/theme';
|
||||
import Store from 'Store/installStore';
|
||||
|
||||
import s from './DnsServer.module.pcss';
|
||||
import { FormValues } from '../../Install';
|
||||
import StepButtons from '../StepButtons';
|
||||
|
||||
enum NETWORK_OPTIONS {
|
||||
ALL = 'all',
|
||||
CUSTOM = 'custom',
|
||||
}
|
||||
|
||||
interface DnsServerProps {
|
||||
values: FormValues;
|
||||
setFieldValue: FormikHelpers<FormValues>['setFieldValue'];
|
||||
}
|
||||
|
||||
const DnsServer: FC<DnsServerProps> = observer(({
|
||||
values,
|
||||
setFieldValue,
|
||||
}) => {
|
||||
const { ui: { intl }, install: { addresses } } = useContext(Store);
|
||||
const { dns: { ip } } = values;
|
||||
const radioValue = ip.length === 1 && ip[0] === DEFAULT_IP_ADDRESS
|
||||
? NETWORK_OPTIONS.ALL : NETWORK_OPTIONS.CUSTOM;
|
||||
|
||||
const onSelectRadio = (v: string | number) => {
|
||||
const value = v === NETWORK_OPTIONS.ALL
|
||||
? [DEFAULT_IP_ADDRESS] : [];
|
||||
setFieldValue('dns.ip', value);
|
||||
};
|
||||
|
||||
const getManualBlock = () => (
|
||||
<div className={s.manualOptions}>
|
||||
{addresses?.interfaces.map((a) => {
|
||||
let name = '';
|
||||
const type = chechNetworkType(a.name);
|
||||
switch (type) {
|
||||
case NETWORK_TYPE.ETHERNET:
|
||||
name = `${intl.getMessage('ethernet')} (${a.name}) `;
|
||||
break;
|
||||
case NETWORK_TYPE.LOCAL:
|
||||
name = `${intl.getMessage('localhost')} (${a.name}) `;
|
||||
break;
|
||||
default:
|
||||
name = a.name || '';
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<div key={a.name}>
|
||||
<div>
|
||||
<div className={s.name}>
|
||||
{name}
|
||||
</div>
|
||||
{a.ipAddresses?.map((addrIp) => (
|
||||
<div key={addrIp} className={s.manualOption}>
|
||||
<div className={theme.typography.subtext}>
|
||||
{addrIp}
|
||||
</div>
|
||||
<Switch
|
||||
checked={values.dns.ip.includes(addrIp)}
|
||||
onChange={() => {
|
||||
const temp = new Set(ip);
|
||||
if (temp.has(addrIp)) {
|
||||
temp.delete(addrIp);
|
||||
} else {
|
||||
temp.add(addrIp);
|
||||
}
|
||||
setFieldValue('dns.ip', Array.from(temp.values()));
|
||||
}}/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={theme.typography.title}>
|
||||
{intl.getMessage('install_dns_server_title')}
|
||||
</div>
|
||||
<div className={cn(theme.typography.text, theme.typography.text_block)}>
|
||||
{intl.getMessage('install_dns_server_desc')}
|
||||
</div>
|
||||
<div className={theme.typography.subTitle}>
|
||||
{intl.getMessage('install_dns_server_network_interfaces')}
|
||||
</div>
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
{intl.getMessage('install_dns_server_network_interfaces_desc')}
|
||||
</div>
|
||||
<Radio
|
||||
value={radioValue}
|
||||
onSelect={onSelectRadio}
|
||||
options={[
|
||||
{
|
||||
value: NETWORK_OPTIONS.ALL,
|
||||
label: intl.getMessage('install_all_networks'),
|
||||
desc: intl.getMessage('install_all_networks_description'),
|
||||
},
|
||||
{
|
||||
value: NETWORK_OPTIONS.CUSTOM,
|
||||
label: intl.getMessage('install_choose_networks'),
|
||||
desc: intl.getMessage('install_choose_networks_desc'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{ radioValue !== NETWORK_OPTIONS.ALL && getManualBlock()}
|
||||
<div className={theme.typography.subTitle}>
|
||||
{intl.getMessage('install_dns_server_port')}
|
||||
</div>
|
||||
<div className={cn(theme.typography.text, theme.typography.text_base)}>
|
||||
{intl.getMessage('install_dns_server_port_desc')}
|
||||
</div>
|
||||
<Input
|
||||
label={`${intl.getMessage('port')}:`}
|
||||
placeholder={intl.getMessage('port')}
|
||||
type="number"
|
||||
name="dnsPort"
|
||||
value={values.dns.port}
|
||||
onChange={(v) => {
|
||||
const port = v === '' ? '' : parseInt(v, 10);
|
||||
setFieldValue('dns.port', port);
|
||||
}}
|
||||
/>
|
||||
<StepButtons
|
||||
setFieldValue={setFieldValue}
|
||||
currentStep={3}
|
||||
values={values}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default DnsServer;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './DnsServer';
|
||||
@@ -0,0 +1,8 @@
|
||||
.button {
|
||||
margin-top: 48px;
|
||||
width: 190px;
|
||||
|
||||
&.inGroup {
|
||||
margin-right: 24px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import React, { FC, useContext } from 'react';
|
||||
import { Button } from 'antd';
|
||||
import cn from 'classnames';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { FormikHelpers } from 'formik';
|
||||
|
||||
import Store from 'Store/installStore';
|
||||
|
||||
import { FormValues } from '../../Install';
|
||||
import s from './StepButtons.module.pcss';
|
||||
|
||||
interface StepButtonsProps {
|
||||
setFieldValue: FormikHelpers<FormValues>['setFieldValue'];
|
||||
currentStep: number;
|
||||
values: FormValues;
|
||||
}
|
||||
|
||||
const StepButtons: FC<StepButtonsProps> = observer(({
|
||||
setFieldValue,
|
||||
currentStep,
|
||||
}) => {
|
||||
const { ui: { intl } } = useContext(Store);
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size="large"
|
||||
type="ghost"
|
||||
className={cn(s.button, s.inGroup)}
|
||||
onClick={() => setFieldValue('step', currentStep - 1)}
|
||||
>
|
||||
{intl.getMessage('back')}
|
||||
</Button>
|
||||
<Button
|
||||
size="large"
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
className={cn(s.button)}
|
||||
>
|
||||
{intl.getMessage('next')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default StepButtons;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './StepButtons';
|
||||
@@ -0,0 +1,3 @@
|
||||
.stepper {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import React, { FC } from 'react';
|
||||
import { Steps } from 'antd';
|
||||
|
||||
import s from './Stepper.module.pcss';
|
||||
|
||||
interface StepperProps {
|
||||
currentStep: number;
|
||||
}
|
||||
|
||||
const { Step } = Steps;
|
||||
|
||||
const Stepper: FC<StepperProps> = ({ currentStep }) => {
|
||||
return (
|
||||
<Steps progressDot current={currentStep} className={s.stepper}>
|
||||
<Step/>
|
||||
<Step/>
|
||||
<Step/>
|
||||
<Step/>
|
||||
<Step/>
|
||||
</Steps>
|
||||
);
|
||||
};
|
||||
|
||||
export default Stepper;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './Stepper';
|
||||
@@ -0,0 +1,15 @@
|
||||
.iconContainer{
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
.icon {
|
||||
width: 185px;
|
||||
height: 57px;
|
||||
}
|
||||
.button {
|
||||
margin-top: 48px;
|
||||
width: 190px;
|
||||
|
||||
&.inGroup {
|
||||
margin-right: 24px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import React, { FC, useContext } from 'react';
|
||||
import { Button } from 'antd';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import Store from 'Store/installStore';
|
||||
import Icon from 'Common/ui/Icon';
|
||||
import theme from 'Lib/theme';
|
||||
|
||||
import s from './Welcome.module.pcss';
|
||||
|
||||
interface WelcomeProps {
|
||||
onNext: () => void;
|
||||
}
|
||||
|
||||
const Welcome: FC<WelcomeProps> = observer(({ onNext }) => {
|
||||
const { ui: { intl } } = useContext(Store);
|
||||
return (
|
||||
<div className={s.content}>
|
||||
<div className={s.iconContainer}>
|
||||
<Icon icon="mainLogo" className={s.icon} />
|
||||
</div>
|
||||
<div className={theme.typography.title}>
|
||||
{intl.getMessage('install_wellcome_title')}
|
||||
</div>
|
||||
<div className={theme.typography.text}>
|
||||
{intl.getMessage('install_wellcome_desc')}
|
||||
</div>
|
||||
<Button
|
||||
size="large"
|
||||
type="primary"
|
||||
className={s.button}
|
||||
onClick={onNext}
|
||||
>
|
||||
{intl.getMessage('install_wellcome_button')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default Welcome;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './Welcome';
|
||||
1
client2/src/components/Install/index.ts
Normal file
1
client2/src/components/Install/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './Install';
|
||||
Reference in New Issue
Block a user