blob: 8cc6265fa92267127aa5d6b6618e3a153a6da20c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { FC, useState, useEffect } from 'react';
import { Container, Row, Col, Card, Alert } from 'react-bootstrap';
import { useTranslation, Trans } from 'react-i18next';
import { Helmet, HelmetProvider } from 'react-helmet-async';
import type { FormDataType } from '@/common/interface';
import {
dbCheck,
installInit,
installBaseInfo,
checkConfigFileExists,
} from '@/services';
import {
Storage,
handleFormError,
scrollToDocTop,
scrollToElementTop,
} from '@/utils';
import { CURRENT_LANG_STORAGE_KEY } from '@/common/constants';
import { BASE_ORIGIN } from '@/router/alias';
import { setupInstallLanguage } from '@/utils/localize';
import { loggedUserInfoStore } from '@/stores';
import {
FirstStep,
SecondStep,
ThirdStep,
FourthStep,
Fifth,
} from './components';
const Index: FC = () => {
const { t } = useTranslation('translation', { keyPrefix: 'install' });
const [step, setStep] = useState(1);
const [loading, setLoading] = useState(true);
const [errorData, setErrorData] = useState<{ [propName: string]: any }>({
msg: '',
});
const [checkData, setCheckData] = useState({
db_table_exist: false,
db_connection_success: false,
});
const [formData, setFormData] = useState<FormDataType>({
lang: {
value: 'en_US',
isInvalid: false,
errorMsg: '',
},
db_type: {
value: 'mysql',
isInvalid: false,
errorMsg: '',
},
db_username: {
value: 'root',
isInvalid: false,
errorMsg: '',
},
db_password: {
value: 'root',
isInvalid: false,
errorMsg: '',
},
db_host: {
value: 'db:3306',
isInvalid: false,
errorMsg: '',
},
db_name: {
value: 'answer',
isInvalid: false,
errorMsg: '',
},
db_file: {
value: '/data/answer.db',
isInvalid: false,
errorMsg: '',
},
site_name: {
value: '',
isInvalid: false,
errorMsg: '',
},
site_url: {
value: BASE_ORIGIN,
isInvalid: false,
errorMsg: '',
},
contact_email: {
value: '',
isInvalid: false,
errorMsg: '',
},
login_required: {
value: false,
isInvalid: false,
errorMsg: '',
},
external_content_display: {
value: 'always_display',
isInvalid: false,
errorMsg: '',
},
name: {
value: '',
isInvalid: false,
errorMsg: '',
},
password: {
value: '',
isInvalid: false,
errorMsg: '',
},
confirm_password: {
value: '',
isInvalid: false,
errorMsg: '',
},
email: {
value: '',
isInvalid: false,
errorMsg: '',
},
ssl_enabled: {
value: false,
isInvalid: false,
errorMsg: '',
},
ssl_mode: {
value: '',
isInvalid: false,
errorMsg: '',
},
ssl_key: {
value: '',
isInvalid: false,
errorMsg: '',
},
ssl_root_cert: {
value: '',
isInvalid: false,
errorMsg: '',
},
ssl_cert: {
value: '',
isInvalid: false,
errorMsg: '',
},
});
const { update, user } = loggedUserInfoStore();
const updateFormData = (params: FormDataType) => {
if (Object.keys(params)?.[0] === 'db_type') {
let updatedFormData = formData;
if (params.db_type.value === 'mysql') {
updatedFormData = {
...updatedFormData,
db_username: { ...updatedFormData.db_username, value: 'root' },
db_password: { ...updatedFormData.db_password, value: 'root' },
db_host: { ...updatedFormData.db_host, value: 'db:3306' },
};
} else if (params.db_type.value === 'postgres') {
updatedFormData = {
...updatedFormData,
db_username: { ...updatedFormData.db_username, value: 'postgres' },
db_password: { ...updatedFormData.db_password, value: 'postgres' },
db_host: { ...updatedFormData.db_host, value: 'db:5432' },
ssl_enabled: { ...updatedFormData.ssl_enabled, value: false },
ssl_mode: { ...updatedFormData.ssl_mode, value: '' },
};
}
return updatedFormData;
}
return formData;
};
const handleChange = (params: FormDataType) => {
setErrorData({
msg: '',
});
const updatedFormData = updateFormData(params);
setFormData({ ...updatedFormData, ...params });
};
const handleErr = (data) => {
scrollToDocTop();
setErrorData(data);
};
const handleNext = async () => {
setErrorData({
msg: '',
});
setStep((pre) => pre + 1);
};
const checkInstall = () => {
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,
ssl_enabled: formData.ssl_enabled.value,
ssl_mode: formData.ssl_mode.value,
ssl_key: formData.ssl_key.value,
ssl_root_cert: formData.ssl_root_cert.value,
ssl_cert: formData.ssl_cert.value,
};
installInit(params)
.then(() => {
handleNext();
})
.catch((err) => {
handleErr(err);
});
};
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,
ssl_enabled: formData.ssl_enabled.value,
ssl_mode: formData.ssl_mode.value,
ssl_key: formData.ssl_key.value,
ssl_root_cert: formData.ssl_root_cert.value,
ssl_cert: formData.ssl_cert.value,
};
dbCheck(params)
.then(() => {
checkInstall();
})
.catch((err) => {
handleErr(err);
});
};
const submitSiteConfig = () => {
const params = {
lang: formData.lang.value,
site_name: formData.site_name.value,
site_url: formData.site_url.value,
contact_email: formData.contact_email.value,
login_required: formData.login_required.value,
external_content_display: formData.external_content_display.value,
name: formData.name.value,
password: formData.password.value,
email: formData.email.value,
};
installBaseInfo(params)
.then(() => {
handleNext();
})
.catch((err) => {
if (err.isError) {
const data = handleFormError(err, formData);
setFormData({ ...data });
const ele = document.getElementById(err.list[0].error_field);
scrollToElementTop(ele);
} else {
handleErr(err);
}
});
};
const handleStep = () => {
if (step === 1) {
Storage.set(CURRENT_LANG_STORAGE_KEY, formData.lang.value);
update({
...user,
language: formData.lang.value,
});
handleNext();
}
if (step === 2) {
submitDatabaseForm();
}
if (step === 3) {
if (errorData.msg) {
checkInstall();
} else {
handleNext();
}
}
if (step === 4) {
submitSiteConfig();
}
if (step > 4) {
handleNext();
}
};
const handleInstallNow = (e) => {
e.preventDefault();
if (checkData.db_table_exist) {
setStep(8);
} else {
setStep(4);
}
};
const configYmlCheck = () => {
checkConfigFileExists()
.then((res) => {
setCheckData({
db_table_exist: res.db_table_exist,
db_connection_success: res.db_connection_success,
});
if (res && res.config_file_exist) {
setupInstallLanguage(Storage.get(CURRENT_LANG_STORAGE_KEY));
if (res.db_connection_success) {
setStep(6);
} else {
setStep(7);
}
}
})
.finally(() => {
setLoading(false);
});
};
useEffect(() => {
configYmlCheck();
}, []);
if (loading) {
return <div />;
}
return (
<HelmetProvider>
<Helmet>
<title>{t('install', { keyPrefix: 'page_title' })}</title>
</Helmet>
<div className="bg-f5 py-5 flex-grow-1">
<Container className="py-3">
<Row className="justify-content-center">
<Col lg={6}>
<h2 className="mb-4 text-center">{t('title')}</h2>
<Card>
<Card.Body>
{errorData?.msg && (
<Alert variant="danger">{errorData?.msg}</Alert>
)}
<FirstStep
visible={step === 1}
data={formData.lang}
changeCallback={handleChange}
nextCallback={handleStep}
/>
<SecondStep
visible={step === 2}
data={formData}
changeCallback={handleChange}
nextCallback={handleStep}
/>
<ThirdStep
visible={step === 3}
nextCallback={handleStep}
errorMsg={errorData}
/>
<FourthStep
visible={step === 4}
data={formData}
changeCallback={handleChange}
nextCallback={handleStep}
/>
<Fifth
visible={step === 5}
siteUrl={formData.site_url.value}
/>
{step === 6 && (
<div>
<h5>{t('warn_title')}</h5>
<p>
<Trans
i18nKey="install.warn_desc"
components={{ 1: <code /> }}
/>{' '}
<Trans i18nKey="install.install_now">
You may try
<a href="###" onClick={(e) => handleInstallNow(e)}>
installing now
</a>
.
</Trans>
</p>
</div>
)}
{step === 7 && (
<div>
<h5>{t('db_failed')}</h5>
<p>
<Trans
i18nKey="install.db_failed_desc"
components={{ 1: <code /> }}
/>
</p>
</div>
)}
{step === 8 && (
<div>
<h5>{t('installed')}</h5>
<p>{t('installed_desc')}</p>
</div>
)}
</Card.Body>
</Card>
</Col>
</Row>
</Container>
</div>
</HelmetProvider>
);
};
export default Index;