Agent chat file drag and drop (#13226)
- Added drag and drop support - The AIChatTab component has been refactored into smaller, more focused components to improve readability, maintainability, and scalability of the codebase. - Introduced a custom useAIChatFileUpload hook to encapsulate and manage file upload logic, promoting code reuse and separation of concerns. ### Demo https://github.com/user-attachments/assets/c4b2a67a-2736-48ae-9ba8-8e124e4b6069 --------- Co-authored-by: Raphaël Bosi <71827178+bosiraphael@users.noreply.github.com> Co-authored-by: neo773 <62795688+neo773@users.noreply.github.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Félix Malfait <felix@twenty.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions <github-actions@twenty.com> Co-authored-by: MD Readul Islam <99027968+readul-islam@users.noreply.github.com> Co-authored-by: readul-islam <developer.readul@gamil.com> Co-authored-by: Thomas des Francs <tdesfrancs@gmail.com> Co-authored-by: Guillim <guillim@users.noreply.github.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com> Co-authored-by: Jean-Baptiste Ronssin <65334819+jbronssin@users.noreply.github.com> Co-authored-by: kahkashan shaik <93042682+kahkashanshaik@users.noreply.github.com> Co-authored-by: martmull <martmull@hotmail.fr> Co-authored-by: Paul Rastoin <45004772+prastoin@users.noreply.github.com> Co-authored-by: bosiraphael <raphael.bosi@gmail.com> Co-authored-by: Naifer <161821705+omarNaifer12@users.noreply.github.com> Co-authored-by: Marie Stoppa <marie.stoppa@essec.edu>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { agentChatSelectedFilesComponentState } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/states/agentChatSelectedFilesComponentState';
|
||||
import { agentChatUploadedFilesComponentState } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/states/agentChatUploadedFilesComponentState';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
File as FileDocument,
|
||||
useCreateFileMutation,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const useAIChatFileUpload = ({ agentId }: { agentId: string }) => {
|
||||
const coreClient = useApolloCoreClient();
|
||||
const [createFile] = useCreateFileMutation({ client: coreClient });
|
||||
const { t } = useLingui();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
const [agentChatSelectedFiles, setAgentChatSelectedFiles] =
|
||||
useRecoilComponentStateV2(agentChatSelectedFilesComponentState, agentId);
|
||||
const [agentChatUploadedFiles, setAgentChatUploadedFiles] =
|
||||
useRecoilComponentStateV2(agentChatUploadedFilesComponentState, agentId);
|
||||
|
||||
const sendFile = async (file: File) => {
|
||||
try {
|
||||
const result = await createFile({
|
||||
variables: {
|
||||
file,
|
||||
},
|
||||
});
|
||||
|
||||
const uploadedFile = result?.data?.createFile;
|
||||
|
||||
if (!isDefined(uploadedFile)) {
|
||||
throw new Error(t`Couldn't upload the file.`);
|
||||
}
|
||||
setAgentChatSelectedFiles(
|
||||
agentChatSelectedFiles.filter((f) => f.name !== file.name),
|
||||
);
|
||||
return uploadedFile;
|
||||
} catch (error) {
|
||||
const fileName = file.name;
|
||||
enqueueErrorSnackBar({
|
||||
message: t`Failed to upload file: ${fileName}`,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const uploadFiles = async (files: File[]) => {
|
||||
const uploadResults = await Promise.allSettled(
|
||||
files.map((file) => sendFile(file)),
|
||||
);
|
||||
|
||||
const successfulUploads = uploadResults.reduce<FileDocument[]>(
|
||||
(acc, result) => {
|
||||
if (result.status === 'fulfilled' && isDefined(result.value)) {
|
||||
acc.push(result.value);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
if (successfulUploads.length > 0) {
|
||||
setAgentChatUploadedFiles([
|
||||
...agentChatUploadedFiles,
|
||||
...successfulUploads,
|
||||
]);
|
||||
}
|
||||
|
||||
const failedCount = uploadResults.filter(
|
||||
(result) => result.status === 'rejected',
|
||||
).length;
|
||||
if (failedCount > 0) {
|
||||
enqueueErrorSnackBar({
|
||||
message: t`${failedCount} file(s) failed to upload`,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return { uploadFiles };
|
||||
};
|
||||
Reference in New Issue
Block a user