系统设置增加依赖代理和镜像设置

This commit is contained in:
whyour 2023-11-25 21:49:33 +08:00
parent 9b7d4cb8fe
commit 3777a4e7b4
13 changed files with 455 additions and 156 deletions

View File

@ -6,7 +6,6 @@ import config from '../config';
import SystemService from '../services/system';
import { celebrate, Joi } from 'celebrate';
import UserService from '../services/user';
import { EnvModel } from '../data/env';
import {
getUniqPath,
handleLogPath,
@ -78,18 +77,16 @@ export default (app: Router) => {
);
route.put(
'/config',
'/config/log-remove-frequency',
celebrate({
body: Joi.object({
logRemoveFrequency: Joi.number().optional().allow(null),
cronConcurrency: Joi.number().optional().allow(null),
logRemoveFrequency: Joi.number().allow(null),
}),
}),
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
const systemService = Container.get(SystemService);
const result = await systemService.updateSystemConfig(req.body);
const result = await systemService.updateLogRemoveFrequency(req.body);
res.send(result);
} catch (e) {
return next(e);
@ -97,6 +94,96 @@ export default (app: Router) => {
},
);
route.put(
'/config/cron-concurrency',
celebrate({
body: Joi.object({
cronConcurrency: Joi.number().allow(null),
}),
}),
async (req: Request, res: Response, next: NextFunction) => {
try {
const systemService = Container.get(SystemService);
const result = await systemService.updateCronConcurrency(req.body);
res.send(result);
} catch (e) {
return next(e);
}
},
);
route.put(
'/config/dependence-proxy',
celebrate({
body: Joi.object({
dependenceProxy: Joi.string().allow('').allow(null),
}),
}),
async (req: Request, res: Response, next: NextFunction) => {
try {
const systemService = Container.get(SystemService);
const result = await systemService.updateDependenceProxy(req.body);
res.send(result);
} catch (e) {
return next(e);
}
},
);
route.put(
'/config/node-mirror',
celebrate({
body: Joi.object({
nodeMirror: Joi.string().allow('').allow(null),
}),
}),
async (req: Request, res: Response, next: NextFunction) => {
try {
const systemService = Container.get(SystemService);
res.setHeader('Content-type', 'application/octet-stream');
await systemService.updateNodeMirror(req.body, res);
} catch (e) {
return next(e);
}
},
);
route.put(
'/config/python-mirror',
celebrate({
body: Joi.object({
pythonMirror: Joi.string().allow('').allow(null),
}),
}),
async (req: Request, res: Response, next: NextFunction) => {
try {
const systemService = Container.get(SystemService);
const result = await systemService.updatePythonMirror(req.body);
res.send(result);
} catch (e) {
return next(e);
}
},
);
route.put(
'/config/linux-mirror',
celebrate({
body: Joi.object({
linuxMirror: Joi.string().allow('').allow(null),
}),
}),
async (req: Request, res: Response, next: NextFunction) => {
try {
const systemService = Container.get(SystemService);
res.setHeader('Content-type', 'application/octet-stream');
await systemService.updateLinuxMirror(req.body, res);
} catch (e) {
return next(e);
}
},
);
route.put(
'/update-check',
async (req: Request, res: Response, next: NextFunction) => {

View File

@ -47,6 +47,7 @@ const configString = 'config sample crontab shareCode diy';
const versionFile = path.join(rootPath, 'version.yaml');
const dataTgzFile = path.join(tmpPath, 'data.tgz');
const shareShellFile = path.join(shellPath, 'share.sh');
const dependenceProxyFile = path.join(configPath, 'dependence-proxy.sh');
if (envFound.error) {
throw new Error("⚠️ Couldn't find .env file ⚠️");
@ -68,6 +69,7 @@ export default {
dataPath,
dataTgzFile,
shareShellFile,
dependenceProxyFile,
configString,
loginFaild,
authError,
@ -89,6 +91,7 @@ export default {
'config.sh.sample',
'cookie.sh',
'crontab.list',
'dependence-proxy.sh',
'env.sh',
'token.json',
],

View File

@ -496,4 +496,4 @@ export async function rmPath(path: string) {
} catch (error) {
Logger.error('[rmPath失败]', error)
}
}
}

View File

@ -14,7 +14,7 @@ import {
import { spawn } from 'cross-spawn';
import SockService from './sock';
import { FindOptions, Op } from 'sequelize';
import { promiseExecSuccess } from '../config/util';
import { fileExist, promiseExecSuccess } from '../config/util';
import dayjs from 'dayjs';
import taskLimit from '../shared/pLimit';
@ -252,10 +252,18 @@ export default class DependenceService {
return resolve(null);
}
}
const cp = spawn(`${depRunCommand} ${dependency.name.trim()}`, {
shell: '/bin/bash',
});
const dependenceProxyFileExist = await fileExist(
config.dependenceProxyFile,
);
const proxyStr = dependenceProxyFileExist
? `pnpm config get registry && source ${config.dependenceProxyFile} &&`
: '';
const cp = spawn(
`${proxyStr} ${depRunCommand} ${dependency.name.trim()}`,
{
shell: '/bin/bash',
},
);
cp.stdout.on('data', async (data) => {
this.sockService.sendMessage({

View File

@ -75,31 +75,140 @@ export default class SystemService {
}
}
public async updateSystemConfig(info: SystemModelInfo) {
public async updateLogRemoveFrequency(info: SystemModelInfo) {
const oDoc = await this.getSystemConfig();
const result = await this.updateAuthDb({
...oDoc,
info,
info: { ...oDoc.info, ...info },
});
if (info.logRemoveFrequency) {
const cron = {
id: result.id || NaN,
name: '删除日志',
command: `ql rmlog ${info.logRemoveFrequency}`,
};
const cron = {
id: result.id || NaN,
name: '删除日志',
command: `ql rmlog ${info.logRemoveFrequency}`,
};
if (oDoc.info?.logRemoveFrequency) {
await this.scheduleService.cancelIntervalTask(cron);
if (info.logRemoveFrequency > 0) {
this.scheduleService.createIntervalTask(cron, {
days: info.logRemoveFrequency,
});
}
}
if (info.logRemoveFrequency && info.logRemoveFrequency > 0) {
this.scheduleService.createIntervalTask(cron, {
days: info.logRemoveFrequency,
});
}
return { code: 200, data: info };
}
public async updateCronConcurrency(info: SystemModelInfo) {
const oDoc = await this.getSystemConfig();
await this.updateAuthDb({
...oDoc,
info: { ...oDoc.info, ...info },
});
if (info.cronConcurrency) {
await taskLimit.setCustomLimit(info.cronConcurrency);
}
return { code: 200, data: info };
}
public async updateDependenceProxy(info: SystemModelInfo) {
const oDoc = await this.getSystemConfig();
await this.updateAuthDb({
...oDoc,
info: { ...oDoc.info, ...info },
});
if (info.dependenceProxy) {
await fs.promises.writeFile(
config.dependenceProxyFile,
`export http_proxy="${info.dependenceProxy}"\nexport https_proxy="${info.dependenceProxy}"`,
);
} else {
await fs.promises.rm(config.dependenceProxyFile);
}
return { code: 200, data: info };
}
public async updateNodeMirror(info: SystemModelInfo, res: Response) {
const oDoc = await this.getSystemConfig();
await this.updateAuthDb({
...oDoc,
info: { ...oDoc.info, ...info },
});
let cmd = 'pnpm config delete registry';
if (info.nodeMirror) {
cmd = `pnpm config set registry ${info.nodeMirror}`;
}
const command = `cd && ${cmd} && pnpm i -g`;
this.scheduleService.runTask(
command,
{
onStart: async (cp) => {
res.setHeader('QL-Task-Pid', `${cp.pid}`);
},
onEnd: async () => {
res.end();
},
onError: async (message: string) => {
res.write(`\n${message}`);
},
onLog: async (message: string) => {
res.write(`\n${message}`);
},
},
{
command,
},
);
}
public async updatePythonMirror(info: SystemModelInfo) {
const oDoc = await this.getSystemConfig();
await this.updateAuthDb({
...oDoc,
info: { ...oDoc.info, ...info },
});
let cmd = 'pip config unset global.index-url';
if (info.pythonMirror) {
cmd = `pip3 config set global.index-url ${info.pythonMirror}`;
}
await promiseExec(cmd);
return { code: 200, data: info };
}
public async updateLinuxMirror(info: SystemModelInfo, res: Response) {
const oDoc = await this.getSystemConfig();
await this.updateAuthDb({
...oDoc,
info: { ...oDoc.info, ...info },
});
let targetDomain = 'dl-cdn.alpinelinux.org';
if (info.linuxMirror) {
targetDomain = info.linuxMirror;
}
const command = `sed -i 's/${
oDoc.info?.linuxMirror || 'dl-cdn.alpinelinux.org'
}/${targetDomain}/g' /etc/apk/repositories && apk update -f`;
this.scheduleService.runTask(
command,
{
onStart: async (cp) => {
res.setHeader('QL-Task-Pid', `${cp.pid}`);
},
onEnd: async () => {
res.end();
},
onError: async (message: string) => {
res.write(`\n${message}`);
},
onLog: async (message: string) => {
res.write(`\n${message}`);
},
},
{
command,
},
);
}
public async checkUpdate() {
try {
const currentVersionContent = await parseVersion(config.versionFile);

View File

@ -86,7 +86,6 @@
"p-queue-cjs": "7.3.4",
"protobufjs": "^7.2.3",
"pstree.remy": "^1.1.8",
"react-hotkeys-hook": "^4.4.1",
"reflect-metadata": "^0.1.13",
"sequelize": "^6.25.5",
"serve-handler": "^6.1.3",
@ -140,10 +139,11 @@
"axios": "^1.4.0",
"compression-webpack-plugin": "9.2.0",
"concurrently": "^7.0.0",
"react-hotkeys-hook": "^4.4.1",
"file-saver": "^2.0.5",
"lint-staged": "^13.0.3",
"monaco-editor": "0.33.0",
"nodemon": "^2.0.15",
"nodemon": "^3.0.1",
"prettier": "^2.5.1",
"qiniu": "^7.4.0",
"qrcode.react": "^1.0.1",

View File

@ -1,9 +1,5 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
'@grpc/grpc-js':
specifier: ^1.8.13
@ -98,9 +94,6 @@ dependencies:
pstree.remy:
specifier: ^1.1.8
version: 1.1.8
react-hotkeys-hook:
specifier: ^4.4.1
version: 4.4.1(react-dom@18.2.0)(react@18.2.0)
reflect-metadata:
specifier: ^0.1.13
version: 0.1.13
@ -266,8 +259,8 @@ devDependencies:
specifier: 0.33.0
version: 0.33.0
nodemon:
specifier: ^2.0.15
version: 2.0.22
specifier: ^3.0.1
version: 3.0.1
prettier:
specifier: ^2.5.1
version: 2.8.8
@ -304,6 +297,9 @@ devDependencies:
react-dom:
specifier: 18.2.0
version: 18.2.0(react@18.2.0)
react-hotkeys-hook:
specifier: ^4.4.1
version: 4.4.1(react-dom@18.2.0)(react@18.2.0)
react-intl-universal:
specifier: ^2.6.21
version: 2.6.21(react@18.2.0)
@ -4139,7 +4135,7 @@ packages:
requiresBuild: true
dependencies:
'@gar/promisify': 1.1.3
semver: 7.5.1
semver: 7.5.4
dev: false
optional: true
@ -5182,7 +5178,7 @@ packages:
ignore: 5.2.4
natural-compare-lite: 1.4.0
regexpp: 3.2.0
semver: 7.5.1
semver: 7.5.4
tsutils: 3.21.0(typescript@5.2.2)
typescript: 5.2.2
transitivePeerDependencies:
@ -5273,7 +5269,7 @@ packages:
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
semver: 7.5.1
semver: 7.5.4
tsutils: 3.21.0(typescript@5.2.2)
typescript: 5.2.2
transitivePeerDependencies:
@ -5294,7 +5290,7 @@ packages:
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
semver: 7.5.1
semver: 7.5.4
tsutils: 3.21.0(typescript@5.2.2)
typescript: 5.2.2
transitivePeerDependencies:
@ -5318,7 +5314,7 @@ packages:
eslint: 8.35.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0(eslint@8.35.0)
semver: 7.5.1
semver: 7.5.4
transitivePeerDependencies:
- supports-color
- typescript
@ -5341,7 +5337,7 @@ packages:
'@typescript-eslint/typescript-estree': 5.59.9(typescript@5.2.2)
eslint: 8.35.0
eslint-scope: 5.1.1
semver: 7.5.1
semver: 7.5.4
transitivePeerDependencies:
- supports-color
- typescript
@ -7717,7 +7713,7 @@ packages:
postcss-modules-scope: 3.0.0(postcss@8.4.24)
postcss-modules-values: 4.0.0(postcss@8.4.24)
postcss-value-parser: 4.2.0
semver: 7.5.1
semver: 7.5.4
webpack: 5.85.1
dev: true
@ -9053,7 +9049,7 @@ packages:
minimatch: 3.1.2
node-abort-controller: 3.1.1
schema-utils: 3.1.2
semver: 7.5.1
semver: 7.5.4
tapable: 2.2.1
typescript: 5.2.2
webpack: 5.85.1
@ -10291,6 +10287,7 @@ packages:
/js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: true
/js-yaml@3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
@ -10745,6 +10742,7 @@ packages:
hasBin: true
dependencies:
js-tokens: 4.0.0
dev: true
/lower-case@2.0.2:
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
@ -11323,9 +11321,9 @@ packages:
engines: {node: '>=6.0.0'}
dev: false
/nodemon@2.0.22:
resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==}
engines: {node: '>=8.10.0'}
/nodemon@3.0.1:
resolution: {integrity: sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==}
engines: {node: '>=10'}
hasBin: true
dependencies:
chokidar: 3.5.3
@ -11333,8 +11331,8 @@ packages:
ignore-by-default: 1.0.1
minimatch: 3.1.2
pstree.remy: 1.1.8
semver: 5.7.1
simple-update-notifier: 1.1.0
semver: 7.5.4
simple-update-notifier: 2.0.0
supports-color: 5.5.0
touch: 3.1.0
undefsafe: 2.0.5
@ -11370,7 +11368,7 @@ packages:
dependencies:
hosted-git-info: 4.1.0
is-core-module: 2.12.1
semver: 7.5.1
semver: 7.5.4
validate-npm-package-license: 3.0.4
dev: true
@ -13705,6 +13703,7 @@ packages:
loose-envify: 1.4.0
react: 18.2.0
scheduler: 0.23.0
dev: true
/react-easy-crop@4.7.4(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-oDi1375Jo/zuPUvo3oauxnNbfy8L4wsbmHD1KB2vT55fdgu+q8/K0w/rDWzy9jz4jfQ94Q9+3Yu366sDDFVmiA==}
@ -13784,7 +13783,7 @@ packages:
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
dev: true
/react-intl-universal@2.6.21(react@18.2.0):
resolution: {integrity: sha512-JJqZMzdB6jd4f0NfGRc9XM/pZElxtrDCWC9pE2yIesDO70SL+jQgaFAucQmstPwYqCcjvLpCgOrjP7cIo4kJnw==}
@ -14002,6 +14001,7 @@ packages:
engines: {node: '>=0.10.0'}
dependencies:
loose-envify: 1.4.0
dev: true
/reactcss@1.2.3(react@18.2.0):
resolution: {integrity: sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==}
@ -14362,6 +14362,7 @@ packages:
resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
dependencies:
loose-envify: 1.4.0
dev: true
/schema-utils@3.1.2:
resolution: {integrity: sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==}
@ -14405,17 +14406,20 @@ packages:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
/semver@7.0.0:
resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==}
hasBin: true
dev: true
/semver@7.5.1:
resolution: {integrity: sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==}
engines: {node: '>=10'}
hasBin: true
dependencies:
lru-cache: 6.0.0
dev: false
/semver@7.5.4:
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
engines: {node: '>=10'}
hasBin: true
dependencies:
lru-cache: 6.0.0
/send@0.18.0:
resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
@ -14597,11 +14601,11 @@ packages:
is-arrayish: 0.3.2
dev: false
/simple-update-notifier@1.1.0:
resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==}
engines: {node: '>=8.10.0'}
/simple-update-notifier@2.0.0:
resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
engines: {node: '>=10'}
dependencies:
semver: 7.0.0
semver: 7.5.4
dev: true
/single-spa@5.9.4:
@ -16388,3 +16392,7 @@ packages:
- encoding
- supports-color
dev: false
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false

View File

@ -472,7 +472,7 @@
"Python 软件包镜像源": "Python Software Package Mirror Source",
"Linux 软件包镜像源": "Linux Software Package Mirror Source",
"代理与镜像源二选一即可": "Either Proxy or Mirror Source can be chosen",
"代理地址, 支持HTTP(S)/SOCK5": "Proxy Address, supports HTTP(S)/SOCK5",
"代理地址, 支持HTTP(S)/SOCK5, ip:port": "Proxy Address, supports HTTP(S)/SOCK5, ip:port",
"NPM 镜像源": "NPM Mirror Source",
"PyPI 镜像源": "PyPI Mirror Source",
"alpine linux 镜像源": "Alpine Linux Mirror Source"

View File

@ -472,7 +472,7 @@
"Python 软件包镜像源": "Python 软件包镜像源",
"Linux 软件包镜像源": "Linux 软件包镜像源",
"代理与镜像源二选一即可": "代理与镜像源二选一即可",
"代理地址, 支持HTTP(S)/SOCK5": "代理地址, 支持HTTP(S)/SOCK5",
"代理地址, 支持HTTP(S)/SOCK5, ip:port": "代理地址, 支持HTTP(S)/SOCK5, ip:port",
"NPM 镜像源": "NPM 镜像源",
"PyPI 镜像源": "PyPI 镜像源",
"alpine linux 镜像源": "alpine linux 镜像源"

View File

@ -15,6 +15,7 @@ import CodeMirror from '@uiw/react-codemirror';
import { useOutletContext } from '@umijs/max';
import { SharedContext } from '@/layouts';
import { langs } from '@uiw/codemirror-extensions-langs';
import { useHotkeys } from 'react-hotkeys-hook';
const Config = () => {
const { headerStyle, isPhone, theme } = useOutletContext<SharedContext>();
@ -68,6 +69,14 @@ const Config = () => {
getConfig(node.value);
};
useHotkeys(
'meta+s',
(e) => {
updateConfig();
},
{ enableOnFormTags: ['textarea'], preventDefault: true },
);
useEffect(() => {
getFiles();
getConfig('config.sh');

View File

@ -4,6 +4,15 @@ import { Button, InputNumber, Form, message, Input, Alert } from 'antd';
import config from '@/utils/config';
import { request } from '@/utils/http';
import './index.less';
import Ansi from 'ansi-to-react';
import pick from 'lodash/pick';
const dataMap = {
'dependence-proxy': 'dependenceProxy',
'node-mirror': 'nodeMirror',
'python-mirror': 'pythonMirror',
'linux-mirror': 'linuxMirror',
};
const Dependence = () => {
const [systemConfig, setSystemConfig] = useState<{
@ -13,6 +22,7 @@ const Dependence = () => {
linuxMirror?: string;
}>();
const [form] = Form.useForm();
const [log, setLog] = useState<string>('');
const getSystemConfig = () => {
request
@ -27,9 +37,31 @@ const Dependence = () => {
});
};
const updateSystemConfig = () => {
const updateSystemConfigStream = (path: keyof typeof dataMap) => {
setLog('执行中...');
request
.put(`${config.apiPrefix}system/config`, systemConfig)
.put<string>(
`${config.apiPrefix}system/config/${path}`,
pick(systemConfig, dataMap[path]),
{
responseType: 'stream',
},
)
.then((res) => {
setLog(() => res);
})
.catch((error: any) => {
console.log(error);
});
};
const updateSystemConfig = (path: keyof typeof dataMap) => {
setLog('');
request
.put(
`${config.apiPrefix}system/config/${path}`,
pick(systemConfig, dataMap[path]),
)
.then(({ code, data }) => {
if (code === 200) {
message.success(intl.get('更新成功'));
@ -45,94 +77,120 @@ const Dependence = () => {
}, []);
return (
<Form layout="vertical" form={form}>
<Form.Item
label={intl.get('代理')}
name="proxy"
extra={intl.get('代理与镜像源二选一即可')}
<div className="dependence-config-wrapper">
<Form layout="vertical" form={form}>
<Form.Item
label={intl.get('代理')}
name="proxy"
extra={intl.get('代理与镜像源二选一即可')}
>
<Input.Group compact>
<Input
placeholder={intl.get('代理地址, 支持HTTP(S)/SOCK5, ip:port')}
style={{ width: 330 }}
value={systemConfig?.dependenceProxy}
onChange={(e) => {
setSystemConfig({
...systemConfig,
dependenceProxy: e.target.value,
});
}}
/>
<Button
type="primary"
onClick={() => {
updateSystemConfig('dependence-proxy');
}}
style={{ width: 84 }}
>
{intl.get('确认')}
</Button>
</Input.Group>
</Form.Item>
<Form.Item label={intl.get('Node 软件包镜像源')} name="node">
<Input.Group compact>
<Input
style={{ width: 330 }}
placeholder={intl.get('NPM 镜像源')}
value={systemConfig?.nodeMirror}
onChange={(e) => {
setSystemConfig({
...systemConfig,
nodeMirror: e.target.value,
});
}}
/>
<Button
type="primary"
onClick={() => {
updateSystemConfigStream('node-mirror');
}}
style={{ width: 84 }}
>
{intl.get('确认')}
</Button>
</Input.Group>
</Form.Item>
<Form.Item label={intl.get('Python 软件包镜像源')} name="python">
<Input.Group compact>
<Input
style={{ width: 330 }}
placeholder={intl.get('PyPI 镜像源')}
value={systemConfig?.pythonMirror}
onChange={(e) => {
setSystemConfig({
...systemConfig,
pythonMirror: e.target.value,
});
}}
/>
<Button
type="primary"
onClick={() => {
updateSystemConfig('python-mirror');
}}
style={{ width: 84 }}
>
{intl.get('确认')}
</Button>
</Input.Group>
</Form.Item>
<Form.Item label={intl.get('Linux 软件包镜像源')} name="linux">
<Input.Group compact>
<Input
style={{ width: 330 }}
placeholder={intl.get('alpine linux 镜像源')}
value={systemConfig?.linuxMirror}
onChange={(e) => {
setSystemConfig({
...systemConfig,
linuxMirror: e.target.value,
});
}}
/>
<Button
type="primary"
onClick={() => {
updateSystemConfigStream('linux-mirror');
}}
style={{ width: 84 }}
>
{intl.get('确认')}
</Button>
</Input.Group>
</Form.Item>
</Form>
<pre
style={{
fontFamily: 'Source Code Pro',
zoom: 0.83,
maxHeight: '100%',
overflowY: 'auto'
}}
>
<Input.Group compact>
<Input
placeholder={intl.get('代理地址, 支持HTTP(S)/SOCK5')}
style={{ width: 330 }}
value={systemConfig?.dependenceProxy}
onChange={(e) => {
setSystemConfig({
...systemConfig,
dependenceProxy: e.target.value,
});
}}
/>
<Button
type="primary"
onClick={updateSystemConfig}
style={{ width: 84 }}
>
{intl.get('确认')}
</Button>
</Input.Group>
</Form.Item>
<Form.Item label={intl.get('Node 软件包镜像源')} name="node">
<Input.Group compact>
<Input
style={{ width: 330 }}
placeholder={intl.get('NPM 镜像源')}
value={systemConfig?.nodeMirror}
onChange={(e) => {
setSystemConfig({ ...systemConfig, nodeMirror: e.target.value });
}}
/>
<Button
type="primary"
onClick={updateSystemConfig}
style={{ width: 84 }}
>
{intl.get('确认')}
</Button>
</Input.Group>
</Form.Item>
<Form.Item label={intl.get('Python 软件包镜像源')} name="python">
<Input.Group compact>
<Input
style={{ width: 330 }}
placeholder={intl.get('PyPI 镜像源')}
value={systemConfig?.pythonMirror}
onChange={(e) => {
setSystemConfig({
...systemConfig,
pythonMirror: e.target.value,
});
}}
/>
<Button
type="primary"
onClick={updateSystemConfig}
style={{ width: 84 }}
>
{intl.get('确认')}
</Button>
</Input.Group>
</Form.Item>
<Form.Item label={intl.get('Linux 软件包镜像源')} name="linux">
<Input.Group compact>
<Input
style={{ width: 330 }}
placeholder={intl.get('alpine linux 镜像源')}
value={systemConfig?.linuxMirror}
onChange={(e) => {
setSystemConfig({ ...systemConfig, linuxMirror: e.target.value });
}}
/>
<Button
type="primary"
onClick={updateSystemConfig}
style={{ width: 84 }}
>
{intl.get('确认')}
</Button>
</Input.Group>
</Form.Item>
</Form>
<Ansi>{log}</Ansi>
</pre>
</div>
);
};

View File

@ -27,3 +27,8 @@
}
}
}
.dependence-config-wrapper {
display: flex;
gap: 40px;
}

View File

@ -21,6 +21,12 @@ import './index.less';
import { UploadOutlined } from '@ant-design/icons';
import Countdown from 'antd/lib/statistic/Countdown';
import useProgress from './progress';
import pick from 'lodash/pick';
const dataMap = {
'log-remove-frequency': 'logRemoveFrequency',
'cron-concurrency': 'cronConcurrency',
};
const Other = ({
systemInfo,
@ -32,7 +38,6 @@ const Other = ({
cronConcurrency?: number | null;
}>();
const [form] = Form.useForm();
const modalRef = useRef<any>();
const [exportLoading, setExportLoading] = useState(false);
const showUploadProgress = useProgress(intl.get('上传'));
const showDownloadProgress = useProgress(intl.get('下载'));
@ -80,9 +85,12 @@ const Other = ({
});
};
const updateSystemConfig = () => {
const updateSystemConfig = (path: keyof typeof dataMap) => {
request
.put(`${config.apiPrefix}system/config`, systemConfig)
.put(
`${config.apiPrefix}system/config/${path}`,
pick(systemConfig, dataMap[path]),
)
.then(({ code, data }) => {
if (code === 200) {
message.success(intl.get('更新成功'));
@ -207,7 +215,9 @@ const Other = ({
/>
<Button
type="primary"
onClick={updateSystemConfig}
onClick={() => {
updateSystemConfig('log-remove-frequency');
}}
style={{ width: 84 }}
>
{intl.get('确认')}
@ -226,7 +236,9 @@ const Other = ({
/>
<Button
type="primary"
onClick={updateSystemConfig}
onClick={() => {
updateSystemConfig('cron-concurrency');
}}
style={{ width: 84 }}
>
{intl.get('确认')}