chore: update license to agpl
This commit is contained in:
parent
9dc4615235
commit
dba375b29a
|
@ -35,3 +35,4 @@ log/
|
|||
.env
|
||||
/web/
|
||||
.github
|
||||
src/common*/
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
# production
|
||||
/build
|
||||
/dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
@ -21,5 +22,3 @@
|
|||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
/dist
|
|
@ -208,10 +208,10 @@ export default class GlobalHeaderRight extends PureComponent {
|
|||
</Menu.Item>
|
||||
<Menu.Item key="ticket">
|
||||
<a
|
||||
href={`${getWebsitePathByLang()}/company/contact/`}
|
||||
href={`https://github.com/infinilabs/console/issues/new`}
|
||||
target="_blank"
|
||||
>
|
||||
<Icon type="mobile" />
|
||||
<Icon type="github" />
|
||||
<FormattedMessage id="menu.header.help.ticket" />
|
||||
</a>
|
||||
</Menu.Item>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,317 +0,0 @@
|
|||
import request from "@/utils/request";
|
||||
import {
|
||||
Modal,
|
||||
Checkbox,
|
||||
Button,
|
||||
Form,
|
||||
Icon,
|
||||
Input,
|
||||
message,
|
||||
Alert,
|
||||
Divider,
|
||||
} from "antd";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { formatMessage, getLocale } from "umi/locale";
|
||||
import { getWebsitePathByLang } from "@/utils/utils";
|
||||
import "./ApplyTrial.scss";
|
||||
import LicenceDesc from "./LicenceDesc";
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 6 },
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 16 },
|
||||
},
|
||||
};
|
||||
|
||||
const tailFormItemLayout = {
|
||||
wrapperCol: {
|
||||
xs: {
|
||||
span: 24,
|
||||
offset: 0,
|
||||
},
|
||||
sm: {
|
||||
span: 16,
|
||||
offset: 6,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const tipsFormItemLayout = {
|
||||
wrapperCol: {
|
||||
xs: {
|
||||
span: 24,
|
||||
offset: 0,
|
||||
},
|
||||
sm: {
|
||||
span: 20,
|
||||
offset: 2,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default Form.create()((props) => {
|
||||
const { form, onLicenceUpdate } = props;
|
||||
const { getFieldDecorator } = form;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const defaultState = {
|
||||
status: -1,
|
||||
error_msg: "",
|
||||
licensed: false,
|
||||
};
|
||||
const [state, setState] = useState(defaultState);
|
||||
|
||||
const onSubmit = () => {
|
||||
form.validateFields(async (err, values) => {
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
setLoading(true);
|
||||
|
||||
const res = await request(`/_license/request_trial?lang=${getLocale()}`, {
|
||||
method: "POST",
|
||||
body: values,
|
||||
});
|
||||
if (res?.acknowledged) {
|
||||
let ack = { status: 1 };
|
||||
if (res?.license) {
|
||||
ack.licensed = true;
|
||||
onLicenceUpdate();
|
||||
}
|
||||
setState({ ...state, ...ack });
|
||||
} else {
|
||||
let error_msg = "";
|
||||
if (typeof res === "undefined") {
|
||||
error_msg = "Request timeout or network problem";
|
||||
} else if (res?.error?.reason) {
|
||||
error_msg = res.error.reason;
|
||||
}
|
||||
setState({ ...state, status: 0, error_msg: error_msg });
|
||||
}
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
props.onClose(); //close parent modal
|
||||
setVisible(false);
|
||||
setState({ ...state, ...defaultState });
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button type="primary" size="small" onClick={() => setVisible(true)}>
|
||||
{formatMessage({ id: "license.button.apply_trial" })}
|
||||
</Button>
|
||||
<Modal
|
||||
title={formatMessage({ id: "license.label.apply_trial.title" })}
|
||||
visible={visible}
|
||||
closable
|
||||
footer={null}
|
||||
onCancel={onClose}
|
||||
destroyOnClose
|
||||
width={560}
|
||||
className={"apply-trial-modal"}
|
||||
>
|
||||
{state.status === -1 ? (
|
||||
<Form {...formItemLayout} colon={false}>
|
||||
<Form.Item {...tipsFormItemLayout}>
|
||||
<div className="tips-wrap">
|
||||
<Icon type="info-circle" theme="twoTone" />
|
||||
<span className="tips-text">
|
||||
{formatMessage({
|
||||
id: "license.label.apply.trial_tips",
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={formatMessage({
|
||||
id: "license.label.apply.organization",
|
||||
})}
|
||||
>
|
||||
{getFieldDecorator("organization", {
|
||||
initialValue: "",
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: formatMessage({
|
||||
id: "license.label.apply.organization.required",
|
||||
}),
|
||||
},
|
||||
],
|
||||
})(<Input maxLength={100} />)}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={formatMessage({
|
||||
id: "license.label.apply.contact",
|
||||
})}
|
||||
>
|
||||
{getFieldDecorator("contact", {
|
||||
initialValue: "",
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: formatMessage({
|
||||
id: "license.label.apply.contact.required",
|
||||
}),
|
||||
},
|
||||
],
|
||||
})(<Input maxLength={50} />)}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={formatMessage({
|
||||
id: "license.label.apply.email",
|
||||
})}
|
||||
>
|
||||
{getFieldDecorator("email", {
|
||||
initialValue: "",
|
||||
rules: [
|
||||
{
|
||||
type: "email",
|
||||
message: formatMessage({
|
||||
id: "license.label.apply.email.valid",
|
||||
}),
|
||||
},
|
||||
{
|
||||
required: true,
|
||||
message: formatMessage({
|
||||
id: "license.label.apply.email.required",
|
||||
}),
|
||||
},
|
||||
],
|
||||
})(
|
||||
<Input
|
||||
maxLength={50}
|
||||
placeholder={formatMessage({
|
||||
id: "license.label.apply.email.placeholder",
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={formatMessage({
|
||||
id: "license.label.apply.phone",
|
||||
})}
|
||||
>
|
||||
{getFieldDecorator("phone", {
|
||||
initialValue: "",
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: formatMessage({
|
||||
id: "license.label.apply.phone.required",
|
||||
}),
|
||||
},
|
||||
],
|
||||
})(<Input maxLength={20} />)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item {...tailFormItemLayout}>
|
||||
<Button type="primary" block loading={loading} onClick={onSubmit}>
|
||||
{formatMessage({ id: "license.label.apply.submit" })}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
<Form.Item {...tailFormItemLayout}>
|
||||
{getFieldDecorator("agreement", {
|
||||
valuePropName: "checked",
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: formatMessage({
|
||||
id: "license.label.agree.required",
|
||||
}),
|
||||
},
|
||||
],
|
||||
})(
|
||||
<Checkbox>
|
||||
{formatMessage({ id: "license.label.agree" })}{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
href={`${getWebsitePathByLang()}/agreement/console`}
|
||||
>
|
||||
{formatMessage({ id: "license.label.agreement" })}
|
||||
</a>
|
||||
</Checkbox>
|
||||
)}
|
||||
</Form.Item>
|
||||
</Form>
|
||||
) : null}
|
||||
{state.status === 0 ? (
|
||||
<div className="status-content">
|
||||
<Icon
|
||||
type="close-circle"
|
||||
theme="filled"
|
||||
style={{
|
||||
fontSize: 48,
|
||||
color: "#FF0000",
|
||||
marginTop: -20,
|
||||
marginBottom: 10,
|
||||
}}
|
||||
/>
|
||||
{state.error_msg ? (
|
||||
<Alert
|
||||
message={"Error Message"}
|
||||
description={state.error_msg}
|
||||
type="error"
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<div>
|
||||
{formatMessage({ id: "license.label.apply.submit.failed.tips" })}
|
||||
</div>
|
||||
<div>
|
||||
{formatMessage({
|
||||
id: "license.label.apply.submit.official_website.link",
|
||||
})}
|
||||
<a
|
||||
target="_blank"
|
||||
href={`${APP_OFFICIAL_WEBSITE}/company/contact`}
|
||||
>{`${APP_OFFICIAL_WEBSITE}/company/contact`}</a>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{state.status === 1 ? (
|
||||
<div className="status-content">
|
||||
<Icon
|
||||
type="check-circle"
|
||||
theme="filled"
|
||||
style={{
|
||||
fontSize: 48,
|
||||
color: "#1890ff",
|
||||
marginTop: 0,
|
||||
marginBottom: 10,
|
||||
}}
|
||||
/>
|
||||
<div className="successfully-tips">
|
||||
{formatMessage({
|
||||
id: "license.label.apply.submit.successfully.tips",
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
{state.licensed && props.licence?.license_type ? (
|
||||
<>
|
||||
<Divider orientation="left">
|
||||
{formatMessage({
|
||||
id: "license.label.apply.submit.divider",
|
||||
})}
|
||||
</Divider>
|
||||
<div>
|
||||
<LicenceDesc licence={props.licence} />
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
});
|
|
@ -1,25 +0,0 @@
|
|||
.apply-trial-modal {
|
||||
.ant-modal-header {
|
||||
.ant-modal-title {
|
||||
text-align: center;
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
.tips-wrap {
|
||||
line-height: 24px;
|
||||
.tips-text {
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
.status-content {
|
||||
min-height: 305px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
.successfully-tips {
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
import { Button } from "antd";
|
||||
import styles from "./Buy.less";
|
||||
import { formatMessage } from "umi/locale";
|
||||
import ApplyTrial from "./ApplyTrial";
|
||||
|
||||
export default (props) => {
|
||||
return APP_OFFICIAL_WEBSITE ? (
|
||||
<div className={styles.buy}>
|
||||
{props?.trialVisible ? <ApplyTrial {...props} /> : null}
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
onClick={() => window.open(APP_OFFICIAL_WEBSITE)}
|
||||
>
|
||||
{formatMessage({ id: "license.button.buy" })}
|
||||
</Button>
|
||||
</div>
|
||||
) : null;
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
.buy {
|
||||
text-align: right;
|
||||
margin-bottom: 16px;
|
||||
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: right;
|
||||
|
||||
:global {
|
||||
.ant-btn {
|
||||
padding: 0 15px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
import { Button, Icon, Descriptions, Result } from 'antd';
|
||||
import styles from './Features.less';
|
||||
import { LICENCE_ROUTES, FEATURES, checkLicenceType } from '.'
|
||||
import { formatMessage } from "umi/locale";
|
||||
|
||||
export default ({ licence }) => {
|
||||
|
||||
const { license_type, expire_at } = licence;
|
||||
|
||||
return (
|
||||
<div className={styles.features}>
|
||||
<Descriptions title={formatMessage({ id: 'license.features.title' })} colon={false} column={4}>
|
||||
{
|
||||
FEATURES.map((item, index) => {
|
||||
const isAllowed =
|
||||
checkLicenceType(license_type, expire_at) ||
|
||||
!item.route ||
|
||||
LICENCE_ROUTES.every((r) => !r.includes(item.route))
|
||||
return (
|
||||
<Descriptions.Item
|
||||
key={index}
|
||||
className={`${styles.default} ${isAllowed ? styles.allow : ''}` }
|
||||
label={''}
|
||||
>
|
||||
<span className={styles.icon}></span>{item.name}
|
||||
</Descriptions.Item>
|
||||
)
|
||||
})
|
||||
}
|
||||
<Descriptions.Item
|
||||
key={-1}
|
||||
className={styles.default}
|
||||
label={(
|
||||
<span className={styles.icon}></span>
|
||||
)}
|
||||
>
|
||||
{formatMessage({ id: 'license.feature.more' })}···
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
.features {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
padding: 12px;
|
||||
background-color: #f7f9fc;
|
||||
|
||||
:global {
|
||||
.ant-descriptions-title {
|
||||
text-align: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.ant-descriptions-row > th, .ant-descriptions-row > td {
|
||||
padding-bottom: 8px;
|
||||
vertical-align: top;
|
||||
|
||||
.ant-descriptions-item-content {
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.default {
|
||||
|
||||
:global {
|
||||
.ant-descriptions-item-content {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: #bbb;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.allow {
|
||||
:global {
|
||||
.ant-descriptions-item-content {
|
||||
color: #575757;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
background-color: #27b148;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background-color: #bbb;
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
vertical-align: 2px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
import styles from "./Licence.less";
|
||||
import { Icon, Input, Button, Descriptions, message } from "antd";
|
||||
import { forwardRef, useImperativeHandle, useEffect, useState } from "react";
|
||||
import { DATE_FORMAT } from ".";
|
||||
import moment from "moment";
|
||||
import request from "@/utils/request";
|
||||
import { formatMessage } from "umi/locale";
|
||||
import LicenceDesc from "./LicenceDesc";
|
||||
|
||||
export default ({ licence, onLicenceUpdate }, ref) => {
|
||||
const {
|
||||
license_type,
|
||||
license_id,
|
||||
issue_to = "-",
|
||||
issue_at,
|
||||
valid_from,
|
||||
expire_at,
|
||||
max_nodes = "-",
|
||||
} = licence || {};
|
||||
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
const [code, setCode] = useState();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const onUpdate = async () => {
|
||||
if (code) {
|
||||
setLoading(true);
|
||||
const res = await request(
|
||||
"/_license/apply",
|
||||
{
|
||||
method: "POST",
|
||||
body: { license: code },
|
||||
},
|
||||
undefined,
|
||||
false
|
||||
);
|
||||
if (res?.acknowledged) {
|
||||
message.success("Licence update succeeded.");
|
||||
setIsEdit(false);
|
||||
onLicenceUpdate();
|
||||
} else {
|
||||
message.error("Licence update failed.");
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
resetCode: () => {
|
||||
setIsEdit(false);
|
||||
setCode();
|
||||
},
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className={styles.licence}>
|
||||
<div className={styles.header}>
|
||||
<LicenceDesc licence={licence} />
|
||||
</div>
|
||||
<div className={styles.licenceBox}>
|
||||
{isEdit ? (
|
||||
<Input.TextArea
|
||||
rows={5}
|
||||
value={code}
|
||||
onChange={(e) => setCode(e.target.value)}
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
<div className={styles.edit}>
|
||||
<a onClick={() => setIsEdit(true)}>
|
||||
<Icon type="edit" />
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.footer}>
|
||||
<Button
|
||||
loading={loading}
|
||||
type="primary"
|
||||
size="small"
|
||||
onClick={onUpdate}
|
||||
>
|
||||
{formatMessage({ id: "license.button.update_license" })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -1,51 +0,0 @@
|
|||
.licence {
|
||||
.header {
|
||||
:global {
|
||||
.ant-descriptions-title {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.ant-descriptions-item {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.licenceBox {
|
||||
height: 133px;
|
||||
background-color: #f7f9fc;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
overflow-y: hidden;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: rgba(187, 187, 187, 1);
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
justify-self: center;
|
||||
align-items: center;
|
||||
|
||||
.edit {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin-top: 4px;
|
||||
|
||||
:global {
|
||||
.anticon {
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: right;
|
||||
margin-bottom: 16px;
|
||||
|
||||
:global {
|
||||
.ant-btn {
|
||||
padding: 0 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
import { Descriptions } from "antd";
|
||||
import { formatMessage } from "umi/locale";
|
||||
import { DATE_FORMAT } from ".";
|
||||
import moment from "moment";
|
||||
|
||||
export default ({ licence }) => {
|
||||
const {
|
||||
license_type,
|
||||
license_id,
|
||||
issue_to = "-",
|
||||
issue_at,
|
||||
valid_from,
|
||||
expire_at,
|
||||
max_nodes = "-",
|
||||
} = licence || {};
|
||||
|
||||
return (
|
||||
<Descriptions size="small" title="" column={1}>
|
||||
<Descriptions.Item
|
||||
label={formatMessage({ id: "license.label.license_type" })}
|
||||
>
|
||||
{license_type}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item
|
||||
label={formatMessage({ id: "license.label.max_nodes" })}
|
||||
>
|
||||
{max_nodes}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item
|
||||
label={formatMessage({ id: "license.label.issue_to" })}
|
||||
>
|
||||
{issue_to}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item
|
||||
label={formatMessage({ id: "license.label.issue_at" })}
|
||||
>
|
||||
{issue_at ? moment(issue_at).format(DATE_FORMAT) : "-"}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item
|
||||
label={formatMessage({ id: "license.label.expire_at" })}
|
||||
>
|
||||
{expire_at ? moment(expire_at).format(DATE_FORMAT) : "-"}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
);
|
||||
};
|
|
@ -1,60 +0,0 @@
|
|||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Icon, Result } from "antd";
|
||||
import moment from "moment";
|
||||
import styles from "./Tips.less";
|
||||
import Features from "./Features";
|
||||
import Buy from "./Buy";
|
||||
import { formatMessage } from "umi/locale";
|
||||
import { LICENCE_ROUTES } from ".";
|
||||
|
||||
export default (props) => {
|
||||
const licence = props.licence;
|
||||
const { license_type, expire_at } = licence;
|
||||
const needProLicense = LICENCE_ROUTES.some((item) =>
|
||||
props.location.pathname.includes(item)
|
||||
);
|
||||
|
||||
const renderHeader = () => {
|
||||
if (moment(expire_at).diff(moment(), "seconds") < 0) {
|
||||
return (
|
||||
<Result
|
||||
className={styles.content}
|
||||
status="error"
|
||||
title={formatMessage({ id: "license.tips.expired.title" })}
|
||||
subTitle={formatMessage({ id: "license.tips.expired.desc" })}
|
||||
icon={<Icon type="clock-circle" />}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
//pro Edition
|
||||
if (needProLicense) {
|
||||
return (
|
||||
<Result
|
||||
className={styles.content}
|
||||
status="warning"
|
||||
title={formatMessage({ id: "license.tips.pro.title" })}
|
||||
subTitle={formatMessage({ id: "license.tips.pro.desc" })}
|
||||
icon={<Icon type="sketch" />}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Result
|
||||
className={styles.content}
|
||||
status="error"
|
||||
title={formatMessage({ id: "license.tips.unlicensed.title" })}
|
||||
subTitle={formatMessage({ id: "license.tips.unlicensed.desc" })}
|
||||
icon={<Icon type="close-circle" />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.tips}>
|
||||
<div className={styles.header}>{renderHeader()}</div>
|
||||
<Features licence={licence} />
|
||||
<Buy trialVisible={!needProLicense} {...props} />
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -1,29 +0,0 @@
|
|||
.tips {
|
||||
.header {
|
||||
.content {
|
||||
padding: 8px 0px;
|
||||
|
||||
:global {
|
||||
.ant-result-icon {
|
||||
margin-bottom: 8px;
|
||||
.anticon {
|
||||
font-size: 34px;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-result-title {
|
||||
font-size: 18px;
|
||||
color: #101010;
|
||||
font-weight: 700;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.ant-result-subtitle {
|
||||
color: #5f5f5f;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
import { Descriptions } from "antd";
|
||||
import { Descriptions, Icon, Typography } from "antd";
|
||||
import moment from "moment";
|
||||
import styles from "./Version.less";
|
||||
import { DATE_FORMAT } from ".";
|
||||
import Features from "./Features";
|
||||
import Buy from "./Buy";
|
||||
import { formatMessage } from "umi/locale";
|
||||
import AGPL from "./AGPL";
|
||||
const { Paragraph, Text } = Typography;
|
||||
|
||||
export default ({ application, licence }) => {
|
||||
const { number, build_date, build_hash } = application?.version || {};
|
||||
|
@ -26,8 +26,29 @@ export default ({ application, licence }) => {
|
|||
<Descriptions.Item label="Hash">{build_hash}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</div>
|
||||
<Features licence={licence} />
|
||||
<Buy />
|
||||
<div style={{ margin: '10px 0', height: 217, overflow: 'hidden' }}>
|
||||
<Icon style={{ transform: 'scale(0.6)', position: 'relative', top: -70, left: -172 }} component={AGPL}/>
|
||||
</div>
|
||||
<div className={styles.licence}>
|
||||
<Paragraph>
|
||||
Copyright (C) INFINI Labs & INFINI LIMITED.
|
||||
</Paragraph>
|
||||
<Paragraph>The INFINI Console is offered under the GNU Affero General Public License v3.0 and as commercial software.</Paragraph>
|
||||
<Paragraph>
|
||||
For commercial licensing, contact us at:
|
||||
<ul>
|
||||
<li>Email: hello@infini.ltd</li>
|
||||
<li>Website: <a href="http://www.infinilabs.com" target="_blank">infinilabs.com</a></li>
|
||||
</ul>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
Open Source licensed under AGPL V3:
|
||||
<br />
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
</Paragraph>
|
||||
<Paragraph>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.</Paragraph>
|
||||
<Paragraph>{`You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.`}</Paragraph>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -10,4 +10,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.licence {
|
||||
word-break: break-all;
|
||||
p {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,86 +9,26 @@ import React, {
|
|||
import { Tabs, Modal } from "antd";
|
||||
import styles from "./index.less";
|
||||
import Version from "./Version";
|
||||
import Tips from "./Tips";
|
||||
import Licence from "./Licence";
|
||||
import moment from "moment";
|
||||
import { formatMessage } from "umi/locale";
|
||||
|
||||
export const DATE_FORMAT = "YYYY.MM.DD HH:mm";
|
||||
|
||||
export const LICENCE_ROUTES = ["/data_tools", "/alerting/channel"];
|
||||
export const LICENCE_NOOPEN_ROUTES = ["/", "/overview"];
|
||||
|
||||
export const FEATURES = [
|
||||
{ name: formatMessage({ id: "license.feature.multi_cluster_access" }) },
|
||||
{ name: formatMessage({ id: "license.feature.multi_cluster_manage" }) },
|
||||
{ name: formatMessage({ id: "license.feature.log_audit" }) },
|
||||
{ name: formatMessage({ id: "license.feature.query_analysis" }) },
|
||||
{ name: formatMessage({ id: "license.feature.visual_analysis" }) },
|
||||
{ name: formatMessage({ id: "license.feature.platform_monitoring" }) },
|
||||
{ name: formatMessage({ id: "license.feature.identity_control" }) },
|
||||
{
|
||||
name: formatMessage({ id: "license.feature.alarm_notification" }),
|
||||
route: "/alerting",
|
||||
},
|
||||
{
|
||||
name: formatMessage({ id: "license.feature.data_migration" }),
|
||||
route: "/data_tools",
|
||||
},
|
||||
{
|
||||
name: formatMessage({ id: "license.feature.data_backup" }),
|
||||
route: "/data_tools",
|
||||
},
|
||||
{
|
||||
name: formatMessage({ id: "license.feature.data_disaster_recovery" }),
|
||||
route: "/data_tools",
|
||||
},
|
||||
];
|
||||
|
||||
export const checkLicenceType = (licenceType, expireAt, isProEdition) => {
|
||||
if (isProEdition) {
|
||||
if (
|
||||
!licenceType ||
|
||||
licenceType === "UnLicensed" ||
|
||||
licenceType === "Free" ||
|
||||
!expireAt
|
||||
)
|
||||
return false;
|
||||
} else {
|
||||
if (!licenceType || licenceType === "UnLicensed" || !expireAt) return false;
|
||||
}
|
||||
|
||||
if (moment(expireAt).diff(moment(), "seconds") > 0) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
key: "version",
|
||||
title: formatMessage({ id: "license.tab.version.title" }),
|
||||
component: Version,
|
||||
},
|
||||
{
|
||||
key: "tips",
|
||||
title: formatMessage({ id: "license.tab.tips.title" }),
|
||||
component: Tips,
|
||||
},
|
||||
{
|
||||
key: "licence",
|
||||
title: formatMessage({ id: "license.tab.license.title" }),
|
||||
component: Licence,
|
||||
},
|
||||
];
|
||||
|
||||
export default forwardRef((props, ref) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [isTips, setIsTips] = useState(false);
|
||||
const triggerTimeRef = useRef(null);
|
||||
const tabRef = useRef(null);
|
||||
|
||||
const {
|
||||
location: { pathname },
|
||||
licence: { license_type, expire_at, loading },
|
||||
} = props;
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
|
@ -96,63 +36,18 @@ export default forwardRef((props, ref) => {
|
|||
close: onClose,
|
||||
}));
|
||||
|
||||
const onOpen = (isTips) => {
|
||||
const onOpen = () => {
|
||||
const isFirstLogin = localStorage.getItem("first-login");
|
||||
if (isFirstLogin !== "true") {
|
||||
setIsTips(isTips);
|
||||
setVisible(true);
|
||||
}
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
setIsTips();
|
||||
setVisible();
|
||||
if (tabRef.current.resetCode) tabRef.current.resetCode();
|
||||
};
|
||||
|
||||
const checkRoutes = (license_type, expire_at, is_pro) => {
|
||||
if (checkLicenceType(license_type, expire_at, is_pro)) {
|
||||
return;
|
||||
}
|
||||
if (triggerTimeRef.current) {
|
||||
const now = moment();
|
||||
if (now.diff(triggerTimeRef.current, "seconds") > 60) {
|
||||
//未授权时每1分钟弹窗提示
|
||||
onOpen(true);
|
||||
triggerTimeRef.current = now;
|
||||
}
|
||||
} else {
|
||||
onOpen(true);
|
||||
triggerTimeRef.current = moment();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
//home overview do not open license window
|
||||
if (LICENCE_NOOPEN_ROUTES.includes(props.location.pathname)) {
|
||||
return;
|
||||
}
|
||||
if (LICENCE_ROUTES.some((item) => props.location.pathname.includes(item))) {
|
||||
//pro Edition
|
||||
checkRoutes(license_type, expire_at, true);
|
||||
} else {
|
||||
//all routes check(except pro Edition)
|
||||
checkRoutes(license_type, expire_at);
|
||||
}
|
||||
}, [pathname, license_type, expire_at, loading]);
|
||||
|
||||
const formatTabs = useMemo(() => {
|
||||
return tabs.filter((item) => {
|
||||
if (isTips && item.key === "version") return false;
|
||||
if (!isTips && item.key === "tips") return false;
|
||||
return true;
|
||||
});
|
||||
}, [isTips]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
|
@ -161,10 +56,10 @@ export default forwardRef((props, ref) => {
|
|||
footer={null}
|
||||
onCancel={onClose}
|
||||
destroyOnClose
|
||||
width={560}
|
||||
width={580}
|
||||
>
|
||||
<Tabs defaultActiveKey="version">
|
||||
{formatTabs.map((item) => (
|
||||
{tabs.map((item) => (
|
||||
<Tabs.TabPane tab={item.title} key={item.key}>
|
||||
<div className={styles.content}>
|
||||
{item.component({ ...props, onClose }, tabRef)}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
:global {
|
||||
|
||||
.ant-modal-body {
|
||||
padding: 20px 0 0 0;
|
||||
padding: 0px 0 0 0;
|
||||
|
||||
.ant-tabs-top-bar {
|
||||
justify-content: center;
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Menu, Icon } from 'antd';
|
|||
import styles from './BottomMenu.less';
|
||||
import Debounce from "lodash-decorators/debounce";
|
||||
import Licence from "@/components/Licence";
|
||||
import { formatMessage } from "umi/locale";
|
||||
|
||||
export default class BottomMenu extends PureComponent {
|
||||
|
||||
|
@ -23,7 +24,7 @@ export default class BottomMenu extends PureComponent {
|
|||
|
||||
const { theme, collapsed, global: { consoleInfo = {}, consoleLicence = {} }, onLicenceShow } = this.props;
|
||||
|
||||
const text = `${consoleLicence.license_type} (${consoleInfo?.application?.version?.number})`
|
||||
const text = `${formatMessage({ id: "license.menu.label" })} (${consoleInfo?.application?.version?.number})`
|
||||
|
||||
return (
|
||||
<div className={styles.bottomMenu}>
|
||||
|
|
|
@ -166,8 +166,6 @@ class BasicLayout extends React.PureComponent {
|
|||
type: "global/fetchConsoleInfo",
|
||||
});
|
||||
|
||||
this.fetchConsoleLicence();
|
||||
|
||||
this.renderRef = requestAnimationFrame(() => {
|
||||
this.setState({
|
||||
rendering: false,
|
||||
|
@ -339,13 +337,6 @@ class BasicLayout extends React.PureComponent {
|
|||
return <SettingDrawer />;
|
||||
}
|
||||
|
||||
fetchConsoleLicence = () => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch({
|
||||
type: "global/fetchConsoleLicence",
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
this.init();
|
||||
|
||||
|
@ -437,7 +428,6 @@ class BasicLayout extends React.PureComponent {
|
|||
version={this.props.global.consoleInfo?.application}
|
||||
licence={this.props.global.consoleLicence}
|
||||
location={this.props.location}
|
||||
onLicenceUpdate={this.fetchConsoleLicence}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
|
|
@ -310,7 +310,7 @@ export default {
|
|||
"menu.header.help.official_website": "Official website",
|
||||
"menu.header.help.release_notes": "Release notes",
|
||||
"menu.header.help.document": "Documentation",
|
||||
"menu.header.help.ticket": "Request support",
|
||||
"menu.header.help.ticket": "Report issue",
|
||||
|
||||
"app.message.operate.success": "Operate successfully",
|
||||
"app.message.operate.failed": "Operate failure",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export default {
|
||||
"license.menu.label": "About",
|
||||
"license.tab.version.title": "Version",
|
||||
"license.tab.tips.title": "License Tips",
|
||||
"license.tab.license.title": "License",
|
||||
|
|
|
@ -315,7 +315,7 @@ export default {
|
|||
"menu.header.help.official_website": "官方网站",
|
||||
"menu.header.help.release_notes": "更新日志",
|
||||
"menu.header.help.document": "产品文档",
|
||||
"menu.header.help.ticket": "提交工单",
|
||||
"menu.header.help.ticket": "提交问题",
|
||||
|
||||
"app.message.operate.success": "操作成功",
|
||||
"app.message.operate.failed": "操作失败",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export default {
|
||||
"license.menu.label": "关于",
|
||||
"license.tab.version.title": "版本信息",
|
||||
"license.tab.tips.title": "授权提示",
|
||||
"license.tab.license.title": "授权信息",
|
||||
|
|
|
@ -2,7 +2,6 @@ import {
|
|||
queryNotices,
|
||||
clearNotices,
|
||||
queryConsoleInfo,
|
||||
queryConsoleLicence,
|
||||
} from "@/services/api";
|
||||
import { message } from "antd";
|
||||
import { searchClusterConfig, getClusterStatus } from "@/services/cluster";
|
||||
|
@ -291,14 +290,6 @@ export default {
|
|||
payload: data,
|
||||
});
|
||||
},
|
||||
|
||||
*fetchConsoleLicence(_, { call, put }) {
|
||||
const data = yield call(queryConsoleLicence);
|
||||
yield put({
|
||||
type: "saveConsoleLicence",
|
||||
payload: data || {},
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
reducers: {
|
||||
|
|
|
@ -5,10 +5,6 @@ export async function queryConsoleInfo() {
|
|||
return request("/_info");
|
||||
}
|
||||
|
||||
export async function queryConsoleLicence() {
|
||||
return request("/_license/info");
|
||||
}
|
||||
|
||||
export async function queryProjectNotice() {
|
||||
return request("/api/project/notice");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue