@@ -1567,12 +1567,16 @@ export type File = {
|
||||
|
||||
export enum FileFolder {
|
||||
AgentChat = 'AgentChat',
|
||||
Assets = 'Assets',
|
||||
Attachment = 'Attachment',
|
||||
File = 'File',
|
||||
FrontComponents = 'FrontComponents',
|
||||
Functions = 'Functions',
|
||||
PersonPicture = 'PersonPicture',
|
||||
ProfilePicture = 'ProfilePicture',
|
||||
ServerlessFunction = 'ServerlessFunction',
|
||||
ServerlessFunctionToDelete = 'ServerlessFunctionToDelete',
|
||||
SourceCode = 'SourceCode',
|
||||
WorkspaceLogo = 'WorkspaceLogo'
|
||||
}
|
||||
|
||||
@@ -2130,6 +2134,7 @@ export type Mutation = {
|
||||
updateWorkspace: Workspace;
|
||||
updateWorkspaceFeatureFlag: Scalars['Boolean'];
|
||||
updateWorkspaceMemberRole: WorkspaceMember;
|
||||
uploadApplicationFile: File;
|
||||
uploadFile: SignedFile;
|
||||
uploadImage: SignedFile;
|
||||
uploadWorkspaceLogo: SignedFile;
|
||||
@@ -3045,6 +3050,14 @@ export type MutationUpdateWorkspaceMemberRoleArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationUploadApplicationFileArgs = {
|
||||
applicationUniversalIdentifier: Scalars['String'];
|
||||
file: Scalars['Upload'];
|
||||
fileFolder: FileFolder;
|
||||
filePath: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationUploadFileArgs = {
|
||||
file: Scalars['Upload'];
|
||||
fileFolder?: InputMaybe<FileFolder>;
|
||||
|
||||
@@ -1544,12 +1544,16 @@ export type File = {
|
||||
|
||||
export enum FileFolder {
|
||||
AgentChat = 'AgentChat',
|
||||
Assets = 'Assets',
|
||||
Attachment = 'Attachment',
|
||||
File = 'File',
|
||||
FrontComponents = 'FrontComponents',
|
||||
Functions = 'Functions',
|
||||
PersonPicture = 'PersonPicture',
|
||||
ProfilePicture = 'ProfilePicture',
|
||||
ServerlessFunction = 'ServerlessFunction',
|
||||
ServerlessFunctionToDelete = 'ServerlessFunctionToDelete',
|
||||
SourceCode = 'SourceCode',
|
||||
WorkspaceLogo = 'WorkspaceLogo'
|
||||
}
|
||||
|
||||
@@ -2096,6 +2100,7 @@ export type Mutation = {
|
||||
updateWorkspace: Workspace;
|
||||
updateWorkspaceFeatureFlag: Scalars['Boolean'];
|
||||
updateWorkspaceMemberRole: WorkspaceMember;
|
||||
uploadApplicationFile: File;
|
||||
uploadFile: SignedFile;
|
||||
uploadImage: SignedFile;
|
||||
uploadWorkspaceLogo: SignedFile;
|
||||
@@ -2955,6 +2960,14 @@ export type MutationUpdateWorkspaceMemberRoleArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationUploadApplicationFileArgs = {
|
||||
applicationUniversalIdentifier: Scalars['String'];
|
||||
file: Scalars['Upload'];
|
||||
fileFolder: FileFolder;
|
||||
filePath: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationUploadFileArgs = {
|
||||
file: Scalars['Upload'];
|
||||
fileFolder?: InputMaybe<FileFolder>;
|
||||
|
||||
@@ -6,12 +6,15 @@ import {
|
||||
printSchema,
|
||||
} from 'graphql/index';
|
||||
import { createClient } from 'graphql-sse';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { type ApiResponse } from '../types/api-response.types';
|
||||
import { ConfigService } from '@/cli/utilities/config/services/config.service';
|
||||
import {
|
||||
type PackageJson,
|
||||
type ApplicationManifest,
|
||||
} from 'twenty-shared/application';
|
||||
import { type FileFolder } from 'twenty-shared/types';
|
||||
|
||||
export class ApiService {
|
||||
private client: AxiosInstance;
|
||||
@@ -414,4 +417,133 @@ export class ApiService {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async uploadFile({
|
||||
filePath,
|
||||
fileFolder,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
filePath: string;
|
||||
fileFolder: FileFolder;
|
||||
applicationUniversalIdentifier: string;
|
||||
}): Promise<ApiResponse<boolean>> {
|
||||
try {
|
||||
const absolutePath = path.resolve(filePath);
|
||||
|
||||
if (!fs.existsSync(absolutePath)) {
|
||||
return {
|
||||
success: false,
|
||||
error: `File not found: ${absolutePath}`,
|
||||
};
|
||||
}
|
||||
|
||||
const filename = path.basename(absolutePath);
|
||||
const buffer = fs.readFileSync(absolutePath);
|
||||
const mimeType = this.getMimeType(filename);
|
||||
|
||||
const mutation = `
|
||||
mutation UploadApplicationFile($file: Upload!, $applicationUniversalIdentifier: String!, $fileFolder: FileFolder!, $filePath: String!) {
|
||||
uploadApplicationFile(file: $file, applicationUniversalIdentifier: $applicationUniversalIdentifier, fileFolder: $fileFolder, filePath: $filePath)
|
||||
{ path }
|
||||
}
|
||||
`;
|
||||
|
||||
const operations = JSON.stringify({
|
||||
query: mutation,
|
||||
variables: {
|
||||
file: null,
|
||||
applicationUniversalIdentifier,
|
||||
filePath,
|
||||
fileFolder,
|
||||
},
|
||||
});
|
||||
|
||||
const map = JSON.stringify({
|
||||
'0': ['variables.file'],
|
||||
});
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('operations', operations);
|
||||
formData.append('map', map);
|
||||
formData.append(
|
||||
'0',
|
||||
new Blob([new Uint8Array(buffer)], { type: mimeType }),
|
||||
filename,
|
||||
);
|
||||
|
||||
const response: AxiosResponse = await this.client.post(
|
||||
'/graphql',
|
||||
formData,
|
||||
);
|
||||
|
||||
if (response.data.errors) {
|
||||
return {
|
||||
success: false,
|
||||
error: response.data.errors[0]?.message || 'Failed to upload file',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data.uploadApplicationFile,
|
||||
message: `Successfully uploaded ${filename}`,
|
||||
};
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error) && error.response) {
|
||||
return {
|
||||
success: false,
|
||||
error: error.response.data?.errors?.[0]?.message || error.message,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private getMimeType(filename: string): string {
|
||||
const ext = path.extname(filename).toLowerCase();
|
||||
const mimeTypes: Record<string, string> = {
|
||||
'.jpg': 'image/jpeg',
|
||||
'.jpeg': 'image/jpeg',
|
||||
'.png': 'image/png',
|
||||
'.gif': 'image/gif',
|
||||
'.webp': 'image/webp',
|
||||
'.svg': 'image/svg+xml',
|
||||
'.bmp': 'image/bmp',
|
||||
'.ico': 'image/x-icon',
|
||||
'.pdf': 'application/pdf',
|
||||
'.doc': 'application/msword',
|
||||
'.docx':
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'.xls': 'application/vnd.ms-excel',
|
||||
'.xlsx':
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'.ppt': 'application/vnd.ms-powerpoint',
|
||||
'.pptx':
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'.txt': 'text/plain',
|
||||
'.csv': 'text/csv',
|
||||
'.json': 'application/json',
|
||||
'.xml': 'application/xml',
|
||||
'.zip': 'application/zip',
|
||||
'.tar': 'application/x-tar',
|
||||
'.gz': 'application/gzip',
|
||||
'.mp3': 'audio/mpeg',
|
||||
'.mp4': 'video/mp4',
|
||||
'.avi': 'video/x-msvideo',
|
||||
'.mov': 'video/quicktime',
|
||||
'.js': 'application/javascript',
|
||||
'.ts': 'application/typescript',
|
||||
'.jsx': 'application/javascript',
|
||||
'.tsx': 'application/typescript',
|
||||
'.html': 'text/html',
|
||||
'.css': 'text/css',
|
||||
};
|
||||
|
||||
return mimeTypes[ext] || 'application/octet-stream';
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { type FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { type ShortCropSize } from 'src/utils/image';
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { ApplicationSyncService } from 'src/engine/core-modules/application/application-sync.service';
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
@@ -20,9 +21,12 @@ import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless
|
||||
import { WorkspaceMigrationBuilderGraphqlApiExceptionInterceptor } from 'src/engine/workspace-manager/workspace-migration/interceptors/workspace-migration-builder-graphql-api-exception.interceptor';
|
||||
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
|
||||
import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
|
||||
import { FileStorageModule } from 'src/engine/core-modules/file-storage/file-storage.module';
|
||||
import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([FileEntity]),
|
||||
ApplicationModule,
|
||||
ApplicationVariableEntityModule,
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheModule,
|
||||
@@ -40,6 +44,7 @@ import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-commo
|
||||
ObjectPermissionModule,
|
||||
PermissionFlagModule,
|
||||
WorkflowCommonModule,
|
||||
FileStorageModule,
|
||||
],
|
||||
providers: [
|
||||
ApplicationResolver,
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import { UseFilters, UseGuards, UseInterceptors } from '@nestjs/common';
|
||||
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import path, { join } from 'path';
|
||||
|
||||
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
import { type Repository } from 'typeorm';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import type { FileUpload } from 'graphql-upload/processRequest.mjs';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { ApplicationExceptionFilter } from 'src/engine/core-modules/application/application-exception-filter';
|
||||
@@ -11,12 +19,21 @@ import { ApplicationDTO } from 'src/engine/core-modules/application/dtos/applica
|
||||
import { ApplicationInput } from 'src/engine/core-modules/application/dtos/application.input';
|
||||
import { UninstallApplicationInput } from 'src/engine/core-modules/application/dtos/uninstallApplicationInput';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { RequireFeatureFlag } from 'src/engine/guards/feature-flag.guard';
|
||||
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { WorkspaceMigrationBuilderGraphqlApiExceptionInterceptor } from 'src/engine/workspace-manager/workspace-migration/interceptors/workspace-migration-builder-graphql-api-exception.interceptor';
|
||||
import { streamToBuffer } from 'src/utils/stream-to-buffer';
|
||||
import { UploadApplicationFileInput } from 'src/engine/core-modules/application/dtos/uploadApplicationFileInput';
|
||||
import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity';
|
||||
import {
|
||||
ApplicationException,
|
||||
ApplicationExceptionCode,
|
||||
} from 'src/engine/core-modules/application/application.exception';
|
||||
import { FileDTO } from 'src/engine/core-modules/file/dtos/file.dto';
|
||||
|
||||
@UseGuards(
|
||||
WorkspaceAuthGuard,
|
||||
@@ -29,6 +46,9 @@ export class ApplicationResolver {
|
||||
constructor(
|
||||
private readonly applicationSyncService: ApplicationSyncService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly fileStorageService: FileStorageService,
|
||||
@InjectRepository(FileEntity)
|
||||
private readonly fileRepository: Repository<FileEntity>,
|
||||
) {}
|
||||
|
||||
@Query(() => [ApplicationDTO])
|
||||
@@ -75,4 +95,61 @@ export class ApplicationResolver {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Mutation(() => FileDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.UPLOAD_FILE))
|
||||
async uploadApplicationFile(
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
@Args({ name: 'file', type: () => GraphQLUpload })
|
||||
{ createReadStream, mimetype }: FileUpload,
|
||||
@Args()
|
||||
{
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder,
|
||||
filePath,
|
||||
}: UploadApplicationFileInput,
|
||||
): Promise<FileDTO> {
|
||||
const allowedApplicationFileFolders: FileFolder[] = [
|
||||
FileFolder.Functions,
|
||||
FileFolder.FrontComponents,
|
||||
FileFolder.Assets,
|
||||
FileFolder.SourceCode,
|
||||
];
|
||||
|
||||
if (!allowedApplicationFileFolders.includes(fileFolder)) {
|
||||
throw new ApplicationException(
|
||||
`Invalid fileFolder for application file upload. Allowed values: ${allowedApplicationFileFolders.join(', ')}`,
|
||||
ApplicationExceptionCode.INVALID_INPUT,
|
||||
);
|
||||
}
|
||||
|
||||
const stream = createReadStream();
|
||||
const buffer = await streamToBuffer(stream);
|
||||
|
||||
const dirname = path.dirname(filePath);
|
||||
|
||||
const filename = path.basename(filePath);
|
||||
|
||||
const folderPath = join(
|
||||
`workspace-${workspaceId}`,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder,
|
||||
dirname,
|
||||
);
|
||||
|
||||
await this.fileStorageService.write({
|
||||
file: buffer,
|
||||
name: filename,
|
||||
folder: folderPath,
|
||||
mimeType: mimetype,
|
||||
});
|
||||
|
||||
const createdFile = this.fileRepository.create({
|
||||
path: join(folderPath, filename),
|
||||
size: buffer.length,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
return await this.fileRepository.save(createdFile);
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { ArgsType, Field } from '@nestjs/graphql';
|
||||
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
@ArgsType()
|
||||
export class UploadApplicationFileInput {
|
||||
@Field(() => String)
|
||||
applicationUniversalIdentifier: string;
|
||||
|
||||
@Field(() => FileFolder)
|
||||
fileFolder: FileFolder;
|
||||
|
||||
@Field(() => String)
|
||||
filePath: string;
|
||||
}
|
||||
+1
-2
@@ -3,8 +3,7 @@ import { Args, Mutation, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import type { FileUpload } from 'graphql-upload/processRequest.mjs';
|
||||
|
||||
|
||||
+1
-2
@@ -5,8 +5,7 @@ import DOMPurify from 'dompurify';
|
||||
import FileType from 'file-type';
|
||||
import sharp from 'sharp';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { type FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { settings } from 'src/engine/constants/settings';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
|
||||
+13
-11
@@ -1,17 +1,7 @@
|
||||
import { registerEnumType } from '@nestjs/graphql';
|
||||
|
||||
import { type KebabCase } from 'type-fest';
|
||||
|
||||
export enum FileFolder {
|
||||
ProfilePicture = 'profile-picture',
|
||||
WorkspaceLogo = 'workspace-logo',
|
||||
Attachment = 'attachment',
|
||||
PersonPicture = 'person-picture',
|
||||
ServerlessFunction = 'serverless-function',
|
||||
ServerlessFunctionToDelete = 'serverless-function-to-delete',
|
||||
File = 'file',
|
||||
AgentChat = 'agent-chat',
|
||||
}
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
registerEnumType(FileFolder, {
|
||||
name: 'FileFolder',
|
||||
@@ -46,6 +36,18 @@ export const fileFolderConfigs: Record<FileFolder, FileFolderConfig> = {
|
||||
[FileFolder.AgentChat]: {
|
||||
ignoreExpirationToken: false,
|
||||
},
|
||||
[FileFolder.Functions]: {
|
||||
ignoreExpirationToken: false,
|
||||
},
|
||||
[FileFolder.FrontComponents]: {
|
||||
ignoreExpirationToken: false,
|
||||
},
|
||||
[FileFolder.Assets]: {
|
||||
ignoreExpirationToken: true,
|
||||
},
|
||||
[FileFolder.SourceCode]: {
|
||||
ignoreExpirationToken: false,
|
||||
},
|
||||
};
|
||||
|
||||
export type AllowedFolders = KebabCase<keyof typeof FileFolder>;
|
||||
|
||||
+1
-2
@@ -3,8 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { extractFolderPathFilenameAndTypeOrThrow } from 'twenty-shared/utils';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { type FileDTO } from 'src/engine/core-modules/file/dtos/file.dto';
|
||||
import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity';
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { checkFileFolder } from 'src/engine/core-modules/file/utils/check-file-folder.utils';
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { checkFilename } from 'src/engine/core-modules/file/utils/check-file-name.utils';
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { checkFilePath } from 'src/engine/core-modules/file/utils/check-file-path.utils';
|
||||
|
||||
|
||||
+3
-4
@@ -1,9 +1,8 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
type AllowedFolders,
|
||||
FileFolder,
|
||||
} from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { type AllowedFolders } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
|
||||
import { kebabCase } from 'src/utils/kebab-case';
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
type AllowedFolders,
|
||||
FileFolder,
|
||||
} from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { type AllowedFolders } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
|
||||
import { kebabCase } from 'src/utils/kebab-case';
|
||||
import { settings } from 'src/engine/constants/settings';
|
||||
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
import { join } from 'path';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { type ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
import {
|
||||
|
||||
+1
-1
@@ -9,12 +9,12 @@ import {
|
||||
type CodeExecutionState,
|
||||
} from 'twenty-shared/ai';
|
||||
import { v4 } from 'uuid';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import {
|
||||
type InputFile,
|
||||
type OutputFile,
|
||||
} from 'src/engine/core-modules/code-interpreter/drivers/interfaces/code-interpreter-driver.interface';
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
|
||||
import {
|
||||
type AccessTokenJwtPayload,
|
||||
|
||||
+1
-2
@@ -2,8 +2,7 @@ import { UseGuards } from '@nestjs/common';
|
||||
import { Args, Mutation, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import type { FileUpload } from 'graphql-upload/processRequest.mjs';
|
||||
|
||||
|
||||
+1
-2
@@ -2,8 +2,7 @@ import { Test, type TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { type DataSource, type Repository } from 'typeorm';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { type ApprovedAccessDomainEntity } from 'src/engine/core-modules/approved-access-domain/approved-access-domain.entity';
|
||||
import { ApprovedAccessDomainService } from 'src/engine/core-modules/approved-access-domain/services/approved-access-domain.service';
|
||||
|
||||
+1
-1
@@ -4,9 +4,9 @@ import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { type APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
|
||||
import { type QueryRunner, IsNull, Not, type Repository } from 'typeorm';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { FileStorageExceptionCode } from 'src/engine/core-modules/file-storage/interfaces/file-storage-exception';
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
|
||||
import { type AppTokenEntity } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||
import { ApprovedAccessDomainService } from 'src/engine/core-modules/approved-access-domain/services/approved-access-domain.service';
|
||||
|
||||
@@ -19,8 +19,7 @@ import assert from 'assert';
|
||||
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import type { FileUpload } from 'graphql-upload/processRequest.mjs';
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
export enum FileFolder {
|
||||
ProfilePicture = 'profile-picture',
|
||||
WorkspaceLogo = 'workspace-logo',
|
||||
Attachment = 'attachment',
|
||||
PersonPicture = 'person-picture',
|
||||
ServerlessFunction = 'serverless-function',
|
||||
ServerlessFunctionToDelete = 'serverless-function-to-delete',
|
||||
File = 'file',
|
||||
AgentChat = 'agent-chat',
|
||||
Functions = 'functions',
|
||||
FrontComponents = 'front-components',
|
||||
Assets = 'assets',
|
||||
SourceCode = 'source-code',
|
||||
}
|
||||
@@ -108,6 +108,7 @@ export type {
|
||||
export { NumberDataType, DateDisplayFormat } from './FieldMetadataSettings';
|
||||
export { FieldMetadataType } from './FieldMetadataType';
|
||||
export type { FieldRatingValue } from './FieldRatingValue';
|
||||
export { FileFolder } from './FileFolder';
|
||||
export type {
|
||||
FilterableFieldType,
|
||||
FilterableAndTSVectorFieldType,
|
||||
|
||||
Reference in New Issue
Block a user