fix: add installation process

This commit is contained in:
shuai 2022-11-03 17:44:59 +08:00
parent 847c9a343e
commit 48654aa995
10 changed files with 289 additions and 56 deletions

View File

@ -18,7 +18,12 @@ module.exports = {
const config = configFunction(proxy, allowedHost);
config.proxy = {
'/answer': {
target: 'http://10.0.10.98:2060',
target: 'http://10.0.20.88:8080',
changeOrigin: true,
secure: false,
},
'/installation': {
target: 'http://10.0.20.88:8080',
changeOrigin: true,
secure: false,
},

View File

@ -739,6 +739,7 @@
"title": "Answer",
"next": "Next",
"done": "Done",
"config_yaml_error": "Cant create the config.yaml file.",
"lang": {
"label": "Please choose a language"
},
@ -779,22 +780,42 @@
"site_information": "Site Information",
"admin_account": "Admin Account",
"site_name": {
"label": "Site Name"
"label": "Site Name",
"msg": "Site Name cannot be empty."
},
"site_url": {
"label": "Site URL",
"text": "The address of your site.",
"msg": {
"empty": "Site URL cannot be empty.",
"incorrect": "Site URL incorrect format."
}
},
"contact_email": {
"label": "Contact Email",
"text": "Email address of key contact responsible for this site."
"text": "Email address of key contact responsible for this site.",
"msg": {
"empty": "Contact Email cannot be empty.",
"incorrect": "Contact Email incorrect format."
}
},
"admin_name": {
"label": "Name"
"label": "Name",
"msg": "Name cannot be empty."
},
"admin_password": {
"label": "Password",
"text": "You will need this password to log in. Please store it in a secure location."
"text": "You will need this password to log in. Please store it in a secure location.",
"msg": "Password cannot be empty."
},
"admin_email": {
"label": "Email",
"text": "You will need this email to log in."
"text": "You will need this email to log in.",
"msg": {
"empty": "Email cannot be empty.",
"incorrect": "Email incorrect format."
}
},
"ready_title": "Your Answer is Ready!",
"ready_description": "If you ever feel like changing more settings, visit <1>admin section</1>; find it in the site menu.",

View File

@ -6,8 +6,9 @@ import Progress from '../Progress';
interface Props {
visible: boolean;
siteUrl: string;
}
const Index: FC<Props> = ({ visible }) => {
const Index: FC<Props> = ({ visible, siteUrl = '' }) => {
const { t } = useTranslation('translation', { keyPrefix: 'install' });
if (!visible) return null;
@ -17,14 +18,15 @@ const Index: FC<Props> = ({ visible }) => {
<p>
<Trans i18nKey="install.ready_description">
If you ever feel like changing more settings, visit
<a href="/">admin section</a>; find it in the site menu.
<a href={`${siteUrl}/users/login`}>admin section</a>; find it in the
site menu.
</Trans>
</p>
<p>{t('good_luck')}</p>
<div className="d-flex align-items-center justify-content-between">
<Progress step={5} />
<Button>{t('done')}</Button>
<Button href={siteUrl}>{t('done')}</Button>
</div>
</div>
);

View File

@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
import type { LangsType, FormValue, FormDataType } from '@/common/interface';
import Progress from '../Progress';
import { languages } from '@/services';
import { getInstallLangOptions } from '@/services';
interface Props {
data: FormValue;
@ -18,8 +18,15 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
const [langs, setLangs] = useState<LangsType[]>();
const getLangs = async () => {
const res: LangsType[] = await languages();
const res: LangsType[] = await getInstallLangOptions();
setLangs(res);
changeCallback({
lang: {
value: res[0].value,
isInvalid: false,
errorMsg: '',
},
});
};
const handleSubmit = () => {

View File

@ -18,6 +18,7 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
let bol = true;
const {
site_name,
site_url,
contact_email,
admin_name,
admin_password,
@ -33,12 +34,40 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
};
}
if (!site_url.value) {
bol = false;
data.site_url = {
value: '',
isInvalid: true,
errorMsg: t('site_name.msg.empty'),
};
}
const reg = /^(http|https):\/\//g;
if (site_url.value && !site_url.value.match(reg)) {
bol = false;
data.site_url = {
value: site_url.value,
isInvalid: true,
errorMsg: t('site_url.msg.incorrect'),
};
}
if (!contact_email.value) {
bol = false;
data.contact_email = {
value: '',
isInvalid: true,
errorMsg: t('contact_email.msg'),
errorMsg: t('contact_email.msg.empty'),
};
}
const mailReg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
if (contact_email.value && !contact_email.value.match(mailReg)) {
bol = false;
data.contact_email = {
value: contact_email.value,
isInvalid: true,
errorMsg: t('contact_email.msg.incorrect'),
};
}
@ -65,7 +94,16 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
data.admin_email = {
value: '',
isInvalid: true,
errorMsg: t('admin_email.msg'),
errorMsg: t('admin_email.msg.empty'),
};
}
if (admin_email.value && !admin_email.value.match(mailReg)) {
bol = false;
data.admin_email = {
value: '',
isInvalid: true,
errorMsg: t('admin_email.msg.incorrect'),
};
}
@ -108,6 +146,27 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
{data.site_name.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="site_url" className="mb-3">
<Form.Label>{t('site_url.label')}</Form.Label>
<Form.Control
required
value={data.site_url.value}
isInvalid={data.site_url.isInvalid}
onChange={(e) => {
changeCallback({
site_url: {
value: e.target.value,
isInvalid: false,
errorMsg: '',
},
});
}}
/>
<Form.Text>{t('site_url.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{data.site_url.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="contact_email" className="mb-3">
<Form.Label>{t('contact_email.label')}</Form.Label>
<Form.Control

View File

@ -6,29 +6,43 @@ import Progress from '../Progress';
interface Props {
visible: boolean;
errorMsg;
nextCallback: () => void;
}
const Index: FC<Props> = ({ visible, nextCallback }) => {
const Index: FC<Props> = ({ visible, errorMsg, nextCallback }) => {
const { t } = useTranslation('translation', { keyPrefix: 'install' });
if (!visible) return null;
return (
<div>
<h5>{t('config_yaml.title')}</h5>
<div className="mb-3">{t('config_yaml.label')}</div>
<div className="fmt">
<p>
<Trans
i18nKey="install.config_yaml.description"
components={{ 1: <code /> }}
/>
</p>
</div>
<FormGroup className="mb-3">
<Form.Control type="text" as="textarea" rows={5} className="fs-14" />
</FormGroup>
<div className="mb-3">{t('config_yaml.info')}</div>
{errorMsg?.msg?.length > 0 ? (
<>
<div className="fmt">
<p>
<Trans
i18nKey="install.config_yaml.description"
components={{ 1: <code /> }}
/>
</p>
</div>
<FormGroup className="mb-3">
<Form.Control
type="text"
as="textarea"
rows={8}
className="fs-14"
value={errorMsg?.default_config}
/>
</FormGroup>
<div className="mb-3">{t('config_yaml.info')}</div>
</>
) : (
<div className="mb-3">{t('config_yaml.label')}</div>
)}
<div className="d-flex align-items-center justify-content-between">
<Progress step={3} />
<Button onClick={nextCallback}>{t('next')}</Button>

View File

@ -3,8 +3,13 @@ import { Container, Row, Col, Card, Alert } from 'react-bootstrap';
import { useTranslation, Trans } from 'react-i18next';
import type { FormDataType } from '@/common/interface';
import { Storage } from '@/utils';
import { PageTitle } from '@/components';
import {
dbCheck,
installInit,
installBaseInfo,
checkConfigFileExists,
} from '@/services';
import {
FirstStep,
@ -16,8 +21,12 @@ import {
const Index: FC = () => {
const { t } = useTranslation('translation', { keyPrefix: 'install' });
const [step, setStep] = useState(1);
const [showError] = useState(false);
const [step, setStep] = useState(3);
const [loading, setLoading] = useState(true);
const [errorData, setErrorData] = useState<{ [propName: string]: any }>({
msg: '',
});
const [tableExist, setTableExist] = useState(false);
const [formData, setFormData] = useState<FormDataType>({
lang: {
@ -26,7 +35,7 @@ const Index: FC = () => {
errorMsg: '',
},
db_type: {
value: '',
value: 'mysql',
isInvalid: false,
errorMsg: '',
},
@ -55,12 +64,16 @@ const Index: FC = () => {
isInvalid: false,
errorMsg: '',
},
site_name: {
value: '',
isInvalid: false,
errorMsg: '',
},
site_url: {
value: '',
isInvalid: false,
errorMsg: '',
},
contact_email: {
value: '',
isInvalid: false,
@ -88,33 +101,107 @@ const Index: FC = () => {
setFormData({ ...formData, ...params });
};
const handleStep = () => {
const handleErr = (data) => {
window.scrollTo(0, 0);
setErrorData(data);
};
const handleNext = async () => {
setErrorData({
msg: '',
});
setStep((pre) => pre + 1);
};
// const handleSubmit = () => {
// const params = {
// lang: formData.lang.value,
// db_type: formData.db_type.value,
// db_username: formData.db_username.value,
// db_password: formData.db_password.value,
// db_host: formData.db_host.value,
// db_name: formData.db_name.value,
// db_file: formData.db_file.value,
// site_name: formData.site_name.value,
// contact_email: formData.contact_email.value,
// admin_name: formData.admin_name.value,
// admin_password: formData.admin_password.value,
// admin_email: formData.admin_email.value,
// };
const submitDatabaseForm = () => {
const params = {
lang: formData.lang.value,
db_type: formData.db_type.value,
db_username: formData.db_username.value,
db_password: formData.db_password.value,
db_host: formData.db_host.value,
db_name: formData.db_name.value,
db_file: formData.db_file.value,
};
dbCheck(params)
.then(() => {
handleNext();
})
.catch((err) => {
console.log(err);
handleErr(err);
});
};
// console.log(params);
// };
const checkInstall = () => {
installInit()
.then(() => {
handleNext();
})
.catch((err) => {
handleErr(err);
});
};
const submitSiteConfig = () => {
const params = {
site_name: formData.site_name.value,
contact_email: formData.contact_email.value,
admin_name: formData.admin_name.value,
admin_password: formData.admin_password.value,
admin_email: formData.admin_email.value,
};
installBaseInfo(params)
.then(() => {
handleNext();
})
.catch((err) => {
handleErr(err);
});
};
const handleStep = () => {
if (step === 2) {
submitDatabaseForm();
} else if (step === 3) {
checkInstall();
} else if (step === 4) {
submitSiteConfig();
} else {
handleNext();
}
};
const handleInstallNow = (e) => {
e.preventDefault();
if (tableExist) {
setStep(7);
} else {
setStep(4);
}
};
const configYmlCheck = () => {
checkConfigFileExists()
.then((res) => {
setTableExist(res?.db_table_exist);
if (res && res.config_file_exist) {
setStep(5);
}
})
.finally(() => {
setLoading(false);
});
};
useEffect(() => {
console.log('step===', Storage.get('INSTALL_STEP'));
configYmlCheck();
}, []);
if (loading) {
return <div />;
}
return (
<div className="page-wrap2">
<PageTitle title={t('install', { keyPrefix: 'page_title' })} />
@ -124,7 +211,9 @@ const Index: FC = () => {
<h2 className="mb-4 text-center">{t('title')}</h2>
<Card>
<Card.Body>
{showError && <Alert variant="danger"> show error msg </Alert>}
{errorData?.msg && (
<Alert variant="danger">{errorData?.msg}</Alert>
)}
<FirstStep
visible={step === 1}
@ -140,7 +229,11 @@ const Index: FC = () => {
nextCallback={handleStep}
/>
<ThirdStep visible={step === 3} nextCallback={handleStep} />
<ThirdStep
visible={step === 3}
nextCallback={handleStep}
errorMsg={errorData}
/>
<FourthStep
visible={step === 4}
@ -149,7 +242,7 @@ const Index: FC = () => {
nextCallback={handleStep}
/>
<Fifth visible={step === 5} />
<Fifth visible={step === 5} siteUrl={formData.site_url.value} />
{step === 6 && (
<div>
<h5>{t('warning')}</h5>
@ -158,7 +251,10 @@ const Index: FC = () => {
The file <code>config.yaml</code> already exists. If you
need to reset any of the configuration items in this
file, please delete it first. You may try{' '}
<a href="/">installing now</a>.
<a href="###" onClick={(e) => handleInstallNow(e)}>
installing now
</a>
.
</Trans>
</p>
</div>

View File

@ -1,3 +1,4 @@
export * from './admin';
export * from './common';
export * from './client';
export * from './install';

View File

@ -0,0 +1,21 @@
import request from '@/utils/request';
export const checkConfigFileExists = () => {
return request.post('/installation/config-file/check');
};
export const dbCheck = (params) => {
return request.post('/installation/db/check', params);
};
export const installInit = () => {
return request.post('/installation/init');
};
export const installBaseInfo = (params) => {
return request.post('/installation/base-info', params);
};
export const getInstallLangOptions = () => {
return request.get('/installation/language/options');
};

View File

@ -73,7 +73,14 @@ class Request {
});
}
if (data.type === 'modal') {
if (data.err_type === 'alert') {
return Promise.reject({
msg,
...data,
});
}
if (data.err_type === 'modal') {
// modal error message
Modal.confirm({
content: msg,