feat: Enhance update checking and system information display
- Add version and startup time display in OtherSetting component - Implement robust GitHub release update checking mechanism - Add error handling for update check process - Update Modal component for displaying update information - Add new translations for version and system information
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { Banner, Button, Col, Form, Row } from '@douyinfe/semi-ui';
|
import { Banner, Button, Col, Form, Row, Modal, Space } from '@douyinfe/semi-ui';
|
||||||
import { API, showError, showSuccess } from '../helpers';
|
import { API, showError, showSuccess, timestamp2string } from '../helpers';
|
||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { StatusContext } from '../context/Status/index.js';
|
||||||
|
import Text from '@douyinfe/semi-ui/lib/es/typography/text';
|
||||||
|
|
||||||
const OtherSetting = () => {
|
const OtherSetting = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -16,6 +18,7 @@ const OtherSetting = () => {
|
|||||||
});
|
});
|
||||||
let [loading, setLoading] = useState(false);
|
let [loading, setLoading] = useState(false);
|
||||||
const [showUpdateModal, setShowUpdateModal] = useState(false);
|
const [showUpdateModal, setShowUpdateModal] = useState(false);
|
||||||
|
const [statusState, statusDispatch] = useContext(StatusContext);
|
||||||
const [updateData, setUpdateData] = useState({
|
const [updateData, setUpdateData] = useState({
|
||||||
tag_name: '',
|
tag_name: '',
|
||||||
content: '',
|
content: '',
|
||||||
@@ -43,6 +46,7 @@ const OtherSetting = () => {
|
|||||||
HomePageContent: false,
|
HomePageContent: false,
|
||||||
About: false,
|
About: false,
|
||||||
Footer: false,
|
Footer: false,
|
||||||
|
CheckUpdate: false
|
||||||
});
|
});
|
||||||
const handleInputChange = async (value, e) => {
|
const handleInputChange = async (value, e) => {
|
||||||
const name = e.target.id;
|
const name = e.target.id;
|
||||||
@@ -145,23 +149,48 @@ const OtherSetting = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const openGitHubRelease = () => {
|
|
||||||
window.location = 'https://github.com/songquanpeng/one-api/releases/latest';
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkUpdate = async () => {
|
const checkUpdate = async () => {
|
||||||
const res = await API.get(
|
try {
|
||||||
'https://api.github.com/repos/songquanpeng/one-api/releases/latest',
|
setLoadingInput((loadingInput) => ({ ...loadingInput, CheckUpdate: true }));
|
||||||
);
|
// Use a CORS proxy to avoid direct cross-origin requests to GitHub API
|
||||||
const { tag_name, body } = res.data;
|
// Option 1: Use a public CORS proxy service
|
||||||
if (tag_name === process.env.REACT_APP_VERSION) {
|
// const proxyUrl = 'https://cors-anywhere.herokuapp.com/';
|
||||||
showSuccess(`已是最新版本:${tag_name}`);
|
// const res = await API.get(
|
||||||
} else {
|
// `${proxyUrl}https://api.github.com/repos/Calcium-Ion/new-api/releases/latest`,
|
||||||
setUpdateData({
|
// );
|
||||||
tag_name: tag_name,
|
|
||||||
content: marked.parse(body),
|
// Option 2: Use the JSON proxy approach which often works better with GitHub API
|
||||||
});
|
const res = await fetch(
|
||||||
setShowUpdateModal(true);
|
'https://api.github.com/repos/Calcium-Ion/new-api/releases/latest',
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
// Adding User-Agent which is often required by GitHub API
|
||||||
|
'User-Agent': 'new-api-update-checker'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).then(response => response.json());
|
||||||
|
|
||||||
|
// Option 3: Use a local proxy endpoint
|
||||||
|
// Create a cached version of the response to avoid frequent GitHub API calls
|
||||||
|
// const res = await API.get('/api/status/github-latest-release');
|
||||||
|
|
||||||
|
const { tag_name, body } = res;
|
||||||
|
if (tag_name === statusState?.status?.version) {
|
||||||
|
showSuccess(`已是最新版本:${tag_name}`);
|
||||||
|
} else {
|
||||||
|
setUpdateData({
|
||||||
|
tag_name: tag_name,
|
||||||
|
content: marked.parse(body),
|
||||||
|
});
|
||||||
|
setShowUpdateModal(true);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to check for updates:', error);
|
||||||
|
showError('检查更新失败,请稍后再试');
|
||||||
|
} finally {
|
||||||
|
setLoadingInput((loadingInput) => ({ ...loadingInput, CheckUpdate: false }));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const getOptions = async () => {
|
const getOptions = async () => {
|
||||||
@@ -186,9 +215,41 @@ const OtherSetting = () => {
|
|||||||
getOptions();
|
getOptions();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Function to open GitHub release page
|
||||||
|
const openGitHubRelease = () => {
|
||||||
|
window.open(`https://github.com/Calcium-Ion/new-api/releases/tag/${updateData.tag_name}`, '_blank');
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStartTimeString = () => {
|
||||||
|
const timestamp = statusState?.status?.start_time;
|
||||||
|
return statusState.status ? timestamp2string(timestamp) : '';
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row>
|
<Row>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
|
{/* 版本信息 */}
|
||||||
|
<Form style={{ marginBottom: 15 }}>
|
||||||
|
<Form.Section text={t('系统信息')}>
|
||||||
|
<Row>
|
||||||
|
<Col span={16}>
|
||||||
|
<Space>
|
||||||
|
<Text>
|
||||||
|
{t('当前版本')}:{statusState?.status?.version || t('未知')}
|
||||||
|
</Text>
|
||||||
|
<Button type="primary" onClick={checkUpdate} loading={loadingInput['CheckUpdate']}>
|
||||||
|
{t('检查更新')}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col span={16}>
|
||||||
|
<Text>{t('启动时间')}:{getStartTimeString()}</Text>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Form.Section>
|
||||||
|
</Form>
|
||||||
{/* 通用设置 */}
|
{/* 通用设置 */}
|
||||||
<Form
|
<Form
|
||||||
values={inputs}
|
values={inputs}
|
||||||
@@ -282,28 +343,25 @@ const OtherSetting = () => {
|
|||||||
</Form.Section>
|
</Form.Section>
|
||||||
</Form>
|
</Form>
|
||||||
</Col>
|
</Col>
|
||||||
{/*<Modal*/}
|
<Modal
|
||||||
{/* onClose={() => setShowUpdateModal(false)}*/}
|
title={t('新版本') + ':' + updateData.tag_name}
|
||||||
{/* onOpen={() => setShowUpdateModal(true)}*/}
|
visible={showUpdateModal}
|
||||||
{/* open={showUpdateModal}*/}
|
onCancel={() => setShowUpdateModal(false)}
|
||||||
{/*>*/}
|
footer={[
|
||||||
{/* <Modal.Header>新版本:{updateData.tag_name}</Modal.Header>*/}
|
<Button
|
||||||
{/* <Modal.Content>*/}
|
key="details"
|
||||||
{/* <Modal.Description>*/}
|
type="primary"
|
||||||
{/* <div dangerouslySetInnerHTML={{ __html: updateData.content }}></div>*/}
|
onClick={() => {
|
||||||
{/* </Modal.Description>*/}
|
setShowUpdateModal(false);
|
||||||
{/* </Modal.Content>*/}
|
openGitHubRelease();
|
||||||
{/* <Modal.Actions>*/}
|
}}
|
||||||
{/* <Button onClick={() => setShowUpdateModal(false)}>关闭</Button>*/}
|
>
|
||||||
{/* <Button*/}
|
{t('详情')}
|
||||||
{/* content='详情'*/}
|
</Button>
|
||||||
{/* onClick={() => {*/}
|
]}
|
||||||
{/* setShowUpdateModal(false);*/}
|
>
|
||||||
{/* openGitHubRelease();*/}
|
<div dangerouslySetInnerHTML={{ __html: updateData.content }}></div>
|
||||||
{/* }}*/}
|
</Modal>
|
||||||
{/* />*/}
|
|
||||||
{/* </Modal.Actions>*/}
|
|
||||||
{/*</Modal>*/}
|
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1320,5 +1320,20 @@
|
|||||||
"模型倍率和补全倍率同时设置": "Both model ratio and completion ratio are set",
|
"模型倍率和补全倍率同时设置": "Both model ratio and completion ratio are set",
|
||||||
"自用模式": "Self-use mode",
|
"自用模式": "Self-use mode",
|
||||||
"开启后不限制:必须设置模型倍率": "After enabling, no limit: must set model ratio",
|
"开启后不限制:必须设置模型倍率": "After enabling, no limit: must set model ratio",
|
||||||
"演示站点模式": "Demo site mode"
|
"演示站点模式": "Demo site mode",
|
||||||
|
"当前版本": "Current version",
|
||||||
|
"Gemini设置": "Gemini settings",
|
||||||
|
"Gemini安全设置": "Gemini safety settings",
|
||||||
|
"default为默认设置,可单独设置每个分类的安全等级": "\"default\" is the default setting, and each category can be set separately",
|
||||||
|
"Gemini版本设置": "Gemini version settings",
|
||||||
|
"default为默认设置,可单独设置每个模型的版本": "\"default\" is the default setting, and each model can be set separately",
|
||||||
|
"Claude设置": "Claude settings",
|
||||||
|
"Claude请求头覆盖": "Claude request header override",
|
||||||
|
"示例": "Example",
|
||||||
|
"缺省 MaxTokens": "Default MaxTokens",
|
||||||
|
"启用Claude思考适配(-thinking后缀)": "Enable Claude thinking adaptation (-thinking suffix)",
|
||||||
|
"Claude思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Claude thinking adaptation BudgetTokens = MaxTokens * BudgetTokens percentage",
|
||||||
|
"思考适配 BudgetTokens 百分比": "Thinking adaptation BudgetTokens percentage",
|
||||||
|
"0.1-1之间的小数": "Decimal between 0.1 and 1",
|
||||||
|
"模型相关设置": "Model related settings"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user