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;
}