= ({ element }) => {
className="h-[28px] w-[28px] rounded-full"
onClick={e => {
e.stopPropagation();
- clearFileAndInput();
+ void clearFileAndInput();
}}
>
diff --git a/packages/ui/src/components/organisms/Form/DynamicForm/fields/FileField/hooks/useFileUpload/useFileUpload.ts b/packages/ui/src/components/organisms/Form/DynamicForm/fields/FileField/hooks/useFileUpload/useFileUpload.ts
index 6523d8eb2f..99046fc8b9 100644
--- a/packages/ui/src/components/organisms/Form/DynamicForm/fields/FileField/hooks/useFileUpload/useFileUpload.ts
+++ b/packages/ui/src/components/organisms/Form/DynamicForm/fields/FileField/hooks/useFileUpload/useFileUpload.ts
@@ -20,7 +20,7 @@ export const useFileUpload = (
const { addTask, removeTask } = useTaskRunner();
const { metadata } = useDynamicForm();
- const { run, isLoading } = useHttp(element.params!.uploadSettings, metadata);
+ const { run, isLoading } = useHttp(element.params!.httpParams!.createDocument || {}, metadata);
const { onChange } = useField(element);
@@ -28,9 +28,9 @@ export const useFileUpload = (
async (e: React.ChangeEvent) => {
removeTask(id);
- const { uploadSettings } = params;
+ const { createDocument } = params?.httpParams || {};
- if (!uploadSettings) {
+ if (!createDocument) {
onChange(e.target?.files?.[0] as File);
console.log('Failed to upload, no upload settings provided');
diff --git a/packages/ui/src/components/organisms/Form/DynamicForm/fields/FileField/hooks/useFileUpload/useFileUpload.unit.test.ts b/packages/ui/src/components/organisms/Form/DynamicForm/fields/FileField/hooks/useFileUpload/useFileUpload.unit.test.ts
deleted file mode 100644
index 64671e7cc1..0000000000
--- a/packages/ui/src/components/organisms/Form/DynamicForm/fields/FileField/hooks/useFileUpload/useFileUpload.unit.test.ts
+++ /dev/null
@@ -1,203 +0,0 @@
-import { useHttp } from '@/common/hooks/useHttp';
-import { renderHook } from '@testing-library/react';
-import { beforeEach, describe, expect, it, vi } from 'vitest';
-import { useDynamicForm } from '../../../../context';
-import { useElement, useField } from '../../../../hooks/external';
-import { useTaskRunner } from '../../../../providers/TaskRunner/hooks/useTaskRunner';
-import { useStack } from '../../../FieldList/providers/StackProvider';
-import { useFileUpload } from './useFileUpload';
-
-vi.mock('@/common/hooks/useHttp');
-vi.mock('../../../../hooks/external');
-vi.mock('../../../../providers/TaskRunner/hooks/useTaskRunner');
-vi.mock('../../../../context');
-vi.mock('../../../FieldList/providers/StackProvider');
-
-describe('useFileUpload', () => {
- const mockElement = {
- id: 'test-id',
- element: 'filefield',
- params: {
- uploadSettings: {
- url: 'test-url',
- resultPath: 'test.path',
- },
- },
- valueDestination: 'test.destination',
- };
-
- const mockParams = {
- uploadSettings: {
- url: 'test-url',
- resultPath: 'test.path',
- },
- };
-
- const mockFile = new File(['test'], 'test.txt');
- const mockEvent = {
- target: {
- files: [mockFile],
- },
- } as unknown as React.ChangeEvent;
-
- const mockOnChange = vi.fn();
- const mockAddTask = vi.fn();
- const mockRemoveTask = vi.fn();
-
- beforeEach(() => {
- vi.clearAllMocks();
-
- vi.mocked(useStack).mockReturnValue({ stack: [] });
- vi.mocked(useElement).mockReturnValue({
- id: 'test-id',
- originId: 'test-origin-id',
- hidden: false,
- });
- vi.mocked(useTaskRunner).mockReturnValue({
- addTask: mockAddTask,
- removeTask: mockRemoveTask,
- tasks: [],
- isRunning: false,
- runTasks: vi.fn(),
- });
- vi.mocked(useDynamicForm).mockReturnValue({
- metadata: {},
- values: {},
- touched: {},
- elementsMap: {},
- fieldHelpers: {},
- } as ReturnType);
- vi.mocked(useHttp).mockReturnValue({
- run: vi.fn().mockResolvedValue('uploaded-file-url'),
- isLoading: false,
- error: null,
- });
- vi.mocked(useField).mockReturnValue({
- value: undefined,
- touched: false,
- disabled: false,
- onChange: mockOnChange,
- onBlur: vi.fn(),
- onFocus: vi.fn(),
- });
- });
-
- it('should handle file upload on change', async () => {
- vi.mocked(useHttp).mockReturnValue({
- run: vi.fn().mockResolvedValue('uploaded-file-url'),
- isLoading: false,
- error: null,
- });
-
- const { result } = renderHook(() => useFileUpload(mockElement, mockParams));
-
- await result.current.handleChange(mockEvent);
-
- expect(useHttp).toHaveBeenCalledWith(mockElement.params.uploadSettings, {});
- expect(mockOnChange).toHaveBeenCalledWith('uploaded-file-url');
- });
-
- it('should handle file upload on submit', async () => {
- const mockParamsWithSubmit = {
- uploadSettings: {
- url: 'test-url',
- resultPath: 'test.path',
- },
- uploadOn: 'submit' as const,
- };
-
- const { result } = renderHook(() => useFileUpload(mockElement, mockParamsWithSubmit));
-
- await result.current.handleChange(mockEvent);
-
- expect(mockOnChange).toHaveBeenCalledWith(mockFile);
- expect(mockAddTask).toHaveBeenCalled();
- });
-
- it('should handle missing upload settings', async () => {
- const mockElementWithoutSettings = {
- ...mockElement,
- params: {
- uploadSettings: undefined as any,
- },
- };
- const mockParamsWithoutSettings = {
- uploadSettings: undefined,
- } as any;
-
- const consoleSpy = vi.spyOn(console, 'log');
-
- const { result } = renderHook(() =>
- useFileUpload(mockElementWithoutSettings, mockParamsWithoutSettings),
- );
-
- await result.current.handleChange(mockEvent);
-
- expect(mockOnChange).toHaveBeenCalledWith(mockFile);
- expect(consoleSpy).toHaveBeenCalledWith('Failed to upload, no upload settings provided');
- });
-
- it('should handle upload error on change', async () => {
- vi.mocked(useHttp).mockReturnValue({
- run: vi.fn().mockRejectedValue(new Error('Upload failed')),
- isLoading: false,
- error: null,
- });
-
- const consoleSpy = vi.spyOn(console, 'error');
-
- const { result } = renderHook(() => useFileUpload(mockElement, mockParams));
-
- await result.current.handleChange(mockEvent);
-
- expect(consoleSpy).toHaveBeenCalledWith('Failed to upload file.', expect.any(Error));
- });
-
- it('should handle upload error on submit', async () => {
- const mockParamsWithSubmit = {
- uploadSettings: {
- url: 'test-url',
- resultPath: 'test.path',
- },
- uploadOn: 'submit' as const,
- };
-
- vi.mocked(useHttp).mockReturnValue({
- run: vi.fn().mockRejectedValue(new Error('Upload failed')),
- isLoading: false,
- error: null,
- });
-
- const consoleSpy = vi.spyOn(console, 'error');
-
- const { result } = renderHook(() => useFileUpload(mockElement, mockParamsWithSubmit));
-
- await result.current.handleChange(mockEvent);
-
- const addedTask = mockAddTask.mock.calls[0][0];
- const context = {};
- await addedTask.run(context);
-
- expect(consoleSpy).toHaveBeenCalledWith('Failed to upload file.', expect.any(Error));
- });
-
- it('should remove existing task before handling change', async () => {
- const { result } = renderHook(() => useFileUpload(mockElement, mockParams));
-
- await result.current.handleChange(mockEvent);
-
- expect(mockRemoveTask).toHaveBeenCalledWith('test-id');
- });
-
- it('should return correct loading state', () => {
- vi.mocked(useHttp).mockReturnValue({
- run: vi.fn(),
- isLoading: true,
- error: null,
- });
-
- const { result } = renderHook(() => useFileUpload(mockElement, mockParams));
-
- expect(result.current.isUploading).toBe(true);
- });
-});
diff --git a/packages/ui/src/components/organisms/Form/DynamicForm/helpers/upload-file/index.ts b/packages/ui/src/components/organisms/Form/DynamicForm/helpers/upload-file/index.ts
deleted file mode 100644
index c3aceca325..0000000000
--- a/packages/ui/src/components/organisms/Form/DynamicForm/helpers/upload-file/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './upload-file';
diff --git a/packages/ui/src/components/organisms/Form/DynamicForm/helpers/upload-file/upload-file.ts b/packages/ui/src/components/organisms/Form/DynamicForm/helpers/upload-file/upload-file.ts
deleted file mode 100644
index c03fd12e53..0000000000
--- a/packages/ui/src/components/organisms/Form/DynamicForm/helpers/upload-file/upload-file.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import axios from 'axios';
-import get from 'lodash/get';
-import { IFileFieldParams } from '../../fields';
-import { IDocumentFieldParams } from '../../fields/DocumentField';
-
-export const uploadFile = async (
- file: File,
- params: IDocumentFieldParams['uploadSettings'] | IFileFieldParams['uploadSettings'],
-) => {
- if (!params) {
- throw new Error('Upload settings are required to upload a file');
- }
-
- const { url, method = 'POST', headers = {} } = params;
-
- const formData = new FormData();
- formData.append('file', file);
-
- const response = await axios({
- method,
- url,
- headers,
- data: formData,
- });
-
- return get(response.data, params.resultPath);
-};
diff --git a/packages/ui/src/components/organisms/Form/DynamicForm/helpers/upload-file/upload-file.unit.test.ts b/packages/ui/src/components/organisms/Form/DynamicForm/helpers/upload-file/upload-file.unit.test.ts
deleted file mode 100644
index 30a4260822..0000000000
--- a/packages/ui/src/components/organisms/Form/DynamicForm/helpers/upload-file/upload-file.unit.test.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import { describe, expect, it, vi } from 'vitest';
-
-import axios from 'axios';
-import { IDocumentFieldParams } from '../../fields';
-import { uploadFile } from './upload-file';
-
-vi.mock('axios');
-const mockedAxios = vi.mocked(axios);
-
-describe('uploadFile', () => {
- const mockFile = new File(['test'], 'test.txt', { type: 'text/plain' });
- const mockParams = {
- url: 'http://test.com/upload',
- method: 'POST' as const,
- headers: { 'Content-Type': 'multipart/form-data' },
- resultPath: 'fileUrl',
- };
-
- it('should throw error if no params provided', async () => {
- mockedAxios.mockRejectedValueOnce(new Error('Upload settings are required to upload a file'));
-
- await expect(
- uploadFile(mockFile, {} as IDocumentFieldParams['uploadSettings']),
- ).rejects.toThrow('Upload settings are required to upload a file');
- });
-
- it('should upload file successfully and return result from specified path', async () => {
- const mockResponse = {
- data: {
- fileUrl: 'http://test.com/files/test.txt',
- },
- };
-
- mockedAxios.mockResolvedValueOnce(mockResponse);
-
- const result = await uploadFile(mockFile, mockParams);
-
- expect(mockedAxios).toHaveBeenCalledWith({
- method: 'POST',
- url: mockParams.url,
- headers: mockParams.headers,
- data: expect.any(FormData),
- });
- expect(result).toBe(mockResponse.data.fileUrl);
- });
-
- it('should use POST as default method if not specified', async () => {
- const paramsWithoutMethod = {
- url: 'http://test.com/upload',
- headers: {},
- resultPath: 'data.fileUrl',
- };
-
- mockedAxios.mockResolvedValueOnce({ data: { fileUrl: 'test' } });
-
- await uploadFile(mockFile, paramsWithoutMethod);
-
- expect(mockedAxios).toHaveBeenCalledWith(
- expect.objectContaining({
- method: 'POST',
- }),
- );
- });
-
- it('should use empty object as default headers if not specified', async () => {
- const paramsWithoutHeaders = {
- url: 'http://test.com/upload',
- method: 'POST' as const,
- resultPath: 'data.fileUrl',
- };
-
- mockedAxios.mockResolvedValueOnce({ data: { fileUrl: 'test' } });
-
- await uploadFile(mockFile, paramsWithoutHeaders);
-
- expect(mockedAxios).toHaveBeenCalledWith(
- expect.objectContaining({
- headers: {},
- }),
- );
- });
-});
diff --git a/services/workflows-service/prisma/data-migrations b/services/workflows-service/prisma/data-migrations
index cd3b6508d5..53c44c78db 160000
--- a/services/workflows-service/prisma/data-migrations
+++ b/services/workflows-service/prisma/data-migrations
@@ -1 +1 @@
-Subproject commit cd3b6508d535d90fdc94000b3d805279bdbd114d
+Subproject commit 53c44c78db829372607349502276233db4836dd8
diff --git a/services/workflows-service/src/collection-flow/collection-flow.service.ts b/services/workflows-service/src/collection-flow/collection-flow.service.ts
index f3a1131593..74847b22fc 100644
--- a/services/workflows-service/src/collection-flow/collection-flow.service.ts
+++ b/services/workflows-service/src/collection-flow/collection-flow.service.ts
@@ -44,6 +44,7 @@ export class CollectionFlowService {
context: WorkflowRuntimeData['context'],
language: string,
projectIds: TProjectIds,
+ tokenScope: ITokenScope,
args?: Prisma.UiDefinitionFindFirstOrThrowArgs,
): Promise {
const workflowDefinition = await this.workflowService.getWorkflowDefinitionById(
@@ -59,6 +60,12 @@ export class CollectionFlowService {
args,
);
+ const workflowRuntimeData = await this.workflowRuntimeDataRepository.findById(
+ tokenScope.workflowRuntimeDataId,
+ {},
+ projectIds,
+ );
+
const translationService = new TranslationService(
this.uiDefinitionService.getTranslationServiceResources(uiDefinition),
);
@@ -84,6 +91,10 @@ export class CollectionFlowService {
? (uiDefinition.definition as unknown as UiDefDefinition)
: undefined,
version: uiDefinition.version,
+ metadata: {
+ businessId: workflowRuntimeData.businessId,
+ entityId: tokenScope.endUserId,
+ },
};
}
diff --git a/services/workflows-service/src/collection-flow/controllers/collection-flow.controller.ts b/services/workflows-service/src/collection-flow/controllers/collection-flow.controller.ts
index f85d7299e6..63c453b0da 100644
--- a/services/workflows-service/src/collection-flow/controllers/collection-flow.controller.ts
+++ b/services/workflows-service/src/collection-flow/controllers/collection-flow.controller.ts
@@ -95,6 +95,7 @@ export class CollectionFlowController {
workflow.context,
params.language,
[tokenScope.projectId],
+ tokenScope,
workflow.uiDefinitionId ? { where: { id: workflow.uiDefinitionId } } : {},
);
}
diff --git a/services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.ts b/services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.ts
index 6a6b8770f0..84218c2b25 100644
--- a/services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.ts
+++ b/services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.ts
@@ -45,6 +45,7 @@ export class CollectionFlowNoUserController {
workflow.context,
params.language,
[tokenScope.projectId],
+ tokenScope,
workflow.uiDefinitionId ? { where: { id: workflow.uiDefinitionId } } : {},
);
}