mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-09-04 23:29:00 +08:00
fix(ui): fix bug on processor page
This commit is contained in:
@@ -62,6 +62,7 @@ const ProfileModal = memo(function ProfileModal({ open, onClose }: ProfileModalP
|
|||||||
confirmLoading={loading}
|
confirmLoading={loading}
|
||||||
okText={t('Save')}
|
okText={t('Save')}
|
||||||
cancelText={t('Cancel')}
|
cancelText={t('Cancel')}
|
||||||
|
forceRender
|
||||||
>
|
>
|
||||||
<Form form={form} layout="vertical">
|
<Form form={form} layout="vertical">
|
||||||
<Form.Item name="username" label={t('Username')}>
|
<Form.Item name="username" label={t('Username')}>
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ const AdaptersPage = memo(function AdaptersPage() {
|
|||||||
width={480}
|
width={480}
|
||||||
open={open}
|
open={open}
|
||||||
onClose={() => { setOpen(false); setEditing(null); }}
|
onClose={() => { setOpen(false); setEditing(null); }}
|
||||||
destroyOnClose
|
destroyOnHidden
|
||||||
extra={
|
extra={
|
||||||
<Space>
|
<Space>
|
||||||
<Button onClick={() => { setOpen(false); setEditing(null); }}>{t('Cancel')}</Button>
|
<Button onClick={() => { setOpen(false); setEditing(null); }}>{t('Cancel')}</Button>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const CreateDirModal: React.FC<CreateDirModalProps> = ({ open, onOk, onCa
|
|||||||
onOk={handleOk}
|
onOk={handleOk}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
okButtonProps={{ disabled: !name.trim() }}
|
okButtonProps={{ disabled: !name.trim() }}
|
||||||
destroyOnClose
|
destroyOnHidden
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
placeholder={t('Folder Name')}
|
placeholder={t('Folder Name')}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export const ProcessorModal: React.FC<ProcessorModalProps> = (props) => {
|
|||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onOk={onOk}
|
onOk={onOk}
|
||||||
confirmLoading={loading}
|
confirmLoading={loading}
|
||||||
destroyOnClose
|
destroyOnHidden
|
||||||
>
|
>
|
||||||
<Form form={form} layout="vertical" onValuesChange={handleFormValuesChange}>
|
<Form form={form} layout="vertical" onValuesChange={handleFormValuesChange}>
|
||||||
<Form.Item name="processor_type" label={t('Processor')} required>
|
<Form.Item name="processor_type" label={t('Processor')} required>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export const RenameModal: React.FC<RenameModalProps> = ({ entry, onOk, onCancel
|
|||||||
onOk={handleOk}
|
onOk={handleOk}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
okButtonProps={{ disabled: !name.trim() || name.trim() === entry?.name }}
|
okButtonProps={{ disabled: !name.trim() || name.trim() === entry?.name }}
|
||||||
destroyOnClose
|
destroyOnHidden
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
placeholder={t('New Name')}
|
placeholder={t('New Name')}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import {
|
|||||||
theme,
|
theme,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import Editor from '@monaco-editor/react';
|
import Editor from '@monaco-editor/react';
|
||||||
import PageCard from '../components/PageCard';
|
|
||||||
import { ProcessorConfigForm } from '../components/ProcessorConfigForm';
|
import { ProcessorConfigForm } from '../components/ProcessorConfigForm';
|
||||||
import PathSelectorModal, { type PathSelectorMode } from '../components/PathSelectorModal';
|
import PathSelectorModal, { type PathSelectorMode } from '../components/PathSelectorModal';
|
||||||
import { processorsApi, type ProcessorTypeMeta } from '../api/processors';
|
import { processorsApi, type ProcessorTypeMeta } from '../api/processors';
|
||||||
@@ -30,6 +29,7 @@ type TabKey = 'editor' | 'runner';
|
|||||||
const ProcessorsPage = memo(function ProcessorsPage() {
|
const ProcessorsPage = memo(function ProcessorsPage() {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { token } = theme.useToken();
|
const { token } = theme.useToken();
|
||||||
|
const [messageApi, contextHolder] = message.useMessage();
|
||||||
const [processors, setProcessors] = useState<ProcessorTypeMeta[]>([]);
|
const [processors, setProcessors] = useState<ProcessorTypeMeta[]>([]);
|
||||||
const [loadingList, setLoadingList] = useState(false);
|
const [loadingList, setLoadingList] = useState(false);
|
||||||
const [selectedType, setSelectedType] = useState<string>('');
|
const [selectedType, setSelectedType] = useState<string>('');
|
||||||
@@ -60,11 +60,11 @@ const ProcessorsPage = memo(function ProcessorsPage() {
|
|||||||
const list = await processorsApi.list();
|
const list = await processorsApi.list();
|
||||||
setProcessors(list);
|
setProcessors(list);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
message.error(err?.message || t('Load failed'));
|
messageApi.error(err?.message || t('Load failed'));
|
||||||
} finally {
|
} finally {
|
||||||
setLoadingList(false);
|
setLoadingList(false);
|
||||||
}
|
}
|
||||||
}, [t]);
|
}, [messageApi, t]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadList();
|
loadList();
|
||||||
@@ -103,7 +103,7 @@ const ProcessorsPage = memo(function ProcessorsPage() {
|
|||||||
})
|
})
|
||||||
.catch((err: any) => {
|
.catch((err: any) => {
|
||||||
if (controller.signal.aborted) return;
|
if (controller.signal.aborted) return;
|
||||||
message.error(err?.message || t('Load failed'));
|
messageApi.error(err?.message || t('Load failed'));
|
||||||
setSource('');
|
setSource('');
|
||||||
setInitialSource('');
|
setInitialSource('');
|
||||||
setModulePath('');
|
setModulePath('');
|
||||||
@@ -114,19 +114,24 @@ const ProcessorsPage = memo(function ProcessorsPage() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => controller.abort();
|
return () => controller.abort();
|
||||||
}, [selectedType, t]);
|
}, [messageApi, selectedType, t]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!selectedProcessorMeta) {
|
||||||
|
form.resetFields();
|
||||||
|
setIsDirectory(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
const defaults: Record<string, any> = {};
|
const defaults: Record<string, any> = {};
|
||||||
selectedProcessorMeta?.config_schema?.forEach(field => {
|
selectedProcessorMeta.config_schema?.forEach(field => {
|
||||||
if (field.default !== undefined) {
|
if (field.default !== undefined) {
|
||||||
defaults[field.key] = field.default;
|
defaults[field.key] = field.default;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
path: '',
|
path: '',
|
||||||
overwrite: !!selectedProcessorMeta?.produces_file,
|
overwrite: !!selectedProcessorMeta.produces_file,
|
||||||
save_to: undefined,
|
save_to: undefined,
|
||||||
config: defaults,
|
config: defaults,
|
||||||
});
|
});
|
||||||
@@ -172,26 +177,26 @@ const ProcessorsPage = memo(function ProcessorsPage() {
|
|||||||
setSavingSource(true);
|
setSavingSource(true);
|
||||||
await processorsApi.updateSource(selectedType, source);
|
await processorsApi.updateSource(selectedType, source);
|
||||||
setInitialSource(source);
|
setInitialSource(source);
|
||||||
message.success(t('Source saved'));
|
messageApi.success(t('Source saved'));
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
message.error(err?.message || t('Operation failed'));
|
messageApi.error(err?.message || t('Operation failed'));
|
||||||
} finally {
|
} finally {
|
||||||
setSavingSource(false);
|
setSavingSource(false);
|
||||||
}
|
}
|
||||||
}, [selectedType, source, t]);
|
}, [messageApi, selectedType, source, t]);
|
||||||
|
|
||||||
const handleReloadProcessors = useCallback(async () => {
|
const handleReloadProcessors = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
setReloading(true);
|
setReloading(true);
|
||||||
await processorsApi.reload();
|
await processorsApi.reload();
|
||||||
message.success(t('Processors reloaded'));
|
messageApi.success(t('Processors reloaded'));
|
||||||
await loadList();
|
await loadList();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
message.error(err?.message || t('Operation failed'));
|
messageApi.error(err?.message || t('Operation failed'));
|
||||||
} finally {
|
} finally {
|
||||||
setReloading(false);
|
setReloading(false);
|
||||||
}
|
}
|
||||||
}, [loadList, t]);
|
}, [loadList, messageApi, t]);
|
||||||
|
|
||||||
const openPathSelector = useCallback((field: 'path' | 'save_to', mode: PathSelectorMode) => {
|
const openPathSelector = useCallback((field: 'path' | 'save_to', mode: PathSelectorMode) => {
|
||||||
setPathModalField(field);
|
setPathModalField(field);
|
||||||
@@ -211,7 +216,7 @@ const ProcessorsPage = memo(function ProcessorsPage() {
|
|||||||
|
|
||||||
const handleRun = useCallback(async () => {
|
const handleRun = useCallback(async () => {
|
||||||
if (!selectedType) {
|
if (!selectedType) {
|
||||||
message.warning(t('Please select a processor'));
|
messageApi.warning(t('Please select a processor'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -237,20 +242,20 @@ const ProcessorsPage = memo(function ProcessorsPage() {
|
|||||||
payload.save_to = values.save_to;
|
payload.save_to = values.save_to;
|
||||||
}
|
}
|
||||||
const resp = await processorsApi.process(payload);
|
const resp = await processorsApi.process(payload);
|
||||||
message.success(`${t('Task submitted')}: ${resp.task_id}`);
|
messageApi.success(`${t('Task submitted')}: ${resp.task_id}`);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err?.errorFields) {
|
if (err?.errorFields) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
message.error(err?.message || t('Operation failed'));
|
messageApi.error(err?.message || t('Operation failed'));
|
||||||
} finally {
|
} finally {
|
||||||
setRunning(false);
|
setRunning(false);
|
||||||
}
|
}
|
||||||
}, [form, selectedProcessorMeta, selectedType, t]);
|
}, [form, messageApi, selectedProcessorMeta, selectedType, t]);
|
||||||
|
|
||||||
const selectedConfigPath = pathModalField === 'path'
|
const selectedConfigPath = pathModalField === 'path'
|
||||||
? form.getFieldValue('path') || '/'
|
? (selectedType ? form.getFieldValue('path') : undefined) || '/'
|
||||||
: form.getFieldValue('save_to') || '/';
|
: (selectedType ? form.getFieldValue('save_to') : undefined) || '/';
|
||||||
|
|
||||||
const renderProcessorList = () => {
|
const renderProcessorList = () => {
|
||||||
if (loadingList) {
|
if (loadingList) {
|
||||||
@@ -369,66 +374,80 @@ const ProcessorsPage = memo(function ProcessorsPage() {
|
|||||||
{
|
{
|
||||||
key: 'runner',
|
key: 'runner',
|
||||||
label: t('Run Processor'),
|
label: t('Run Processor'),
|
||||||
children: selectedType ? (
|
forceRender: true,
|
||||||
|
children: (
|
||||||
<Form form={form} layout="vertical" disabled={!selectedType} style={{ padding: '12px 0' }}>
|
<Form form={form} layout="vertical" disabled={!selectedType} style={{ padding: '12px 0' }}>
|
||||||
{isDirectory && (
|
{selectedType ? (
|
||||||
<Text type="secondary" style={{ display: 'block', marginBottom: 12 }}>
|
<>
|
||||||
{t('Directory processing always overwrites original files')}
|
{isDirectory && (
|
||||||
</Text>
|
<Text type="secondary" style={{ display: 'block', marginBottom: 12 }}>
|
||||||
|
{t('Directory processing always overwrites original files')}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
<Form.Item
|
||||||
|
label={t('Target Path')}
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<Flex gap={8} align="center">
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<Form.Item
|
||||||
|
name="path"
|
||||||
|
rules={[{ required: true, message: t('Please select a path') }]}
|
||||||
|
noStyle
|
||||||
|
>
|
||||||
|
<Input placeholder={t('Select a path')} />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
<Button onClick={() => openPathSelector('path', 'file')}>{t('Select File')}</Button>
|
||||||
|
<Button onClick={() => openPathSelector('path', 'directory')}>{t('Select Directory')}</Button>
|
||||||
|
</Flex>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="overwrite"
|
||||||
|
label={t('Overwrite original')}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch disabled={isDirectory} />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
{selectedProcessorMeta?.produces_file && !overwriteValue && (
|
||||||
|
<Form.Item label={t('Save To')}>
|
||||||
|
<Flex gap={8} align="center">
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<Form.Item name="save_to" noStyle>
|
||||||
|
<Input placeholder={t('Optional output path')} />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
<Button onClick={() => openPathSelector('save_to', 'any')}>{t('Select')}</Button>
|
||||||
|
</Flex>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<ProcessorConfigForm
|
||||||
|
processorMeta={selectedProcessorMeta}
|
||||||
|
form={form}
|
||||||
|
configPath={['config']}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Form.Item>
|
||||||
|
<Button type="primary" onClick={handleRun} loading={running} disabled={!selectedType}>
|
||||||
|
{t('Run')}
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Empty style={{ marginTop: 64 }} description={t('Select a processor')} />
|
||||||
)}
|
)}
|
||||||
<Form.Item
|
|
||||||
name="path"
|
|
||||||
label={t('Target Path')}
|
|
||||||
rules={[{ required: true, message: t('Please select a path') }]}
|
|
||||||
>
|
|
||||||
<Flex gap={8} align="center">
|
|
||||||
<Input placeholder={t('Select a path')} style={{ flex: 1 }} />
|
|
||||||
<Button onClick={() => openPathSelector('path', 'file')}>{t('Select File')}</Button>
|
|
||||||
<Button onClick={() => openPathSelector('path', 'directory')}>{t('Select Directory')}</Button>
|
|
||||||
</Flex>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
name="overwrite"
|
|
||||||
label={t('Overwrite original')}
|
|
||||||
valuePropName="checked"
|
|
||||||
>
|
|
||||||
<Switch disabled={isDirectory} />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
{selectedProcessorMeta?.produces_file && !overwriteValue && (
|
|
||||||
<Form.Item
|
|
||||||
name="save_to"
|
|
||||||
label={t('Save To')}
|
|
||||||
>
|
|
||||||
<Flex gap={8} align="center">
|
|
||||||
<Input placeholder={t('Optional output path')} style={{ flex: 1 }} />
|
|
||||||
<Button onClick={() => openPathSelector('save_to', 'any')}>{t('Select')}</Button>
|
|
||||||
</Flex>
|
|
||||||
</Form.Item>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<ProcessorConfigForm
|
|
||||||
processorMeta={selectedProcessorMeta}
|
|
||||||
form={form}
|
|
||||||
configPath={['config']}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Form.Item>
|
|
||||||
<Button type="primary" onClick={handleRun} loading={running} disabled={!selectedType}>
|
|
||||||
{t('Run')}
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
</Form>
|
||||||
) : (
|
|
||||||
<Empty style={{ marginTop: 64 }} description={t('Select a processor')} />
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageCard title={t('Processors')}>
|
<>
|
||||||
<Flex gap={16} style={{ height: '100%' }}>
|
{contextHolder}
|
||||||
|
<Flex gap={16} style={{ height: 'calc(100vh - 88px)' }}>
|
||||||
<Card
|
<Card
|
||||||
style={{ flex: '0 0 320px', minWidth: 280, display: 'flex', flexDirection: 'column' }}
|
style={{ flex: '0 0 320px', minWidth: 280, display: 'flex', flexDirection: 'column' }}
|
||||||
title={t('Processor List')}
|
title={t('Processor List')}
|
||||||
@@ -475,7 +494,7 @@ const ProcessorsPage = memo(function ProcessorsPage() {
|
|||||||
onOk={handlePathSelected}
|
onOk={handlePathSelected}
|
||||||
onCancel={() => setPathModalOpen(false)}
|
onCancel={() => setPathModalOpen(false)}
|
||||||
/>
|
/>
|
||||||
</PageCard>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ const TasksPage = memo(function TasksPage() {
|
|||||||
width={480}
|
width={480}
|
||||||
open={open}
|
open={open}
|
||||||
onClose={() => { setOpen(false); setEditing(null); }}
|
onClose={() => { setOpen(false); setEditing(null); }}
|
||||||
destroyOnClose
|
destroyOnHidden
|
||||||
extra={
|
extra={
|
||||||
<Space>
|
<Space>
|
||||||
<Button onClick={() => { setOpen(false); setEditing(null); }}>{t('Cancel')}</Button>
|
<Button onClick={() => { setOpen(false); setEditing(null); }}>{t('Cancel')}</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user