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