diff --git a/client/src/pages/automation/knowledge-bases/components/hooks/useCreateKnowledgeBaseDialog.ts b/client/src/pages/automation/knowledge-bases/components/hooks/useCreateKnowledgeBaseDialog.ts index 77986c1d4d8..678d952ef0c 100644 --- a/client/src/pages/automation/knowledge-bases/components/hooks/useCreateKnowledgeBaseDialog.ts +++ b/client/src/pages/automation/knowledge-bases/components/hooks/useCreateKnowledgeBaseDialog.ts @@ -1,5 +1,6 @@ import {useCreateKnowledgeBaseMutation} from '@/shared/middleware/graphql'; import {useEnvironmentStore} from '@/shared/stores/useEnvironmentStore'; +import {getCookie} from '@/shared/util/cookie-utils'; import {useQueryClient} from '@tanstack/react-query'; import {ChangeEvent, useState} from 'react'; @@ -38,53 +39,74 @@ export default function useCreateKnowledgeBaseDialog({workspaceId}: UseCreateKno setUploading(false); }; - const startSimulatedUpload = () => { - setUploading(true); + const uploadFile = async (knowledgeBaseId: string, file: File, index: number) => { + setSelectedFiles((prev) => { + const copy = [...prev]; + copy[index] = {...copy[index], status: 'uploading'}; + + return copy; + }); + + try { + const formData = new FormData(); + + formData.append('file', file); + + const response = await fetch(`/api/automation/internal/knowledge-bases/${knowledgeBaseId}/documents`, { + body: formData, + headers: { + 'X-XSRF-TOKEN': getCookie('XSRF-TOKEN') || '', + }, + method: 'POST', + }); + + if (!response.ok) { + throw new Error(`Upload failed: ${response.statusText}`); + } - selectedFiles.forEach((_, index) => { setSelectedFiles((prev) => { const copy = [...prev]; - copy[index] = {...copy[index], status: 'uploading'}; + copy[index] = { + ...copy[index], + status: 'completed', + statusMessage: 'Uploaded successfully', + }; return copy; }); + } catch (error) { + setSelectedFiles((prev) => { + const copy = [...prev]; + copy[index] = { + ...copy[index], + status: 'error', + statusMessage: error instanceof Error ? error.message : 'Upload failed', + }; - setTimeout(() => { - setSelectedFiles((prev) => { - const copy = [...prev]; - copy[index] = {...copy[index], status: 'processing', statusMessage: 'Processing document...'}; - - return copy; - }); - }, 1000); - - setTimeout(() => { - setSelectedFiles((prev) => { - const copy = [...prev]; - copy[index] = { - ...copy[index], - status: 'completed', - statusMessage: 'Document processed successfully', - }; - - return copy; - }); - - if (index === selectedFiles.length - 1) { - setTimeout(() => { - queryClient.invalidateQueries({queryKey: ['knowledgeBases']}); - setOpen(false); - resetForm(); - }, 500); - } - }, 3000); - }); + return copy; + }); + } + }; + + const uploadFiles = async (knowledgeBaseId: string, files: SelectedFileI[]) => { + setUploading(true); + + await Promise.all(files.map((selectedFile, index) => uploadFile(knowledgeBaseId, selectedFile.file, index))); + + queryClient.invalidateQueries({queryKey: ['knowledgeBases']}); + + setTimeout(() => { + setOpen(false); + resetForm(); + }, 500); }; const createMutation = useCreateKnowledgeBaseMutation({ - onSuccess: () => { - if (selectedFiles.length > 0) { - startSimulatedUpload(); + onSuccess: (data) => { + const knowledgeBaseId = data.createKnowledgeBase?.id; + + if (selectedFiles.length > 0 && knowledgeBaseId) { + uploadFiles(knowledgeBaseId, selectedFiles); } else { queryClient.invalidateQueries({queryKey: ['knowledgeBases']}); setOpen(false); diff --git a/client/src/pages/platform/workflow-editor/components/properties/components/property-input/PropertyInput.test.tsx b/client/src/pages/platform/workflow-editor/components/properties/components/property-input/PropertyInput.test.tsx index 29986a16b85..c4bf3f0c2fd 100644 --- a/client/src/pages/platform/workflow-editor/components/properties/components/property-input/PropertyInput.test.tsx +++ b/client/src/pages/platform/workflow-editor/components/properties/components/property-input/PropertyInput.test.tsx @@ -133,17 +133,17 @@ describe('PropertyInput', async () => { }); it('uses minute precision (step=60) for time inputs so the field is easily clearable', () => { - const {container} = render(); + render(); - const input = container.querySelector('input[type="time"]'); + const input = screen.getByLabelText(/time/i); expect(input).toHaveAttribute('step', '60'); }); it('keeps step=1 for non-time inputs', () => { - const {container} = render(); + render(); - const input = container.querySelector('input[type="date"]'); + const input = screen.getByLabelText(/date/i); expect(input).toHaveAttribute('step', '1'); }); diff --git a/client/src/pages/platform/workflow-editor/components/properties/hooks/useProperty.ts b/client/src/pages/platform/workflow-editor/components/properties/hooks/useProperty.ts index d2ff78dbc27..8190644ce99 100644 --- a/client/src/pages/platform/workflow-editor/components/properties/hooks/useProperty.ts +++ b/client/src/pages/platform/workflow-editor/components/properties/hooks/useProperty.ts @@ -569,10 +569,10 @@ export const useProperty = ({ let resolvedValue: unknown; - if (isNumericalInput) { - resolvedValue = parseFloat(valueToSave as string); - } else if (valueToSave === '' && isDateOrTimeControlType) { + if (valueToSave === '' && (isNumericalInput || isDateOrTimeControlType)) { resolvedValue = null; + } else if (isNumericalInput) { + resolvedValue = parseFloat(valueToSave as string); } else { resolvedValue = valueToSave; }