Compare commits

...
7 Commits
Author SHA1 Message Date
whyour 47c194c1f4 更新版本 v2.19.1 2025-05-24 15:03:08 +08:00
whyour 7d65d96ebd 修复 demo 环境提示 2025-05-24 14:56:49 +08:00
whyour 224000b63b 修复依赖是否安装检查逻辑 2025-05-23 23:45:43 +08:00
whyour 1c18668bad 修复文件下载参数 2025-05-22 00:09:19 +08:00
whyour f94582b68d 修复查询 python 依赖存在逻辑 2025-05-21 01:25:24 +08:00
whyour eb1c00984c 修复任务视图状态包含筛选 2025-05-20 23:40:18 +08:00
whyour 1a185f5682 修复创建脚本可能失败 2025-05-20 01:00:08 +08:00
33 changed files with 271 additions and 315 deletions
+4 -1
View File
@@ -232,7 +232,7 @@ export default (app: Router) => {
celebrate({ celebrate({
body: Joi.object({ body: Joi.object({
filename: Joi.string().required(), filename: Joi.string().required(),
path: Joi.string().allow(''), path: Joi.string().optional().allow(''),
}), }),
}), }),
async (req: Request, res: Response, next: NextFunction) => { async (req: Request, res: Response, next: NextFunction) => {
@@ -241,6 +241,9 @@ export default (app: Router) => {
filename: string; filename: string;
path: string; path: string;
}; };
if (!path) {
path = '';
}
const scriptService = Container.get(ScriptService); const scriptService = Container.get(ScriptService);
const filePath = scriptService.checkFilePath(path, filename); const filePath = scriptService.checkFilePath(path, filename);
if (!filePath) { if (!filePath) {
+21
View File
@@ -514,6 +514,27 @@ export async function setSystemTimezone(timezone: string): Promise<boolean> {
} }
} }
export function getGetCommand(type: DependenceTypes, name: string): string {
const baseCommands = {
[DependenceTypes.nodejs]: `pnpm ls -g | grep "${name}" | head -1`,
[DependenceTypes.python3]: `
python3 -c "exec('''
name='${name}'
try:
from importlib.metadata import version
print(version(name))
except:
import importlib.util as u
import importlib.metadata as m
spec=u.find_spec(name)
print(name if spec else '')
''')"`,
[DependenceTypes.linux]: `apk info -es ${name}`,
};
return baseCommands[type];
}
export function getInstallCommand(type: DependenceTypes, name: string): string { export function getInstallCommand(type: DependenceTypes, name: string): string {
const baseCommands = { const baseCommands = {
[DependenceTypes.nodejs]: 'pnpm add -g', [DependenceTypes.nodejs]: 'pnpm add -g',
-6
View File
@@ -41,12 +41,6 @@ export enum DependenceTypes {
'linux', 'linux',
} }
export enum GetDependenceCommandTypes {
'pnpm ls -g ',
'pip3 show --disable-pip-version-check',
'apk info -es',
}
export enum versionDependenceCommandTypes { export enum versionDependenceCommandTypes {
'@', '@',
'==', '==',
+3 -1
View File
@@ -116,7 +116,9 @@ export default async () => {
`Neither content nor source specified for ${item.target}`, `Neither content nor source specified for ${item.target}`,
); );
} }
const content = item.content || (await fs.readFile(item.source!)); const content =
item.content ||
(await fs.readFile(item.source!, { encoding: 'utf-8' }));
await writeFileWithLock(item.target, content); await writeFileWithLock(item.target, content);
} }
} }
+23 -9
View File
@@ -215,14 +215,24 @@ export default class CronService {
operate2 = Op.and; operate2 = Op.and;
break; break;
case 'In': case 'In':
q[Op.or] = [ if (
{ property === 'status' &&
[property]: Array.isArray(value) ? value : [value], !value.includes(CrontabStatus.disabled)
}, ) {
property === 'status' && value.includes(2) q[Op.and] = [
? { isDisabled: 1 } { [property]: Array.isArray(value) ? value : [value] },
: {}, { isDisabled: 0 },
]; ];
} else {
q[Op.or] = [
{
[property]: Array.isArray(value) ? value : [value],
},
property === 'status' && value.includes(CrontabStatus.disabled)
? { isDisabled: 1 }
: {},
];
}
break; break;
case 'Nin': case 'Nin':
q[Op.and] = [ q[Op.and] = [
@@ -560,7 +570,10 @@ export default class CronService {
if (logFileExist) { if (logFileExist) {
return await getFileContentByName(`${absolutePath}`); return await getFileContentByName(`${absolutePath}`);
} else { } else {
return '任务未运行'; return typeof doc.status === 'number' &&
[CrontabStatus.queued, CrontabStatus.running].includes(doc.status)
? '运行中...'
: '任务空闲中';
} }
} }
@@ -694,6 +707,7 @@ export default class CronService {
})); }));
if (isDemoEnv()) { if (isDemoEnv()) {
await writeFileWithLock(config.crontabFile, '');
return; return;
} }
await cronClient.addCron(regularCrons); await cronClient.addCron(regularCrons);
+3 -9
View File
@@ -6,7 +6,6 @@ import {
DependenceStatus, DependenceStatus,
DependenceTypes, DependenceTypes,
DependenceModel, DependenceModel,
GetDependenceCommandTypes,
versionDependenceCommandTypes, versionDependenceCommandTypes,
} from '../data/dependence'; } from '../data/dependence';
import { spawn } from 'cross-spawn'; import { spawn } from 'cross-spawn';
@@ -19,6 +18,7 @@ import {
promiseExecSuccess, promiseExecSuccess,
getInstallCommand, getInstallCommand,
getUninstallCommand, getUninstallCommand,
getGetCommand,
} from '../config/util'; } from '../config/util';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import taskLimit from '../shared/pLimit'; import taskLimit from '../shared/pLimit';
@@ -252,7 +252,7 @@ export default class DependenceService {
// 判断是否已经安装过依赖 // 判断是否已经安装过依赖
if (isInstall && !force) { if (isInstall && !force) {
const getCommandPrefix = GetDependenceCommandTypes[dependency.type]; const getCommand = getGetCommand(dependency.type, depName);
const depVersionStr = versionDependenceCommandTypes[dependency.type]; const depVersionStr = versionDependenceCommandTypes[dependency.type];
let depVersion = ''; let depVersion = '';
if (depName.includes(depVersionStr)) { if (depName.includes(depVersionStr)) {
@@ -269,13 +269,7 @@ export default class DependenceService {
const isLinuxDependence = dependency.type === DependenceTypes.linux; const isLinuxDependence = dependency.type === DependenceTypes.linux;
const isPythonDependence = const isPythonDependence =
dependency.type === DependenceTypes.python3; dependency.type === DependenceTypes.python3;
const depInfo = ( const depInfo = (await promiseExecSuccess(getCommand))
await promiseExecSuccess(
isNodeDependence
? `${getCommandPrefix} | grep "${depName}" | head -1`
: `${getCommandPrefix} ${depName}`,
)
)
.replace(/\s{2,}/, ' ') .replace(/\s{2,}/, ' ')
.replace(/\s+$/, ''); .replace(/\s+$/, '');
+1 -1
View File
@@ -13,7 +13,7 @@ function getUniqueLockPath(filePath: string) {
export async function writeFileWithLock( export async function writeFileWithLock(
filePath: string, filePath: string,
content: string | Buffer, content: string,
options: Parameters<typeof writeFile>[2] = {}, options: Parameters<typeof writeFile>[2] = {},
) { ) {
if (typeof options === 'string') { if (typeof options === 'string') {
+11 -12
View File
@@ -56,12 +56,10 @@ interface LogItem {
const CronDetailModal = ({ const CronDetailModal = ({
cron = {}, cron = {},
handleCancel, handleCancel,
visible,
theme, theme,
isPhone, isPhone,
}: { }: {
cron?: any; cron?: any;
visible: boolean;
handleCancel: (needUpdate?: boolean) => void; handleCancel: (needUpdate?: boolean) => void;
theme: string; theme: string;
isPhone: boolean; isPhone: boolean;
@@ -440,7 +438,7 @@ const CronDetailModal = ({
</div> </div>
} }
centered centered
open={visible} open={true}
forceRender forceRender
footer={false} footer={false}
onCancel={() => handleCancel()} onCancel={() => handleCancel()}
@@ -559,15 +557,16 @@ const CronDetailModal = ({
{contentList[activeTabKey]} {contentList[activeTabKey]}
</Card> </Card>
</div> </div>
<CronLogModal {isLogModalVisible && (
visible={isLogModalVisible} <CronLogModal
handleCancel={() => { handleCancel={() => {
setIsLogModalVisible(false); setIsLogModalVisible(false);
}} }}
cron={cron} cron={cron}
data={log} data={log}
logUrl={logUrl} logUrl={logUrl}
/> />
)}
</Modal> </Modal>
); );
}; };
+52 -49
View File
@@ -1037,55 +1037,58 @@ const Crontab = () => {
components={isPhone || pageConf.size < 50 ? undefined : vt} components={isPhone || pageConf.size < 50 ? undefined : vt}
/> />
</div> </div>
<CronLogModal {isLogModalVisible && (
visible={isLogModalVisible} <CronLogModal
handleCancel={() => { handleCancel={() => {
getCronDetail(logCron); getCronDetail(logCron);
setIsLogModalVisible(false); setIsLogModalVisible(false);
}} }}
cron={logCron} cron={logCron}
/> />
<CronModal )}
visible={isModalVisible} {isModalVisible && (
handleCancel={handleCancel} <CronModal handleCancel={handleCancel} cron={editedCron} />
cron={editedCron} )}
/> {isLabelModalVisible && (
<CronLabelModal <CronLabelModal
visible={isLabelModalVisible} handleCancel={(needUpdate?: boolean) => {
handleCancel={(needUpdate?: boolean) => { setIsLabelModalVisible(false);
setIsLabelModalVisible(false); if (needUpdate) {
if (needUpdate) { getCrons();
getCrons(); }
} }}
}} ids={selectedRowIds}
ids={selectedRowIds} />
/> )}
<CronDetailModal {isDetailModalVisible && (
visible={isDetailModalVisible} <CronDetailModal
handleCancel={() => { handleCancel={() => {
setIsDetailModalVisible(false); setIsDetailModalVisible(false);
}} }}
cron={detailCron} cron={detailCron}
theme={theme} theme={theme}
isPhone={isPhone} isPhone={isPhone}
/> />
<ViewCreateModal )}
visible={isCreateViewModalVisible} {isCreateViewModalVisible && (
handleCancel={(data) => { <ViewCreateModal
setIsCreateViewModalVisible(false); handleCancel={(data) => {
getCronViews(); setIsCreateViewModalVisible(false);
}} getCronViews();
/> }}
<ViewManageModal />
cronViews={cronViews} )}
visible={isViewManageModalVisible} {isViewManageModalVisible && (
handleCancel={() => { <ViewManageModal
setIsViewManageModalVisible(false); cronViews={cronViews}
}} handleCancel={() => {
cronViewChange={(data) => { setIsViewManageModalVisible(false);
getCronViews(); }}
}} cronViewChange={(data) => {
/> getCronViews();
}}
/>
)}
</PageContainer> </PageContainer>
); );
}; };
+3 -6
View File
@@ -25,12 +25,10 @@ const { Countdown } = Statistic;
const CronLogModal = ({ const CronLogModal = ({
cron, cron,
handleCancel, handleCancel,
visible,
data, data,
logUrl, logUrl,
}: { }: {
cron?: any; cron?: any;
visible: boolean;
handleCancel: () => void; handleCancel: () => void;
data?: string; data?: string;
logUrl?: string; logUrl?: string;
@@ -120,11 +118,10 @@ const CronLogModal = ({
}; };
useEffect(() => { useEffect(() => {
if (cron && cron.id && visible) { if (cron && cron.id) {
getCronLog(true); getCronLog(true);
scrollInfoRef.current.down = true;
} }
}, [cron, visible]); }, [cron]);
useEffect(() => { useEffect(() => {
if (data) { if (data) {
@@ -139,7 +136,7 @@ const CronLogModal = ({
return ( return (
<Modal <Modal
title={titleElement()} title={titleElement()}
open={visible} open={true}
centered centered
className="log-modal" className="log-modal"
forceRender forceRender
+2 -15
View File
@@ -12,10 +12,8 @@ import { ScheduleType } from './type';
const CronModal = ({ const CronModal = ({
cron, cron,
handleCancel, handleCancel,
visible,
}: { }: {
cron?: any; cron?: any;
visible: boolean;
handleCancel: (needUpdate?: boolean) => void; handleCancel: (needUpdate?: boolean) => void;
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -58,11 +56,6 @@ const CronModal = ({
} }
}; };
useEffect(() => {
form.resetFields();
setScheduleType(getScheduleType(cron?.schedule));
}, [cron, visible]);
const handleScheduleTypeChange = (type: ScheduleType) => { const handleScheduleTypeChange = (type: ScheduleType) => {
setScheduleType(type); setScheduleType(type);
form.setFieldValue('schedule', ''); form.setFieldValue('schedule', '');
@@ -146,7 +139,7 @@ const CronModal = ({
return ( return (
<Modal <Modal
title={cron?.id ? intl.get('编辑任务') : intl.get('创建任务')} title={cron?.id ? intl.get('编辑任务') : intl.get('创建任务')}
open={visible} open={true}
forceRender forceRender
centered centered
maskClosable={false} maskClosable={false}
@@ -251,10 +244,8 @@ const CronModal = ({
const CronLabelModal = ({ const CronLabelModal = ({
ids, ids,
handleCancel, handleCancel,
visible,
}: { }: {
ids: Array<string>; ids: Array<string>;
visible: boolean;
handleCancel: (needUpdate?: boolean) => void; handleCancel: (needUpdate?: boolean) => void;
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -290,10 +281,6 @@ const CronLabelModal = ({
}); });
}; };
useEffect(() => {
form.resetFields();
}, [ids, visible]);
const buttons = [ const buttons = [
<Button onClick={() => handleCancel(false)}>{intl.get('取消')}</Button>, <Button onClick={() => handleCancel(false)}>{intl.get('取消')}</Button>,
<Button type="primary" danger onClick={() => update('delete')}> <Button type="primary" danger onClick={() => update('delete')}>
@@ -307,7 +294,7 @@ const CronLabelModal = ({
return ( return (
<Modal <Modal
title={intl.get('批量修改标签')} title={intl.get('批量修改标签')}
open={visible} open={true}
footer={buttons} footer={buttons}
centered centered
maskClosable={false} maskClosable={false}
+11 -15
View File
@@ -56,10 +56,8 @@ enum ViewFilterRelation {
const ViewCreateModal = ({ const ViewCreateModal = ({
view, view,
handleCancel, handleCancel,
visible,
}: { }: {
view?: any; view?: any;
visible: boolean;
handleCancel: (param?: any) => void; handleCancel: (param?: any) => void;
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -101,17 +99,6 @@ const ViewCreateModal = ({
} }
}; };
useEffect(() => {
if (!view) {
form.resetFields();
}
form.setFieldsValue(
view || {
filters: [{ property: 'command' }],
},
);
}, [view, visible]);
const OperationElement = ({ name, ...others }: { name: number }) => { const OperationElement = ({ name, ...others }: { name: number }) => {
const property = form.getFieldValue(['filters', name, 'property']); const property = form.getFieldValue(['filters', name, 'property']);
return ( return (
@@ -172,7 +159,7 @@ const ViewCreateModal = ({
return ( return (
<Modal <Modal
title={view ? intl.get('编辑视图') : intl.get('创建视图')} title={view ? intl.get('编辑视图') : intl.get('创建视图')}
open={visible} open={true}
forceRender forceRender
width={580} width={580}
centered centered
@@ -190,7 +177,16 @@ const ViewCreateModal = ({
onCancel={() => handleCancel()} onCancel={() => handleCancel()}
confirmLoading={loading} confirmLoading={loading}
> >
<Form form={form} layout="vertical" name="env_modal"> <Form
form={form}
layout="vertical"
initialValues={
view || {
filters: [{ property: 'command' }],
}
}
name="env_modal"
>
<Form.Item <Form.Item
name="name" name="name"
label={intl.get('视图名称')} label={intl.get('视图名称')}
+10 -11
View File
@@ -68,11 +68,9 @@ const DragableBodyRow = ({
const ViewManageModal = ({ const ViewManageModal = ({
cronViews, cronViews,
handleCancel, handleCancel,
visible,
cronViewChange, cronViewChange,
}: { }: {
cronViews: any[]; cronViews: any[];
visible: boolean;
handleCancel: () => void; handleCancel: () => void;
cronViewChange: (data?: any) => void; cronViewChange: (data?: any) => void;
}) => { }) => {
@@ -218,7 +216,7 @@ const ViewManageModal = ({
return ( return (
<Modal <Modal
title={intl.get('视图管理')} title={intl.get('视图管理')}
open={visible} open={true}
centered centered
width={620} width={620}
onCancel={() => handleCancel()} onCancel={() => handleCancel()}
@@ -263,14 +261,15 @@ const ViewManageModal = ({
}} }}
/> />
</DndProvider> </DndProvider>
<ViewCreateModal {isCreateViewModalVisible && (
view={editedView} <ViewCreateModal
visible={isCreateViewModalVisible} view={editedView}
handleCancel={(data) => { handleCancel={(data) => {
setIsCreateViewModalVisible(false); setIsCreateViewModalVisible(false);
cronViewChange(data); cronViewChange(data);
}} }}
/> />
)}
</Modal> </Modal>
); );
}; };
+8 -8
View File
@@ -618,15 +618,15 @@ const Dependence = () => {
]} ]}
/> />
{children} {children}
<DependenceModal {isModalVisible && (
visible={isModalVisible} <DependenceModal
handleCancel={handleCancel} handleCancel={handleCancel}
dependence={editedDependence} dependence={editedDependence}
defaultType={type} defaultType={type}
/> />
{logDependence && ( )}
{logDependence && isLogModalVisible && (
<DependenceLogModal <DependenceLogModal
visible={isLogModalVisible}
handleCancel={(needRemove?: boolean) => { handleCancel={(needRemove?: boolean) => {
setIsLogModalVisible(false); setIsLogModalVisible(false);
if (needRemove) { if (needRemove) {
+1 -3
View File
@@ -15,10 +15,8 @@ import { Status } from './type';
const DependenceLogModal = ({ const DependenceLogModal = ({
dependence, dependence,
handleCancel, handleCancel,
visible,
}: { }: {
dependence?: any; dependence?: any;
visible: boolean;
handleCancel: (needRemove?: boolean) => void; handleCancel: (needRemove?: boolean) => void;
}) => { }) => {
const [value, setValue] = useState<string>(''); const [value, setValue] = useState<string>('');
@@ -128,7 +126,7 @@ const DependenceLogModal = ({
return ( return (
<Modal <Modal
title={titleElement()} title={titleElement()}
open={visible} open={true}
centered centered
className="log-modal" className="log-modal"
forceRender forceRender
+1 -7
View File
@@ -14,11 +14,9 @@ enum DependenceTypes {
const DependenceModal = ({ const DependenceModal = ({
dependence, dependence,
handleCancel, handleCancel,
visible,
defaultType, defaultType,
}: { }: {
dependence?: any; dependence?: any;
visible: boolean;
handleCancel: (cks?: any[]) => void; handleCancel: (cks?: any[]) => void;
defaultType: string; defaultType: string;
}) => { }) => {
@@ -61,14 +59,10 @@ const DependenceModal = ({
} }
}; };
useEffect(() => {
form.resetFields();
}, [dependence, visible]);
return ( return (
<Modal <Modal
title={dependence ? intl.get('编辑依赖') : intl.get('创建依赖')} title={dependence ? intl.get('编辑依赖') : intl.get('创建依赖')}
open={visible} open={true}
forceRender forceRender
centered centered
maskClosable={false} maskClosable={false}
+1 -7
View File
@@ -7,10 +7,8 @@ import config from '@/utils/config';
const EditNameModal = ({ const EditNameModal = ({
ids, ids,
handleCancel, handleCancel,
visible,
}: { }: {
ids?: string[]; ids?: string[];
visible: boolean;
handleCancel: () => void; handleCancel: () => void;
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -34,14 +32,10 @@ const EditNameModal = ({
} }
}; };
useEffect(() => {
form.resetFields();
}, [ids, visible]);
return ( return (
<Modal <Modal
title={intl.get('修改环境变量名称')} title={intl.get('修改环境变量名称')}
open={visible} open={true}
forceRender forceRender
centered centered
maskClosable={false} maskClosable={false}
+9 -10
View File
@@ -616,16 +616,15 @@ const Env = () => {
/> />
</DndProvider> </DndProvider>
</div> </div>
<EnvModal {isModalVisible && (
visible={isModalVisible} <EnvModal handleCancel={handleCancel} env={editedEnv} />
handleCancel={handleCancel} )}
env={editedEnv} {isEditNameModalVisible && (
/> <EditNameModal
<EditNameModal handleCancel={handleEditNameCancel}
visible={isEditNameModalVisible} ids={selectedRowIds}
handleCancel={handleEditNameCancel} />
ids={selectedRowIds} )}
/>
</PageContainer> </PageContainer>
); );
}; };
+1 -7
View File
@@ -7,10 +7,8 @@ import config from '@/utils/config';
const EnvModal = ({ const EnvModal = ({
env, env,
handleCancel, handleCancel,
visible,
}: { }: {
env?: any; env?: any;
visible: boolean;
handleCancel: (cks?: any[]) => void; handleCancel: (cks?: any[]) => void;
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -55,14 +53,10 @@ const EnvModal = ({
} }
}; };
useEffect(() => {
form.resetFields();
}, [env, visible]);
return ( return (
<Modal <Modal
title={env ? intl.get('编辑变量') : intl.get('创建变量')} title={env ? intl.get('编辑变量') : intl.get('创建变量')}
open={visible} open={true}
forceRender forceRender
centered centered
maskClosable={false} maskClosable={false}
+15 -8
View File
@@ -14,6 +14,17 @@ const Error = () => {
const [data, setData] = useState(intl.get('暂无日志')); const [data, setData] = useState(intl.get('暂无日志'));
const retryTimes = useRef(1); const retryTimes = useRef(1);
const loopStatus = (message: string) => {
if (retryTimes.current > 3) {
setData(message);
return;
}
retryTimes.current += 1;
setTimeout(() => {
getHealthStatus(false);
}, 3000);
};
const getHealthStatus = (needLoading: boolean = true) => { const getHealthStatus = (needLoading: boolean = true) => {
needLoading && setLoading(true); needLoading && setLoading(true);
request request
@@ -27,19 +38,15 @@ const Error = () => {
} }
return; return;
} }
if (retryTimes.current > 3) {
setData(error?.details); loopStatus(error?.details);
return;
}
retryTimes.current += 1;
setTimeout(() => {
getHealthStatus(false);
}, 3000);
}) })
.catch((error) => { .catch((error) => {
const responseStatus = error.response.status; const responseStatus = error.response.status;
if (responseStatus === 401) { if (responseStatus === 401) {
history.push('/login'); history.push('/login');
} else {
loopStatus(error.response?.message || error?.message);
} }
}) })
.finally(() => needLoading && setLoading(false)); .finally(() => needLoading && setLoading(false));
+21 -21
View File
@@ -25,11 +25,9 @@ const EditModal = ({
currentNode, currentNode,
content, content,
handleCancel, handleCancel,
visible,
}: { }: {
treeData?: any; treeData?: any;
content?: string; content?: string;
visible: boolean;
currentNode: any; currentNode: any;
handleCancel: () => void; handleCancel: () => void;
}) => { }) => {
@@ -223,7 +221,7 @@ const EditModal = ({
width={'100%'} width={'100%'}
headerStyle={{ padding: '11px 24px' }} headerStyle={{ padding: '11px 24px' }}
onClose={cancel} onClose={cancel}
open={visible} open={true}
> >
{/* @ts-ignore */} {/* @ts-ignore */}
<SplitPane <SplitPane
@@ -256,24 +254,26 @@ const EditModal = ({
<Ansi>{log}</Ansi> <Ansi>{log}</Ansi>
</pre> </pre>
</SplitPane> </SplitPane>
<SaveModal {saveModalVisible && (
visible={saveModalVisible} <SaveModal
handleCancel={() => { handleCancel={() => {
setSaveModalVisible(false); setSaveModalVisible(false);
}} }}
file={{ file={{
content: content:
editorRef.current && editorRef.current &&
editorRef.current.getValue().replace(/\r\n/g, '\n'), editorRef.current.getValue().replace(/\r\n/g, '\n'),
...cNode, ...cNode,
}} }}
/> />
<SettingModal )}
visible={settingModalVisible} {settingModalVisible && (
handleCancel={() => { <SettingModal
setSettingModalVisible(false); handleCancel={() => {
}} setSettingModalVisible(false);
/> }}
/>
)}
</Drawer> </Drawer>
); );
}; };
+2 -8
View File
@@ -19,9 +19,7 @@ const { Option } = Select;
const EditScriptNameModal = ({ const EditScriptNameModal = ({
handleCancel, handleCancel,
treeData, treeData,
visible,
}: { }: {
visible: boolean;
treeData: any[]; treeData: any[];
handleCancel: (file?: { handleCancel: (file?: {
filename: string; filename: string;
@@ -53,7 +51,7 @@ const EditScriptNameModal = ({
directory ? intl.get('创建文件夹成功') : intl.get('创建文件成功'), directory ? intl.get('创建文件夹成功') : intl.get('创建文件成功'),
); );
const key = path ? `${path}/` : ''; const key = path ? `${path}/` : '';
const filename = file ? file.name : (directory || inputFilename); const filename = file ? file.name : directory || inputFilename;
handleCancel({ handleCancel({
filename, filename,
path, path,
@@ -95,14 +93,10 @@ const EditScriptNameModal = ({
setDirs(dirs); setDirs(dirs);
}, [treeData]); }, [treeData]);
useEffect(() => {
form.resetFields();
}, [visible]);
return ( return (
<Modal <Modal
title={intl.get('创建')} title={intl.get('创建')}
open={visible} open={true}
forceRender forceRender
centered centered
maskClosable={false} maskClosable={false}
+13 -12
View File
@@ -710,9 +710,8 @@ const Script = () => {
}} }}
/> />
)} )}
{isLogModalVisible && ( {isLogModalVisible && isLogModalVisible && (
<EditModal <EditModal
visible={isLogModalVisible}
treeData={data} treeData={data}
currentNode={currentNode} currentNode={currentNode}
content={value} content={value}
@@ -721,16 +720,18 @@ const Script = () => {
}} }}
/> />
)} )}
<EditScriptNameModal {isAddFileModalVisible && (
visible={isAddFileModalVisible} <EditScriptNameModal
treeData={data} treeData={data}
handleCancel={addFileModalClose} handleCancel={addFileModalClose}
/> />
<RenameModal )}
visible={isRenameFileModalVisible} {isRenameFileModalVisible && (
handleCancel={handleRenameFileCancel} <RenameModal
currentNode={currentNode} handleCancel={handleRenameFileCancel}
/> currentNode={currentNode}
/>
)}
</div> </div>
</PageContainer> </PageContainer>
); );
+1 -7
View File
@@ -7,10 +7,8 @@ import config from '@/utils/config';
const RenameModal = ({ const RenameModal = ({
currentNode, currentNode,
handleCancel, handleCancel,
visible,
}: { }: {
currentNode?: any; currentNode?: any;
visible: boolean;
handleCancel: () => void; handleCancel: () => void;
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -38,14 +36,10 @@ const RenameModal = ({
} }
}; };
useEffect(() => {
form.resetFields();
}, [currentNode, visible]);
return ( return (
<Modal <Modal
title={intl.get('重命名')} title={intl.get('重命名')}
open={visible} open={true}
forceRender forceRender
centered centered
maskClosable={false} maskClosable={false}
+1 -8
View File
@@ -7,10 +7,8 @@ import config from '@/utils/config';
const SaveModal = ({ const SaveModal = ({
file, file,
handleCancel, handleCancel,
visible,
}: { }: {
file?: any; file?: any;
visible: boolean;
handleCancel: (cks?: any[]) => void; handleCancel: (cks?: any[]) => void;
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -32,15 +30,10 @@ const SaveModal = ({
}); });
}; };
useEffect(() => {
form.resetFields();
setLoading(false);
}, [file, visible]);
return ( return (
<Modal <Modal
title={intl.get('保存文件')} title={intl.get('保存文件')}
open={visible} open={true}
forceRender forceRender
centered centered
maskClosable={false} maskClosable={false}
+1 -8
View File
@@ -7,10 +7,8 @@ import config from '@/utils/config';
const SettingModal = ({ const SettingModal = ({
file, file,
handleCancel, handleCancel,
visible,
}: { }: {
file?: any; file?: any;
visible: boolean;
handleCancel: (cks?: any[]) => void; handleCancel: (cks?: any[]) => void;
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -30,15 +28,10 @@ const SettingModal = ({
}); });
}; };
useEffect(() => {
form.resetFields();
setLoading(false);
}, [file, visible]);
return ( return (
<Modal <Modal
title={intl.get('运行设置')} title={intl.get('运行设置')}
open={visible} open={true}
forceRender forceRender
centered centered
onCancel={() => handleCancel()} onCancel={() => handleCancel()}
+1 -7
View File
@@ -7,10 +7,8 @@ import config from '@/utils/config';
const AppModal = ({ const AppModal = ({
app, app,
handleCancel, handleCancel,
visible,
}: { }: {
app?: any; app?: any;
visible: boolean;
handleCancel: (needUpdate?: boolean) => void; handleCancel: (needUpdate?: boolean) => void;
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -41,14 +39,10 @@ const AppModal = ({
} }
}; };
useEffect(() => {
form.resetFields();
}, [app, visible]);
return ( return (
<Modal <Modal
title={app ? intl.get('编辑应用') : intl.get('创建应用')} title={app ? intl.get('编辑应用') : intl.get('创建应用')}
open={visible} open={true}
forceRender forceRender
centered centered
maskClosable={false} maskClosable={false}
+3 -5
View File
@@ -363,11 +363,9 @@ const Setting = () => {
]} ]}
/> />
</div> </div>
<AppModal {isModalVisible && (
visible={isModalVisible} <AppModal handleCancel={handleCancel} app={editedApp} />
handleCancel={handleCancel} )}
app={editedApp}
/>
</PageContainer> </PageContainer>
); );
}; };
+14 -12
View File
@@ -579,18 +579,20 @@ const Subscription = () => {
loading={loading} loading={loading}
rowClassName={getRowClassName} rowClassName={getRowClassName}
/> />
<SubscriptionModal {isModalVisible && (
visible={isModalVisible} <SubscriptionModal
handleCancel={handleCancel} handleCancel={handleCancel}
subscription={editedSubscription} subscription={editedSubscription}
/> />
<SubscriptionLogModal )}
visible={isLogModalVisible} {isLogModalVisible && (
handleCancel={() => { <SubscriptionLogModal
setIsLogModalVisible(false); handleCancel={() => {
}} setIsLogModalVisible(false);
subscription={logSubscription} }}
/> subscription={logSubscription}
/>
)}
</PageContainer> </PageContainer>
); );
}; };
+3 -5
View File
@@ -14,12 +14,10 @@ import Ansi from 'ansi-to-react';
const SubscriptionLogModal = ({ const SubscriptionLogModal = ({
subscription, subscription,
handleCancel, handleCancel,
visible,
data, data,
logUrl, logUrl,
}: { }: {
subscription?: any; subscription?: any;
visible: boolean;
handleCancel: () => void; handleCancel: () => void;
data?: string; data?: string;
logUrl?: string; logUrl?: string;
@@ -79,10 +77,10 @@ const SubscriptionLogModal = ({
}; };
useEffect(() => { useEffect(() => {
if (subscription && subscription.id && visible) { if (subscription && subscription.id) {
getCronLog(true); getCronLog(true);
} }
}, [subscription, visible]); }, [subscription]);
useEffect(() => { useEffect(() => {
if (data) { if (data) {
@@ -97,7 +95,7 @@ const SubscriptionLogModal = ({
return ( return (
<Modal <Modal
title={titleElement()} title={titleElement()}
open={visible} open={true}
centered centered
className="log-modal" className="log-modal"
forceRender forceRender
+19 -24
View File
@@ -22,17 +22,19 @@ const fileUrlRegx = /([^\/\:]+\/[^\/\.]+)\.[a-z]+$/;
const SubscriptionModal = ({ const SubscriptionModal = ({
subscription, subscription,
handleCancel, handleCancel,
visible,
}: { }: {
subscription?: any; subscription?: any;
visible: boolean;
handleCancel: (needUpdate?: boolean) => void; handleCancel: (needUpdate?: boolean) => void;
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [type, setType] = useState('public-repo'); const [type, setType] = useState(subscription?.type || 'public-repo');
const [scheduleType, setScheduleType] = useState('crontab'); const [scheduleType, setScheduleType] = useState(
const [pullType, setPullType] = useState<'ssh-key' | 'user-pwd'>('ssh-key'); subscription?.schedule_type || 'crontab',
);
const [pullType, setPullType] = useState<'ssh-key' | 'user-pwd'>(
subscription?.pull_type || 'ssh-key',
);
const handleOk = async (values: any) => { const handleOk = async (values: any) => {
setLoading(true); setLoading(true);
@@ -255,29 +257,17 @@ const SubscriptionModal = ({
}; };
useEffect(() => { useEffect(() => {
if (visible) { window.addEventListener('paste', onPaste);
window.addEventListener('paste', onPaste);
} else {
window.removeEventListener('paste', onPaste);
}
}, [visible]);
useEffect(() => { return () => {
form.setFieldsValue( window.removeEventListener('paste', onPaste);
{ ...subscription, ...formatParams(subscription) } || {}, };
); }, []);
setType((subscription && subscription.type) || 'public-repo');
setScheduleType((subscription && subscription.schedule_type) || 'crontab');
setPullType((subscription && subscription.pull_type) || 'ssh-key');
if (!subscription) {
form.resetFields();
}
}, [subscription, visible]);
return ( return (
<Modal <Modal
title={subscription ? intl.get('编辑订阅') : intl.get('创建订阅')} title={subscription ? intl.get('编辑订阅') : intl.get('创建订阅')}
open={visible} open={true}
forceRender forceRender
centered centered
maskClosable={false} maskClosable={false}
@@ -294,7 +284,12 @@ const SubscriptionModal = ({
onCancel={() => handleCancel()} onCancel={() => handleCancel()}
confirmLoading={loading} confirmLoading={loading}
> >
<Form form={form} name="form_in_modal" layout="vertical"> <Form
form={form}
name="form_in_modal"
layout="vertical"
initialValues={{ ...subscription, ...formatParams(subscription) }}
>
<Form.Item <Form.Item
name="name" name="name"
label={intl.get('名称')} label={intl.get('名称')}
+1 -1
View File
@@ -14,7 +14,7 @@ export interface IResponseData {
code?: number; code?: number;
data?: any; data?: any;
message?: string; message?: string;
errors?: any[]; error?: any;
} }
export type Override< export type Override<
+11 -12
View File
@@ -1,13 +1,12 @@
version: 2.19.0 version: 2.19.1
changeLogLink: https://t.me/jiao_long/429 changeLogLink: https://t.me/jiao_long/430
publishTime: 2025-05-11 08:00 publishTime: 2025-05-24 16:00
changeLog: | changeLog: |
1. 缓存 node 和 python 依赖,linux 依赖需要增加映射目录 1. 修复依赖是否安装检查逻辑
2. 减少启动服务数,节约启动内存约 50% 2. 修复文件下载 path 参数
3. 邮箱通知支持多个收件人 3. 修复 python 查询逻辑
4. boot 任务改为在依赖安装完成后执行 4. 修复任务视图状态筛选
5. 修复脚本管理查询子目录逻辑 5. 修复创建脚本可能失败
6. 修复脚本管理增加文件夹 6. 修复重置用户名失败
7. 修复 QLAPI 修复环境变量 remarks 7. 修复无法识别 python 依赖安装的命令
8. 修复 mjs 依赖查不到 8. 其他缺陷修复
9. 修复无法删除日志文件