Skip to content

Commit 74e1620

Browse files
xqvvuc121914yu
andauthored
fix: plugin file selector (#5871)
* fix: plugin file selector * fix: render * fix: upload * fix: file selector auth --------- Co-authored-by: archer <[email protected]>
1 parent 8ca5ebe commit 74e1620

File tree

5 files changed

+87
-38
lines changed

5 files changed

+87
-38
lines changed

packages/service/common/s3/sources/chat/type.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ import { ObjectIdSchema } from '@fastgpt/global/common/type/mongo';
33

44
export const ChatFileUploadSchema = z.object({
55
appId: ObjectIdSchema,
6-
chatId: z.string().length(24),
6+
chatId: z.string().nonempty(),
77
uId: z.string().nonempty(),
88
filename: z.string().nonempty()
99
});
1010
export type CheckChatFileKeys = z.infer<typeof ChatFileUploadSchema>;
1111

1212
export const DelChatFileByPrefixSchema = z.object({
1313
appId: ObjectIdSchema,
14-
chatId: z.string().length(24).optional(),
14+
chatId: z.string().nonempty().optional(),
1515
uId: z.string().nonempty().optional()
1616
});
1717
export type DelChatFileByPrefixParams = z.infer<typeof DelChatFileByPrefixSchema>;

projects/app/src/components/core/app/formRender/FileSelector.tsx

Lines changed: 79 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { DragEvent } from 'react';
2-
import React, { useCallback, useMemo, useState } from 'react';
2+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
33
import type { UserInputFileItemType } from '../../chat/ChatContainer/ChatBox/type';
44
import {
55
Box,
@@ -31,8 +31,9 @@ import { ChatBoxContext } from '../../chat/ChatContainer/ChatBox/Provider';
3131
import { POST } from '@/web/common/api/request';
3232
import { getErrText } from '@fastgpt/global/common/error/utils';
3333
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
34-
import { useDebounceEffect } from 'ahooks';
3534
import { formatFileSize, parseUrlToFileType } from '@fastgpt/global/common/file/tools';
35+
import { ChatItemContext } from '@/web/core/chat/context/chatItemContext';
36+
import { PluginRunContext } from '../../chat/ChatContainer/PluginRunBox/context';
3637

3738
const FileSelector = ({
3839
fileUrls,
@@ -45,49 +46,86 @@ const FileSelector = ({
4546
canSelectCustomFileExtension,
4647
customFileExtensionList,
4748
canLocalUpload,
48-
canUrlUpload
49+
canUrlUpload,
50+
isDisabled = false
4951
}: AppFileSelectConfigType & {
50-
fileUrls: string[];
51-
onChange: (e: string[]) => void;
52+
fileUrls: string[] | any[]; // Can be string[] or file object[]
53+
onChange: (e: any[]) => void;
5254
canLocalUpload?: boolean;
5355
canUrlUpload?: boolean;
56+
isDisabled?: boolean;
5457
}) => {
5558
const { feConfigs } = useSystemStore();
5659
const { toast } = useToast();
5760
const { t } = useTranslation();
5861

59-
const outLinkAuthData = useContextSelector(ChatBoxContext, (v) => v.outLinkAuthData);
60-
const appId = useContextSelector(ChatBoxContext, (v) => v.appId);
61-
const chatId = useContextSelector(ChatBoxContext, (v) => v.chatId);
62+
const chatBoxOutLinkAuthData = useContextSelector(ChatBoxContext, (v) => v?.outLinkAuthData);
63+
const chatBoxAppId = useContextSelector(ChatBoxContext, (v) => v?.appId);
64+
const chatBoxChatId = useContextSelector(ChatBoxContext, (v) => v?.chatId);
65+
66+
const pluginOutLinkAuthData = useContextSelector(PluginRunContext, (v) => v?.outLinkAuthData);
67+
const pluginAppId = useContextSelector(PluginRunContext, (v) => v?.appId);
68+
const pluginChatId = useContextSelector(PluginRunContext, (v) => v?.chatId);
69+
70+
const chatItemAppId = useContextSelector(ChatItemContext, (v) => v?.chatBoxData?.appId);
71+
const chatItemChatId = useContextSelector(ChatItemContext, (v) => v?.chatBoxData?.chatId);
72+
73+
const outLinkAuthData = useMemo(
74+
() => ({
75+
...(chatBoxOutLinkAuthData || {}),
76+
...(pluginOutLinkAuthData || {})
77+
}),
78+
[chatBoxOutLinkAuthData, pluginOutLinkAuthData]
79+
);
80+
const appId = useMemo(
81+
() => chatBoxAppId || pluginAppId || chatItemAppId || '',
82+
[chatBoxAppId, pluginAppId, chatItemAppId]
83+
);
84+
const chatId = useMemo(
85+
() => chatBoxChatId || pluginChatId || chatItemChatId || '',
86+
[chatBoxChatId, pluginChatId, chatItemChatId]
87+
);
88+
89+
const [cloneFiles, setCloneFiles] = useState<UserInputFileItemType[]>(() => {
90+
return fileUrls
91+
.map((item) => {
92+
const url = typeof item === 'string' ? item : item?.url || item?.key;
93+
const key = typeof item === 'string' ? undefined : item?.key;
94+
const name = typeof item === 'string' ? undefined : item?.name;
95+
const type = typeof item === 'string' ? undefined : item?.type;
96+
97+
if (!url) return null as unknown as UserInputFileItemType;
6298

63-
const [cloneFiles, setCloneFiles] = useState<UserInputFileItemType[]>(
64-
fileUrls
65-
.map((url) => {
6699
const fileType = parseUrlToFileType(url);
67-
if (!fileType) return null as unknown as UserInputFileItemType;
100+
if (!fileType && !type) return null as unknown as UserInputFileItemType;
68101

69102
return {
70103
id: getNanoid(6),
71-
name: fileType.name || url,
72-
type: fileType.type,
73-
icon: getFileIcon(fileType.name || url),
74-
url: fileType.url,
104+
name: name || fileType?.name || url,
105+
type: type || fileType?.type || ChatFileTypeEnum.file,
106+
icon: getFileIcon(name || fileType?.name || url),
107+
url: typeof item === 'string' ? fileType?.url : item?.url,
75108
status: 1,
76-
key: url.startsWith('chat/') ? url : undefined
109+
key: key || (typeof item === 'string' && url.startsWith('chat/') ? url : undefined)
77110
};
78111
})
79-
.filter(Boolean) as UserInputFileItemType[]
80-
);
81-
// 采用异步更新顶层的方式
82-
useDebounceEffect(
83-
() => {
84-
onChange(cloneFiles.map((file) => file.key || file.url || '').filter(Boolean));
85-
},
86-
[cloneFiles],
87-
{
88-
wait: 1000
89-
}
90-
);
112+
.filter(Boolean) as UserInputFileItemType[];
113+
});
114+
115+
useEffect(() => {
116+
const fileObjects = cloneFiles
117+
.filter((file) => file.url || file.key)
118+
.map((file) => {
119+
const fileObj = {
120+
type: file.type,
121+
name: file.name,
122+
key: file.key,
123+
url: file.url || file.key || ''
124+
};
125+
return fileObj;
126+
});
127+
onChange(fileObjects as any);
128+
}, [cloneFiles, onChange]);
91129

92130
const fileType = useMemo(() => {
93131
return getUploadFileType({
@@ -378,9 +416,10 @@ const FileSelector = ({
378416
borderColor={'myGray.250'}
379417
borderRadius={'md'}
380418
userSelect={'none'}
381-
{...(isMaxSelected
419+
{...(isMaxSelected || isDisabled
382420
? {
383-
cursor: 'not-allowed'
421+
cursor: 'not-allowed',
422+
opacity: isDisabled ? 0.6 : 1
384423
}
385424
: {
386425
cursor: 'pointer',
@@ -397,10 +436,10 @@ const FileSelector = ({
397436
})}
398437
>
399438
<MyIcon name={'common/uploadFileFill'} w={'32px'} />
400-
{isMaxSelected ? (
439+
{isMaxSelected || isDisabled ? (
401440
<>
402441
<Box fontWeight={'500'} fontSize={'sm'}>
403-
{t('file:reached_max_file_count')}
442+
{isDisabled ? t('common:Running') : t('file:reached_max_file_count')}
404443
</Box>
405444
</>
406445
) : (
@@ -427,7 +466,7 @@ const FileSelector = ({
427466
zIndex={10}
428467
/>
429468
<Input
430-
isDisabled={isMaxSelected}
469+
isDisabled={isMaxSelected || isDisabled}
431470
value={urlInput}
432471
onChange={(e) => setUrlInput(e.target.value)}
433472
onBlur={(e) => handleAddUrl(e.target.value)}
@@ -437,7 +476,11 @@ const FileSelector = ({
437476
pl={8}
438477
py={1.5}
439478
placeholder={
440-
isMaxSelected ? t('file:reached_max_file_count') : t('chat:click_to_add_url')
479+
isDisabled
480+
? t('common:Running')
481+
: isMaxSelected
482+
? t('file:reached_max_file_count')
483+
: t('chat:click_to_add_url')
441484
}
442485
/>
443486
</InputGroup>
@@ -476,6 +519,7 @@ const FileSelector = ({
476519
aria-label={'Delete file'}
477520
icon={<MyIcon name={'close'} w={'1rem'} />}
478521
onClick={() => handleDeleteFile(file.id)}
522+
isDisabled={isDisabled}
479523
/>
480524
) : (
481525
<HStack w={'24px'} h={'24px'} justifyContent={'center'}>

projects/app/src/components/core/app/formRender/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ const InputRender = (props: InputRenderProps) => {
224224
customFileExtensionList={props.customFileExtensionList}
225225
canLocalUpload={props.canLocalUpload}
226226
canUrlUpload={props.canUrlUpload}
227+
isDisabled={isDisabled}
227228
/>
228229
);
229230
}

projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderInput.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ const RenderInput = () => {
282282
fieldName={inputKey}
283283
modelList={llmModelList}
284284
isRichText={false}
285+
canLocalUpload={input.canLocalUpload ?? true}
285286
/>
286287
);
287288
}}

projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodePluginIO/InputEditModal.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ export const defaultInput: FlowNodeInputItemType = {
2525
list: [{ label: '', value: '' }],
2626
maxFiles: 5,
2727
canSelectFile: true,
28-
canSelectImg: true
28+
canSelectImg: true,
29+
canLocalUpload: true,
30+
canUrlUpload: false
2931
};
3032

3133
const FieldEditModal = ({
@@ -153,6 +155,7 @@ const FieldEditModal = ({
153155

154156
const onSubmitSuccess = useCallback(
155157
(data: FlowNodeInputItemType, action: 'confirm' | 'continue') => {
158+
console.log('data', data);
156159
data.label = data?.label?.trim();
157160

158161
if (!data.label) {

0 commit comments

Comments
 (0)