mirror of
https://github.com/whyour/qinglong.git
synced 2026-08-12 19:30:48 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
742d0b2135 | ||
|
|
2081364325 | ||
|
|
39dc31916e | ||
|
|
5395cebdb4 | ||
|
|
fe934fa4af | ||
|
|
461fa8e131 | ||
|
|
4618a19c04 | ||
|
|
e2bd15683e | ||
|
|
648b9c4520 | ||
|
|
b4e4e84bbd | ||
|
|
aa5d6f3cb6 | ||
|
|
e9416c23df | ||
|
|
ef4999be55 | ||
|
|
e7be4999b0 | ||
|
|
5907553670 | ||
|
|
0b9066525a | ||
|
|
ac904cae61 | ||
|
|
4d5fa320ea | ||
|
|
003defedcf | ||
|
|
40e8041401 | ||
|
|
a8174e89be | ||
|
|
cce83f7a4c | ||
|
|
4f7649f157 | ||
|
|
b002cbef3a | ||
|
|
1d93fe0de0 | ||
|
|
2d936f1341 | ||
|
|
b40673e9ac | ||
|
|
637874e426 | ||
|
|
de71d1a258 | ||
|
|
e174e190ee |
+1
-1
@@ -20,7 +20,7 @@ src/.umi
|
||||
src/.umi-production
|
||||
src/.umi-test
|
||||
.env.local
|
||||
env
|
||||
.env
|
||||
history
|
||||
version.ts
|
||||
config
|
||||
|
||||
@@ -4,6 +4,7 @@ const CompressionPlugin = require('compression-webpack-plugin');
|
||||
const baseUrl = process.env.QlBaseUrl || '/';
|
||||
export default defineConfig({
|
||||
hash: true,
|
||||
jsMinifier: 'terser',
|
||||
antd: {},
|
||||
locale: {
|
||||
antd: true,
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@ import { celebrate, Joi } from 'celebrate';
|
||||
import multer from 'multer';
|
||||
import config from '../config';
|
||||
import fs from 'fs';
|
||||
import { safeJSONParse } from '../config/util';
|
||||
const route = Router();
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
@@ -200,7 +201,7 @@ export default (app: Router) => {
|
||||
try {
|
||||
const envService = Container.get(EnvService);
|
||||
const fileContent = await fs.promises.readFile(req!.file!.path, 'utf8');
|
||||
const parseContent = JSON.parse(fileContent);
|
||||
const parseContent = safeJSONParse(fileContent);
|
||||
const data = Array.isArray(parseContent)
|
||||
? parseContent
|
||||
: [parseContent];
|
||||
|
||||
@@ -265,9 +265,11 @@ export default (app: Router) => {
|
||||
let { filename, path, pid } = req.body;
|
||||
const { name, ext } = parse(filename);
|
||||
const filePath = join(config.scriptPath, path, `${name}.swap${ext}`);
|
||||
const logPath = join(config.logPath, path, `${name}.swap`);
|
||||
|
||||
const scriptService = Container.get(ScriptService);
|
||||
const result = await scriptService.stopScript(filePath, pid);
|
||||
emptyDir(logPath);
|
||||
res.send(result);
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
|
||||
+17
-1
@@ -174,7 +174,10 @@ export default (app: Router) => {
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const systemService = Container.get(SystemService);
|
||||
const uniqPath = await getUniqPath(req.body.command);
|
||||
const command = req.body.command
|
||||
const idStr = `cat ${config.crontabFile} | grep -E "${command}" | perl -pe "s|.*ID=(.*) ${command}.*|\\1|" | head -1 | awk -F " " '{print $1}' | xargs echo -n`;
|
||||
let id = await promiseExec(idStr);
|
||||
const uniqPath = await getUniqPath(command, id);
|
||||
const logTime = dayjs().format('YYYY-MM-DD-HH-mm-ss-SSS');
|
||||
const logPath = `${uniqPath}/${logTime}.log`;
|
||||
res.setHeader('Content-type', 'application/octet-stream');
|
||||
@@ -249,4 +252,17 @@ export default (app: Router) => {
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
route.get(
|
||||
'/log',
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const systemService = Container.get(SystemService);
|
||||
await systemService.getSystemLog(res);
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
@@ -18,10 +18,12 @@ async function startServer() {
|
||||
const server = app
|
||||
.listen(config.port, () => {
|
||||
Logger.debug(`✌️ 后端服务启动成功!`);
|
||||
console.debug(`✌️ 后端服务启动成功!`);
|
||||
process.send?.('ready');
|
||||
})
|
||||
.on('error', (err) => {
|
||||
Logger.error(err);
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import dotenv from 'dotenv';
|
||||
import path from 'path';
|
||||
import { createRandomString } from './util';
|
||||
import { createRandomString } from './share';
|
||||
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
|
||||
@@ -30,6 +30,7 @@ const logPath = path.join(dataPath, 'log/');
|
||||
const dbPath = path.join(dataPath, 'db/');
|
||||
const uploadPath = path.join(dataPath, 'upload/');
|
||||
const sshdPath = path.join(dataPath, 'ssh.d/');
|
||||
const systemLogPath = path.join(dataPath, 'syslog/');
|
||||
|
||||
const envFile = path.join(configPath, 'env.sh');
|
||||
const confFile = path.join(configPath, 'config.sh');
|
||||
@@ -110,4 +111,5 @@ export default {
|
||||
lastVersionFile,
|
||||
sqliteFile,
|
||||
sshdPath,
|
||||
systemLogPath,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
export function createRandomString(min: number, max: number): string {
|
||||
const num = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
const english = [
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
'e',
|
||||
'f',
|
||||
'g',
|
||||
'h',
|
||||
'i',
|
||||
'j',
|
||||
'k',
|
||||
'l',
|
||||
'm',
|
||||
'n',
|
||||
'o',
|
||||
'p',
|
||||
'q',
|
||||
'r',
|
||||
's',
|
||||
't',
|
||||
'u',
|
||||
'v',
|
||||
'w',
|
||||
'x',
|
||||
'y',
|
||||
'z',
|
||||
];
|
||||
const ENGLISH = [
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'I',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'M',
|
||||
'N',
|
||||
'O',
|
||||
'P',
|
||||
'Q',
|
||||
'R',
|
||||
'S',
|
||||
'T',
|
||||
'U',
|
||||
'V',
|
||||
'W',
|
||||
'X',
|
||||
'Y',
|
||||
'Z',
|
||||
];
|
||||
const special = ['-', '_'];
|
||||
const config = num.concat(english).concat(ENGLISH).concat(special);
|
||||
|
||||
const arr = [];
|
||||
arr.push(getOne(num));
|
||||
arr.push(getOne(english));
|
||||
arr.push(getOne(ENGLISH));
|
||||
arr.push(getOne(special));
|
||||
|
||||
const len = min + Math.floor(Math.random() * (max - min + 1));
|
||||
|
||||
for (let i = 4; i < len; i++) {
|
||||
arr.push(config[Math.floor(Math.random() * config.length)]);
|
||||
}
|
||||
|
||||
const newArr = [];
|
||||
for (let j = 0; j < len; j++) {
|
||||
newArr.push(arr.splice(Math.random() * arr.length, 1)[0]);
|
||||
}
|
||||
|
||||
function getOne(arr: any[]) {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
|
||||
return newArr.join('');
|
||||
}
|
||||
+30
-95
@@ -9,6 +9,9 @@ import { promisify } from 'util';
|
||||
import { load } from 'js-yaml';
|
||||
import config from './index';
|
||||
import { TASK_COMMAND } from './const';
|
||||
import Logger from '../loaders/logger';
|
||||
|
||||
export * from './share';
|
||||
|
||||
export function getFileContentByName(fileName: string) {
|
||||
if (fs.existsSync(fileName)) {
|
||||
@@ -36,91 +39,6 @@ export function getLastModifyFilePath(dir: string) {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
export function createRandomString(min: number, max: number): string {
|
||||
const num = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
const english = [
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
'e',
|
||||
'f',
|
||||
'g',
|
||||
'h',
|
||||
'i',
|
||||
'j',
|
||||
'k',
|
||||
'l',
|
||||
'm',
|
||||
'n',
|
||||
'o',
|
||||
'p',
|
||||
'q',
|
||||
'r',
|
||||
's',
|
||||
't',
|
||||
'u',
|
||||
'v',
|
||||
'w',
|
||||
'x',
|
||||
'y',
|
||||
'z',
|
||||
];
|
||||
const ENGLISH = [
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'I',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'M',
|
||||
'N',
|
||||
'O',
|
||||
'P',
|
||||
'Q',
|
||||
'R',
|
||||
'S',
|
||||
'T',
|
||||
'U',
|
||||
'V',
|
||||
'W',
|
||||
'X',
|
||||
'Y',
|
||||
'Z',
|
||||
];
|
||||
const special = ['-', '_'];
|
||||
const config = num.concat(english).concat(ENGLISH).concat(special);
|
||||
|
||||
const arr = [];
|
||||
arr.push(getOne(num));
|
||||
arr.push(getOne(english));
|
||||
arr.push(getOne(ENGLISH));
|
||||
arr.push(getOne(special));
|
||||
|
||||
const len = min + Math.floor(Math.random() * (max - min + 1));
|
||||
|
||||
for (let i = 4; i < len; i++) {
|
||||
arr.push(config[Math.floor(Math.random() * config.length)]);
|
||||
}
|
||||
|
||||
const newArr = [];
|
||||
for (let j = 0; j < len; j++) {
|
||||
newArr.push(arr.splice(Math.random() * arr.length, 1)[0]);
|
||||
}
|
||||
|
||||
function getOne(arr: any[]) {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
|
||||
return newArr.join('');
|
||||
}
|
||||
|
||||
export function getToken(req: any) {
|
||||
const { authorization = '' } = req.headers;
|
||||
if (authorization && authorization.split(' ')[0] === 'Bearer') {
|
||||
@@ -307,22 +225,28 @@ interface IFile {
|
||||
type: 'directory' | 'file';
|
||||
parent: string;
|
||||
mtime: number;
|
||||
size?: number;
|
||||
children?: IFile[];
|
||||
}
|
||||
|
||||
export function dirSort(a: IFile, b: IFile) {
|
||||
if (a.type !== b.type) return FileType[a.type] < FileType[b.type] ? -1 : 1;
|
||||
else if (a.mtime !== b.mtime) return a.mtime > b.mtime ? -1 : 1;
|
||||
export function dirSort(a: IFile, b: IFile): number {
|
||||
if (a.type !== b.type) {
|
||||
return FileType[a.type] < FileType[b.type] ? -1 : 1
|
||||
} else if (a.mtime !== b.mtime) {
|
||||
return a.mtime > b.mtime ? -1 : 1
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function readDirs(
|
||||
dir: string,
|
||||
baseDir: string = '',
|
||||
blacklist: string[] = [],
|
||||
) {
|
||||
): IFile[] {
|
||||
const relativePath = path.relative(baseDir, dir);
|
||||
const files = fs.readdirSync(dir);
|
||||
const result: any = files
|
||||
const result: IFile[] = files
|
||||
.filter((x) => !blacklist.includes(x))
|
||||
.map((file: string) => {
|
||||
const subPath = path.join(dir, file);
|
||||
@@ -344,6 +268,7 @@ export function readDirs(
|
||||
isLeaf: true,
|
||||
key,
|
||||
parent: relativePath,
|
||||
size: stats.size,
|
||||
mtime: stats.mtime.getTime(),
|
||||
};
|
||||
});
|
||||
@@ -522,11 +447,8 @@ export async function parseContentVersion(content: string): Promise<IVersion> {
|
||||
return load(content) as IVersion;
|
||||
}
|
||||
|
||||
export async function getUniqPath(command: string): Promise<string> {
|
||||
const idStr = `cat ${config.crontabFile} | grep -E "${command}" | perl -pe "s|.*ID=(.*) ${command}.*|\\1|" | head -1 | awk -F " " '{print $1}' | xargs echo -n`;
|
||||
let id = await promiseExec(idStr);
|
||||
|
||||
if (/^\d\d*\d$/.test(id)) {
|
||||
export async function getUniqPath(command: string, id: string): Promise<string> {
|
||||
if (/^\d+$/.test(id)) {
|
||||
id = `_${id}`;
|
||||
} else {
|
||||
id = '';
|
||||
@@ -558,3 +480,16 @@ export async function getUniqPath(command: string): Promise<string> {
|
||||
|
||||
return `${str}${id}`;
|
||||
}
|
||||
|
||||
export function safeJSONParse(value?: string) {
|
||||
if (!value) {
|
||||
return {};
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (error) {
|
||||
Logger.error('[JSON.parse失败]', error)
|
||||
return {};
|
||||
}
|
||||
}
|
||||
+20
-10
@@ -7,18 +7,28 @@ import linkDeps from './deps';
|
||||
import initTask from './initTask';
|
||||
|
||||
export default async ({ expressApp }: { expressApp: Application }) => {
|
||||
await depInjectorLoader();
|
||||
Logger.info('✌️ Dependency Injector loaded');
|
||||
try {
|
||||
depInjectorLoader();
|
||||
Logger.info('✌️ Dependency Injector loaded');
|
||||
console.log('✌️ Dependency Injector loaded');
|
||||
|
||||
await expressLoader({ app: expressApp });
|
||||
Logger.info('✌️ Express loaded');
|
||||
expressLoader({ app: expressApp });
|
||||
Logger.info('✌️ Express loaded');
|
||||
console.log('✌️ Express loaded');
|
||||
|
||||
await initData();
|
||||
Logger.info('✌️ init data loaded');
|
||||
await initData();
|
||||
Logger.info('✌️ init data loaded');
|
||||
console.log('✌️ init data loaded');
|
||||
|
||||
await linkDeps();
|
||||
Logger.info('✌️ link deps loaded');
|
||||
await linkDeps();
|
||||
Logger.info('✌️ link deps loaded');
|
||||
console.log('✌️ link deps loaded');
|
||||
|
||||
initTask();
|
||||
Logger.info('✌️ init task loaded');
|
||||
initTask();
|
||||
Logger.info('✌️ init task loaded');
|
||||
console.log('✌️ init task loaded');
|
||||
} catch (error) {
|
||||
Logger.error(`✌️ depInjectorLoader expressLoader initData linkDeps failed, ${error}`);
|
||||
console.error(`✌️ depInjectorLoader expressLoader initData linkDeps failed ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
+3
-2
@@ -122,9 +122,10 @@ export default async () => {
|
||||
});
|
||||
}
|
||||
|
||||
console.log('✌️ DB loaded');
|
||||
Logger.info('✌️ DB loaded');
|
||||
} catch (error) {
|
||||
Logger.info('✌️ DB load failed');
|
||||
Logger.info(error);
|
||||
console.error('✌️ DB load failed');
|
||||
Logger.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import routes from '../api';
|
||||
import config from '../config';
|
||||
import jwt, { UnauthorizedError } from 'express-jwt';
|
||||
import fs from 'fs';
|
||||
import { getPlatform, getToken } from '../config/util';
|
||||
import { getPlatform, getToken, safeJSONParse } from '../config/util';
|
||||
import Container from 'typedi';
|
||||
import OpenService from '../services/open';
|
||||
import rewrite from 'express-urlrewrite';
|
||||
@@ -15,6 +15,7 @@ import { EnvModel } from '../data/env';
|
||||
import { errors } from 'celebrate';
|
||||
import { createProxyMiddleware } from 'http-proxy-middleware';
|
||||
import { serveEnv } from '../config/serverEnv';
|
||||
import Logger from './logger';
|
||||
|
||||
export default ({ app }: { app: Application }) => {
|
||||
app.enable('trust proxy');
|
||||
@@ -25,9 +26,10 @@ export default ({ app }: { app: Application }) => {
|
||||
app.use(
|
||||
'/api/public',
|
||||
createProxyMiddleware({
|
||||
target: `http://localhost:${config.publicPort}/api`,
|
||||
target: `http://0.0.0.0:${config.publicPort}/api`,
|
||||
changeOrigin: true,
|
||||
pathRewrite: { '/api/public': '' },
|
||||
logProvider: () => Logger
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -36,7 +38,7 @@ export default ({ app }: { app: Application }) => {
|
||||
|
||||
app.use(
|
||||
jwt({
|
||||
secret: config.secret as string,
|
||||
secret: config.secret,
|
||||
algorithms: ['HS384'],
|
||||
}).unless({
|
||||
path: [...config.apiWhiteList, /^\/open\//],
|
||||
@@ -83,7 +85,7 @@ export default ({ app }: { app: Application }) => {
|
||||
|
||||
const data = fs.readFileSync(config.authConfigFile, 'utf8');
|
||||
if (data && headerToken) {
|
||||
const { token = '', tokens = {} } = JSON.parse(data);
|
||||
const { token = '', tokens = {} } = safeJSONParse(data);
|
||||
if (headerToken === token || tokens[req.platform] === headerToken) {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ const TaskAfterFile = path.join(configPath, 'task_after.sh');
|
||||
const homedir = os.homedir();
|
||||
const sshPath = path.resolve(homedir, '.ssh');
|
||||
const sshdPath = path.join(dataPath, 'ssh.d');
|
||||
const systemLogPath = path.join(dataPath, 'syslog');
|
||||
|
||||
export default async () => {
|
||||
const authFileExist = await fileExist(authConfigFile);
|
||||
@@ -39,6 +40,7 @@ export default async () => {
|
||||
const sshDirExist = await fileExist(sshPath);
|
||||
const bakDirExist = await fileExist(bakPath);
|
||||
const sshdDirExist = await fileExist(sshdPath);
|
||||
const systemLogDirExist = await fileExist(systemLogPath);
|
||||
const tmpDirExist = await fileExist(tmpPath);
|
||||
const scriptNotifyJsFileExist = await fileExist(scriptNotifyJsFile);
|
||||
const scriptNotifyPyFileExist = await fileExist(scriptNotifyPyFile);
|
||||
@@ -77,6 +79,10 @@ export default async () => {
|
||||
fs.mkdirSync(sshdPath);
|
||||
}
|
||||
|
||||
if (!systemLogDirExist) {
|
||||
fs.mkdirSync(systemLogPath);
|
||||
}
|
||||
|
||||
// 初始化文件
|
||||
if (!authFileExist) {
|
||||
fs.writeFileSync(authConfigFile, fs.readFileSync(sampleAuthFile));
|
||||
@@ -105,4 +111,5 @@ export default async () => {
|
||||
dotenv.config({ path: confFile });
|
||||
|
||||
Logger.info('✌️ Init file down');
|
||||
console.log('✌️ Init file down');
|
||||
};
|
||||
|
||||
+27
-21
@@ -1,32 +1,38 @@
|
||||
import winston from 'winston';
|
||||
import 'winston-daily-rotate-file';
|
||||
import config from '../config';
|
||||
import path from 'path';
|
||||
|
||||
const transports = [];
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
transports.push(new winston.transports.Console());
|
||||
} else {
|
||||
transports.push(
|
||||
new winston.transports.Console({
|
||||
format: winston.format.combine(
|
||||
winston.format.cli(),
|
||||
winston.format.splat(),
|
||||
),
|
||||
}),
|
||||
);
|
||||
const levelMap: Record<string, string> = {
|
||||
info: '🔵',
|
||||
warn: '🟡',
|
||||
error: '🔴',
|
||||
debug: '🔶'
|
||||
}
|
||||
|
||||
const customFormat = winston.format.combine(
|
||||
winston.format.splat(),
|
||||
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
|
||||
winston.format.align(),
|
||||
winston.format.printf((i) => `[${levelMap[i.level]}${i.level}] [${[i.timestamp]}]: ${i.message}`),
|
||||
);
|
||||
|
||||
const defaultOptions = {
|
||||
format: customFormat,
|
||||
datePattern: "YYYY-MM-DD",
|
||||
maxSize: "20m",
|
||||
maxFiles: "7d",
|
||||
};
|
||||
|
||||
const LoggerInstance = winston.createLogger({
|
||||
level: config.logs.level,
|
||||
levels: winston.config.npm.levels,
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp({
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
}),
|
||||
winston.format.errors({ stack: true }),
|
||||
winston.format.splat(),
|
||||
winston.format.json(),
|
||||
),
|
||||
transports,
|
||||
transports: [
|
||||
new winston.transports.DailyRotateFile({
|
||||
filename: path.join(config.systemLogPath, '%DATE%.log'),
|
||||
...defaultOptions,
|
||||
})
|
||||
],
|
||||
});
|
||||
|
||||
export default LoggerInstance;
|
||||
|
||||
@@ -29,4 +29,5 @@ export default async ({ expressApp }: { expressApp: Application }) => {
|
||||
expressApp.use(Sentry.Handlers.tracingHandler());
|
||||
|
||||
Logger.info('✌️ Sentry loaded');
|
||||
console.log('✌️ Sentry loaded');
|
||||
};
|
||||
|
||||
@@ -10,9 +10,11 @@ export default async ({ server }: { server: Server }) => {
|
||||
|
||||
process.on('SIGINT', (singal) => {
|
||||
Logger.warn(`Server need close, singal ${singal}`);
|
||||
console.warn(`Server need close, singal ${singal}`);
|
||||
exitTime++;
|
||||
if (exitTime >= 3) {
|
||||
Logger.warn('Forcing server close');
|
||||
console.warn('Forcing server close');
|
||||
clearTimeout(timer);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -28,11 +30,13 @@ export default async ({ server }: { server: Server }) => {
|
||||
|
||||
process.on('uncaughtException', (error) => {
|
||||
Logger.error('Uncaught exception:', error);
|
||||
console.error('Uncaught exception:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
Logger.error('Unhandled rejection:', reason);
|
||||
Logger.error('Unhandled rejection:', reason, promise);
|
||||
console.error('Unhandled rejection:', reason, promise);
|
||||
process.exit(1);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Container } from 'typedi';
|
||||
import SockService from '../services/sock';
|
||||
import config from '../config/index';
|
||||
import fs from 'fs';
|
||||
import { getPlatform } from '../config/util';
|
||||
import { getPlatform, safeJSONParse } from '../config/util';
|
||||
|
||||
export default async ({ server }: { server: Server }) => {
|
||||
const echo = sockJs.createServer({ prefix: '/api/ws', log: () => {} });
|
||||
@@ -20,7 +20,7 @@ export default async ({ server }: { server: Server }) => {
|
||||
const platform = getPlatform(conn.headers['user-agent'] || '') || 'desktop';
|
||||
const headerToken = conn.url.replace(`${conn.pathname}?token=`, '');
|
||||
if (data) {
|
||||
const { token = '', tokens = {} } = JSON.parse(data);
|
||||
const { token = '', tokens = {} } = safeJSONParse(data);
|
||||
if (headerToken === token || tokens[platform] === headerToken) {
|
||||
conn.write(JSON.stringify({ type: 'ping', message: 'hanhh' }));
|
||||
sockService.addClient(conn);
|
||||
|
||||
+3
-1
@@ -6,7 +6,7 @@ import { credentials } from '@grpc/grpc-js';
|
||||
|
||||
const app = express();
|
||||
const client = new HealthClient(
|
||||
`localhost:${config.cronPort}`,
|
||||
`0.0.0.0:${config.cronPort}`,
|
||||
credentials.createInsecure(),
|
||||
);
|
||||
|
||||
@@ -25,9 +25,11 @@ app
|
||||
await require('./loaders/db').default();
|
||||
|
||||
Logger.debug(`✌️ 公共服务启动成功!`);
|
||||
console.debug(`✌️ 公共服务启动成功!`);
|
||||
process.send?.('ready');
|
||||
})
|
||||
.on('error', (err) => {
|
||||
Logger.error(err);
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -22,13 +22,18 @@ const addCron = (
|
||||
cmdStr = `${TASK_PREFIX}${cmdStr}`;
|
||||
}
|
||||
|
||||
Logger.info(
|
||||
'[schedule][创建定时任务], 任务ID: %s, cron: %s, 执行命令: %s',
|
||||
id,
|
||||
schedule,
|
||||
command,
|
||||
);
|
||||
|
||||
scheduleStacks.set(
|
||||
id,
|
||||
nodeSchedule.scheduleJob(id, schedule, async () => {
|
||||
Logger.info(
|
||||
`当前时间: ${dayjs().format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)},运行命令: ${cmdStr}`,
|
||||
`[schedule][准备运行任务] 命令: ${cmdStr}`,
|
||||
);
|
||||
runCron(`ID=${id} ${cmdStr}`);
|
||||
}),
|
||||
|
||||
@@ -10,7 +10,7 @@ import config from '../config';
|
||||
|
||||
class Client {
|
||||
private client = new CronClient(
|
||||
`localhost:${config.cronPort}`,
|
||||
`0.0.0.0:${config.cronPort}`,
|
||||
credentials.createInsecure(),
|
||||
);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ServerUnaryCall, sendUnaryData } from '@grpc/grpc-js';
|
||||
import { DeleteCronRequest, DeleteCronResponse } from '../protos/cron';
|
||||
import { scheduleStacks } from './data';
|
||||
import Logger from '../loaders/logger';
|
||||
|
||||
const delCron = (
|
||||
call: ServerUnaryCall<DeleteCronRequest, DeleteCronResponse>,
|
||||
@@ -8,6 +9,10 @@ const delCron = (
|
||||
) => {
|
||||
for (const id of call.request.ids) {
|
||||
if (scheduleStacks.has(id)) {
|
||||
Logger.info(
|
||||
'[schedule][取消定时任务], 任务ID: %s',
|
||||
id,
|
||||
);
|
||||
scheduleStacks.get(id)?.cancel();
|
||||
scheduleStacks.delete(id);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ const check = async (
|
||||
switch (call.request.service) {
|
||||
case 'cron':
|
||||
const res = await promiseExec(
|
||||
`curl -s http://localhost:${config.port}/api/system`,
|
||||
`curl -s http://0.0.0.0:${config.port}/api/system`,
|
||||
);
|
||||
|
||||
if (res.includes('200')) {
|
||||
|
||||
@@ -11,7 +11,7 @@ const server = new Server();
|
||||
server.addService(HealthService, { check });
|
||||
server.addService(CronService, { addCron, delCron });
|
||||
server.bindAsync(
|
||||
`localhost:${config.cronPort}`,
|
||||
`0.0.0.0:${config.cronPort}`,
|
||||
ServerCredentials.createInsecure(),
|
||||
(err, port) => {
|
||||
if (err) {
|
||||
@@ -19,6 +19,7 @@ server.bindAsync(
|
||||
}
|
||||
server.start();
|
||||
Logger.debug(`✌️ 定时服务启动成功!`);
|
||||
console.debug(`✌️ 定时服务启动成功!`);
|
||||
process.send?.('ready');
|
||||
},
|
||||
);
|
||||
|
||||
+22
-20
@@ -5,7 +5,7 @@ import { Crontab, CrontabModel, CrontabStatus } from '../data/cron';
|
||||
import { exec, execSync } from 'child_process';
|
||||
import fs from 'fs';
|
||||
import cron_parser from 'cron-parser';
|
||||
import { getFileContentByName, fileExist, killTask } from '../config/util';
|
||||
import { getFileContentByName, fileExist, killTask, getUniqPath, safeJSONParse } from '../config/util';
|
||||
import { promises, existsSync } from 'fs';
|
||||
import { Op, where, col as colFn, FindOptions, fn } from 'sequelize';
|
||||
import path from 'path';
|
||||
@@ -13,10 +13,11 @@ import { TASK_PREFIX, QL_PREFIX } from '../config/const';
|
||||
import cronClient from '../schedule/client';
|
||||
import taskLimit from '../shared/pLimit';
|
||||
import { spawn } from 'cross-spawn';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
@Service()
|
||||
export default class CronService {
|
||||
constructor(@Inject('logger') private logger: winston.Logger) {}
|
||||
constructor(@Inject('logger') private logger: winston.Logger) { }
|
||||
|
||||
private isSixCron(cron: Crontab) {
|
||||
const { schedule } = cron;
|
||||
@@ -161,7 +162,7 @@ export default class CronService {
|
||||
case 'In':
|
||||
q[Op.or] = [
|
||||
{
|
||||
[property]: value,
|
||||
[property]: Array.isArray(value) ? value : [value],
|
||||
},
|
||||
property === 'status' && value.includes(2)
|
||||
? { isDisabled: 1 }
|
||||
@@ -172,7 +173,7 @@ export default class CronService {
|
||||
q[Op.and] = [
|
||||
{
|
||||
[property]: {
|
||||
[Op.notIn]: value,
|
||||
[Op.notIn]: Array.isArray(value) ? value : [value],
|
||||
},
|
||||
},
|
||||
property === 'status' && value.includes(2)
|
||||
@@ -308,9 +309,9 @@ export default class CronService {
|
||||
const searchText = params?.searchValue;
|
||||
const page = Number(params?.page || '0');
|
||||
const size = Number(params?.size || '0');
|
||||
const viewQuery = JSON.parse(params?.queryString || '{}');
|
||||
const filterQuery = JSON.parse(params?.filters || '{}');
|
||||
const sorterQuery = JSON.parse(params?.sorter || '{}');
|
||||
const viewQuery = safeJSONParse(params?.queryString);
|
||||
const filterQuery = safeJSONParse(params?.filters);
|
||||
const sorterQuery = safeJSONParse(params?.sorter);
|
||||
|
||||
let query: any = {};
|
||||
let order = [
|
||||
@@ -370,7 +371,7 @@ export default class CronService {
|
||||
try {
|
||||
await killTask(doc.pid);
|
||||
} catch (error) {
|
||||
this.logger.silly(error);
|
||||
this.logger.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,8 +392,14 @@ export default class CronService {
|
||||
}
|
||||
|
||||
let { id, command, log_path } = cron;
|
||||
const absolutePath = path.resolve(config.logPath, `${log_path}`);
|
||||
const logFileExist = log_path && (await fileExist(absolutePath));
|
||||
const uniqPath = await getUniqPath(command, `${id}`);
|
||||
const logTime = dayjs().format('YYYY-MM-DD-HH-mm-ss-SSS');
|
||||
const logDirPath = path.resolve(config.logPath, `${uniqPath}`);
|
||||
if (log_path?.split('/')?.every(x => x !== uniqPath)) {
|
||||
fs.mkdirSync(logDirPath, { recursive: true });
|
||||
}
|
||||
const logPath = `${uniqPath}/${logTime}.log`;
|
||||
const absolutePath = path.resolve(config.logPath, `${logPath}`);
|
||||
|
||||
this.logger.silly('Running job');
|
||||
this.logger.silly('ID: ' + id);
|
||||
@@ -412,26 +419,22 @@ export default class CronService {
|
||||
cmdStr = `${cmdStr} now`;
|
||||
}
|
||||
|
||||
const cp = spawn(`ID=${id} ${cmdStr}`, { shell: '/bin/bash' });
|
||||
const cp = spawn(`real_log_path=${logPath} ID=${id} ${cmdStr}`, { shell: '/bin/bash' });
|
||||
|
||||
await CrontabModel.update(
|
||||
{ status: CrontabStatus.running, pid: cp.pid },
|
||||
{ status: CrontabStatus.running, pid: cp.pid, log_path: logPath },
|
||||
{ where: { id } },
|
||||
);
|
||||
cp.stderr.on('data', (data) => {
|
||||
if (logFileExist) {
|
||||
fs.appendFileSync(`${absolutePath}`, `${data.toString()}`);
|
||||
}
|
||||
fs.appendFileSync(`${absolutePath}`, `${data.toString()}`);
|
||||
});
|
||||
cp.on('error', (err) => {
|
||||
if (logFileExist) {
|
||||
fs.appendFileSync(`${absolutePath}`, `${JSON.stringify(err)}`);
|
||||
}
|
||||
fs.appendFileSync(`${absolutePath}`, `${JSON.stringify(err)}`);
|
||||
});
|
||||
|
||||
cp.on('exit', async (code, signal) => {
|
||||
this.logger.info(
|
||||
`任务 ${command} 进程id: ${cp.pid} 退出,退出码 ${code}`,
|
||||
`[panel][任务退出] 任务 ${command} 进程id: ${cp.pid}, 退出码 ${code}`,
|
||||
);
|
||||
});
|
||||
cp.on('close', async (code) => {
|
||||
@@ -530,7 +533,6 @@ export default class CronService {
|
||||
}
|
||||
});
|
||||
|
||||
this.logger.silly(crontab_string);
|
||||
fs.writeFileSync(config.crontabFile, crontab_string);
|
||||
|
||||
execSync(`crontab ${config.crontabFile}`);
|
||||
|
||||
@@ -202,11 +202,9 @@ export default class EnvService {
|
||||
let value = group
|
||||
.map((x) => x.value)
|
||||
.join('&')
|
||||
.replace(/(\\)[^n]/g, '\\\\')
|
||||
.replace(/(\\$)/, '\\\\')
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/'/g, "'\\''")
|
||||
.trim();
|
||||
env_string += `export ${key}="${value}"\n`;
|
||||
env_string += `export ${key}='${value}'\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-14
@@ -66,9 +66,8 @@ export default class ScheduleService {
|
||||
|
||||
cp.stderr.on('data', async (data) => {
|
||||
this.logger.info(
|
||||
'[执行任务失败] %s,时间:%s, 错误信息:%j',
|
||||
'[panel][执行任务失败] 命令: %s, 错误信息: %j',
|
||||
command,
|
||||
new Date().toLocaleString(),
|
||||
data.toString(),
|
||||
);
|
||||
await callbacks.onError?.(data.toString());
|
||||
@@ -76,9 +75,8 @@ export default class ScheduleService {
|
||||
|
||||
cp.on('error', async (err) => {
|
||||
this.logger.error(
|
||||
'[创建任务失败] %s,时间:%s, 错误信息:%j',
|
||||
'[panel][创建任务失败] 命令: %s, 错误信息: %j',
|
||||
command,
|
||||
new Date().toLocaleString(),
|
||||
err,
|
||||
);
|
||||
await callbacks.onError?.(JSON.stringify(err));
|
||||
@@ -86,7 +84,7 @@ export default class ScheduleService {
|
||||
|
||||
cp.on('exit', async (code, signal) => {
|
||||
this.logger.info(
|
||||
`[任务退出] ${command} 进程id: ${cp.pid},退出码 ${code}`,
|
||||
`[panel][任务退出] ${command} 进程id: ${cp.pid}, 退出码 ${code}`,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -100,10 +98,9 @@ export default class ScheduleService {
|
||||
resolve(null);
|
||||
});
|
||||
} catch (error) {
|
||||
await this.logger.error(
|
||||
'执行任务%s失败,时间:%s, 错误信息:%j',
|
||||
this.logger.error(
|
||||
'[panel][执行任务失败] 命令: %s, 错误信息: %j',
|
||||
command,
|
||||
new Date().toLocaleString(),
|
||||
error,
|
||||
);
|
||||
await callbacks.onError?.(JSON.stringify(error));
|
||||
@@ -119,7 +116,7 @@ export default class ScheduleService {
|
||||
) {
|
||||
const _id = this.formatId(id);
|
||||
this.logger.info(
|
||||
'[创建cron任务],任务ID: %s,cron: %s,任务名: %s,执行命令: %s',
|
||||
'[panel][创建cron任务], 任务ID: %s, cron: %s, 任务名: %s, 执行命令: %s',
|
||||
_id,
|
||||
schedule,
|
||||
name,
|
||||
@@ -140,7 +137,7 @@ export default class ScheduleService {
|
||||
|
||||
async cancelCronTask({ id = 0, name }: ScheduleTaskType) {
|
||||
const _id = this.formatId(id);
|
||||
this.logger.info('[取消定时任务],任务名:%s', name);
|
||||
this.logger.info('[panel][取消定时任务], 任务名: %s', name);
|
||||
if (this.scheduleStacks.has(_id)) {
|
||||
this.scheduleStacks.get(_id)?.cancel();
|
||||
this.scheduleStacks.delete(_id);
|
||||
@@ -155,7 +152,7 @@ export default class ScheduleService {
|
||||
) {
|
||||
const _id = this.formatId(id);
|
||||
this.logger.info(
|
||||
'[创建interval任务],任务ID: %s,任务名: %s,执行命令: %s',
|
||||
'[panel][创建interval任务], 任务ID: %s, 任务名: %s, 执行命令: %s',
|
||||
_id,
|
||||
name,
|
||||
command,
|
||||
@@ -167,9 +164,8 @@ export default class ScheduleService {
|
||||
},
|
||||
(err) => {
|
||||
this.logger.error(
|
||||
'执行任务%s失败,时间:%s, 错误信息:%j',
|
||||
'[执行任务失败] 命令: %s, 错误信息: %j',
|
||||
command,
|
||||
new Date().toLocaleString(),
|
||||
err,
|
||||
);
|
||||
},
|
||||
@@ -190,7 +186,7 @@ export default class ScheduleService {
|
||||
|
||||
async cancelIntervalTask({ id = 0, name }: ScheduleTaskType) {
|
||||
const _id = this.formatId(id);
|
||||
this.logger.info('[取消interval任务],任务ID: %s,任务名:%s', _id, name);
|
||||
this.logger.info('[取消interval任务], 任务ID: %s, 任务名: %s', _id, name);
|
||||
this.intervalSchedule.removeById(_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,10 +53,9 @@ export default class ScriptService {
|
||||
}
|
||||
|
||||
public async stopScript(filePath: string, pid: number) {
|
||||
let str = '';
|
||||
if (!pid) {
|
||||
const relativePath = path.relative(config.scriptPath, filePath);
|
||||
pid = await getPid(`${TASK_COMMAND} -l ${relativePath} now`);
|
||||
pid = await getPid(`${TASK_COMMAND} -l ${relativePath} now`) as number;
|
||||
}
|
||||
try {
|
||||
await killTask(pid);
|
||||
|
||||
@@ -58,7 +58,7 @@ export default class SshKeyService {
|
||||
|
||||
private generateSingleSshConfig(alias: string, host: string, proxy?: string) {
|
||||
if (host === 'github.com') {
|
||||
host = `ssh.github.com\n Port 443\n HostkeyAlgorithms +ssh-rsa\n PubkeyAcceptedAlgorithms +ssh-rsa`;
|
||||
host = `ssh.github.com\n Port 443\n HostkeyAlgorithms +ssh-rsa`;
|
||||
}
|
||||
const proxyStr = proxy
|
||||
? ` ProxyCommand nc -v -x ${proxy} %h %p 2>/dev/null\n`
|
||||
|
||||
@@ -301,17 +301,9 @@ export default class SubscriptionService {
|
||||
try {
|
||||
await killTask(doc.pid);
|
||||
} catch (error) {
|
||||
this.logger.silly(error);
|
||||
this.logger.error(error);
|
||||
}
|
||||
}
|
||||
const absolutePath = await handleLogPath(doc.log_path as string);
|
||||
|
||||
fs.appendFileSync(
|
||||
`${absolutePath}`,
|
||||
`\n## 执行结束... ${dayjs().format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)}${LOG_END_SYMBOL}`,
|
||||
);
|
||||
}
|
||||
|
||||
await SubscriptionModel.update(
|
||||
|
||||
@@ -21,11 +21,14 @@ import {
|
||||
parseContentVersion,
|
||||
parseVersion,
|
||||
promiseExec,
|
||||
readDirs,
|
||||
} from '../config/util';
|
||||
import { TASK_COMMAND } from '../config/const';
|
||||
import taskLimit from '../shared/pLimit';
|
||||
import tar from 'tar';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { sum } from 'lodash';
|
||||
|
||||
@Service()
|
||||
export default class SystemService {
|
||||
@@ -275,4 +278,29 @@ export default class SystemService {
|
||||
return { code: 400, message: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
public async getSystemLog(res: Response) {
|
||||
const result = readDirs(config.systemLogPath, config.systemLogPath);
|
||||
const logs = result.reverse().filter((x) => x.title.endsWith('.log'));
|
||||
res.set({
|
||||
'Content-Length': sum(logs.map((x) => x.size)),
|
||||
});
|
||||
(function sendFiles(res, fileNames) {
|
||||
if (fileNames.length === 0) {
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
const currentLog = fileNames.shift();
|
||||
if (currentLog) {
|
||||
const currentFileStream = fs.createReadStream(
|
||||
path.join(config.systemLogPath, currentLog.title),
|
||||
);
|
||||
currentFileStream.on('end', () => {
|
||||
sendFiles(res, fileNames);
|
||||
});
|
||||
currentFileStream.pipe(res, { end: false });
|
||||
}
|
||||
})(res, logs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
fileExist,
|
||||
getNetIp,
|
||||
getPlatform,
|
||||
safeJSONParse,
|
||||
} from '../config/util';
|
||||
import config from '../config';
|
||||
import * as fs from 'fs';
|
||||
@@ -327,7 +328,7 @@ export default class UserService {
|
||||
|
||||
private getAuthInfo() {
|
||||
const content = fs.readFileSync(config.authConfigFile, 'utf8');
|
||||
return JSON.parse(content || '{}');
|
||||
return safeJSONParse(content);
|
||||
}
|
||||
|
||||
private updateAuthInfo(authInfo: any, info: any) {
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
import pLimit from 'p-limit';
|
||||
import os from 'os';
|
||||
import { AuthDataType, AuthModel } from '../data/auth';
|
||||
import Logger from '../loaders/logger';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
class TaskLimit {
|
||||
private oneLimit = pLimit(1);
|
||||
private updateLogLimit = pLimit(1);
|
||||
private cpuLimit = pLimit(Math.max(os.cpus().length, 4));
|
||||
|
||||
get cpuLimitActiveCount() {
|
||||
return this.cpuLimit.activeCount;
|
||||
}
|
||||
|
||||
get cpuLimitPendingCount() {
|
||||
return this.cpuLimit.pendingCount;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.setCustomLimit();
|
||||
}
|
||||
@@ -26,6 +36,9 @@ class TaskLimit {
|
||||
}
|
||||
|
||||
public runWithCpuLimit<T>(fn: () => Promise<T>): Promise<T> {
|
||||
Logger.info(
|
||||
`[schedule][任务加入队列] 运行中任务数: ${this.cpuLimitActiveCount}, 等待中任务数: ${this.cpuLimitPendingCount}`,
|
||||
);
|
||||
return this.cpuLimit(fn);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,29 +5,27 @@ import Logger from '../loaders/logger';
|
||||
export function runCron(cmd: string): Promise<number> {
|
||||
return taskLimit.runWithCpuLimit(() => {
|
||||
return new Promise(async (resolve: any) => {
|
||||
Logger.silly('运行命令: ' + cmd);
|
||||
Logger.info(`[schedule][开始执行任务] 运行命令: ${cmd}`);
|
||||
|
||||
const cp = spawn(cmd, { shell: '/bin/bash' });
|
||||
|
||||
cp.stderr.on('data', (data) => {
|
||||
Logger.info(
|
||||
'[执行任务失败] %s,时间:%s, 错误信息:%j',
|
||||
'[schedule][执行任务失败] 命令: %s, 错误信息: %j',
|
||||
cmd,
|
||||
new Date().toLocaleString(),
|
||||
data.toString(),
|
||||
);
|
||||
});
|
||||
cp.on('error', (err) => {
|
||||
Logger.error(
|
||||
'[创建任务失败] %s,时间:%s, 错误信息:%j',
|
||||
'[schedule][创建任务失败] 命令: %s, 错误信息: %j',
|
||||
cmd,
|
||||
new Date().toLocaleString(),
|
||||
err,
|
||||
);
|
||||
});
|
||||
|
||||
cp.on('close', async (code) => {
|
||||
Logger.info(`[任务退出] ${cmd} 进程id: ${cp.pid} 退出,退出码 ${code}`);
|
||||
Logger.info(`[schedule][任务退出] ${cmd} 进程id: ${cp.pid} 退出, 退出码 ${code}`);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
+3
-2
@@ -96,6 +96,7 @@
|
||||
"typedi": "^0.10.0",
|
||||
"uuid": "^8.3.2",
|
||||
"winston": "^3.6.0",
|
||||
"winston-daily-rotate-file": "^4.7.1",
|
||||
"yargs": "^17.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -127,6 +128,8 @@
|
||||
"@types/sockjs-client": "^1.5.1",
|
||||
"@types/tar": "^6.1.5",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@uiw/codemirror-extensions-langs": "^4.21.9",
|
||||
"@uiw/react-codemirror": "^4.21.9",
|
||||
"@umijs/max": "^4.0.72",
|
||||
"@umijs/ssr-darkreader": "^4.9.45",
|
||||
"ahooks": "^3.7.8",
|
||||
@@ -134,7 +137,6 @@
|
||||
"antd": "^4.24.8",
|
||||
"antd-img-crop": "^4.2.3",
|
||||
"axios": "^1.4.0",
|
||||
"codemirror": "^5.65.2",
|
||||
"compression-webpack-plugin": "9.2.0",
|
||||
"concurrently": "^7.0.0",
|
||||
"file-saver": "^2.0.5",
|
||||
@@ -148,7 +150,6 @@
|
||||
"rc-tween-one": "^3.0.6",
|
||||
"rc-virtual-list": "3.5.3",
|
||||
"react": "18.2.0",
|
||||
"react-codemirror2": "^7.2.1",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-diff-viewer": "^3.1.1",
|
||||
"react-dnd": "^14.0.2",
|
||||
|
||||
Generated
+649
-21
@@ -124,6 +124,9 @@ dependencies:
|
||||
winston:
|
||||
specifier: ^3.6.0
|
||||
version: 3.9.0
|
||||
winston-daily-rotate-file:
|
||||
specifier: ^4.7.1
|
||||
version: 4.7.1(winston@3.9.0)
|
||||
yargs:
|
||||
specifier: ^17.3.1
|
||||
version: 17.7.2
|
||||
@@ -213,6 +216,12 @@ devDependencies:
|
||||
'@types/uuid':
|
||||
specifier: ^8.3.4
|
||||
version: 8.3.4
|
||||
'@uiw/codemirror-extensions-langs':
|
||||
specifier: ^4.21.9
|
||||
version: 4.21.9(@codemirror/autocomplete@6.9.0)(@codemirror/language-data@6.3.1)(@codemirror/language@6.9.0)(@codemirror/legacy-modes@6.3.3)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)(@lezer/highlight@1.1.6)(@lezer/javascript@1.4.5)(@lezer/lr@1.3.10)
|
||||
'@uiw/react-codemirror':
|
||||
specifier: ^4.21.9
|
||||
version: 4.21.9(@babel/runtime@7.22.3)(@codemirror/autocomplete@6.9.0)(@codemirror/language@6.9.0)(@codemirror/lint@6.4.0)(@codemirror/search@6.5.1)(@codemirror/state@6.2.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.16.0)(codemirror@6.0.1)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@umijs/max':
|
||||
specifier: ^4.0.72
|
||||
version: 4.0.72(@types/node@17.0.45)(@types/react-dom@18.2.4)(@types/react@18.2.8)(prettier@2.8.8)(react-dom@18.2.0)(react@18.2.0)(sockjs-client@1.6.1)(typescript@4.8.4)(webpack@5.85.1)
|
||||
@@ -234,9 +243,6 @@ devDependencies:
|
||||
axios:
|
||||
specifier: ^1.4.0
|
||||
version: 1.4.0
|
||||
codemirror:
|
||||
specifier: ^5.65.2
|
||||
version: 5.65.13
|
||||
compression-webpack-plugin:
|
||||
specifier: 9.2.0
|
||||
version: 9.2.0(webpack@5.85.1)
|
||||
@@ -276,9 +282,6 @@ devDependencies:
|
||||
react:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0
|
||||
react-codemirror2:
|
||||
specifier: ^7.2.1
|
||||
version: 7.2.1(codemirror@5.65.13)(react@18.2.0)
|
||||
react-copy-to-clipboard:
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0(react@18.2.0)
|
||||
@@ -2762,6 +2765,298 @@ packages:
|
||||
tinycolor2: 1.6.0
|
||||
dev: true
|
||||
|
||||
/@codemirror/autocomplete@6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4):
|
||||
resolution: {integrity: sha512-Fbwm0V/Wn3BkEJZRhr0hi5BhCo5a7eBL6LYaliPjOSwCyfOpnjXY59HruSxOUNV+1OYer0Tgx1zRNQttjXyDog==}
|
||||
peerDependencies:
|
||||
'@codemirror/language': ^6.0.0
|
||||
'@codemirror/state': ^6.0.0
|
||||
'@codemirror/view': ^6.0.0
|
||||
'@lezer/common': ^1.0.0
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/common': 1.0.4
|
||||
dev: true
|
||||
|
||||
/@codemirror/commands@6.2.4:
|
||||
resolution: {integrity: sha512-42lmDqVH0ttfilLShReLXsDfASKLXzfyC36bzwcqzox9PlHulMcsUOfHXNo2X2aFMVNUoQ7j+d4q5bnfseYoOA==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/common': 1.0.4
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-angular@0.1.2:
|
||||
resolution: {integrity: sha512-Nq7lmx9SU+JyoaRcs6SaJs7uAmW2W06HpgJVQYeZptVGNWDzDvzhjwVb/ZuG1rwTlOocY4Y9GwNOBuKCeJbKtw==}
|
||||
dependencies:
|
||||
'@codemirror/lang-html': 6.4.5
|
||||
'@codemirror/lang-javascript': 6.1.9
|
||||
'@codemirror/language': 6.9.0
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-cpp@6.0.2:
|
||||
resolution: {integrity: sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@lezer/cpp': 1.1.1
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-css@6.2.1(@codemirror/view@6.16.0):
|
||||
resolution: {integrity: sha512-/UNWDNV5Viwi/1lpr/dIXJNWiwDxpw13I4pTUAsNxZdg6E0mI2kTQb0P2iHczg1Tu+H4EBgJR+hYhKiHKko7qg==}
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/css': 1.1.3
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/view'
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-html@6.4.5:
|
||||
resolution: {integrity: sha512-dUCSxkIw2G+chaUfw3Gfu5kkN83vJQN8gfQDp9iEHsIZluMJA0YJveT12zg/28BJx+uPsbQ6VimKCgx3oJrZxA==}
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/lang-css': 6.2.1(@codemirror/view@6.16.0)
|
||||
'@codemirror/lang-javascript': 6.1.9
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/css': 1.1.3
|
||||
'@lezer/html': 1.3.6
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-java@6.0.1:
|
||||
resolution: {integrity: sha512-OOnmhH67h97jHzCuFaIEspbmsT98fNdhVhmA3zCxW0cn7l8rChDhZtwiwJ/JOKXgfm4J+ELxQihxaI7bj7mJRg==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@lezer/java': 1.0.4
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-javascript@6.1.9:
|
||||
resolution: {integrity: sha512-z3jdkcqOEBT2txn2a87A0jSy6Te3679wg/U8QzMeftFt+4KA6QooMwfdFzJiuC3L6fXKfTXZcDocoaxMYfGz0w==}
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/lint': 6.4.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/javascript': 1.4.5
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-json@6.0.1:
|
||||
resolution: {integrity: sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@lezer/json': 1.0.1
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-less@6.0.1(@codemirror/view@6.16.0):
|
||||
resolution: {integrity: sha512-ABcsKBjLbyPZwPR5gePpc8jEKCQrFF4pby2WlMVdmJOOr7OWwwyz8DZonPx/cKDE00hfoSLc8F7yAcn/d6+rTQ==}
|
||||
dependencies:
|
||||
'@codemirror/lang-css': 6.2.1(@codemirror/view@6.16.0)
|
||||
'@codemirror/language': 6.9.0
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/view'
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-lezer@6.0.1:
|
||||
resolution: {integrity: sha512-WHwjI7OqKFBEfkunohweqA5B/jIlxaZso6Nl3weVckz8EafYbPZldQEKSDb4QQ9H9BUkle4PVELP4sftKoA0uQ==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/lezer': 1.1.2
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-markdown@6.2.0:
|
||||
resolution: {integrity: sha512-deKegEQVzfBAcLPqsJEa+IxotqPVwWZi90UOEvQbfa01NTAw8jNinrykuYPTULGUj+gha0ZG2HBsn4s5d64Qrg==}
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/lang-html': 6.4.5
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/markdown': 1.1.0
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-php@6.0.1:
|
||||
resolution: {integrity: sha512-ublojMdw/PNWa7qdN5TMsjmqkNuTBD3k6ndZ4Z0S25SBAiweFGyY68AS3xNcIOlb6DDFDvKlinLQ40vSLqf8xA==}
|
||||
dependencies:
|
||||
'@codemirror/lang-html': 6.4.5
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/php': 1.0.1
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-python@6.1.3(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4):
|
||||
resolution: {integrity: sha512-S9w2Jl74hFlD5nqtUMIaXAq9t5WlM0acCkyuQWUUSvZclk1sV+UfnpFiZzuZSG+hfEaOmxKR5UxY/Uxswn7EhQ==}
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/language': 6.9.0
|
||||
'@lezer/python': 1.1.8
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/state'
|
||||
- '@codemirror/view'
|
||||
- '@lezer/common'
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-rust@6.0.1:
|
||||
resolution: {integrity: sha512-344EMWFBzWArHWdZn/NcgkwMvZIWUR1GEBdwG8FEp++6o6vT6KL9V7vGs2ONsKxxFUPXKI0SPcWhyYyl2zPYxQ==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@lezer/rust': 1.0.1
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-sass@6.0.2(@codemirror/view@6.16.0):
|
||||
resolution: {integrity: sha512-l/bdzIABvnTo1nzdY6U+kPAC51czYQcOErfzQ9zSm9D8GmNPD0WTW8st/CJwBTPLO8jlrbyvlSEcN20dc4iL0Q==}
|
||||
dependencies:
|
||||
'@codemirror/lang-css': 6.2.1(@codemirror/view@6.16.0)
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/sass': 1.0.3
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/view'
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-sql@6.5.4(@codemirror/view@6.16.0)(@lezer/common@1.0.4):
|
||||
resolution: {integrity: sha512-5Gq7fYtT/5HbNyIG7a8vYaqOYQU3JbgtBe3+derkrFUXRVcjkf8WVgz++PIbMFAQsOFMDdDR+uiNM8ZRRuXH+w==}
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/view'
|
||||
- '@lezer/common'
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-vue@0.1.2:
|
||||
resolution: {integrity: sha512-D4YrefiRBAr+CfEIM4S3yvGSbYW+N69mttIfGMEf7diHpRbmygDxS+R/5xSqjgtkY6VO6qmUrre1GkRcWeZa9A==}
|
||||
dependencies:
|
||||
'@codemirror/lang-html': 6.4.5
|
||||
'@codemirror/lang-javascript': 6.1.9
|
||||
'@codemirror/language': 6.9.0
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-wast@6.0.1:
|
||||
resolution: {integrity: sha512-sQLsqhRjl2MWG3rxZysX+2XAyed48KhLBHLgq9xcKxIJu3npH/G+BIXW5NM5mHeDUjG0jcGh9BcjP0NfMStuzA==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@codemirror/lang-xml@6.0.2(@codemirror/view@6.16.0):
|
||||
resolution: {integrity: sha512-JQYZjHL2LAfpiZI2/qZ/qzDuSqmGKMwyApYmEUUCTxLM4MWS7sATUEfIguZQr9Zjx/7gcdnewb039smF6nC2zw==}
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/xml': 1.0.2
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/view'
|
||||
dev: true
|
||||
|
||||
/@codemirror/language-data@6.3.1(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4):
|
||||
resolution: {integrity: sha512-p6jhJmvhGe1TG1EGNhwH7nFWWFSTJ8NDKnB2fVx5g3t+PpO0+63R7GJNxjS0TmmH3cdMxZbzejsik+rlEh1EyQ==}
|
||||
dependencies:
|
||||
'@codemirror/lang-angular': 0.1.2
|
||||
'@codemirror/lang-cpp': 6.0.2
|
||||
'@codemirror/lang-css': 6.2.1(@codemirror/view@6.16.0)
|
||||
'@codemirror/lang-html': 6.4.5
|
||||
'@codemirror/lang-java': 6.0.1
|
||||
'@codemirror/lang-javascript': 6.1.9
|
||||
'@codemirror/lang-json': 6.0.1
|
||||
'@codemirror/lang-less': 6.0.1(@codemirror/view@6.16.0)
|
||||
'@codemirror/lang-markdown': 6.2.0
|
||||
'@codemirror/lang-php': 6.0.1
|
||||
'@codemirror/lang-python': 6.1.3(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/lang-rust': 6.0.1
|
||||
'@codemirror/lang-sass': 6.0.2(@codemirror/view@6.16.0)
|
||||
'@codemirror/lang-sql': 6.5.4(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/lang-vue': 0.1.2
|
||||
'@codemirror/lang-wast': 6.0.1
|
||||
'@codemirror/lang-xml': 6.0.2(@codemirror/view@6.16.0)
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/legacy-modes': 6.3.3
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/state'
|
||||
- '@codemirror/view'
|
||||
- '@lezer/common'
|
||||
dev: true
|
||||
|
||||
/@codemirror/language@6.9.0:
|
||||
resolution: {integrity: sha512-nFu311/0ne/qGuGCL3oKuktBgzVOaxCHZPZv1tLSZkNjPYxxvkjSbzno3MlErG2tgw1Yw1yF8BxMCegeMXqpiw==}
|
||||
dependencies:
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
style-mod: 4.0.3
|
||||
dev: true
|
||||
|
||||
/@codemirror/legacy-modes@6.3.3:
|
||||
resolution: {integrity: sha512-X0Z48odJ0KIoh/HY8Ltz75/4tDYc9msQf1E/2trlxFaFFhgjpVHjZ/BCXe1Lk7s4Gd67LL/CeEEHNI+xHOiESg==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
dev: true
|
||||
|
||||
/@codemirror/lint@6.4.0:
|
||||
resolution: {integrity: sha512-6VZ44Ysh/Zn07xrGkdtNfmHCbGSHZzFBdzWi0pbd7chAQ/iUcpLGX99NYRZTa7Ugqg4kEHCqiHhcZnH0gLIgSg==}
|
||||
dependencies:
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
crelt: 1.0.6
|
||||
dev: true
|
||||
|
||||
/@codemirror/search@6.5.1:
|
||||
resolution: {integrity: sha512-4jupk4JwkeVbrN2pStY74q6OJEYqwosB4koA66nyLeVedadtX9MHI38j2vbYmnfDGurDApP3OZO46MrWalcjiQ==}
|
||||
dependencies:
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
crelt: 1.0.6
|
||||
dev: true
|
||||
|
||||
/@codemirror/state@6.2.1:
|
||||
resolution: {integrity: sha512-RupHSZ8+OjNT38zU9fKH2sv+Dnlr8Eb8sl4NOnnqz95mCFTZUaiRP8Xv5MeeaG0px2b8Bnfe7YGwCV3nsBhbuw==}
|
||||
dev: true
|
||||
|
||||
/@codemirror/theme-one-dark@6.1.2:
|
||||
resolution: {integrity: sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/highlight': 1.1.6
|
||||
dev: true
|
||||
|
||||
/@codemirror/view@6.16.0:
|
||||
resolution: {integrity: sha512-1Z2HkvkC3KR/oEZVuW9Ivmp8TWLzGEd8T8TA04TTwPvqogfkHBdYSlflytDOqmkUxM2d1ywTg7X2dU5mC+SXvg==}
|
||||
dependencies:
|
||||
'@codemirror/state': 6.2.1
|
||||
style-mod: 4.0.3
|
||||
w3c-keyname: 2.2.8
|
||||
dev: true
|
||||
|
||||
/@colors/colors@1.5.0:
|
||||
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
|
||||
engines: {node: '>=0.1.90'}
|
||||
@@ -3562,6 +3857,114 @@ packages:
|
||||
resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==}
|
||||
dev: true
|
||||
|
||||
/@lezer/common@1.0.4:
|
||||
resolution: {integrity: sha512-lZHlk8p67x4aIDtJl6UQrXSOP6oi7dQR3W/geFVrENdA1JDaAJWldnVqVjPMJupbTKbzDfFcePfKttqVidS/dg==}
|
||||
dev: true
|
||||
|
||||
/@lezer/cpp@1.1.1:
|
||||
resolution: {integrity: sha512-eS1M3L3U2mDowoFVPG7tEp01SWu9/68Nx3HEBgLJVn3N9ku7g5S7WdFv0jzmcTipAyONYfZJ+7x4WRkfdB2Ung==}
|
||||
dependencies:
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@lezer/css@1.1.3:
|
||||
resolution: {integrity: sha512-SjSM4pkQnQdJDVc80LYzEaMiNy9txsFbI7HsMgeVF28NdLaAdHNtQ+kB/QqDUzRBV/75NTXjJ/R5IdC8QQGxMg==}
|
||||
dependencies:
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@lezer/highlight@1.1.6:
|
||||
resolution: {integrity: sha512-cmSJYa2us+r3SePpRCjN5ymCqCPv+zyXmDl0ciWtVaNiORT/MxM7ZgOMQZADD0o51qOaOg24qc/zBViOIwAjJg==}
|
||||
dependencies:
|
||||
'@lezer/common': 1.0.4
|
||||
dev: true
|
||||
|
||||
/@lezer/html@1.3.6:
|
||||
resolution: {integrity: sha512-Kk9HJARZTc0bAnMQUqbtuhFVsB4AnteR2BFUWfZV7L/x1H0aAKz6YabrfJ2gk/BEgjh9L3hg5O4y2IDZRBdzuQ==}
|
||||
dependencies:
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@lezer/java@1.0.4:
|
||||
resolution: {integrity: sha512-POc53LHf2AuNeRXjqZbXNu88GKj0KZTjjSx0L7tYeXlrEHF+3NAQx+dEwKVuCbkl0ZMtpRy2VsDYOV7KKV0oyg==}
|
||||
dependencies:
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@lezer/javascript@1.4.5:
|
||||
resolution: {integrity: sha512-FmBUHz8K1V22DgjTd6SrIG9owbzOYZ1t3rY6vGEmw+e2RVBd7sqjM8uXEVRFmfxKFn1Mx2ABJehHjrN3G2ZpmA==}
|
||||
dependencies:
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@lezer/json@1.0.1:
|
||||
resolution: {integrity: sha512-nkVC27qiEZEjySbi6gQRuMwa2sDu2PtfjSgz0A4QF81QyRGm3kb2YRzLcOPcTEtmcwvrX/cej7mlhbwViA4WJw==}
|
||||
dependencies:
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@lezer/lezer@1.1.2:
|
||||
resolution: {integrity: sha512-O8yw3CxPhzYHB1hvwbdozjnAslhhR8A5BH7vfEMof0xk3p+/DFDfZkA9Tde6J+88WgtwaHy4Sy6ThZSkaI0Evw==}
|
||||
dependencies:
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@lezer/lr@1.3.10:
|
||||
resolution: {integrity: sha512-BZfVvf7Re5BIwJHlZXbJn9L8lus5EonxQghyn+ih8Wl36XMFBPTXC0KM0IdUtj9w/diPHsKlXVgL+AlX2jYJ0Q==}
|
||||
dependencies:
|
||||
'@lezer/common': 1.0.4
|
||||
dev: true
|
||||
|
||||
/@lezer/markdown@1.1.0:
|
||||
resolution: {integrity: sha512-JYOI6Lkqbl83semCANkO3CKbKc0pONwinyagBufWBm+k4yhIcqfCF8B8fpEpvJLmIy7CAfwiq7dQ/PzUZA340g==}
|
||||
dependencies:
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/highlight': 1.1.6
|
||||
dev: true
|
||||
|
||||
/@lezer/php@1.0.1:
|
||||
resolution: {integrity: sha512-aqdCQJOXJ66De22vzdwnuC502hIaG9EnPK2rSi+ebXyUd+j7GAX1mRjWZOVOmf3GST1YUfUCu6WXDiEgDGOVwA==}
|
||||
dependencies:
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@lezer/python@1.1.8:
|
||||
resolution: {integrity: sha512-1T/XsmeF57ijrjpC0Zmrf9YeO5mn2zC1XeSNrOnc0KB+6PgxJ5m7kWKt0CnwyS74oHQXbJxUUL+QDQJR26c1Gw==}
|
||||
dependencies:
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@lezer/rust@1.0.1:
|
||||
resolution: {integrity: sha512-j+ToFKM6Wpglv3OQ4ebHYdYIMT2dh0ziCCV0rTf47AWiHOVhR0WjaKrBq+yuvDQNEhr5sxPxVI7+naJIgpqcsQ==}
|
||||
dependencies:
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@lezer/sass@1.0.3:
|
||||
resolution: {integrity: sha512-n4l2nVOB7gWiGU/Cg2IVxpt2Ic9Hgfgy/7gk+p/XJibAsPXs0lSbsfGwQgwsAw9B/euYo3oS6lEFr9WytoqcZg==}
|
||||
dependencies:
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@lezer/xml@1.0.2:
|
||||
resolution: {integrity: sha512-dlngsWceOtQBMuBPw5wtHpaxdPJ71aVntqjbpGkFtWsp4WtQmCnuTjQGocviymydN6M18fhj6UQX3oiEtSuY7w==}
|
||||
dependencies:
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@loadable/component@5.15.2(react@18.1.0):
|
||||
resolution: {integrity: sha512-ryFAZOX5P2vFkUdzaAtTG88IGnr9qxSdvLRvJySXcUA4B4xVWurUNADu3AnKPksxOZajljqTrDEDcYjeL4lvLw==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -3644,6 +4047,19 @@ packages:
|
||||
state-local: 1.0.7
|
||||
dev: true
|
||||
|
||||
/@nextjournal/lang-clojure@1.0.0:
|
||||
resolution: {integrity: sha512-gOCV71XrYD0DhwGoPMWZmZ0r92/lIHsqQu9QWdpZYYBwiChNwMO4sbVMP7eTuAqffFB2BTtCSC+1skSH9d3bNg==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@nextjournal/lezer-clojure': 1.0.0
|
||||
dev: true
|
||||
|
||||
/@nextjournal/lezer-clojure@1.0.0:
|
||||
resolution: {integrity: sha512-VZyuGu4zw5mkTOwQBTaGVNWmsOZAPw5ZRxu1/Knk/Xfs7EDBIogwIs5UXTYkuECX5ZQB8eOB+wKA2pc7VyqaZQ==}
|
||||
dependencies:
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3:
|
||||
resolution: {integrity: sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==}
|
||||
requiresBuild: true
|
||||
@@ -3878,6 +4294,82 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: true
|
||||
|
||||
/@replit/codemirror-lang-csharp@6.1.0(@codemirror/autocomplete@6.9.0)(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)(@lezer/highlight@1.1.6)(@lezer/lr@1.3.10):
|
||||
resolution: {integrity: sha512-Dtyk9WVrdPPgkgTp8MUX9HyXd87O7UZnFrE647gjHUZY8p0UN+z0m6dPfk6rJMsTTvMcl7YbDUykxfeqB6EQOQ==}
|
||||
peerDependencies:
|
||||
'@codemirror/autocomplete': ^6.0.0
|
||||
'@codemirror/language': ^6.0.0
|
||||
'@codemirror/state': ^6.0.0
|
||||
'@codemirror/view': ^6.0.0
|
||||
'@lezer/common': ^1.0.0
|
||||
'@lezer/highlight': ^1.0.0
|
||||
'@lezer/lr': ^1.0.0
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@replit/codemirror-lang-nix@6.0.1(@codemirror/autocomplete@6.9.0)(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)(@lezer/highlight@1.1.6)(@lezer/lr@1.3.10):
|
||||
resolution: {integrity: sha512-lvzjoYn9nfJzBD5qdm3Ut6G3+Or2wEacYIDJ49h9+19WSChVnxv4ojf+rNmQ78ncuxIt/bfbMvDLMeMP0xze6g==}
|
||||
peerDependencies:
|
||||
'@codemirror/autocomplete': ^6.0.0
|
||||
'@codemirror/language': ^6.0.0
|
||||
'@codemirror/state': ^6.0.0
|
||||
'@codemirror/view': ^6.0.0
|
||||
'@lezer/common': ^1.0.0
|
||||
'@lezer/highlight': ^1.0.0
|
||||
'@lezer/lr': ^1.0.0
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@replit/codemirror-lang-solidity@6.0.1(@codemirror/language@6.9.0):
|
||||
resolution: {integrity: sha512-kDnak0xZelGmvzJwKTpMTl6gYSfFq9hnxrkbLaMV0CARq/MFvDQJmcmYon/k8uZqXy6DfzewKDV8tx9kY2WUZg==}
|
||||
peerDependencies:
|
||||
'@codemirror/language': ^6.0.0
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
dev: true
|
||||
|
||||
/@replit/codemirror-lang-svelte@6.0.0(@codemirror/autocomplete@6.9.0)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.5)(@codemirror/lang-javascript@6.1.9)(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)(@lezer/highlight@1.1.6)(@lezer/javascript@1.4.5)(@lezer/lr@1.3.10):
|
||||
resolution: {integrity: sha512-U2OqqgMM6jKelL0GNWbAmqlu1S078zZNoBqlJBW+retTc5M4Mha6/Y2cf4SVg6ddgloJvmcSpt4hHrVoM4ePRA==}
|
||||
peerDependencies:
|
||||
'@codemirror/autocomplete': ^6.0.0
|
||||
'@codemirror/lang-css': ^6.0.1
|
||||
'@codemirror/lang-html': ^6.2.0
|
||||
'@codemirror/lang-javascript': ^6.1.1
|
||||
'@codemirror/language': ^6.0.0
|
||||
'@codemirror/state': ^6.0.0
|
||||
'@codemirror/view': ^6.0.0
|
||||
'@lezer/common': ^1.0.0
|
||||
'@lezer/highlight': ^1.0.0
|
||||
'@lezer/javascript': ^1.2.0
|
||||
'@lezer/lr': ^1.0.0
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/lang-css': 6.2.1(@codemirror/view@6.16.0)
|
||||
'@codemirror/lang-html': 6.4.5
|
||||
'@codemirror/lang-javascript': 6.1.9
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/javascript': 1.4.5
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/@sentry-internal/tracing@7.54.0:
|
||||
resolution: {integrity: sha512-JsyhZ0wWZ+VqbHJg+azqRGdYJDkcI5R9+pnkO6SzbzxrRewqMAIwzkpPee3oI7vG99uhMEkOkMjHu0nQGwkOQw==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -4828,6 +5320,101 @@ packages:
|
||||
eslint-visitor-keys: 3.4.1
|
||||
dev: true
|
||||
|
||||
/@uiw/codemirror-extensions-basic-setup@4.21.9(@codemirror/autocomplete@6.9.0)(@codemirror/commands@6.2.4)(@codemirror/language@6.9.0)(@codemirror/lint@6.4.0)(@codemirror/search@6.5.1)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0):
|
||||
resolution: {integrity: sha512-TQT6aF8brxZpFnk/K4fm/K/9k9eF3PMav/KKjHlYrGUT8BTNk/qL+ximLtIzvTUhmBFchjM1lrqSJdvpVom7/w==}
|
||||
peerDependencies:
|
||||
'@codemirror/autocomplete': '>=6.0.0'
|
||||
'@codemirror/commands': '>=6.0.0'
|
||||
'@codemirror/language': '>=6.0.0'
|
||||
'@codemirror/lint': '>=6.0.0'
|
||||
'@codemirror/search': '>=6.0.0'
|
||||
'@codemirror/state': '>=6.0.0'
|
||||
'@codemirror/view': '>=6.0.0'
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/commands': 6.2.4
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/lint': 6.4.0
|
||||
'@codemirror/search': 6.5.1
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
dev: true
|
||||
|
||||
/@uiw/codemirror-extensions-langs@4.21.9(@codemirror/autocomplete@6.9.0)(@codemirror/language-data@6.3.1)(@codemirror/language@6.9.0)(@codemirror/legacy-modes@6.3.3)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)(@lezer/highlight@1.1.6)(@lezer/javascript@1.4.5)(@lezer/lr@1.3.10):
|
||||
resolution: {integrity: sha512-s1VT1rss0iyvrtRl7BZtC5H7U5uQtCKTaD8wxjQrgZz5un9wHVvy9twU97aJGQR0FwbKWqK8/1iiICRJTRCoZA==}
|
||||
peerDependencies:
|
||||
'@codemirror/language-data': '>=6.0.0'
|
||||
'@codemirror/legacy-modes': '>=6.0.0'
|
||||
dependencies:
|
||||
'@codemirror/lang-angular': 0.1.2
|
||||
'@codemirror/lang-cpp': 6.0.2
|
||||
'@codemirror/lang-css': 6.2.1(@codemirror/view@6.16.0)
|
||||
'@codemirror/lang-html': 6.4.5
|
||||
'@codemirror/lang-java': 6.0.1
|
||||
'@codemirror/lang-javascript': 6.1.9
|
||||
'@codemirror/lang-json': 6.0.1
|
||||
'@codemirror/lang-less': 6.0.1(@codemirror/view@6.16.0)
|
||||
'@codemirror/lang-lezer': 6.0.1
|
||||
'@codemirror/lang-markdown': 6.2.0
|
||||
'@codemirror/lang-php': 6.0.1
|
||||
'@codemirror/lang-python': 6.1.3(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/lang-rust': 6.0.1
|
||||
'@codemirror/lang-sass': 6.0.2(@codemirror/view@6.16.0)
|
||||
'@codemirror/lang-sql': 6.5.4(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/lang-vue': 0.1.2
|
||||
'@codemirror/lang-wast': 6.0.1
|
||||
'@codemirror/lang-xml': 6.0.2(@codemirror/view@6.16.0)
|
||||
'@codemirror/language-data': 6.3.1(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/legacy-modes': 6.3.3
|
||||
'@nextjournal/lang-clojure': 1.0.0
|
||||
'@replit/codemirror-lang-csharp': 6.1.0(@codemirror/autocomplete@6.9.0)(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)(@lezer/highlight@1.1.6)(@lezer/lr@1.3.10)
|
||||
'@replit/codemirror-lang-nix': 6.0.1(@codemirror/autocomplete@6.9.0)(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)(@lezer/highlight@1.1.6)(@lezer/lr@1.3.10)
|
||||
'@replit/codemirror-lang-solidity': 6.0.1(@codemirror/language@6.9.0)
|
||||
'@replit/codemirror-lang-svelte': 6.0.0(@codemirror/autocomplete@6.9.0)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.5)(@codemirror/lang-javascript@6.1.9)(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)(@lezer/highlight@1.1.6)(@lezer/javascript@1.4.5)(@lezer/lr@1.3.10)
|
||||
codemirror-lang-mermaid: 0.2.2
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/autocomplete'
|
||||
- '@codemirror/language'
|
||||
- '@codemirror/state'
|
||||
- '@codemirror/view'
|
||||
- '@lezer/common'
|
||||
- '@lezer/highlight'
|
||||
- '@lezer/javascript'
|
||||
- '@lezer/lr'
|
||||
dev: true
|
||||
|
||||
/@uiw/react-codemirror@4.21.9(@babel/runtime@7.22.3)(@codemirror/autocomplete@6.9.0)(@codemirror/language@6.9.0)(@codemirror/lint@6.4.0)(@codemirror/search@6.5.1)(@codemirror/state@6.2.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.16.0)(codemirror@6.0.1)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-aeLegPz2iCvqJjhzXp2WUMqpMZDqxsTnF3rX9kGRlfY6vQLsrjoctj0cQ29uxEtFYJChOVjtCOtnQUlyIuNAHQ==}
|
||||
peerDependencies:
|
||||
'@babel/runtime': '>=7.11.0'
|
||||
'@codemirror/state': '>=6.0.0'
|
||||
'@codemirror/theme-one-dark': '>=6.0.0'
|
||||
'@codemirror/view': '>=6.0.0'
|
||||
codemirror: '>=6.0.0'
|
||||
react: '>=16.8.0 || 18'
|
||||
react-dom: '>=16.8.0 || 18'
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.22.3
|
||||
'@codemirror/commands': 6.2.4
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/theme-one-dark': 6.1.2
|
||||
'@codemirror/view': 6.16.0
|
||||
'@uiw/codemirror-extensions-basic-setup': 4.21.9(@codemirror/autocomplete@6.9.0)(@codemirror/commands@6.2.4)(@codemirror/language@6.9.0)(@codemirror/lint@6.4.0)(@codemirror/search@6.5.1)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)
|
||||
codemirror: 6.0.1(@lezer/common@1.0.4)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/autocomplete'
|
||||
- '@codemirror/language'
|
||||
- '@codemirror/lint'
|
||||
- '@codemirror/search'
|
||||
dev: true
|
||||
|
||||
/@umijs/ast@4.0.72:
|
||||
resolution: {integrity: sha512-WatRvU09vsx4Hlu5hemPA7a+QK4pJvzmQz/9LxN/KVgn+wZXi717qHFLu5eoV6XO7HlFZaEBGq2aHpDj0ngA8w==}
|
||||
dependencies:
|
||||
@@ -6657,8 +7244,26 @@ packages:
|
||||
mimic-response: 1.0.1
|
||||
dev: false
|
||||
|
||||
/codemirror@5.65.13:
|
||||
resolution: {integrity: sha512-SVWEzKXmbHmTQQWaz03Shrh4nybG0wXx2MEu3FO4ezbPW8IbnZEd5iGHGEffSUaitKYa3i+pHpBsSvw8sPHtzg==}
|
||||
/codemirror-lang-mermaid@0.2.2:
|
||||
resolution: {integrity: sha512-AqSzkQgfWsjBbifio3dy/zDj6WXEw4g52Mq6bltIWLMWryWWRMpFwjQSlHtCGOol1FENYObUF5KI4ofiv8bjXA==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
dev: true
|
||||
|
||||
/codemirror@6.0.1(@lezer/common@1.0.4):
|
||||
resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==}
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/commands': 6.2.4
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/lint': 6.4.0
|
||||
'@codemirror/search': 6.5.1
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
transitivePeerDependencies:
|
||||
- '@lezer/common'
|
||||
dev: true
|
||||
|
||||
/color-convert@1.9.3:
|
||||
@@ -6970,6 +7575,10 @@ packages:
|
||||
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
|
||||
dev: true
|
||||
|
||||
/crelt@1.0.6:
|
||||
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
|
||||
dev: true
|
||||
|
||||
/cron-parser@4.8.1:
|
||||
resolution: {integrity: sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@@ -8273,6 +8882,12 @@ packages:
|
||||
resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
|
||||
dev: true
|
||||
|
||||
/file-stream-rotator@0.6.1:
|
||||
resolution: {integrity: sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==}
|
||||
dependencies:
|
||||
moment: 2.29.4
|
||||
dev: false
|
||||
|
||||
/file-uri-to-path@2.0.0:
|
||||
resolution: {integrity: sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -10787,6 +11402,11 @@ packages:
|
||||
engines: {node: '>= 0.10.0'}
|
||||
dev: true
|
||||
|
||||
/object-hash@2.2.0:
|
||||
resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==}
|
||||
engines: {node: '>= 6'}
|
||||
dev: false
|
||||
|
||||
/object-inspect@1.12.3:
|
||||
resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
|
||||
|
||||
@@ -12903,19 +13523,6 @@ packages:
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: true
|
||||
|
||||
/react-codemirror2@7.2.1(codemirror@5.65.13)(react@18.2.0):
|
||||
resolution: {integrity: sha512-t7YFmz1AXdlImgHXA9Ja0T6AWuopilub24jRaQdPVbzUJVNKIYuy3uCFZYa7CE5S3UW6SrSa5nAqVQvtzRF9gw==}
|
||||
peerDependencies:
|
||||
codemirror: 5.x
|
||||
react: '>=15.5 <=16.x || 18'
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
dependencies:
|
||||
codemirror: 5.65.13
|
||||
react: 18.2.0
|
||||
dev: true
|
||||
|
||||
/react-copy-to-clipboard@5.1.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==}
|
||||
peerDependencies:
|
||||
@@ -14307,6 +14914,10 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/style-mod@4.0.3:
|
||||
resolution: {integrity: sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw==}
|
||||
dev: true
|
||||
|
||||
/style-search@0.1.0:
|
||||
resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==}
|
||||
dev: true
|
||||
@@ -15308,6 +15919,10 @@ packages:
|
||||
acorn-walk: 8.2.0
|
||||
dev: true
|
||||
|
||||
/w3c-keyname@2.2.8:
|
||||
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
|
||||
dev: true
|
||||
|
||||
/walker@1.0.8:
|
||||
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
|
||||
dependencies:
|
||||
@@ -15489,6 +16104,19 @@ packages:
|
||||
semver: 5.7.1
|
||||
dev: true
|
||||
|
||||
/winston-daily-rotate-file@4.7.1(winston@3.9.0):
|
||||
resolution: {integrity: sha512-7LGPiYGBPNyGHLn9z33i96zx/bd71pjBn9tqQzO3I4Tayv94WPmBNwKC7CO1wPHdP9uvu+Md/1nr6VSH9h0iaA==}
|
||||
engines: {node: '>=8'}
|
||||
peerDependencies:
|
||||
winston: ^3
|
||||
dependencies:
|
||||
file-stream-rotator: 0.6.1
|
||||
object-hash: 2.2.0
|
||||
triple-beam: 1.3.0
|
||||
winston: 3.9.0
|
||||
winston-transport: 4.5.0
|
||||
dev: false
|
||||
|
||||
/winston-transport@4.5.0:
|
||||
resolution: {integrity: sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==}
|
||||
engines: {node: '>= 6.4.0'}
|
||||
|
||||
+1
-1
@@ -456,7 +456,7 @@ class WeCom:
|
||||
return respone["errmsg"]
|
||||
|
||||
def send_mpnews(self, title, message, media_id, touser="@all"):
|
||||
send_url = f"https://{self.HOST}/cgi-bin/message/send?access_token={self.get_access_token()}"
|
||||
send_url = f"{self.ORIGIN}/cgi-bin/message/send?access_token={self.get_access_token()}"
|
||||
send_values = {
|
||||
"touser": touser,
|
||||
"msgtype": "mpnews",
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ add_cron_api() {
|
||||
local sub_id="$4"
|
||||
fi
|
||||
|
||||
if [[ ! $sub_id ]];then
|
||||
if [[ ! $sub_id ]]; then
|
||||
sub_id="null"
|
||||
fi
|
||||
|
||||
|
||||
+19
-11
@@ -86,6 +86,11 @@ check_server() {
|
||||
fi
|
||||
}
|
||||
|
||||
env_str_to_array() {
|
||||
local IFS="&"
|
||||
read -ra array <<<"${!env_param}"
|
||||
}
|
||||
|
||||
## 正常运行单个脚本,$1:传入参数
|
||||
run_normal() {
|
||||
local file_param=$1
|
||||
@@ -113,8 +118,7 @@ run_concurrent() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local envs=$(eval echo "\$${env_param}")
|
||||
local array=($(echo $envs | sed 's/&/ /g'))
|
||||
env_str_to_array
|
||||
local tempArr=$(echo $num_param | sed "s/-max/-${#array[@]}/g" | sed "s/max-/${#array[@]}-/g" | perl -pe "s|(\d+)(-\|~\|_)(\d+)|{\1..\3}|g")
|
||||
local runArr=($(eval echo $tempArr))
|
||||
runArr=($(awk -v RS=' ' '!a[$1]++' <<<${runArr[@]}))
|
||||
@@ -125,11 +129,13 @@ run_concurrent() {
|
||||
let n++
|
||||
done
|
||||
|
||||
local cookieStr=$(echo ${array_run[*]} | sed 's/\ /\&/g')
|
||||
[[ ! -z $cookieStr ]] && export ${env_param}=${cookieStr}
|
||||
local cookieStr=$(
|
||||
IFS="&"
|
||||
echo "${array_run[*]}"
|
||||
)
|
||||
[[ ! -z $cookieStr ]] && export "${env_param}=${cookieStr}"
|
||||
|
||||
local envs=$(eval echo "\$${env_param}")
|
||||
local array=($(echo $envs | sed 's/&/ /g'))
|
||||
env_str_to_array
|
||||
single_log_time=$(date "+%Y-%m-%d-%H-%M-%S.%3N")
|
||||
|
||||
cd $dir_scripts
|
||||
@@ -139,7 +145,7 @@ run_concurrent() {
|
||||
file_param=${file_param/$relative_path\//}
|
||||
fi
|
||||
for i in "${!array[@]}"; do
|
||||
export ${env_param}=${array[i]}
|
||||
export "${env_param}=${array[i]}"
|
||||
single_log_path="$dir_log/$log_dir/${single_log_time}_$((i + 1)).log"
|
||||
eval $timeoutCmd $which_program $file_param &>$single_log_path &
|
||||
done
|
||||
@@ -161,8 +167,7 @@ run_designated() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local envs=$(eval echo "\$${env_param}")
|
||||
local array=($(echo $envs | sed 's/&/ /g'))
|
||||
env_str_to_array
|
||||
local tempArr=$(echo $num_param | sed "s/-max/-${#array[@]}/g" | sed "s/max-/${#array[@]}-/g" | perl -pe "s|(\d+)(-\|~\|_)(\d+)|{\1..\3}|g")
|
||||
local runArr=($(eval echo $tempArr))
|
||||
runArr=($(awk -v RS=' ' '!a[$1]++' <<<${runArr[@]}))
|
||||
@@ -173,8 +178,11 @@ run_designated() {
|
||||
let n++
|
||||
done
|
||||
|
||||
local cookieStr=$(echo ${array_run[*]} | sed 's/\ /\&/g')
|
||||
[[ ! -z $cookieStr ]] && export ${env_param}=${cookieStr}
|
||||
local cookieStr=$(
|
||||
IFS="&"
|
||||
echo "${array_run[*]}"
|
||||
)
|
||||
[[ ! -z $cookieStr ]] && export "${env_param}=${cookieStr}"
|
||||
|
||||
cd $dir_scripts
|
||||
local relative_path="${file_param%/*}"
|
||||
|
||||
+1
-1
@@ -296,7 +296,7 @@ git_clone_scripts() {
|
||||
|
||||
set_proxy "$proxy"
|
||||
|
||||
git clone --depth=1 $part_cmd $url $dir
|
||||
git clone --depth=1 $part_cmd $url $dir 2>&1
|
||||
exit_status=$?
|
||||
|
||||
unset_proxy
|
||||
|
||||
+3
-3
@@ -31,7 +31,7 @@ output_list_add_drop() {
|
||||
local list=$1
|
||||
local type=$2
|
||||
if [[ -s $list ]]; then
|
||||
echo -e "检测到有${type}的定时任务:\n"
|
||||
echo -e "检测到有${type}的定时任务:"
|
||||
cat $list
|
||||
echo
|
||||
fi
|
||||
@@ -134,10 +134,10 @@ update_repo() {
|
||||
git_clone_scripts "${formatUrl}" ${repo_path} "${branch}" "${proxy}"
|
||||
|
||||
if [[ $exit_status -eq 0 ]]; then
|
||||
echo -e "\n更新${repo_path}成功...\n"
|
||||
echo -e "\n拉取 ${uniq_path} 成功...\n"
|
||||
diff_scripts "$repo_path" "$author" "$path" "$blackword" "$dependence" "$extensions" "$autoAddCron" "$autoDelCron"
|
||||
else
|
||||
echo -e "\n更新${repo_path}失败,请检查网络...\n"
|
||||
echo -e "\n拉取 ${uniq_path} 失败,请检查网络...\n"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const baseUrl = window.__ENV__QlBaseUrl || '/';
|
||||
import { setLocale } from '@umijs/max';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
export function rootContainer(container: any) {
|
||||
@@ -9,6 +10,7 @@ export function rootContainer(container: any) {
|
||||
let currentLocale = intl.determineLocale({
|
||||
urlLocaleKey: 'lang',
|
||||
cookieLocaleKey: 'lang',
|
||||
localStorageLocaleKey: 'lang',
|
||||
}).slice(0, 2);
|
||||
|
||||
if (!currentLocale || !Object.keys(locales).includes(currentLocale)) {
|
||||
@@ -16,6 +18,7 @@ export function rootContainer(container: any) {
|
||||
}
|
||||
|
||||
intl.init({ currentLocale, locales });
|
||||
setLocale(currentLocale === 'zh' ? 'zh-CN' : 'en-US');
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
+31
-9
@@ -1,6 +1,5 @@
|
||||
@import '~antd/es/style/themes/default.less';
|
||||
@import '~@/styles/variable.less';
|
||||
@import '~codemirror/lib/codemirror.css';
|
||||
|
||||
@font-face {
|
||||
font-family: 'Source Code Pro';
|
||||
@@ -32,9 +31,24 @@ body {
|
||||
}
|
||||
|
||||
.log-modal {
|
||||
.ant-modal {
|
||||
padding-bottom: 0 !important;
|
||||
width: 580px !important;
|
||||
&.ant-modal {
|
||||
max-width: 1000px !important;
|
||||
width: 80vw !important;
|
||||
}
|
||||
|
||||
.ant-modal-body {
|
||||
overflow-y: auto;
|
||||
min-height: 300px;
|
||||
max-height: calc(80vh - 110px);
|
||||
max-height: calc(80vh - var(--vh-offset, 110px));
|
||||
padding: 0;
|
||||
display: flex;
|
||||
|
||||
.log-container {
|
||||
width: 100%;
|
||||
padding: 24px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
@@ -87,10 +101,12 @@ body {
|
||||
}
|
||||
|
||||
.ant-tooltip {
|
||||
max-width: 500px !important;
|
||||
max-width: 300px !important;
|
||||
|
||||
.ant-tooltip-inner {
|
||||
word-break: break-all !important;
|
||||
max-height: 300px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,8 +198,14 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.log-modal {
|
||||
&.ant-modal {
|
||||
width: calc(100vw - 16px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tooltip {
|
||||
max-width: 250px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,9 +390,9 @@ select:-webkit-autofill:focus {
|
||||
}
|
||||
|
||||
pre {
|
||||
word-break: break-all !important;
|
||||
white-space: break-spaces !important;
|
||||
padding: 0 !important;
|
||||
word-break: break-all;
|
||||
white-space: break-spaces;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.virtuallist {
|
||||
|
||||
@@ -32,9 +32,6 @@ import {
|
||||
import SockJS from 'sockjs-client';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { init } from '../utils/init';
|
||||
import 'codemirror/mode/javascript/javascript';
|
||||
import 'codemirror/mode/python/python';
|
||||
import 'codemirror/mode/shell/shell';
|
||||
|
||||
export interface SharedContext {
|
||||
headerStyle: React.CSSProperties;
|
||||
|
||||
@@ -448,5 +448,8 @@
|
||||
"编辑订阅": "Edit Subscription",
|
||||
"Subscription表达式格式有误": "Incorrect Subscription Expression Format",
|
||||
"一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)": "The 'Group Code' for One-to-Many Push (Below One-to-Many Push->Your Group (if not, create one)->Group Code, if you are the creator of the group, you also need to click 'View QR Code' to scan and bind, otherwise you cannot receive group messages)",
|
||||
"登录已过期,请重新登录": "Login session has expired, please log in again"
|
||||
"登录已过期,请重新登录": "Login session has expired, please log in again",
|
||||
"系统日志": "System Logs",
|
||||
"主题": "Theme",
|
||||
"语言": "Language"
|
||||
}
|
||||
|
||||
+12
-9
@@ -337,7 +337,7 @@
|
||||
"飞书机器人": "飞书机器人",
|
||||
"自定义通知": "自定义通知",
|
||||
"已关闭": "已关闭",
|
||||
"gotify的url地址,例如 https://push.example.de:8080": "gotify的url地址,例如 https://push.example.de:8080",
|
||||
"gotify的url地址,例如 https://push.example.de:8080": "gotify的url地址,例如 https://push.example.de:8080",
|
||||
"gotify的消息应用token码": "gotify的消息应用token码",
|
||||
"推送消息的优先级": "推送消息的优先级",
|
||||
"chat的url地址": "chat的url地址",
|
||||
@@ -349,21 +349,21 @@
|
||||
"PushDeer的Key,https://github.com/easychen/pushdeer": "PushDeer的Key,https://github.com/easychen/pushdeer",
|
||||
"PushDeer的自架API endpoint,默认是 https://api2.pushdeer.com/message/push": "PushDeer的自架API endpoint,默认是 https://api2.pushdeer.com/message/push",
|
||||
"Bark的信息IP/设备码,例如:https://api.day.app/XXXXXXXX": "Bark的信息IP/设备码,例如:https://api.day.app/XXXXXXXX",
|
||||
"BARK推送图标,自定义推送图标 (需iOS15或以上才能显示)": "BARK推送图标,自定义推送图标 (需iOS15或以上才能显示)",
|
||||
"BARK推送铃声,铃声列表去APP查看复制填写": "BARK推送铃声,铃声列表去APP查看复制填写",
|
||||
"BARK推送消息的分组, 默认为qinglong": "BARK推送消息的分组, 默认为qinglong",
|
||||
"BARK推送图标,自定义推送图标 (需iOS15或以上才能显示)": "BARK推送图标,自定义推送图标 (需iOS15或以上才能显示)",
|
||||
"BARK推送铃声,铃声列表去APP查看复制填写": "BARK推送铃声,铃声列表去APP查看复制填写",
|
||||
"BARK推送消息的分组,默认为qinglong": "BARK推送消息的分组,默认为qinglong",
|
||||
"telegram机器人的token,例如:1077xxx4424:AAFjv0FcqxxxxxxgEMGfi22B4yh15R5uw": "telegram机器人的token,例如:1077xxx4424:AAFjv0FcqxxxxxxgEMGfi22B4yh15R5uw",
|
||||
"telegram用户的id,例如:129xxx206": "telegram用户的id,例如:129xxx206",
|
||||
"代理IP": "代理IP",
|
||||
"代理端口": "代理端口",
|
||||
"telegram代理配置认证参数, 用户名与密码用英文冒号连接 user:password": "telegram代理配置认证参数, 用户名与密码用英文冒号连接 user:password",
|
||||
"telegram代理配置认证参数,用户名与密码用英文冒号连接 user:password": "telegram代理配置认证参数, 用户名与密码用英文冒号连接 user:password",
|
||||
"telegram api自建的反向代理地址,默认tg官方api": "telegram api自建的反向代理地址,默认tg官方api",
|
||||
"钉钉机器人webhook token,例如:5a544165465465645d0f31dca676e7bd07415asdasd": "钉钉机器人webhook token,例如:5a544165465465645d0f31dca676e7bd07415asdasd",
|
||||
"密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串": "密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串",
|
||||
"企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa": "企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa",
|
||||
"企业微信机器人的webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa": "企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa",
|
||||
"企业微信代理地址": "企业微信代理地址",
|
||||
"corpid,corpsecret,touser(注:多个成员ID使用|隔开),agentid,消息类型(选填,不填默认文本消息类型) 注意用,号隔开(英文输入法的逗号),例如:wwcfrs,B-76WERQ,qinglong,1000001,2COat": "corpid,corpsecret,touser(注:多个成员ID使用|隔开),agentid,消息类型(选填,不填默认文本消息类型) 注意用,号隔开(英文输入法的逗号),例如:wwcfrs,B-76WERQ,qinglong,1000001,2COat",
|
||||
"密钥key,智能微秘书个人中心获取apikey,申请地址:https://wechat.aibotk.com/signup?from=ql": "密钥key,智能微秘书个人中心获取apikey,申请地址:https://wechat.aibotk.com/signup?from=ql",
|
||||
"corpid、corpsecret、touser(注:多个成员ID使用|隔开)、agentid、消息类型(选填,不填默认文本消息类型) 注意用,号隔开(英文输入法的逗号),例如:wwcfrs,B-76WERQ,qinglong,1000001,2COat": "corpid,corpsecret,touser(注:多个成员ID使用|隔开),agentid,消息类型(选填,不填默认文本消息类型) 注意用,号隔开(英文输入法的逗号),例如:wwcfrs,B-76WERQ,qinglong,1000001,2COat",
|
||||
"密钥key,智能微秘书个人中心获取apikey,申请地址:https://wechat.aibotk.com/signup?from=ql": "密钥key,智能微秘书个人中心获取apikey,申请地址:https://wechat.aibotk.com/signup?from=ql",
|
||||
"发送的目标,群组或者好友": "发送的目标,群组或者好友",
|
||||
"请输入要发送的目标": "请输入要发送的目标",
|
||||
"群聊": "群聊",
|
||||
@@ -448,5 +448,8 @@
|
||||
"编辑订阅": "编辑订阅",
|
||||
"Subscription表达式格式有误": "Subscription表达式格式有误",
|
||||
"一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)": "一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)",
|
||||
"登录已过期,请重新登录": "登录已过期,请重新登录"
|
||||
"登录已过期,请重新登录": "登录已过期,请重新登录",
|
||||
"系统日志": "系统日志",
|
||||
"主题": "主题",
|
||||
"语言": "语言"
|
||||
}
|
||||
|
||||
@@ -11,9 +11,10 @@ import config from '@/utils/config';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { request } from '@/utils/http';
|
||||
import Editor from '@monaco-editor/react';
|
||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||
import CodeMirror from '@uiw/react-codemirror';
|
||||
import { useOutletContext } from '@umijs/max';
|
||||
import { SharedContext } from '@/layouts';
|
||||
import { langs } from '@uiw/codemirror-extensions-langs';
|
||||
|
||||
const Config = () => {
|
||||
const { headerStyle, isPhone, theme } = useOutletContext<SharedContext>();
|
||||
@@ -104,16 +105,11 @@ const Config = () => {
|
||||
{isPhone ? (
|
||||
<CodeMirror
|
||||
value={value}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
styleActiveLine: true,
|
||||
matchBrackets: true,
|
||||
mode: 'shell',
|
||||
}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
theme={theme.includes('dark') ? 'dark' : 'light'}
|
||||
extensions={[langs.shell()]}
|
||||
onChange={(value) => {
|
||||
setValue(value);
|
||||
}}
|
||||
onChange={(editor, data, value) => {}}
|
||||
/>
|
||||
) : (
|
||||
<Editor
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
.log-item {
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: #fafafa;
|
||||
background: #f2f2f2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,18 +186,6 @@ tr.drop-over-upward td {
|
||||
}
|
||||
}
|
||||
|
||||
.log-modal {
|
||||
.log-container {
|
||||
overflow-y: auto;
|
||||
min-height: 300px;
|
||||
max-height: calc(80vh - 110px);
|
||||
max-height: calc(80vh - var(--vh-offset, 110px));
|
||||
|
||||
padding: 24px;
|
||||
margin: -24px;
|
||||
}
|
||||
}
|
||||
|
||||
body[data-mode='desktop'] {
|
||||
.crontab-wrapper {
|
||||
tbody .ant-table-cell {
|
||||
@@ -205,3 +193,7 @@ body[data-mode='desktop'] {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cron.pinned-cron > td {
|
||||
background: #f2f2f2;
|
||||
}
|
||||
+38
-72
@@ -68,53 +68,25 @@ const Crontab = () => {
|
||||
title: intl.get('名称'),
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
fixed: isPhone ? undefined : 'left',
|
||||
fixed: 'left',
|
||||
width: 120,
|
||||
render: (text: string, record: any) => (
|
||||
<>
|
||||
<Paragraph
|
||||
style={{
|
||||
wordBreak: 'break-all',
|
||||
marginBottom: 0,
|
||||
}}
|
||||
ellipsis={{ tooltip: text, rows: 2 }}
|
||||
>
|
||||
<a
|
||||
onClick={() => {
|
||||
setDetailCron(record);
|
||||
setIsDetailModalVisible(true);
|
||||
}}
|
||||
>
|
||||
{record.labels?.length > 0 && record.labels[0] !== '' && false ? (
|
||||
<Popover
|
||||
placement="right"
|
||||
trigger={isPhone ? 'click' : 'hover'}
|
||||
content={
|
||||
<div>
|
||||
{record.labels?.map((label: string) => (
|
||||
<Tag
|
||||
color="blue"
|
||||
key={label}
|
||||
style={{ cursor: 'point' }}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSearchValue(`label:${label}`);
|
||||
setSearchText(`label:${label}`);
|
||||
}}
|
||||
>
|
||||
<a>{label}</a>
|
||||
</Tag>
|
||||
))}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{record.name || '-'}
|
||||
</Popover>
|
||||
) : (
|
||||
record.name || '-'
|
||||
)}
|
||||
{record.isPinned ? (
|
||||
<span>
|
||||
<PushpinOutlined />
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
{record.name || '-'}
|
||||
</a>
|
||||
</>
|
||||
</Paragraph>
|
||||
),
|
||||
sorter: {
|
||||
compare: (a, b) => a?.name?.localeCompare(b?.name),
|
||||
@@ -124,7 +96,7 @@ const Crontab = () => {
|
||||
title: intl.get('命令/脚本'),
|
||||
dataIndex: 'command',
|
||||
key: 'command',
|
||||
width: 200,
|
||||
width: 240,
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<Paragraph
|
||||
@@ -214,7 +186,7 @@ const Crontab = () => {
|
||||
},
|
||||
{
|
||||
title: intl.get('最后运行时长'),
|
||||
width: 180,
|
||||
width: 167,
|
||||
dataIndex: 'last_running_time',
|
||||
key: 'last_running_time',
|
||||
sorter: {
|
||||
@@ -232,7 +204,7 @@ const Crontab = () => {
|
||||
title: intl.get('最后运行时间'),
|
||||
dataIndex: 'last_execution_time',
|
||||
key: 'last_execution_time',
|
||||
width: 150,
|
||||
width: 141,
|
||||
sorter: {
|
||||
compare: (a, b) => {
|
||||
return (a.last_execution_time || 0) - (b.last_execution_time || 0);
|
||||
@@ -259,7 +231,7 @@ const Crontab = () => {
|
||||
},
|
||||
{
|
||||
title: intl.get('下次运行时间'),
|
||||
width: 150,
|
||||
width: 144,
|
||||
sorter: {
|
||||
compare: (a: any, b: any) => {
|
||||
return a.nextRunTime - b.nextRunTime;
|
||||
@@ -276,7 +248,7 @@ const Crontab = () => {
|
||||
},
|
||||
{
|
||||
title: intl.get('关联订阅'),
|
||||
width: 190,
|
||||
width: 185,
|
||||
render: (text, record: any) =>
|
||||
record.sub_id ? (
|
||||
<Name
|
||||
@@ -292,46 +264,40 @@ const Crontab = () => {
|
||||
{
|
||||
title: intl.get('操作'),
|
||||
key: 'action',
|
||||
width: 130,
|
||||
width: 140,
|
||||
fixed: isPhone ? undefined : 'right',
|
||||
render: (text, record, index) => {
|
||||
const isPc = !isPhone;
|
||||
return (
|
||||
<Space size="middle">
|
||||
{record.status === CrontabStatus.idle && (
|
||||
<Tooltip title={isPc ? intl.get('运行') : ''}>
|
||||
<a
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
runCron(record, index);
|
||||
}}
|
||||
>
|
||||
<PlayCircleOutlined />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
{record.status !== CrontabStatus.idle && (
|
||||
<Tooltip title={isPc ? intl.get('停止') : ''}>
|
||||
<a
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
stopCron(record, index);
|
||||
}}
|
||||
>
|
||||
<PauseCircleOutlined />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title={isPc ? intl.get('日志') : ''}>
|
||||
<a
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setLogCron({ ...record, timestamp: Date.now() });
|
||||
runCron(record, index);
|
||||
}}
|
||||
>
|
||||
<FileTextOutlined />
|
||||
{intl.get('运行')}
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
{record.status !== CrontabStatus.idle && (
|
||||
<a
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
stopCron(record, index);
|
||||
}}
|
||||
>
|
||||
{intl.get('停止')}
|
||||
</a>
|
||||
)}
|
||||
<a
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setLogCron({ ...record, timestamp: Date.now() });
|
||||
}}
|
||||
>
|
||||
{intl.get('日志')}
|
||||
</a>
|
||||
<MoreBtn key="more" record={record} index={index} />
|
||||
</Space>
|
||||
);
|
||||
@@ -1041,7 +1007,7 @@ const Crontab = () => {
|
||||
dataSource={value}
|
||||
rowKey="id"
|
||||
size="middle"
|
||||
scroll={{ x: 1000, y: tableScrollHeight }}
|
||||
scroll={{ x: 1200, y: tableScrollHeight }}
|
||||
loading={loading}
|
||||
rowSelection={rowSelection}
|
||||
rowClassName={getRowClassName}
|
||||
|
||||
@@ -50,8 +50,8 @@ const CronLogModal = ({
|
||||
log && !logEnded(log) && !log.includes('任务未运行'),
|
||||
);
|
||||
setExecuting(hasNext);
|
||||
autoScroll();
|
||||
if (hasNext) {
|
||||
autoScroll();
|
||||
setTimeout(() => {
|
||||
getCronLog();
|
||||
}, 2000);
|
||||
@@ -74,7 +74,7 @@ const CronLogModal = ({
|
||||
document
|
||||
.querySelector('#log-flag')!
|
||||
.scrollIntoView({ behavior: 'smooth' });
|
||||
}, 1000);
|
||||
}, 600);
|
||||
};
|
||||
|
||||
const cancel = () => {
|
||||
@@ -124,9 +124,6 @@ const CronLogModal = ({
|
||||
open={visible}
|
||||
centered
|
||||
className="log-modal"
|
||||
bodyStyle={{
|
||||
minHeight: '300px',
|
||||
}}
|
||||
forceRender
|
||||
onOk={() => cancel()}
|
||||
onCancel={() => cancel()}
|
||||
@@ -145,7 +142,6 @@ const CronLogModal = ({
|
||||
isPhone
|
||||
? {
|
||||
fontFamily: 'Source Code Pro',
|
||||
width: 375,
|
||||
zoom: 0.83,
|
||||
}
|
||||
: {}
|
||||
|
||||
@@ -83,7 +83,7 @@ const CronModal = ({
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
autoSize={true}
|
||||
autoSize={{ minRows: 1, maxRows: 5 }}
|
||||
placeholder={intl.get(
|
||||
'支持输入脚本路径/任意系统可执行命令/task 脚本路径',
|
||||
)}
|
||||
|
||||
@@ -400,7 +400,7 @@ const Dependence = () => {
|
||||
const { type, message, references } = socketMessage;
|
||||
if (
|
||||
type === 'installDependence' &&
|
||||
message.includes(intl.get('开始时间')) &&
|
||||
message.includes('开始时间') &&
|
||||
references.length > 0
|
||||
) {
|
||||
const result = [...value];
|
||||
@@ -409,7 +409,7 @@ const Dependence = () => {
|
||||
if (index !== -1) {
|
||||
result.splice(index, 1, {
|
||||
...value[index],
|
||||
status: message.includes(intl.get('安装')) ? Status.安装中 : Status.删除中,
|
||||
status: message.includes('安装') ? Status.安装中 : Status.删除中,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -417,14 +417,14 @@ const Dependence = () => {
|
||||
}
|
||||
if (
|
||||
type === 'installDependence' &&
|
||||
message.includes(intl.get('结束时间')) &&
|
||||
message.includes('结束时间') &&
|
||||
references.length > 0
|
||||
) {
|
||||
let status;
|
||||
if (message.includes(intl.get('安装'))) {
|
||||
status = message.includes(intl.get('成功')) ? Status.已安装 : Status.安装失败;
|
||||
if (message.includes('安装')) {
|
||||
status = message.includes('成功') ? Status.已安装 : Status.安装失败;
|
||||
} else {
|
||||
status = message.includes(intl.get('成功')) ? Status.已删除 : Status.删除失败;
|
||||
status = message.includes('成功') ? Status.已删除 : Status.删除失败;
|
||||
}
|
||||
const result = [...value];
|
||||
for (let i = 0; i < references.length; i++) {
|
||||
|
||||
@@ -56,8 +56,8 @@ const DependenceLogModal = ({
|
||||
) {
|
||||
const log = (data.log || []).join('') as string;
|
||||
setValue(log);
|
||||
setExecuting(!log.includes(intl.get('结束时间')));
|
||||
setIsRemoveFailed(log.includes(intl.get('删除失败')));
|
||||
setExecuting(!log.includes('结束时间'));
|
||||
setIsRemoveFailed(log.includes('删除失败'));
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -103,9 +103,9 @@ const DependenceLogModal = ({
|
||||
references.length > 0 &&
|
||||
references.includes(dependence.id)
|
||||
) {
|
||||
if (message.includes(intl.get('结束时间'))) {
|
||||
if (message.includes('结束时间')) {
|
||||
setExecuting(false);
|
||||
setIsRemoveFailed(message.includes(intl.get('删除失败')));
|
||||
setIsRemoveFailed(message.includes('删除失败'));
|
||||
}
|
||||
setValue(`${value}${message}`);
|
||||
}
|
||||
@@ -121,11 +121,6 @@ const DependenceLogModal = ({
|
||||
open={visible}
|
||||
centered
|
||||
className="log-modal"
|
||||
bodyStyle={{
|
||||
overflowY: 'auto',
|
||||
maxHeight: 'calc(70vh - var(--vh-offset, 0px))',
|
||||
minHeight: '300px',
|
||||
}}
|
||||
forceRender
|
||||
onOk={() => cancel()}
|
||||
onCancel={() => cancel()}
|
||||
@@ -135,23 +130,24 @@ const DependenceLogModal = ({
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
{loading ? (
|
||||
<PageLoading />
|
||||
) : (
|
||||
<pre
|
||||
style={
|
||||
isPhone
|
||||
? {
|
||||
fontFamily: 'Source Code Pro',
|
||||
width: 375,
|
||||
zoom: 0.83,
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<Ansi>{value}</Ansi>
|
||||
</pre>
|
||||
)}
|
||||
<div className="log-container">
|
||||
{loading ? (
|
||||
<PageLoading />
|
||||
) : (
|
||||
<pre
|
||||
style={
|
||||
isPhone
|
||||
? {
|
||||
fontFamily: 'Source Code Pro',
|
||||
zoom: 0.83,
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<Ansi>{value}</Ansi>
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -130,7 +130,7 @@ const DependenceModal = ({
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
autoSize={true}
|
||||
autoSize={{ minRows: 1, maxRows: 5 }}
|
||||
placeholder={intl.get('请输入依赖名称')}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
Vendored
+44
-14
@@ -1,4 +1,4 @@
|
||||
import intl from 'react-intl-universal'
|
||||
import intl from 'react-intl-universal';
|
||||
import React, {
|
||||
useCallback,
|
||||
useRef,
|
||||
@@ -42,7 +42,7 @@ import useTableScrollHeight from '@/hooks/useTableScrollHeight';
|
||||
import Copy from '../../components/copy';
|
||||
import { useVT } from 'virtualizedtableforantd4';
|
||||
|
||||
const { Text } = Typography;
|
||||
const { Paragraph } = Typography;
|
||||
const { Search } = Input;
|
||||
|
||||
enum Status {
|
||||
@@ -149,7 +149,7 @@ const Env = () => {
|
||||
title: intl.get('状态'),
|
||||
key: 'status',
|
||||
dataIndex: 'status',
|
||||
width: 80,
|
||||
width: 100,
|
||||
filters: [
|
||||
{
|
||||
text: intl.get('已启用'),
|
||||
@@ -186,7 +186,11 @@ const Env = () => {
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={
|
||||
isPc ? (record.status === Status.已禁用 ? intl.get('启用') : intl.get('禁用')) : ''
|
||||
isPc
|
||||
? record.status === Status.已禁用
|
||||
? intl.get('启用')
|
||||
: intl.get('禁用')
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<a onClick={() => enabledOrDisabledEnv(record, index)}>
|
||||
@@ -232,14 +236,24 @@ const Env = () => {
|
||||
|
||||
const enabledOrDisabledEnv = (record: any, index: number) => {
|
||||
Modal.confirm({
|
||||
title: `确认${record.status === Status.已禁用 ? intl.get('启用') : intl.get('禁用')}`,
|
||||
title: `确认${
|
||||
record.status === Status.已禁用 ? intl.get('启用') : intl.get('禁用')
|
||||
}`,
|
||||
content: (
|
||||
<>
|
||||
{intl.get('确认')}{record.status === Status.已禁用 ? intl.get('启用') : intl.get('禁用')}
|
||||
{intl.get('确认')}
|
||||
{record.status === Status.已禁用
|
||||
? intl.get('启用')
|
||||
: intl.get('禁用')}
|
||||
Env{' '}
|
||||
<Text style={{ wordBreak: 'break-all' }} type="warning">
|
||||
<Paragraph
|
||||
style={{ wordBreak: 'break-all', display: 'inline' }}
|
||||
ellipsis={{ rows: 6, expandable: true }}
|
||||
type="warning"
|
||||
copyable
|
||||
>
|
||||
{record.value}
|
||||
</Text>{' '}
|
||||
</Paragraph>{' '}
|
||||
{intl.get('吗')}
|
||||
</>
|
||||
),
|
||||
@@ -254,7 +268,11 @@ const Env = () => {
|
||||
.then(({ code, data }) => {
|
||||
if (code === 200) {
|
||||
message.success(
|
||||
`${record.status === Status.已禁用 ? intl.get('启用') : intl.get('禁用')}${intl.get('成功')}`,
|
||||
`${
|
||||
record.status === Status.已禁用
|
||||
? intl.get('启用')
|
||||
: intl.get('禁用')
|
||||
}${intl.get('成功')}`,
|
||||
);
|
||||
const newStatus =
|
||||
record.status === Status.已禁用 ? Status.已启用 : Status.已禁用;
|
||||
@@ -289,9 +307,14 @@ const Env = () => {
|
||||
content: (
|
||||
<>
|
||||
{intl.get('确认删除变量')}{' '}
|
||||
<Text style={{ wordBreak: 'break-all' }} type="warning">
|
||||
<Paragraph
|
||||
style={{ wordBreak: 'break-all', display: 'inline' }}
|
||||
ellipsis={{ rows: 6, expandable: true }}
|
||||
type="warning"
|
||||
copyable
|
||||
>
|
||||
{record.name}: {record.value}
|
||||
</Text>{' '}
|
||||
</Paragraph>{' '}
|
||||
{intl.get('吗')}
|
||||
</>
|
||||
),
|
||||
@@ -435,7 +458,13 @@ const Env = () => {
|
||||
const operateEnvs = (operationStatus: number) => {
|
||||
Modal.confirm({
|
||||
title: `确认${OperationName[operationStatus]}`,
|
||||
content: <>{intl.get('确认')}{OperationName[operationStatus]}{intl.get('选中的变量吗')}</>,
|
||||
content: (
|
||||
<>
|
||||
{intl.get('确认')}
|
||||
{OperationName[operationStatus]}
|
||||
{intl.get('选中的变量吗')}
|
||||
</>
|
||||
),
|
||||
onOk() {
|
||||
request
|
||||
.put(
|
||||
@@ -567,7 +596,8 @@ const Env = () => {
|
||||
</Button>
|
||||
<span style={{ marginLeft: 8 }}>
|
||||
{intl.get('已选择')}
|
||||
<a>{selectedRowIds?.length}</a>{intl.get('项')}
|
||||
<a>{selectedRowIds?.length}</a>
|
||||
{intl.get('项')}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -579,7 +609,7 @@ const Env = () => {
|
||||
dataSource={value}
|
||||
rowKey="id"
|
||||
size="middle"
|
||||
scroll={{ x: 1000, y: tableScrollHeight }}
|
||||
scroll={{ x: 1200, y: tableScrollHeight }}
|
||||
components={vt}
|
||||
loading={loading}
|
||||
onRow={(record: any, index: number | undefined) => {
|
||||
|
||||
Vendored
+15
-6
@@ -1,4 +1,4 @@
|
||||
import intl from 'react-intl-universal'
|
||||
import intl from 'react-intl-universal';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Modal, message, Input, Form, Radio } from 'antd';
|
||||
import { request } from '@/utils/http';
|
||||
@@ -44,7 +44,9 @@ const EnvModal = ({
|
||||
);
|
||||
|
||||
if (code === 200) {
|
||||
message.success(env ? intl.get('更新变量成功') : intl.get('创建变量成功'));
|
||||
message.success(
|
||||
env ? intl.get('更新变量成功') : intl.get('创建变量成功'),
|
||||
);
|
||||
handleCancel(data);
|
||||
}
|
||||
setLoading(false);
|
||||
@@ -82,7 +84,11 @@ const EnvModal = ({
|
||||
name="name"
|
||||
label={intl.get('名称')}
|
||||
rules={[
|
||||
{ required: true, message: intl.get('请输入环境变量名称'), whitespace: true },
|
||||
{
|
||||
required: true,
|
||||
message: intl.get('请输入环境变量名称'),
|
||||
whitespace: true,
|
||||
},
|
||||
{
|
||||
pattern: /^[a-zA-Z_][0-9a-zA-Z_]*$/,
|
||||
message: intl.get('只能输入字母数字下划线,且不能以数字开头'),
|
||||
@@ -108,12 +114,15 @@ const EnvModal = ({
|
||||
name="value"
|
||||
label={intl.get('值')}
|
||||
rules={[
|
||||
{ required: true, message: intl.get('请输入环境变量值'), whitespace: true },
|
||||
{
|
||||
required: true,
|
||||
message: intl.get('请输入环境变量值'),
|
||||
whitespace: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
autoSize={true}
|
||||
autoSize={{ minRows: 1, maxRows: 8 }}
|
||||
placeholder={intl.get('请输入环境变量值')}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@@ -185,7 +185,7 @@ const Initialization = () => {
|
||||
style={{ maxWidth: 400 }}
|
||||
>
|
||||
<Input.TextArea
|
||||
autoSize={true}
|
||||
autoSize={{ minRows: 1, maxRows: 5 }}
|
||||
placeholder={`请输入${x.label}`}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
+4
-10
@@ -16,7 +16,7 @@ import { PageContainer } from '@ant-design/pro-layout';
|
||||
import Editor from '@monaco-editor/react';
|
||||
import { request } from '@/utils/http';
|
||||
import styles from './index.module.less';
|
||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||
import CodeMirror from '@uiw/react-codemirror';
|
||||
import SplitPane from 'react-split-pane';
|
||||
import { useOutletContext } from '@umijs/max';
|
||||
import { SharedContext } from '@/layouts';
|
||||
@@ -278,17 +278,11 @@ const Log = () => {
|
||||
{isPhone && (
|
||||
<CodeMirror
|
||||
value={value}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true,
|
||||
matchBrackets: true,
|
||||
readOnly: true,
|
||||
}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
readOnly={true}
|
||||
theme={theme.includes('dark') ? 'dark' : 'light'}
|
||||
onChange={(value, viewUpdate) => {
|
||||
setValue(value);
|
||||
}}
|
||||
onChange={(editor, data, value) => {}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -224,6 +224,7 @@ const EditModal = ({
|
||||
minSize={200}
|
||||
defaultSize="50%"
|
||||
style={{ height: 'calc(100vh - 55px)' }}
|
||||
pane2Style={{ overflowY: 'auto' }}
|
||||
>
|
||||
<Editor
|
||||
language={language}
|
||||
@@ -241,7 +242,6 @@ const EditModal = ({
|
||||
/>
|
||||
<pre
|
||||
style={{
|
||||
height: '100%',
|
||||
padding: '0 15px',
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -20,7 +20,7 @@ import Editor from '@monaco-editor/react';
|
||||
import { request } from '@/utils/http';
|
||||
import styles from './index.module.less';
|
||||
import EditModal from './editModal';
|
||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||
import CodeMirror from '@uiw/react-codemirror';
|
||||
import SplitPane from 'react-split-pane';
|
||||
import {
|
||||
DeleteOutlined,
|
||||
@@ -43,6 +43,7 @@ import useFilterTreeData from '@/hooks/useFilterTreeData';
|
||||
import uniq from 'lodash/uniq';
|
||||
import IconFont from '@/components/iconfont';
|
||||
import RenameModal from './renameModal';
|
||||
import { langs } from '@uiw/codemirror-extensions-langs';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
@@ -580,18 +581,14 @@ const Script = () => {
|
||||
{isPhone && (
|
||||
<CodeMirror
|
||||
value={value}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true,
|
||||
matchBrackets: true,
|
||||
mode,
|
||||
readOnly: !isEditing,
|
||||
}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
extensions={
|
||||
mode ? [langs[mode as keyof typeof langs]()] : undefined
|
||||
}
|
||||
theme={theme.includes('dark') ? 'dark' : 'light'}
|
||||
readOnly={!isEditing}
|
||||
onChange={(value) => {
|
||||
setValue(value);
|
||||
}}
|
||||
onChange={(editor, data, value) => {}}
|
||||
/>
|
||||
)}
|
||||
<EditModal
|
||||
|
||||
@@ -10,6 +10,7 @@ const { Link } = Typography;
|
||||
enum TVersion {
|
||||
'develop' = '开发版',
|
||||
'master' = '正式版',
|
||||
'debian' = '正式版'
|
||||
}
|
||||
|
||||
const About = ({ systemInfo }: { systemInfo: SharedContext['systemInfo'] }) => {
|
||||
|
||||
@@ -75,16 +75,7 @@ const CheckUpdate = ({ socketMessage, systemInfo }: any) => {
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
content: (
|
||||
<pre
|
||||
style={{
|
||||
fontSize: 12,
|
||||
fontWeight: 400,
|
||||
}}
|
||||
>
|
||||
{lastLog}
|
||||
</pre>
|
||||
),
|
||||
content: <pre>{lastLog}</pre>,
|
||||
okText: intl.get('下载更新'),
|
||||
cancelText: intl.get('以后再说'),
|
||||
onOk() {
|
||||
@@ -109,16 +100,7 @@ const CheckUpdate = ({ socketMessage, systemInfo }: any) => {
|
||||
okButtonProps: { disabled: true },
|
||||
title: intl.get('下载更新中...'),
|
||||
centered: true,
|
||||
content: (
|
||||
<pre
|
||||
style={{
|
||||
fontSize: 12,
|
||||
fontWeight: 400,
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</pre>
|
||||
),
|
||||
content: <pre>{value}</pre>,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -177,7 +159,7 @@ const CheckUpdate = ({ socketMessage, systemInfo }: any) => {
|
||||
}
|
||||
|
||||
const newMessage = `${value}${_message}`;
|
||||
const updateFailed = newMessage.includes(intl.get('失败'));
|
||||
const updateFailed = newMessage.includes('失败');
|
||||
|
||||
modalRef.current.update({
|
||||
maskClosable: updateFailed,
|
||||
@@ -185,20 +167,13 @@ const CheckUpdate = ({ socketMessage, systemInfo }: any) => {
|
||||
okButtonProps: { disabled: !updateFailed },
|
||||
content: (
|
||||
<>
|
||||
<pre
|
||||
style={{
|
||||
fontSize: 12,
|
||||
fontWeight: 400,
|
||||
}}
|
||||
>
|
||||
{newMessage}
|
||||
</pre>
|
||||
<pre>{newMessage}</pre>
|
||||
<div id="log-identifier" style={{ paddingBottom: 5 }}></div>
|
||||
</>
|
||||
),
|
||||
});
|
||||
|
||||
if (updateFailed && !value.includes(intl.get('失败,请检查'))) {
|
||||
if (updateFailed && !value.includes('失败,请检查')) {
|
||||
message.error(intl.get('更新失败,请检查网络及日志或稍后再试'));
|
||||
}
|
||||
|
||||
@@ -209,7 +184,7 @@ const CheckUpdate = ({ socketMessage, systemInfo }: any) => {
|
||||
.getElementById('log-identifier')!
|
||||
.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
|
||||
if (_message.includes(intl.get('更新包下载成功'))) {
|
||||
if (_message.includes('更新包下载成功')) {
|
||||
setTimeout(() => {
|
||||
showReloadModal();
|
||||
}, 1000);
|
||||
|
||||
+111
-61
@@ -1,5 +1,5 @@
|
||||
import intl from 'react-intl-universal';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import {
|
||||
Button,
|
||||
InputNumber,
|
||||
@@ -32,6 +32,8 @@ import About from './about';
|
||||
import { useOutletContext } from '@umijs/max';
|
||||
import { SharedContext } from '@/layouts';
|
||||
import './index.less';
|
||||
import CodeMirror from '@uiw/react-codemirror';
|
||||
import useResizeObserver from '@react-hook/resize-observer';
|
||||
|
||||
const { Text } = Typography;
|
||||
const isDemoEnv = window.__ENV__DeployEnv === 'demo';
|
||||
@@ -41,6 +43,7 @@ const Setting = () => {
|
||||
headerStyle,
|
||||
isPhone,
|
||||
user,
|
||||
theme,
|
||||
reloadUser,
|
||||
reloadTheme,
|
||||
socketMessage,
|
||||
@@ -113,7 +116,17 @@ const Setting = () => {
|
||||
const [editedApp, setEditedApp] = useState<any>();
|
||||
const [tabActiveKey, setTabActiveKey] = useState('security');
|
||||
const [loginLogData, setLoginLogData] = useState<any[]>([]);
|
||||
const [systemLogData, setSystemLogData] = useState<string>('');
|
||||
const [notificationInfo, setNotificationInfo] = useState<any>();
|
||||
const containergRef = useRef<HTMLDivElement>(null);
|
||||
const [height, setHeight] = useState<number>(0);
|
||||
|
||||
useResizeObserver(containergRef, (entry) => {
|
||||
const _height = entry.target.parentElement?.parentElement?.offsetHeight;
|
||||
if (_height && height !== _height - 66) {
|
||||
setHeight(_height - 66);
|
||||
}
|
||||
});
|
||||
|
||||
const getApps = () => {
|
||||
setLoading(true);
|
||||
@@ -232,6 +245,19 @@ const Setting = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const getSystemLog = () => {
|
||||
request
|
||||
.get<Blob>(`${config.apiPrefix}system/log`, {
|
||||
responseType: 'blob',
|
||||
})
|
||||
.then(async (res) => {
|
||||
setSystemLogData(await res.text());
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
const tabChange = (activeKey: string) => {
|
||||
setTabActiveKey(activeKey);
|
||||
if (activeKey === 'app') {
|
||||
@@ -240,6 +266,8 @@ const Setting = () => {
|
||||
getLoginLog();
|
||||
} else if (activeKey === 'notification') {
|
||||
getNotification();
|
||||
} else if (activeKey === 'syslog') {
|
||||
getSystemLog();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -279,66 +307,88 @@ const Setting = () => {
|
||||
: []
|
||||
}
|
||||
>
|
||||
<Tabs
|
||||
defaultActiveKey="security"
|
||||
size="small"
|
||||
tabPosition="top"
|
||||
onChange={tabChange}
|
||||
items={[
|
||||
...(!isDemoEnv
|
||||
? [
|
||||
{
|
||||
key: 'security',
|
||||
label: intl.get('安全设置'),
|
||||
children: (
|
||||
<SecuritySettings user={user} userChange={reloadUser} />
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
key: 'app',
|
||||
label: intl.get('应用设置'),
|
||||
children: (
|
||||
<Table
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
dataSource={dataSource}
|
||||
rowKey="id"
|
||||
size="middle"
|
||||
scroll={{ x: 768 }}
|
||||
loading={loading}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'notification',
|
||||
label: intl.get('通知设置'),
|
||||
children: <NotificationSetting data={notificationInfo} />,
|
||||
},
|
||||
{
|
||||
key: 'login',
|
||||
label: intl.get('登录日志'),
|
||||
children: <LoginLog data={loginLogData} />,
|
||||
},
|
||||
{
|
||||
key: 'other',
|
||||
label: intl.get('其他设置'),
|
||||
children: (
|
||||
<Other
|
||||
reloadTheme={reloadTheme}
|
||||
socketMessage={socketMessage}
|
||||
systemInfo={systemInfo}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'about',
|
||||
label: intl.get('关于'),
|
||||
children: <About systemInfo={systemInfo} />,
|
||||
},
|
||||
]}
|
||||
></Tabs>
|
||||
<div ref={containergRef}>
|
||||
<Tabs
|
||||
defaultActiveKey="security"
|
||||
size="small"
|
||||
tabPosition="top"
|
||||
onChange={tabChange}
|
||||
items={[
|
||||
...(!isDemoEnv
|
||||
? [
|
||||
{
|
||||
key: 'security',
|
||||
label: intl.get('安全设置'),
|
||||
children: (
|
||||
<SecuritySettings user={user} userChange={reloadUser} />
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
key: 'app',
|
||||
label: intl.get('应用设置'),
|
||||
children: (
|
||||
<Table
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
dataSource={dataSource}
|
||||
rowKey="id"
|
||||
size="middle"
|
||||
scroll={{ x: 768 }}
|
||||
loading={loading}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'notification',
|
||||
label: intl.get('通知设置'),
|
||||
children: <NotificationSetting data={notificationInfo} />,
|
||||
},
|
||||
{
|
||||
key: 'syslog',
|
||||
label: intl.get('系统日志'),
|
||||
children: (
|
||||
<CodeMirror
|
||||
maxHeight={`${height}px`}
|
||||
value={systemLogData}
|
||||
onCreateEditor={(view) => {
|
||||
setTimeout(() => {
|
||||
view.scrollDOM.scrollTo({
|
||||
top: view.scrollDOM.scrollHeight,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
readOnly={true}
|
||||
theme={theme.includes('dark') ? 'dark' : 'light'}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'login',
|
||||
label: intl.get('登录日志'),
|
||||
children: <LoginLog data={loginLogData} />,
|
||||
},
|
||||
{
|
||||
key: 'other',
|
||||
label: intl.get('其他设置'),
|
||||
children: (
|
||||
<Other
|
||||
reloadTheme={reloadTheme}
|
||||
socketMessage={socketMessage}
|
||||
systemInfo={systemInfo}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'about',
|
||||
label: intl.get('关于'),
|
||||
children: <About systemInfo={systemInfo} />,
|
||||
},
|
||||
]}
|
||||
></Tabs>
|
||||
</div>
|
||||
<AppModal
|
||||
visible={isModalVisible}
|
||||
handleCancel={handleCancel}
|
||||
|
||||
@@ -19,7 +19,7 @@ enum LoginStatusColor {
|
||||
const columns = [
|
||||
{
|
||||
title: intl.get('序号'),
|
||||
width: 40,
|
||||
width: 50,
|
||||
render: (text: string, record: any, index: number) => {
|
||||
return index + 1;
|
||||
},
|
||||
@@ -75,7 +75,7 @@ const LoginLog = ({ data }: any) => {
|
||||
dataSource={data}
|
||||
rowKey="id"
|
||||
size="middle"
|
||||
scroll={{ x: 768 }}
|
||||
scroll={{ x: 1000 }}
|
||||
sticky
|
||||
/>
|
||||
</>
|
||||
|
||||
@@ -88,7 +88,7 @@ const NotificationSetting = ({ data }: any) => {
|
||||
) : (
|
||||
<Input.TextArea
|
||||
disabled={loading}
|
||||
autoSize={true}
|
||||
autoSize={{ minRows: 1, maxRows: 5 }}
|
||||
placeholder={x.placeholder || `请输入${x.label}`}
|
||||
/>
|
||||
)}
|
||||
|
||||
+48
-12
@@ -9,7 +9,7 @@ import {
|
||||
Input,
|
||||
Upload,
|
||||
Modal,
|
||||
Progress,
|
||||
Select,
|
||||
} from 'antd';
|
||||
import * as DarkReader from '@umijs/ssr-darkreader';
|
||||
import config from '@/utils/config';
|
||||
@@ -22,12 +22,6 @@ import { UploadOutlined } from '@ant-design/icons';
|
||||
import Countdown from 'antd/lib/statistic/Countdown';
|
||||
import useProgress from './progress';
|
||||
|
||||
const optionsWithDisabled = [
|
||||
{ label: intl.get('亮色'), value: 'light' },
|
||||
{ label: intl.get('暗色'), value: 'dark' },
|
||||
{ label: intl.get('跟随系统'), value: 'auto' },
|
||||
];
|
||||
|
||||
const Other = ({
|
||||
systemInfo,
|
||||
socketMessage,
|
||||
@@ -67,6 +61,13 @@ const Other = ({
|
||||
reloadTheme();
|
||||
};
|
||||
|
||||
const handleLangChange = (v: string) => {
|
||||
localStorage.setItem('lang', v);
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const getSystemConfig = () => {
|
||||
request
|
||||
.get(`${config.apiPrefix}system/config`)
|
||||
@@ -167,12 +168,27 @@ const Other = ({
|
||||
initialValue={defaultTheme}
|
||||
>
|
||||
<Radio.Group
|
||||
options={optionsWithDisabled}
|
||||
onChange={themeChange}
|
||||
value={defaultTheme}
|
||||
optionType="button"
|
||||
buttonStyle="solid"
|
||||
/>
|
||||
>
|
||||
<Radio.Button
|
||||
value="light"
|
||||
style={{ width: 70, textAlign: 'center' }}
|
||||
>
|
||||
{intl.get('亮色')}
|
||||
</Radio.Button>
|
||||
<Radio.Button value="dark" style={{ width: 66, textAlign: 'center' }}>
|
||||
{intl.get('暗色')}
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
value="auto"
|
||||
style={{ width: 129, textAlign: 'center' }}
|
||||
>
|
||||
{intl.get('跟随系统')}
|
||||
</Radio.Button>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={intl.get('日志删除频率')}
|
||||
@@ -190,7 +206,11 @@ const Other = ({
|
||||
setSystemConfig({ ...systemConfig, logRemoveFrequency: value });
|
||||
}}
|
||||
/>
|
||||
<Button type="primary" onClick={updateSystemConfig}>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={updateSystemConfig}
|
||||
style={{ width: 84 }}
|
||||
>
|
||||
{intl.get('确认')}
|
||||
</Button>
|
||||
</Input.Group>
|
||||
@@ -198,18 +218,34 @@ const Other = ({
|
||||
<Form.Item label={intl.get('定时任务并发数')} name="frequency">
|
||||
<Input.Group compact>
|
||||
<InputNumber
|
||||
style={{ width: 150 }}
|
||||
style={{ width: 180 }}
|
||||
min={1}
|
||||
value={systemConfig?.cronConcurrency}
|
||||
onChange={(value) => {
|
||||
setSystemConfig({ ...systemConfig, cronConcurrency: value });
|
||||
}}
|
||||
/>
|
||||
<Button type="primary" onClick={updateSystemConfig}>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={updateSystemConfig}
|
||||
style={{ width: 84 }}
|
||||
>
|
||||
{intl.get('确认')}
|
||||
</Button>
|
||||
</Input.Group>
|
||||
</Form.Item>
|
||||
<Form.Item label={intl.get('语言')} name="lang">
|
||||
<Select
|
||||
defaultValue={localStorage.getItem('lang') || ''}
|
||||
style={{ width: 264 }}
|
||||
onChange={handleLangChange}
|
||||
options={[
|
||||
{ value: '', label: intl.get('跟随系统') },
|
||||
{ value: 'zh', label: '简体中文' },
|
||||
{ value: 'en', label: 'English' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label={intl.get('数据备份还原')} name="frequency">
|
||||
<Button type="primary" onClick={exportData} loading={exportLoading}>
|
||||
{exportLoading ? intl.get('生成数据中...') : intl.get('备份')}
|
||||
|
||||
@@ -188,7 +188,7 @@ const SecuritySettings = ({ user, userChange }: any) => {
|
||||
hasFeedback
|
||||
style={{ maxWidth: 300 }}
|
||||
>
|
||||
<Input placeholder={intl.get('用户名')} />
|
||||
<Input autoComplete="username" placeholder={intl.get('用户名')} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={intl.get('密码')}
|
||||
@@ -203,7 +203,11 @@ const SecuritySettings = ({ user, userChange }: any) => {
|
||||
hasFeedback
|
||||
style={{ maxWidth: 300 }}
|
||||
>
|
||||
<Input type="password" placeholder={intl.get('密码')} />
|
||||
<Input
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
placeholder={intl.get('密码')}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Button type="primary" htmlType="submit">
|
||||
{intl.get('保存')}
|
||||
|
||||
@@ -184,45 +184,39 @@ const Subscription = () => {
|
||||
{
|
||||
title: intl.get('操作'),
|
||||
key: 'action',
|
||||
width: 130,
|
||||
width: 140,
|
||||
render: (text: string, record: any, index: number) => {
|
||||
const isPc = !isPhone;
|
||||
return (
|
||||
<Space size="middle">
|
||||
{record.status === SubscriptionStatus.idle && (
|
||||
<Tooltip title={isPc ? intl.get('运行') : ''}>
|
||||
<a
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
runSubscription(record, index);
|
||||
}}
|
||||
>
|
||||
<PlayCircleOutlined />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
{record.status !== SubscriptionStatus.idle && (
|
||||
<Tooltip title={isPc ? intl.get('停止') : ''}>
|
||||
<a
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
stopSubsciption(record, index);
|
||||
}}
|
||||
>
|
||||
<PauseCircleOutlined />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title={isPc ? intl.get('日志') : ''}>
|
||||
<a
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setLogSubscription({ ...record, timestamp: Date.now() });
|
||||
runSubscription(record, index);
|
||||
}}
|
||||
>
|
||||
<FileTextOutlined />
|
||||
{intl.get('运行')}
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
{record.status !== SubscriptionStatus.idle && (
|
||||
<a
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
stopSubsciption(record, index);
|
||||
}}
|
||||
>
|
||||
{intl.get('停止')}
|
||||
</a>
|
||||
)}
|
||||
<a
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setLogSubscription({ ...record, timestamp: Date.now() });
|
||||
}}
|
||||
>
|
||||
{intl.get('日志')}
|
||||
</a>
|
||||
<MoreBtn key="more" record={record} index={index} />
|
||||
</Space>
|
||||
);
|
||||
|
||||
@@ -99,9 +99,6 @@ const SubscriptionLogModal = ({
|
||||
open={visible}
|
||||
centered
|
||||
className="log-modal"
|
||||
bodyStyle={{
|
||||
minHeight: '300px',
|
||||
}}
|
||||
forceRender
|
||||
onOk={() => cancel()}
|
||||
onCancel={() => cancel()}
|
||||
@@ -111,23 +108,24 @@ const SubscriptionLogModal = ({
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
{loading ? (
|
||||
<PageLoading />
|
||||
) : (
|
||||
<pre
|
||||
style={
|
||||
isPhone
|
||||
? {
|
||||
fontFamily: 'Source Code Pro',
|
||||
width: 375,
|
||||
zoom: 0.83,
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
{value}
|
||||
</pre>
|
||||
)}
|
||||
<div className="log-container">
|
||||
{loading ? (
|
||||
<PageLoading />
|
||||
) : (
|
||||
<pre
|
||||
style={
|
||||
isPhone
|
||||
? {
|
||||
fontFamily: 'Source Code Pro',
|
||||
zoom: 0.83,
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
{value}
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -241,10 +241,9 @@ const SubscriptionModal = ({
|
||||
|
||||
const onNamePaste = useCallback((e) => {
|
||||
const text = e.clipboardData.getData('text') as string;
|
||||
if (text.startsWith('ql ')) {
|
||||
if (text.includes('ql repo') || text.includes('ql raw')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
onPaste(e);
|
||||
}, []);
|
||||
|
||||
const formatParams = (sub) => {
|
||||
@@ -327,10 +326,9 @@ const SubscriptionModal = ({
|
||||
]}
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
autoSize={true}
|
||||
autoSize={{ minRows: 1, maxRows: 5 }}
|
||||
placeholder={intl.get('请输入订阅链接')}
|
||||
onPaste={onUrlChange}
|
||||
onPaste={onNamePaste}
|
||||
onChange={onUrlChange}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -338,7 +336,7 @@ const SubscriptionModal = ({
|
||||
<Form.Item name="branch" label={intl.get('分支')}>
|
||||
<Input
|
||||
placeholder={intl.get('请输入分支')}
|
||||
onPaste={onBranchChange}
|
||||
onPaste={onNamePaste}
|
||||
onChange={onBranchChange}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -401,7 +399,10 @@ const SubscriptionModal = ({
|
||||
{scheduleType === 'interval' ? (
|
||||
<IntervalSelect />
|
||||
) : (
|
||||
<Input placeholder={intl.get('秒(可选) 分 时 天 月 周')} />
|
||||
<Input
|
||||
onPaste={onNamePaste}
|
||||
placeholder={intl.get('秒(可选) 分 时 天 月 周')}
|
||||
/>
|
||||
)}
|
||||
</Form.Item>
|
||||
{type !== 'file' && (
|
||||
@@ -413,10 +414,11 @@ const SubscriptionModal = ({
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
autoSize={true}
|
||||
autoSize={{ minRows: 1, maxRows: 5 }}
|
||||
placeholder={intl.get(
|
||||
'请输入脚本筛选白名单关键词,多个关键词竖线分割',
|
||||
)}
|
||||
onPaste={onNamePaste}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
@@ -426,10 +428,11 @@ const SubscriptionModal = ({
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
autoSize={true}
|
||||
autoSize={{ minRows: 1, maxRows: 5 }}
|
||||
placeholder={intl.get(
|
||||
'请输入脚本筛选黑名单关键词,多个关键词竖线分割',
|
||||
)}
|
||||
onPaste={onNamePaste}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
@@ -439,10 +442,11 @@ const SubscriptionModal = ({
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
autoSize={true}
|
||||
autoSize={{ minRows: 1, maxRows: 5 }}
|
||||
placeholder={intl.get(
|
||||
'请输入脚本依赖文件关键词,多个关键词竖线分割',
|
||||
)}
|
||||
onPaste={onNamePaste}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
@@ -452,7 +456,10 @@ const SubscriptionModal = ({
|
||||
'仓库需要拉取的文件后缀,多个后缀空格分隔,默认使用配置文件中的RepoFileExtensions',
|
||||
)}
|
||||
>
|
||||
<Input placeholder={intl.get('请输入文件后缀')} />
|
||||
<Input
|
||||
onPaste={onNamePaste}
|
||||
placeholder={intl.get('请输入文件后缀')}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="sub_before"
|
||||
@@ -462,8 +469,9 @@ const SubscriptionModal = ({
|
||||
)}
|
||||
>
|
||||
<Input.TextArea
|
||||
onPaste={onNamePaste}
|
||||
rows={4}
|
||||
autoSize={true}
|
||||
autoSize={{ minRows: 1, maxRows: 5 }}
|
||||
placeholder={intl.get('请输入运行订阅前要执行的命令')}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -475,8 +483,9 @@ const SubscriptionModal = ({
|
||||
)}
|
||||
>
|
||||
<Input.TextArea
|
||||
onPaste={onNamePaste}
|
||||
rows={4}
|
||||
autoSize={true}
|
||||
autoSize={{ minRows: 1, maxRows: 5 }}
|
||||
placeholder={intl.get('请输入运行订阅后要执行的命令')}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -490,6 +499,7 @@ const SubscriptionModal = ({
|
||||
)}
|
||||
>
|
||||
<Input
|
||||
onPaste={onNamePaste}
|
||||
placeholder={
|
||||
type === 'private-repo'
|
||||
? 'SOCK5代理,例如 IP:PORT'
|
||||
|
||||
+1
-1
@@ -174,7 +174,7 @@ export default {
|
||||
},
|
||||
{
|
||||
label: 'barkGroup',
|
||||
tip: intl.get('BARK推送消息的分组, 默认为qinglong'),
|
||||
tip: intl.get('BARK推送消息的分组,默认为qinglong'),
|
||||
},
|
||||
],
|
||||
telegramBot: [
|
||||
|
||||
+12
-11
@@ -1,12 +1,13 @@
|
||||
version: 2.16.0
|
||||
changeLogLink: https://t.me/jiao_long/388
|
||||
publishTime: 2023-08-06 16:00
|
||||
version: 2.16.2
|
||||
changeLogLink: https://t.me/jiao_long/393
|
||||
publishTime: 2023-09-02 07:00
|
||||
changeLog: |
|
||||
1. 多语言支持英文界面
|
||||
2. 定时任务增加关联订阅
|
||||
3. 删除订阅支持自动删除任务和脚本
|
||||
4. 定时任务支持运行 mjs 后缀文件
|
||||
5. PushMe消息通道增加 params 参数
|
||||
6. 修复 6 位 cron 不以 task 开头定时任务运行失败
|
||||
7. 修复任务详情日志列表过多卡顿
|
||||
8. 修复定时任务列表虚拟滚动
|
||||
1. 系统设置增加语言设置
|
||||
2. 修复环境变量有空格时并发数量错误
|
||||
3. 修复环境变量特殊字符转义
|
||||
4. 修复仓库订阅 ssh 配置
|
||||
5. 修复停止订阅执行日志
|
||||
6. 修改定时任务置顶样式
|
||||
7. 修改任务日志样式
|
||||
8. 修复环境变量值 tip 样式
|
||||
9. 其他 bug 修复
|
||||
|
||||
Reference in New Issue
Block a user