import React, { useCallback, useEffect, useState } from 'react'; import { Modal, message, InputNumber, Form, Radio, Select, Input } from 'antd'; import { request } from '@/utils/http'; import config from '@/utils/config'; import cron_parser from 'cron-parser'; const { Option } = Select; const repoUrlRegx = /[^\/\:]+\/[^\/]+(?=\.git)/; const fileUrlRegx = /[^\/\:]+\/[^\/]+$/; 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 handleOk = async (values: any) => { setLoading(true); const method = subscription ? 'put' : 'post'; const payload = { ...values }; if (subscription) { payload.id = subscription.id; } try { const { code, data } = await request[method]( `${config.apiPrefix}subscriptions`, { data: payload, }, ); if (code === 200) { message.success(subscription ? '更新订阅成功' : '新建订阅成功'); } else { message.error(data); } setLoading(false); handleCancel(data); } catch (error: any) { setLoading(false); } }; const typeChange = (e) => { setType(e.target.value); const _url = form.getFieldValue('url'); const _branch = form.getFieldValue('branch'); form.setFieldsValue({ alias: formatAlias(_url, _branch, e.target.value), }); if (_url) { form.validateFields(['url']); } }; const scheduleTypeChange = (e) => { setScheduleType(e.target.value); form.setFieldsValue({ schedule: '' }); }; const pullTypeChange = (e) => { setPullType(e.target.value); }; const onUrlChange = (e) => { const _branch = form.getFieldValue('branch'); form.setFieldsValue({ alias: formatAlias(e.target.value, _branch), }); }; const onBranchChange = (e) => { const _url = form.getFieldValue('url'); form.setFieldsValue({ alias: formatAlias(_url, e.target.value), }); }; const formatAlias = (_url: string, _branch: string, _type = type) => { let _alias = ''; const _regx = _type === 'file' ? fileUrlRegx : repoUrlRegx; if (_regx.test(_url)) { _alias = _url.match(_regx)![0].replaceAll('/', '_').replaceAll('.', '_'); } if (_branch) { _alias = _alias + '_' + _branch; } return _alias; }; const IntervalSelect = ({ value, onChange, }: { value?: any; onChange?: (param: any) => void; }) => { const [intervalType, setIntervalType] = useState('days'); const [intervalNumber, setIntervalNumber] = useState(); const intervalTypeChange = (type: string) => { setIntervalType(type); onChange?.({ type, value: intervalNumber }); }; const numberChange = (value: number) => { setIntervalNumber(value); onChange?.({ type: intervalType, value }); }; useEffect(() => { if (value) { setIntervalType(value.type); setIntervalNumber(value.value); } }, [value]); return ( ); }; const PullOptions = ({ value, onChange, type, }: { value?: any; type: 'ssh-key' | 'user-pwd'; onChange?: (param: any) => void; }) => { return type === 'ssh-key' ? ( ) : ( <> ); }; const onPaste = useCallback((e: any) => { const text = e.clipboardData.getData('text'); if (!subscription && text.includes('ql ')) { const [ , type, url, whitelist, blacklist, dependences, branch, extensions, ] = text.split(' ').map((x) => x.trim()); form.setFieldsValue({ type: type === 'raw' ? 'file' : url.startsWith('http') ? 'public-repo' : 'private-repo', url, whitelist, blacklist, dependences, branch, extensions, }); } }, []); useEffect(() => { if (visible) { window.addEventListener('paste', onPaste); } else { window.removeEventListener('paste', onPaste); } }, [visible]); useEffect(() => { form.setFieldsValue(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]); const isFirefox = navigator.userAgent.includes('Firefox'); const isSafari = navigator.userAgent.includes('Safari') && !navigator.userAgent.includes('Chrome'); const isQQBrowser = navigator.userAgent.includes('QQBrowser'); return ( 新建订阅 支持repo/raw命令,粘贴导入 ) } visible={visible} forceRender centered maskClosable={false} onOk={() => { form .validateFields() .then((values) => { handleOk(values); }) .catch((info) => { console.log('Validate Failed:', info); }); }} onCancel={() => handleCancel()} confirmLoading={loading} >
公开仓库 私有仓库 单文件 {type !== 'file' && ( )} {type === 'private-repo' && ( <> 私钥 用户名密码/Token )} crontab interval { if ( scheduleType === 'interval' || !value || cron_parser.parseExpression(value).hasNext() ) { return Promise.resolve(); } else { return Promise.reject('Subscription表达式格式有误'); } }, }, ]} > {scheduleType === 'interval' ? ( ) : ( )} {type !== 'file' && ( <> )}
); }; export default SubscriptionModal;