From 77d15356e1350a667911262169aa45ff0ddaaada Mon Sep 17 00:00:00 2001 From: Etienne <45695613+etiennejouan@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:42:19 +0100 Subject: [PATCH] Files v2 - Use Files field in attachment (#17707) - Add FILES field on attachment - Adapt Attachment logic in front to use new resolver/controller - Update files-field logic to infer applicationId from fieldMetadataId + ask for fieldMetadataId in upload resolver - Design update To do in next PR : - Adapt activity files logic --- .../src/generated-metadata/graphql.ts | 8 +- .../twenty-front/src/generated/graphql.ts | 2 + .../files/components/AttachmentList.tsx | 24 +- .../files/components/AttachmentRow.tsx | 43 +- .../files/hooks/useUploadAttachmentFile.tsx | 76 +- .../activities/files/types/Attachment.ts | 3 + .../graphql/mutations/uploadFilesFieldFile.ts | 4 +- .../ui/hooks/useOpenFieldInputEditMode.ts | 1 + .../display/components/FilesFieldDisplay.tsx | 24 +- .../hooks/useUploadFilesFieldFile.ts | 4 +- .../input/components/FilesFieldInput.tsx | 8 +- .../input/hooks/useOpenFilesFieldInput.tsx | 20 + .../meta-types/utils/uploadMultipleFiles.ts | 8 +- .../ui/states/filesFieldUploadState.ts | 16 + .../SettingsNonCompositeFieldTypeConfigs.ts | 2 +- .../ui/field/display/components/FileChip.tsx | 38 +- .../field/display/components/FilesDisplay.tsx | 11 + .../display/components/UploadFileChip.tsx | 54 + .../enums/feature-flag-key.enum.ts | 1 + .../file/files-field/files-field.module.ts | 8 +- .../file/files-field/files-field.service.ts | 19 +- .../resolvers/files-field.resolver.ts | 10 +- .../workspace-entity-manager.spec.ts | 1 + .../workspace-entity-manager.ts | 7 +- .../files-field-sync/files-field-sync.ts | 128 +- .../workspace-insert-query-builder.ts | 7 +- .../workspace-update-query-builder.ts | 16 +- ...adata-related-entity-ids.util.spec.ts.snap | 2571 +++++++++-------- ...hment-standard-flat-field-metadata.util.ts | 24 +- .../constant/standard-field-ids.ts | 1 + .../attachment.workspace-entity.ts | 5 + .../files-field-download.integration-spec.ts | 73 +- .../files-field-sync.integration-spec.ts | 73 +- ...pload-files-field-file.integration-spec.ts | 96 +- ...-test-objects-with-all-field-types.util.ts | 30 +- .../upload-files-field-file-mutation.util.ts | 12 + .../src/metadata/standard-object.constant.ts | 3 + .../src/assets/icons/illustration-file.svg | 7 +- 38 files changed, 1905 insertions(+), 1533 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-field/ui/states/filesFieldUploadState.ts create mode 100644 packages/twenty-front/src/modules/ui/field/display/components/UploadFileChip.tsx create mode 100644 packages/twenty-server/test/integration/graphql/utils/upload-files-field-file-mutation.util.ts diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 89c5ecacda..3ce19c4ade 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1477,6 +1477,7 @@ export enum FeatureFlagKey { IS_COMMAND_MENU_ITEM_ENABLED = 'IS_COMMAND_MENU_ITEM_ENABLED', IS_DASHBOARD_V2_ENABLED = 'IS_DASHBOARD_V2_ENABLED', IS_EMAILING_DOMAIN_ENABLED = 'IS_EMAILING_DOMAIN_ENABLED', + IS_FILES_FIELD_MIGRATED = 'IS_FILES_FIELD_MIGRATED', IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_MARKETPLACE_ENABLED = 'IS_MARKETPLACE_ENABLED', @@ -3114,6 +3115,7 @@ export type MutationUploadFileArgs = { export type MutationUploadFilesFieldFileArgs = { + fieldMetadataId: Scalars['String']; file: Scalars['Upload']; }; @@ -5979,6 +5981,7 @@ export type DeleteFileMutation = { __typename?: 'Mutation', deleteFile: { __type export type UploadFilesFieldFileMutationVariables = Exact<{ file: Scalars['Upload']; + fieldMetadataId: Scalars['String']; }>; @@ -10326,8 +10329,8 @@ export type DeleteFileMutationHookResult = ReturnType; export type DeleteFileMutationOptions = Apollo.BaseMutationOptions; export const UploadFilesFieldFileDocument = gql` - mutation UploadFilesFieldFile($file: Upload!) { - uploadFilesFieldFile(file: $file) { + mutation UploadFilesFieldFile($file: Upload!, $fieldMetadataId: String!) { + uploadFilesFieldFile(file: $file, fieldMetadataId: $fieldMetadataId) { id path size @@ -10351,6 +10354,7 @@ export type UploadFilesFieldFileMutationFn = Apollo.MutationFunction @@ -134,6 +137,10 @@ export const AttachmentList = ({ isAttachmentPreviewEnabledState, ); + const isFilesFieldMigrated = useIsFeatureEnabled( + FeatureFlagKey.IS_FILES_FIELD_MIGRATED, + ); + const hasDownloadPermission = useHasPermissionFlag( PermissionFlagType.DOWNLOAD_FILE, ); @@ -144,6 +151,16 @@ export const AttachmentList = ({ const { openModal, closeModal } = useModal(); + const getAttachmentUrl = (attachment: Attachment) => { + const fileUrl = isFilesFieldMigrated + ? attachment.file?.[0]?.url || attachment.fullPath + : attachment.fullPath; + + assertIsDefinedOrThrow(fileUrl, new Error(t`File URL is not defined`)); + + return fileUrl; + }; + const onUploadFile = async (file: File) => { await uploadAttachmentFile(file, targetableObject); }; @@ -167,7 +184,10 @@ export const AttachmentList = ({ const handleDownload = () => { if (!previewedAttachment) return; - downloadFile(previewedAttachment.fullPath, previewedAttachment.name); + downloadFile( + getAttachmentUrl(previewedAttachment), + previewedAttachment.name, + ); }; return ( @@ -248,7 +268,7 @@ export const AttachmentList = ({ > diff --git a/packages/twenty-front/src/modules/activities/files/components/AttachmentRow.tsx b/packages/twenty-front/src/modules/activities/files/components/AttachmentRow.tsx index 5fdcc9785f..aa9ae7b7c8 100644 --- a/packages/twenty-front/src/modules/activities/files/components/AttachmentRow.tsx +++ b/packages/twenty-front/src/modules/activities/files/components/AttachmentRow.tsx @@ -9,17 +9,21 @@ import { FieldContext, type GenericFieldContextType, } from '@/object-record/record-field/ui/contexts/FieldContext'; +import { getFileCategoryFromExtension } from '@/object-record/record-field/ui/utils/getFileCategoryFromExtension'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; +import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useState } from 'react'; -import { isDefined } from 'twenty-shared/utils'; +import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils'; import { FileIcon } from '@/file/components/FileIcon'; import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag'; +import { t } from '@lingui/core/macro'; import { IconCalendar, OverflowingTextWithTooltip } from 'twenty-ui/display'; import { isNavigationModifierPressed } from 'twenty-ui/utilities'; import { PermissionFlagType } from '~/generated-metadata/graphql'; +import { FeatureFlagKey } from '~/generated/graphql'; import { formatToHumanReadableDate } from '~/utils/date-utils'; import { getFileNameAndExtension } from '~/utils/file/getFileNameAndExtension'; @@ -82,6 +86,10 @@ export const AttachmentRow = ({ const theme = useTheme(); const [isEditing, setIsEditing] = useState(false); + const isFilesFieldMigrated = useIsFeatureEnabled( + FeatureFlagKey.IS_FILES_FIELD_MIGRATED, + ); + const hasDownloadPermission = useHasPermissionFlag( PermissionFlagType.DOWNLOAD_FILE, ); @@ -92,6 +100,16 @@ export const AttachmentRow = ({ const [attachmentFileName, setAttachmentFileName] = useState(originalFileName); + const fileCategory = isFilesFieldMigrated + ? getFileCategoryFromExtension(attachment.file?.[0]?.extension) + : attachment.fileCategory; + + const fileUrl = isFilesFieldMigrated + ? attachment.file?.[0]?.url + : attachment.fullPath; + + assertIsDefinedOrThrow(fileUrl, new Error(t`File URL is not defined`)); + const { destroyOneRecord: destroyOneAttachment } = useDestroyOneRecord({ objectNameSingular: CoreObjectNameSingular.Attachment, }); @@ -114,7 +132,19 @@ export const AttachmentRow = ({ updateOneRecord({ objectNameSingular: CoreObjectNameSingular.Attachment, idToUpdate: attachment.id, - updateOneRecordInput: { name: newFileName }, + updateOneRecordInput: { + name: newFileName, + ...(isFilesFieldMigrated && isDefined(attachment.file?.[0]?.fileId) + ? { + file: [ + { + fileId: attachment.file?.[0]?.fileId, + label: newFileName, + }, + ], + } + : {}), + }, }); }; @@ -133,10 +163,7 @@ export const AttachmentRow = ({ }; const handleDownload = () => { - downloadFile( - attachment.fullPath, - `${attachmentFileName}${attachmentFileExtension}`, - ); + downloadFile(fileUrl, `${attachmentFileName}${attachmentFileExtension}`); }; const handleOpenDocument = (e: React.MouseEvent) => { @@ -162,7 +189,7 @@ export const AttachmentRow = ({ > - + {isEditing ? ( diff --git a/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx b/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx index b00e61cb03..6dd05ecd8c 100644 --- a/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx +++ b/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx @@ -3,22 +3,39 @@ import { getFileType } from '@/activities/files/utils/getFileType'; import { type ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivityTargetObjectFieldIdName'; import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient'; +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; -import { isDefined } from 'twenty-shared/utils'; +import { t } from '@lingui/core/macro'; +import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils'; import { FileFolder, useUploadFileMutation, + useUploadFilesFieldFileMutation, } from '~/generated-metadata/graphql'; -import { FeatureFlagKey } from '~/generated/graphql'; +import { FeatureFlagKey, FieldMetadataType } from '~/generated/graphql'; export const useUploadAttachmentFile = () => { const coreClient = useApolloCoreClient(); const [uploadFile] = useUploadFileMutation({ client: coreClient }); + const [uploadFilesFieldFile] = useUploadFilesFieldFileMutation({ + client: coreClient, + }); const isAttachmentMigrated = useIsFeatureEnabled( FeatureFlagKey.IS_ATTACHMENT_MIGRATED, ); + const isFilesFieldMigrated = useIsFeatureEnabled( + FeatureFlagKey.IS_FILES_FIELD_MIGRATED, + ); + + const { objectMetadataItem: attachmentMetadata } = useObjectMetadataItem({ + objectNameSingular: CoreObjectNameSingular.Attachment, + }); + + const filesFieldMetadataId = attachmentMetadata.fields.find( + (field) => field.type === FieldMetadataType.FILES && field.name === 'file', + )?.id; const { createOneRecord: createOneAttachment } = useCreateOneRecord({ @@ -30,21 +47,44 @@ export const useUploadAttachmentFile = () => { file: File, targetableObject: ActivityTargetableObject, ) => { - const result = await uploadFile({ - variables: { - file, - fileFolder: FileFolder.Attachment, - }, - }); + let attachmentPath: string; + let fileId: string | undefined; - const signedFile = result?.data?.uploadFile; + if (isFilesFieldMigrated) { + assertIsDefinedOrThrow( + filesFieldMetadataId, + new Error(t`File field not found for attachment object`), + ); - if (!isDefined(signedFile)) { - throw new Error("Couldn't upload the attachment."); + const result = await uploadFilesFieldFile({ + variables: { file, fieldMetadataId: filesFieldMetadataId }, + }); + + const uploadedFile = result?.data?.uploadFilesFieldFile; + + if (!isDefined(uploadedFile)) { + throw new Error("Couldn't upload the attachment."); + } + + attachmentPath = uploadedFile.path; + fileId = uploadedFile.id; + } else { + const result = await uploadFile({ + variables: { + file, + fileFolder: FileFolder.Attachment, + }, + }); + + const signedFile = result?.data?.uploadFile; + + if (!isDefined(signedFile)) { + throw new Error("Couldn't upload the attachment."); + } + + attachmentPath = signedFile.path; } - const { path: attachmentPath } = signedFile; - const targetableObjectFieldIdName = getActivityTargetObjectFieldIdName({ nameSingular: targetableObject.targetObjectNameSingular, isMorphRelation: isAttachmentMigrated, @@ -55,6 +95,16 @@ export const useUploadAttachmentFile = () => { fullPath: attachmentPath, fileCategory: getFileType(file.name), [targetableObjectFieldIdName]: targetableObject.id, + ...(isFilesFieldMigrated && isDefined(fileId) + ? { + file: [ + { + fileId, + label: file.name, + }, + ], + } + : {}), } as Partial; const createdAttachment = await createOneAttachment(attachmentToCreate); diff --git a/packages/twenty-front/src/modules/activities/files/types/Attachment.ts b/packages/twenty-front/src/modules/activities/files/types/Attachment.ts index 70422f5731..02ac27c32d 100644 --- a/packages/twenty-front/src/modules/activities/files/types/Attachment.ts +++ b/packages/twenty-front/src/modules/activities/files/types/Attachment.ts @@ -1,3 +1,5 @@ +import { type FieldFilesValue } from '@/object-record/record-field/ui/types/FieldMetadata'; + import { type AttachmentFileCategory } from './AttachmentFileCategory'; export type { AttachmentFileCategory }; @@ -7,6 +9,7 @@ export type Attachment = { name: string; fullPath: string; fileCategory: AttachmentFileCategory; + file?: FieldFilesValue[] | null; companyId?: string | null; personId?: string | null; taskId?: string | null; diff --git a/packages/twenty-front/src/modules/file/graphql/mutations/uploadFilesFieldFile.ts b/packages/twenty-front/src/modules/file/graphql/mutations/uploadFilesFieldFile.ts index 853c6b950f..fea82be603 100644 --- a/packages/twenty-front/src/modules/file/graphql/mutations/uploadFilesFieldFile.ts +++ b/packages/twenty-front/src/modules/file/graphql/mutations/uploadFilesFieldFile.ts @@ -1,8 +1,8 @@ import { gql } from '@apollo/client'; export const UPLOAD_FILES_FIELD_FILE = gql` - mutation UploadFilesFieldFile($file: Upload!) { - uploadFilesFieldFile(file: $file) { + mutation UploadFilesFieldFile($file: Upload!, $fieldMetadataId: String!) { + uploadFilesFieldFile(file: $file, fieldMetadataId: $fieldMetadataId) { id path size diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenFieldInputEditMode.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenFieldInputEditMode.ts index b444c6a5a3..3d7ed3ba76 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenFieldInputEditMode.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/useOpenFieldInputEditMode.ts @@ -99,6 +99,7 @@ export const useOpenFieldInputEditMode = () => { if (isDefined(objectMetadataItem)) { openFilesFieldInput({ fieldName: fieldDefinition.metadata.fieldName, + fieldMetadataId: fieldDefinition.fieldMetadataId, recordId, prefix, updateRecord: (updateInput) => { diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/FilesFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/FilesFieldDisplay.tsx index a87934aa77..634bd4a75b 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/FilesFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/FilesFieldDisplay.tsx @@ -1,14 +1,30 @@ +import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { useFilesFieldDisplay } from '@/object-record/record-field/ui/meta-types/hooks/useFilesFieldDisplay'; +import { filesFieldUploadState } from '@/object-record/record-field/ui/states/filesFieldUploadState'; import { FilesDisplay } from '@/ui/field/display/components/FilesDisplay'; +import { useContext } from 'react'; +import { useRecoilValue } from 'recoil'; export const FilesFieldDisplay = () => { + const { recordId, fieldDefinition } = useContext(FieldContext); const { fieldValue, disableChipClick } = useFilesFieldDisplay(); - if (!Array.isArray(fieldValue)) { - return <>; - } + const uploadState = useRecoilValue( + filesFieldUploadState({ + recordId, + fieldName: fieldDefinition.metadata.fieldName, + }), + ); + + const isUploadWindowOpen = uploadState === 'UPLOAD_WINDOW_OPEN'; + const isFileUploading = uploadState === 'UPLOADING_FILE'; return ( - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useUploadFilesFieldFile.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useUploadFilesFieldFile.ts index ae12f0d6f1..eb495aee9e 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useUploadFilesFieldFile.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useUploadFilesFieldFile.ts @@ -15,10 +15,10 @@ export const useUploadFilesFieldFile = () => { const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar(); const { t } = useLingui(); - const uploadFile = async (file: File) => { + const uploadFile = async (file: File, fieldMetadataId: string) => { try { const result = await uploadFilesFieldFile({ - variables: { file }, + variables: { file, fieldMetadataId }, }); const uploadedFile = result?.data?.uploadFilesFieldFile; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/FilesFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/FilesFieldInput.tsx index dfed2191b8..25325b2d4c 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/FilesFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/FilesFieldInput.tsx @@ -61,9 +61,13 @@ export const FilesFieldInput = () => { const nextValue = parseFilesArrayToFilesValue(updatedFiles); if (isDefined(nextValue)) { setDraftValue(nextValue); + + if (nextValue.length === 0) { + onEnter?.({ newValue: nextValue }); + } } }, - [parseFilesArrayToFilesValue, setDraftValue], + [parseFilesArrayToFilesValue, setDraftValue, onEnter], ); const handleUploadClick = useCallback(() => { @@ -89,6 +93,7 @@ export const FilesFieldInput = () => { try { const uploadedFiles = await uploadMultipleFiles( selectedFiles, + fieldDefinition.fieldMetadataId, uploadFile, ); @@ -113,6 +118,7 @@ export const FilesFieldInput = () => { handleChange, onEnter, parseFilesArrayToFilesValue, + fieldDefinition, ]); const setIsFieldInError = useSetRecoilComponentState( diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenFilesFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenFilesFieldInput.tsx index eacaf52421..24ca4a7938 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenFilesFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenFilesFieldInput.tsx @@ -1,6 +1,7 @@ import { useFileUpload } from '@/file-upload/hooks/useFileUpload'; import { useUploadFilesFieldFile } from '@/object-record/record-field/ui/meta-types/hooks/useUploadFilesFieldFile'; import { uploadMultipleFiles } from '@/object-record/record-field/ui/meta-types/utils/uploadMultipleFiles'; +import { filesFieldUploadState } from '@/object-record/record-field/ui/states/filesFieldUploadState'; import { type FieldFilesValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix'; @@ -36,6 +37,7 @@ export const useOpenFilesFieldInput = () => { ({ snapshot, set }) => async ({ fieldName, + fieldMetadataId, recordId, prefix, updateRecord, @@ -43,6 +45,7 @@ export const useOpenFilesFieldInput = () => { fieldDefinition, }: { fieldName: string; + fieldMetadataId: string; recordId: string; prefix?: string; updateRecord: (updateInput: Record) => void; @@ -92,6 +95,11 @@ export const useOpenFilesFieldInput = () => { const currentFileCount = isDefined(fieldValue) ? fieldValue.length : 0; + set( + filesFieldUploadState({ recordId, fieldName }), + 'UPLOAD_WINDOW_OPEN', + ); + openFileUpload({ multiple: true, onUpload: async (selectedFiles: File[]) => { @@ -100,6 +108,8 @@ export const useOpenFilesFieldInput = () => { message: t`Cannot upload more than ${maxNumberOfValues} files`, }); + set(filesFieldUploadState({ recordId, fieldName }), null); + if (isTableContext && isDefined(recordTableId)) { set( recordTableCellEditModePositionComponentState.atomFamily({ @@ -117,9 +127,15 @@ export const useOpenFilesFieldInput = () => { return; } + set( + filesFieldUploadState({ recordId, fieldName }), + 'UPLOADING_FILE', + ); + try { const uploadedFiles = await uploadMultipleFiles( selectedFiles, + fieldMetadataId, uploadFile, ); @@ -129,6 +145,8 @@ export const useOpenFilesFieldInput = () => { }); } } finally { + set(filesFieldUploadState({ recordId, fieldName }), null); + if (isTableContext && isDefined(recordTableId)) { set( recordTableCellEditModePositionComponentState.atomFamily({ @@ -146,6 +164,8 @@ export const useOpenFilesFieldInput = () => { } }, onCancel: () => { + set(filesFieldUploadState({ recordId, fieldName }), null); + if (isTableContext && isDefined(recordTableId)) { set( recordTableCellEditModePositionComponentState.atomFamily({ diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/utils/uploadMultipleFiles.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/utils/uploadMultipleFiles.ts index 0982d5647d..f3ed1c1ccb 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/utils/uploadMultipleFiles.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/utils/uploadMultipleFiles.ts @@ -3,12 +3,16 @@ import { isDefined } from 'twenty-shared/utils'; export const uploadMultipleFiles = async ( files: File[], - uploadFile: (file: File) => Promise, + fieldMetadataId: string, + uploadFile: ( + file: File, + fieldMetadataId: string, + ) => Promise, ): Promise => { const uploadedFiles: FieldFilesValue[] = []; for (const file of files) { - const uploadedFile = await uploadFile(file); + const uploadedFile = await uploadFile(file, fieldMetadataId); if (isDefined(uploadedFile)) { uploadedFiles.push(uploadedFile); } diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/states/filesFieldUploadState.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/states/filesFieldUploadState.ts new file mode 100644 index 0000000000..05fa715e28 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/states/filesFieldUploadState.ts @@ -0,0 +1,16 @@ +import { atomFamily } from 'recoil'; + +type FilesFieldUploadStateKey = { + recordId: string; + fieldName: string; +}; + +type FilesFieldUploadState = 'UPLOAD_WINDOW_OPEN' | 'UPLOADING_FILE' | null; + +export const filesFieldUploadState = atomFamily< + FilesFieldUploadState, + FilesFieldUploadStateKey +>({ + key: 'filesFieldUploadState', + default: null, +}); diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs.ts b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs.ts index c6b838e587..c5303bd552 100644 --- a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs.ts +++ b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs.ts @@ -144,7 +144,7 @@ export const SETTINGS_NON_COMPOSITE_FIELD_TYPE_CONFIGS: SettingsNonCompositeFiel [FieldMetadataType.FILES]: { label: 'Files', Icon: IllustrationIconFile, - category: 'Advanced', + category: 'Basic', exampleValues: [ [ { diff --git a/packages/twenty-front/src/modules/ui/field/display/components/FileChip.tsx b/packages/twenty-front/src/modules/ui/field/display/components/FileChip.tsx index 5e9b6549d5..aa220eed5d 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/FileChip.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/FileChip.tsx @@ -1,11 +1,18 @@ +import styled from '@emotion/styled'; + import { FileIcon } from '@/file/components/FileIcon'; import { type FieldFilesValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { getFileCategoryFromExtension } from '@/object-record/record-field/ui/utils/getFileCategoryFromExtension'; -import { isDefined } from 'twenty-shared/utils'; -import { ChipVariant, LinkChip } from 'twenty-ui/components'; +import { Chip, ChipVariant } from 'twenty-ui/components'; const MAX_WIDTH = 120; +const StyledClickableContainer = styled.div<{ clickable: boolean }>` + cursor: ${({ clickable }) => (clickable ? 'pointer' : 'inherit')}; + display: inline-flex; + min-width: 0; +`; + type FileChipProps = { file: FieldFilesValue; onClick: (file: FieldFilesValue) => void; @@ -17,8 +24,10 @@ export const FileChip = ({ onClick, forceDisableClick, }: FileChipProps) => { - const handleClick = (event: React.MouseEvent): void => { - if (isDefined(forceDisableClick)) { + const isClickable = forceDisableClick !== true; + + const handleMouseDown = (event: React.MouseEvent): void => { + if (!isClickable) { return; } event.preventDefault(); @@ -36,14 +45,17 @@ export const FileChip = ({ ); return ( - + + + ); }; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/FilesDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/FilesDisplay.tsx index c646bc3cdf..c2751dfd97 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/FilesDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/FilesDisplay.tsx @@ -2,6 +2,7 @@ import { downloadFile } from '@/activities/files/utils/downloadFile'; import { isAttachmentPreviewEnabledState } from '@/client-config/states/isAttachmentPreviewEnabledState'; import { type FieldFilesValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { FileChip } from '@/ui/field/display/components/FileChip'; +import { UploadFileChip } from '@/ui/field/display/components/UploadFileChip'; import { filePreviewState } from '@/ui/field/display/states/filePreviewState'; import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList'; import { useRecoilValue, useSetRecoilState } from 'recoil'; @@ -10,11 +11,15 @@ import { isDefined } from 'twenty-shared/utils'; type FilesDisplayProps = { value?: FieldFilesValue[]; forceDisableClick?: boolean; + isUploadWindowOpen?: boolean; + isFileUploading?: boolean; }; export const FilesDisplay = ({ value, forceDisableClick, + isUploadWindowOpen = false, + isFileUploading = false, }: FilesDisplayProps) => { const setFilePreview = useSetRecoilState(filePreviewState); const isAttachmentPreviewEnabled = useRecoilValue( @@ -32,6 +37,12 @@ export const FilesDisplay = ({ }; if (!isDefined(value) || value.length === 0) { + if (isFileUploading) { + return ; + } + if (isUploadWindowOpen) { + return ; + } return <>; } diff --git a/packages/twenty-front/src/modules/ui/field/display/components/UploadFileChip.tsx b/packages/twenty-front/src/modules/ui/field/display/components/UploadFileChip.tsx new file mode 100644 index 0000000000..5d796786b9 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/field/display/components/UploadFileChip.tsx @@ -0,0 +1,54 @@ +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; +import { IconArrowUp } from 'twenty-ui/display'; +import { Loader } from 'twenty-ui/feedback'; + +const StyledContainer = styled.div` + align-items: center; + background-color: ${({ theme }) => theme.background.transparent.light}; + border-radius: ${({ theme }) => theme.border.radius.sm}; + display: flex; + gap: ${({ theme }) => theme.spacing(1)}; + height: ${({ theme }) => theme.spacing(5)}; + padding: 0 ${({ theme }) => theme.spacing(1)}; + margin-right: ${({ theme }) => theme.spacing(1)}; +`; + +const StyledIconBox = styled.div` + align-items: center; + background-color: ${({ theme }) => theme.font.color.tertiary}; + border-radius: ${({ theme }) => theme.border.radius.sm}; + color: ${({ theme }) => theme.background.primary}; + display: flex; + height: 14px; + justify-content: center; + width: 14px; +`; + +const StyledStaticLoader = styled.div` + align-items: center; + border: 1px solid ${({ theme }) => theme.font.color.tertiary}; + border-radius: 12px; + box-sizing: border-box; + display: flex; + height: 12px; + justify-content: center; + width: 24px; +`; + +type UploadFileChipProps = { + isLoading?: boolean; +}; + +export const UploadFileChip = ({ isLoading = true }: UploadFileChipProps) => { + const theme = useTheme(); + + return ( + + + + + {isLoading ? : } + + ); +}; diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts index 774dbf9d26..7f05938ef5 100644 --- a/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts @@ -14,6 +14,7 @@ export enum FeatureFlagKey { IS_ATTACHMENT_MIGRATED = 'IS_ATTACHMENT_MIGRATED', IS_NOTE_TARGET_MIGRATED = 'IS_NOTE_TARGET_MIGRATED', IS_TASK_TARGET_MIGRATED = 'IS_TASK_TARGET_MIGRATED', + IS_FILES_FIELD_MIGRATED = 'IS_FILES_FIELD_MIGRATED', IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED = 'IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_SSE_DB_EVENTS_ENABLED = 'IS_SSE_DB_EVENTS_ENABLED', diff --git a/packages/twenty-server/src/engine/core-modules/file/files-field/files-field.module.ts b/packages/twenty-server/src/engine/core-modules/file/files-field/files-field.module.ts index 15bbc086ec..f6b9fcc882 100644 --- a/packages/twenty-server/src/engine/core-modules/file/files-field/files-field.module.ts +++ b/packages/twenty-server/src/engine/core-modules/file/files-field/files-field.module.ts @@ -12,13 +12,19 @@ import { FilesFieldDeletionListener } from 'src/engine/core-modules/file/files-f import { FilesFieldResolver } from 'src/engine/core-modules/file/files-field/resolvers/files-field.resolver'; import { JwtModule } from 'src/engine/core-modules/jwt/jwt.module'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module'; @Module({ imports: [ JwtModule, - TypeOrmModule.forFeature([FileEntity, WorkspaceEntity, ApplicationEntity]), + TypeOrmModule.forFeature([ + FileEntity, + WorkspaceEntity, + ApplicationEntity, + FieldMetadataEntity, + ]), PermissionsModule, FileStorageModule, WorkspaceManyOrAllFlatEntityMapsCacheModule, diff --git a/packages/twenty-server/src/engine/core-modules/file/files-field/files-field.service.ts b/packages/twenty-server/src/engine/core-modules/file/files-field/files-field.service.ts index a8d3212522..ba4ae219f2 100644 --- a/packages/twenty-server/src/engine/core-modules/file/files-field/files-field.service.ts +++ b/packages/twenty-server/src/engine/core-modules/file/files-field/files-field.service.ts @@ -20,6 +20,7 @@ import { removeFileFolderFromFileEntityPath } from 'src/engine/core-modules/file import { sanitizeFile } from 'src/engine/core-modules/file/utils/sanitize-file.utils'; import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { FilesFieldException, @@ -32,6 +33,8 @@ export class FilesFieldService { private readonly fileStorageService: FileStorageService, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, + @InjectRepository(FieldMetadataEntity) + private readonly fieldMetadataRepository: Repository, @InjectRepository(FileEntity) private readonly fileRepository: Repository, private readonly twentyConfigService: TwentyConfigService, @@ -43,13 +46,13 @@ export class FilesFieldService { filename, declaredMimeType, workspaceId, - applicationId, + fieldMetadataId, }: { file: Buffer; filename: string; declaredMimeType: string | undefined; workspaceId: string; - applicationId: string; + fieldMetadataId: string; }): Promise { const { mimeType, ext } = await extractFileInfo({ file, @@ -62,16 +65,24 @@ export class FilesFieldService { const fileId = v4(); const name = `${fileId}${ext ? `.${ext}` : ''}`; + const fieldMetadata = await this.fieldMetadataRepository.findOneOrFail({ + select: ['applicationId', 'universalIdentifier'], + where: { + id: fieldMetadataId, + workspaceId, + }, + }); + const application = await this.applicationRepository.findOneOrFail({ where: { - id: applicationId, + id: fieldMetadata.applicationId, workspaceId, }, }); return await this.fileStorageService.writeFile_v2({ sourceFile: sanitizedFile, - resourcePath: name, + resourcePath: `${fieldMetadata.universalIdentifier}/${name}`, mimeType, fileFolder: FileFolder.FilesField, applicationUniversalIdentifier: application.universalIdentifier, diff --git a/packages/twenty-server/src/engine/core-modules/file/files-field/resolvers/files-field.resolver.ts b/packages/twenty-server/src/engine/core-modules/file/files-field/resolvers/files-field.resolver.ts index 35bae99539..7ef3420e19 100644 --- a/packages/twenty-server/src/engine/core-modules/file/files-field/resolvers/files-field.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/file/files-field/resolvers/files-field.resolver.ts @@ -27,9 +27,15 @@ export class FilesFieldResolver { @UseGuards(SettingsPermissionGuard(PermissionFlagType.UPLOAD_FILE)) async uploadFilesFieldFile( @AuthWorkspace() - { id: workspaceId, workspaceCustomApplicationId }: WorkspaceEntity, + { id: workspaceId }: WorkspaceEntity, @Args({ name: 'file', type: () => GraphQLUpload }) { createReadStream, filename, mimetype }: FileUpload, + @Args({ + name: 'fieldMetadataId', + type: () => String, + nullable: false, + }) + fieldMetadataId: string, ): Promise { const stream = createReadStream(); const buffer = await streamToBuffer(stream); @@ -39,7 +45,7 @@ export class FilesFieldResolver { filename, declaredMimeType: mimetype, workspaceId, - applicationId: workspaceCustomApplicationId, + fieldMetadataId, }); } } diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts index bc1997afb1..fcc22ca82f 100644 --- a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts +++ b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts @@ -243,6 +243,7 @@ describe('WorkspaceEntityManager', () => { IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED: false, IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: false, IS_MARKETPLACE_ENABLED: false, + IS_FILES_FIELD_MIGRATED: false, }, userWorkspaceRoleMap: {}, eventEmitterService: { diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.ts index f89e8ea89c..eaad6cd56e 100644 --- a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.ts +++ b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.ts @@ -1223,7 +1223,6 @@ export class WorkspaceEntityManager extends EntityManager { let filesFieldDiffByEntityIndex = null; let filesFieldFileIds = null; - let fileIdToApplicationId = new Map(); filesFieldDiffByEntityIndex = filesFieldSync.computeFilesFieldDiffBeforeUpsert( @@ -1241,7 +1240,6 @@ export class WorkspaceEntityManager extends EntityManager { }); filesFieldFileIds = result.fileIds; - fileIdToApplicationId = result.fileIdToApplicationId; entityWithConnectedRelations.splice( 0, @@ -1286,10 +1284,7 @@ export class WorkspaceEntityManager extends EntityManager { .finally(() => queryRunnerForEntityPersistExecutor.release()); if (isDefined(filesFieldFileIds)) { - await filesFieldSync.updateFileEntityRecords( - filesFieldFileIds, - fileIdToApplicationId, - ); + await filesFieldSync.updateFileEntityRecords(filesFieldFileIds); } const resultArray = Array.isArray(result) ? result : [result]; diff --git a/packages/twenty-server/src/engine/twenty-orm/field-operations/files-field-sync/files-field-sync.ts b/packages/twenty-server/src/engine/twenty-orm/field-operations/files-field-sync/files-field-sync.ts index a32d127a64..c1091507ef 100644 --- a/packages/twenty-server/src/engine/twenty-orm/field-operations/files-field-sync/files-field-sync.ts +++ b/packages/twenty-server/src/engine/twenty-orm/field-operations/files-field-sync/files-field-sync.ts @@ -277,6 +277,28 @@ export class FilesFieldSync { } } + private validateFileFieldUniversalIdentifier( + fileId: string, + fileEntity: FileEntity, + fileIdToFieldUniversalIdentifier: Map, + ): void { + const expectedUniversalIdentifier = + fileIdToFieldUniversalIdentifier.get(fileId); + + if ( + isDefined(expectedUniversalIdentifier) && + !fileEntity.path.includes(expectedUniversalIdentifier) + ) { + throw new TwentyORMException( + `File ${fileId} was not uploaded for this field`, + TwentyORMExceptionCode.INVALID_INPUT, + { + userFriendlyMessage: msg`File ${fileId} was not uploaded for this field. Please re-upload the file.`, + }, + ); + } + } + private validateAndComputeFilesFieldDiff( entity: Record, filesField: FlatFieldMetadata, @@ -358,7 +380,6 @@ export class FilesFieldSync { toUpdate: Set; toRemove: Set; }; - fileIdToApplicationId: Map; }> { if (Object.keys(filesFieldDiffByEntityIndex).length === 0) { return { @@ -368,7 +389,6 @@ export class FilesFieldSync { toUpdate: new Set(), toRemove: new Set(), }, - fileIdToApplicationId: new Map(), }; } @@ -377,12 +397,11 @@ export class FilesFieldSync { this.internalContext, ); - const { toAdd, toUpdate, toRemove, fileIdToApplicationId } = - await this.validateAndEnrichFileDiffs( - filesFieldDiffByEntityIndex, - workspaceId, - objectMetadata.id, - ); + const { toAdd, toUpdate, toRemove } = await this.validateAndEnrichFileDiffs( + filesFieldDiffByEntityIndex, + workspaceId, + objectMetadata.id, + ); const updatedEntities = this.updateEntitiesWithEnrichedFilesFieldValues( entities, @@ -392,7 +411,6 @@ export class FilesFieldSync { return { entities: updatedEntities, fileIds: { toAdd, toUpdate, toRemove }, - fileIdToApplicationId, }; } @@ -404,7 +422,6 @@ export class FilesFieldSync { toAdd: Set; toUpdate: Set; toRemove: Set; - fileIdToApplicationId: Map; }> { const allFileIds = { toAdd: new Set(), @@ -412,28 +429,39 @@ export class FilesFieldSync { toRemove: new Set(), }; - const fileIdToApplicationId = new Map(); const allFileIdsToFetch = new Set(); const filesFields = this.getFilesFields(objectMetadataId); - const fieldNameToApplicationId = new Map( - filesFields.map((field) => [field.name, field.applicationId]), + const fieldNameToUniversalIdentifier = new Map( + filesFields.map((field) => [field.name, field.universalIdentifier]), ); + const fileIdToFieldUniversalIdentifier = new Map(); + for (const entityDiffs of Object.values(filesFieldDiffByEntityIndex)) { for (const [fieldName, diff] of Object.entries(entityDiffs)) { - const fieldApplicationId = fieldNameToApplicationId.get(fieldName); + const fieldUniversalIdentifier = + fieldNameToUniversalIdentifier.get(fieldName); diff.toAdd.forEach((file) => { allFileIds.toAdd.add(file.fileId); allFileIdsToFetch.add(file.fileId); - if (fieldApplicationId) { - fileIdToApplicationId.set(file.fileId, fieldApplicationId); + if (isDefined(fieldUniversalIdentifier)) { + fileIdToFieldUniversalIdentifier.set( + file.fileId, + fieldUniversalIdentifier, + ); } }); diff.toUpdate.forEach((file) => { allFileIds.toUpdate.add(file.fileId); allFileIdsToFetch.add(file.fileId); + if (isDefined(fieldUniversalIdentifier)) { + fileIdToFieldUniversalIdentifier.set( + file.fileId, + fieldUniversalIdentifier, + ); + } }); diff.toRemove.forEach((file) => { allFileIds.toRemove.add(file.fileId); @@ -442,7 +470,7 @@ export class FilesFieldSync { } if (allFileIdsToFetch.size === 0 && allFileIds.toRemove.size === 0) { - return { ...allFileIds, fileIdToApplicationId }; + return allFileIds; } const existingFiles = await this.fileRepository.find({ @@ -469,6 +497,12 @@ export class FilesFieldSync { ); } + this.validateFileFieldUniversalIdentifier( + file.fileId, + fileEntity, + fileIdToFieldUniversalIdentifier, + ); + if (!fileEntity.settings?.isTemporaryFile) { const fileId = file.fileId; @@ -494,6 +528,12 @@ export class FilesFieldSync { ); } + this.validateFileFieldUniversalIdentifier( + file.fileId, + fileEntity, + fileIdToFieldUniversalIdentifier, + ); + if (fileEntity.settings?.isTemporaryFile) { throw new TwentyORMException( `File ${file.fileId} to update should not be a temporary file`, @@ -507,50 +547,24 @@ export class FilesFieldSync { } } - return { ...allFileIds, fileIdToApplicationId }; + return allFileIds; } - async updateFileEntityRecords( - fileIds: { - toAdd: Set; - toUpdate: Set; - toRemove: Set; - }, - fileIdToApplicationId: Map, - ): Promise { + async updateFileEntityRecords(fileIds: { + toAdd: Set; + toUpdate: Set; + toRemove: Set; + }): Promise { if (fileIds.toAdd.size > 0) { - const fileIdsByApplicationId = Array.from(fileIds.toAdd).reduce( - (acc, fileId) => { - const applicationId = fileIdToApplicationId.get(fileId); - - if (!applicationId) { - throw new TwentyORMException( - `Application ID not found for file ${fileId}`, - TwentyORMExceptionCode.INVALID_INPUT, - ); - } - - acc[applicationId] = [...(acc[applicationId] || []), fileId]; - - return acc; - }, - {} as Record, - ); - - for (const [applicationId, fileIds] of Object.entries( - fileIdsByApplicationId, - )) { - await this.fileRepository.update( - { id: In(fileIds) }, - { - settings: { - isTemporaryFile: false, - toDelete: false, - }, - applicationId, + await this.fileRepository.update( + { id: In([...fileIds.toAdd]) }, + { + settings: { + isTemporaryFile: false, + toDelete: false, }, - ); - } + }, + ); } if (fileIds.toRemove.size > 0) { diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts index 6e16229f88..08e7e67aa0 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts @@ -169,7 +169,6 @@ export class WorkspaceInsertQueryBuilder< ); let filesFieldFileIds = null; - let fileIdToApplicationId = new Map(); const entities = Array.isArray(this.expressionMap.valuesSet) ? this.expressionMap.valuesSet @@ -191,7 +190,6 @@ export class WorkspaceInsertQueryBuilder< }); filesFieldFileIds = result.fileIds; - fileIdToApplicationId = result.fileIdToApplicationId; this.expressionMap.valuesSet = Array.isArray( this.expressionMap.valuesSet, @@ -227,10 +225,7 @@ export class WorkspaceInsertQueryBuilder< const result = await super.execute(); if (isDefined(filesFieldFileIds)) { - await this.filesFieldSync.updateFileEntityRecords( - filesFieldFileIds, - fileIdToApplicationId, - ); + await this.filesFieldSync.updateFileEntityRecords(filesFieldFileIds); } const eventSelectQueryBuilder = ( this.connection.manager as WorkspaceEntityManager diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-update-query-builder.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-update-query-builder.ts index edb303cdc1..3d6a9ae012 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-update-query-builder.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-update-query-builder.ts @@ -173,7 +173,6 @@ export class WorkspaceUpdateQueryBuilder< let filesFieldDiffByEntityIndex = null; let filesFieldFileIds = null; - let fileIdToApplicationId = new Map(); const updatePayload = Array.isArray(this.expressionMap.valuesSet) ? (this.expressionMap.valuesSet[0] ?? {}) @@ -197,7 +196,6 @@ export class WorkspaceUpdateQueryBuilder< }); filesFieldFileIds = result.fileIds; - fileIdToApplicationId = result.fileIdToApplicationId; this.expressionMap.valuesSet = result.entities[0]; } @@ -236,10 +234,7 @@ export class WorkspaceUpdateQueryBuilder< const result = await super.execute(); if (isDefined(filesFieldFileIds)) { - await this.filesFieldSync.updateFileEntityRecords( - filesFieldFileIds, - fileIdToApplicationId, - ); + await this.filesFieldSync.updateFileEntityRecords(filesFieldFileIds); } const after = await eventSelectQueryBuilder.getMany(); @@ -374,7 +369,6 @@ export class WorkspaceUpdateQueryBuilder< let filesFieldDiffByEntityIndex = null; let filesFieldFileIds = null; - let fileIdToApplicationId = null; const entities = this.manyInputs.map((input) => input.partialEntity); @@ -394,7 +388,6 @@ export class WorkspaceUpdateQueryBuilder< }); filesFieldFileIds = result.fileIds; - fileIdToApplicationId = result.fileIdToApplicationId; this.manyInputs = result.entities.map((updatedEntity, index) => ({ criteria: this.manyInputs[index].criteria, @@ -451,11 +444,8 @@ export class WorkspaceUpdateQueryBuilder< results.push(result); } - if (isDefined(filesFieldFileIds) && isDefined(fileIdToApplicationId)) { - await this.filesFieldSync.updateFileEntityRecords( - filesFieldFileIds, - fileIdToApplicationId, - ); + if (isDefined(filesFieldFileIds)) { + await this.filesFieldSync.updateFileEntityRecords(filesFieldFileIds); } const afterRecords = await eventSelectQueryBuilder.getMany(); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap index 8b317e3053..d65449c041 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap @@ -8,16 +8,19 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "id": "00000000-0000-0000-0000-000000000002", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000008", + "id": "00000000-0000-0000-0000-000000000009", }, "deletedAt": { "id": "00000000-0000-0000-0000-000000000004", }, + "file": { + "id": "00000000-0000-0000-0000-000000000006", + }, "fileCategory": { - "id": "00000000-0000-0000-0000-000000000007", + "id": "00000000-0000-0000-0000-000000000008", }, "fullPath": { - "id": "00000000-0000-0000-0000-000000000006", + "id": "00000000-0000-0000-0000-000000000007", }, "id": { "id": "00000000-0000-0000-0000-000000000001", @@ -26,232 +29,232 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "id": "00000000-0000-0000-0000-000000000005", }, "targetCompany": { - "id": "00000000-0000-0000-0000-000000000013", - }, - "targetDashboard": { - "id": "00000000-0000-0000-0000-000000000015", - }, - "targetNote": { - "id": "00000000-0000-0000-0000-000000000011", - }, - "targetOpportunity": { "id": "00000000-0000-0000-0000-000000000014", }, - "targetPerson": { + "targetDashboard": { + "id": "00000000-0000-0000-0000-000000000016", + }, + "targetNote": { "id": "00000000-0000-0000-0000-000000000012", }, + "targetOpportunity": { + "id": "00000000-0000-0000-0000-000000000015", + }, + "targetPerson": { + "id": "00000000-0000-0000-0000-000000000013", + }, "targetTask": { - "id": "00000000-0000-0000-0000-000000000010", + "id": "00000000-0000-0000-0000-000000000011", }, "targetWorkflow": { - "id": "00000000-0000-0000-0000-000000000016", + "id": "00000000-0000-0000-0000-000000000017", }, "updatedAt": { "id": "00000000-0000-0000-0000-000000000003", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000009", + "id": "00000000-0000-0000-0000-000000000010", }, }, - "id": "00000000-0000-0000-0000-000000000017", + "id": "00000000-0000-0000-0000-000000000018", "views": undefined, }, "blocklist": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000019", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000021", - }, - "handle": { - "id": "00000000-0000-0000-0000-000000000022", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000018", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000020", }, - "workspaceMember": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000022", + }, + "handle": { "id": "00000000-0000-0000-0000-000000000023", }, + "id": { + "id": "00000000-0000-0000-0000-000000000019", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000021", + }, + "workspaceMember": { + "id": "00000000-0000-0000-0000-000000000024", + }, }, - "id": "00000000-0000-0000-0000-000000000024", + "id": "00000000-0000-0000-0000-000000000025", "views": undefined, }, "calendarChannel": { "fields": { "calendarChannelEventAssociations": { - "id": "00000000-0000-0000-0000-000000000045", - }, - "connectedAccount": { - "id": "00000000-0000-0000-0000-000000000038", - }, - "contactAutoCreationPolicy": { - "id": "00000000-0000-0000-0000-000000000042", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000035", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000037", - }, - "handle": { - "id": "00000000-0000-0000-0000-000000000039", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000034", - }, - "isContactAutoCreationEnabled": { - "id": "00000000-0000-0000-0000-000000000041", - }, - "isSyncEnabled": { - "id": "00000000-0000-0000-0000-000000000043", - }, - "syncCursor": { - "id": "00000000-0000-0000-0000-000000000044", - }, - "syncStage": { - "id": "00000000-0000-0000-0000-000000000048", - }, - "syncStageStartedAt": { - "id": "00000000-0000-0000-0000-000000000049", - }, - "syncStatus": { - "id": "00000000-0000-0000-0000-000000000047", - }, - "syncedAt": { - "id": "00000000-0000-0000-0000-000000000050", - }, - "throttleFailureCount": { "id": "00000000-0000-0000-0000-000000000046", }, - "updatedAt": { + "connectedAccount": { + "id": "00000000-0000-0000-0000-000000000039", + }, + "contactAutoCreationPolicy": { + "id": "00000000-0000-0000-0000-000000000043", + }, + "createdAt": { "id": "00000000-0000-0000-0000-000000000036", }, - "visibility": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000038", + }, + "handle": { "id": "00000000-0000-0000-0000-000000000040", }, + "id": { + "id": "00000000-0000-0000-0000-000000000035", + }, + "isContactAutoCreationEnabled": { + "id": "00000000-0000-0000-0000-000000000042", + }, + "isSyncEnabled": { + "id": "00000000-0000-0000-0000-000000000044", + }, + "syncCursor": { + "id": "00000000-0000-0000-0000-000000000045", + }, + "syncStage": { + "id": "00000000-0000-0000-0000-000000000049", + }, + "syncStageStartedAt": { + "id": "00000000-0000-0000-0000-000000000050", + }, + "syncStatus": { + "id": "00000000-0000-0000-0000-000000000048", + }, + "syncedAt": { + "id": "00000000-0000-0000-0000-000000000051", + }, + "throttleFailureCount": { + "id": "00000000-0000-0000-0000-000000000047", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000037", + }, + "visibility": { + "id": "00000000-0000-0000-0000-000000000041", + }, }, - "id": "00000000-0000-0000-0000-000000000051", + "id": "00000000-0000-0000-0000-000000000052", "views": undefined, }, "calendarChannelEventAssociation": { "fields": { "calendarChannel": { - "id": "00000000-0000-0000-0000-000000000029", - }, - "calendarEvent": { "id": "00000000-0000-0000-0000-000000000030", }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000026", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000028", - }, - "eventExternalId": { + "calendarEvent": { "id": "00000000-0000-0000-0000-000000000031", }, - "id": { - "id": "00000000-0000-0000-0000-000000000025", - }, - "recurringEventExternalId": { - "id": "00000000-0000-0000-0000-000000000032", - }, - "updatedAt": { + "createdAt": { "id": "00000000-0000-0000-0000-000000000027", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000029", + }, + "eventExternalId": { + "id": "00000000-0000-0000-0000-000000000032", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000026", + }, + "recurringEventExternalId": { + "id": "00000000-0000-0000-0000-000000000033", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000028", + }, }, - "id": "00000000-0000-0000-0000-000000000033", + "id": "00000000-0000-0000-0000-000000000034", "views": undefined, }, "calendarEvent": { "fields": { "calendarChannelEventAssociations": { - "id": "00000000-0000-0000-0000-000000000080", - }, - "calendarEventParticipants": { "id": "00000000-0000-0000-0000-000000000081", }, + "calendarEventParticipants": { + "id": "00000000-0000-0000-0000-000000000082", + }, "conferenceLink": { - "id": "00000000-0000-0000-0000-000000000079", + "id": "00000000-0000-0000-0000-000000000080", }, "conferenceSolution": { - "id": "00000000-0000-0000-0000-000000000078", + "id": "00000000-0000-0000-0000-000000000079", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000065", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000067", - }, - "description": { - "id": "00000000-0000-0000-0000-000000000075", - }, - "endsAt": { - "id": "00000000-0000-0000-0000-000000000072", - }, - "externalCreatedAt": { - "id": "00000000-0000-0000-0000-000000000073", - }, - "externalUpdatedAt": { - "id": "00000000-0000-0000-0000-000000000074", - }, - "iCalUid": { - "id": "00000000-0000-0000-0000-000000000077", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000064", - }, - "isCanceled": { - "id": "00000000-0000-0000-0000-000000000069", - }, - "isFullDay": { - "id": "00000000-0000-0000-0000-000000000070", - }, - "location": { - "id": "00000000-0000-0000-0000-000000000076", - }, - "startsAt": { - "id": "00000000-0000-0000-0000-000000000071", - }, - "title": { - "id": "00000000-0000-0000-0000-000000000068", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000066", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000068", + }, + "description": { + "id": "00000000-0000-0000-0000-000000000076", + }, + "endsAt": { + "id": "00000000-0000-0000-0000-000000000073", + }, + "externalCreatedAt": { + "id": "00000000-0000-0000-0000-000000000074", + }, + "externalUpdatedAt": { + "id": "00000000-0000-0000-0000-000000000075", + }, + "iCalUid": { + "id": "00000000-0000-0000-0000-000000000078", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000065", + }, + "isCanceled": { + "id": "00000000-0000-0000-0000-000000000070", + }, + "isFullDay": { + "id": "00000000-0000-0000-0000-000000000071", + }, + "location": { + "id": "00000000-0000-0000-0000-000000000077", + }, + "startsAt": { + "id": "00000000-0000-0000-0000-000000000072", + }, + "title": { + "id": "00000000-0000-0000-0000-000000000069", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000067", + }, }, - "id": "00000000-0000-0000-0000-000000000091", + "id": "00000000-0000-0000-0000-000000000092", "views": { "allCalendarEvents": { - "id": "00000000-0000-0000-0000-000000000090", + "id": "00000000-0000-0000-0000-000000000091", "viewFields": { "conferenceLink": { - "id": "00000000-0000-0000-0000-000000000087", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000089", - }, - "endsAt": { - "id": "00000000-0000-0000-0000-000000000084", - }, - "isCanceled": { "id": "00000000-0000-0000-0000-000000000088", }, - "isFullDay": { + "createdAt": { + "id": "00000000-0000-0000-0000-000000000090", + }, + "endsAt": { "id": "00000000-0000-0000-0000-000000000085", }, - "location": { + "isCanceled": { + "id": "00000000-0000-0000-0000-000000000089", + }, + "isFullDay": { "id": "00000000-0000-0000-0000-000000000086", }, + "location": { + "id": "00000000-0000-0000-0000-000000000087", + }, "startsAt": { - "id": "00000000-0000-0000-0000-000000000083", + "id": "00000000-0000-0000-0000-000000000084", }, "title": { - "id": "00000000-0000-0000-0000-000000000082", + "id": "00000000-0000-0000-0000-000000000083", }, }, "viewGroups": {}, @@ -261,145 +264,145 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "calendarEventParticipant": { "fields": { "calendarEvent": { - "id": "00000000-0000-0000-0000-000000000056", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000053", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000055", - }, - "displayName": { - "id": "00000000-0000-0000-0000-000000000058", - }, - "handle": { "id": "00000000-0000-0000-0000-000000000057", }, - "id": { - "id": "00000000-0000-0000-0000-000000000052", - }, - "isOrganizer": { - "id": "00000000-0000-0000-0000-000000000059", - }, - "person": { - "id": "00000000-0000-0000-0000-000000000061", - }, - "responseStatus": { - "id": "00000000-0000-0000-0000-000000000060", - }, - "updatedAt": { + "createdAt": { "id": "00000000-0000-0000-0000-000000000054", }, - "workspaceMember": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000056", + }, + "displayName": { + "id": "00000000-0000-0000-0000-000000000059", + }, + "handle": { + "id": "00000000-0000-0000-0000-000000000058", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000053", + }, + "isOrganizer": { + "id": "00000000-0000-0000-0000-000000000060", + }, + "person": { "id": "00000000-0000-0000-0000-000000000062", }, + "responseStatus": { + "id": "00000000-0000-0000-0000-000000000061", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000055", + }, + "workspaceMember": { + "id": "00000000-0000-0000-0000-000000000063", + }, }, - "id": "00000000-0000-0000-0000-000000000063", + "id": "00000000-0000-0000-0000-000000000064", "views": undefined, }, "company": { "fields": { "accountOwner": { - "id": "00000000-0000-0000-0000-000000000108", - }, - "address": { - "id": "00000000-0000-0000-0000-000000000098", - }, - "annualRecurringRevenue": { - "id": "00000000-0000-0000-0000-000000000102", - }, - "attachments": { - "id": "00000000-0000-0000-0000-000000000113", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000093", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000105", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000095", - }, - "domainName": { - "id": "00000000-0000-0000-0000-000000000097", - }, - "employees": { - "id": "00000000-0000-0000-0000-000000000099", - }, - "favorites": { - "id": "00000000-0000-0000-0000-000000000112", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000092", - }, - "idealCustomerProfile": { - "id": "00000000-0000-0000-0000-000000000103", - }, - "linkedinLink": { - "id": "00000000-0000-0000-0000-000000000100", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000096", - }, - "noteTargets": { - "id": "00000000-0000-0000-0000-000000000110", - }, - "opportunities": { - "id": "00000000-0000-0000-0000-000000000111", - }, - "people": { - "id": "00000000-0000-0000-0000-000000000107", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000104", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000115", - }, - "taskTargets": { "id": "00000000-0000-0000-0000-000000000109", }, - "timelineActivities": { + "address": { + "id": "00000000-0000-0000-0000-000000000099", + }, + "annualRecurringRevenue": { + "id": "00000000-0000-0000-0000-000000000103", + }, + "attachments": { "id": "00000000-0000-0000-0000-000000000114", }, - "updatedAt": { + "createdAt": { "id": "00000000-0000-0000-0000-000000000094", }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000106", }, - "xLink": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000096", + }, + "domainName": { + "id": "00000000-0000-0000-0000-000000000098", + }, + "employees": { + "id": "00000000-0000-0000-0000-000000000100", + }, + "favorites": { + "id": "00000000-0000-0000-0000-000000000113", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000093", + }, + "idealCustomerProfile": { + "id": "00000000-0000-0000-0000-000000000104", + }, + "linkedinLink": { "id": "00000000-0000-0000-0000-000000000101", }, + "name": { + "id": "00000000-0000-0000-0000-000000000097", + }, + "noteTargets": { + "id": "00000000-0000-0000-0000-000000000111", + }, + "opportunities": { + "id": "00000000-0000-0000-0000-000000000112", + }, + "people": { + "id": "00000000-0000-0000-0000-000000000108", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000105", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000116", + }, + "taskTargets": { + "id": "00000000-0000-0000-0000-000000000110", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000115", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000095", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000107", + }, + "xLink": { + "id": "00000000-0000-0000-0000-000000000102", + }, }, - "id": "00000000-0000-0000-0000-000000000125", + "id": "00000000-0000-0000-0000-000000000126", "views": { "allCompanies": { - "id": "00000000-0000-0000-0000-000000000124", + "id": "00000000-0000-0000-0000-000000000125", "viewFields": { "accountOwner": { - "id": "00000000-0000-0000-0000-000000000119", - }, - "address": { - "id": "00000000-0000-0000-0000-000000000123", - }, - "createdAt": { "id": "00000000-0000-0000-0000-000000000120", }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000118", + "address": { + "id": "00000000-0000-0000-0000-000000000124", }, - "domainName": { - "id": "00000000-0000-0000-0000-000000000117", - }, - "employees": { + "createdAt": { "id": "00000000-0000-0000-0000-000000000121", }, - "linkedinLink": { + "createdBy": { + "id": "00000000-0000-0000-0000-000000000119", + }, + "domainName": { + "id": "00000000-0000-0000-0000-000000000118", + }, + "employees": { "id": "00000000-0000-0000-0000-000000000122", }, + "linkedinLink": { + "id": "00000000-0000-0000-0000-000000000123", + }, "name": { - "id": "00000000-0000-0000-0000-000000000116", + "id": "00000000-0000-0000-0000-000000000117", }, }, "viewGroups": {}, @@ -409,118 +412,118 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "connectedAccount": { "fields": { "accessToken": { - "id": "00000000-0000-0000-0000-000000000132", - }, - "accountOwner": { - "id": "00000000-0000-0000-0000-000000000134", - }, - "authFailedAt": { - "id": "00000000-0000-0000-0000-000000000136", - }, - "calendarChannels": { - "id": "00000000-0000-0000-0000-000000000139", - }, - "connectionParameters": { - "id": "00000000-0000-0000-0000-000000000142", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000127", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000129", - }, - "handle": { - "id": "00000000-0000-0000-0000-000000000130", - }, - "handleAliases": { - "id": "00000000-0000-0000-0000-000000000140", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000126", - }, - "lastCredentialsRefreshedAt": { - "id": "00000000-0000-0000-0000-000000000137", - }, - "lastSyncHistoryId": { - "id": "00000000-0000-0000-0000-000000000135", - }, - "messageChannels": { - "id": "00000000-0000-0000-0000-000000000138", - }, - "provider": { - "id": "00000000-0000-0000-0000-000000000131", - }, - "refreshToken": { "id": "00000000-0000-0000-0000-000000000133", }, - "scopes": { - "id": "00000000-0000-0000-0000-000000000141", + "accountOwner": { + "id": "00000000-0000-0000-0000-000000000135", }, - "updatedAt": { + "authFailedAt": { + "id": "00000000-0000-0000-0000-000000000137", + }, + "calendarChannels": { + "id": "00000000-0000-0000-0000-000000000140", + }, + "connectionParameters": { + "id": "00000000-0000-0000-0000-000000000143", + }, + "createdAt": { "id": "00000000-0000-0000-0000-000000000128", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000130", + }, + "handle": { + "id": "00000000-0000-0000-0000-000000000131", + }, + "handleAliases": { + "id": "00000000-0000-0000-0000-000000000141", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000127", + }, + "lastCredentialsRefreshedAt": { + "id": "00000000-0000-0000-0000-000000000138", + }, + "lastSyncHistoryId": { + "id": "00000000-0000-0000-0000-000000000136", + }, + "messageChannels": { + "id": "00000000-0000-0000-0000-000000000139", + }, + "provider": { + "id": "00000000-0000-0000-0000-000000000132", + }, + "refreshToken": { + "id": "00000000-0000-0000-0000-000000000134", + }, + "scopes": { + "id": "00000000-0000-0000-0000-000000000142", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000129", + }, }, - "id": "00000000-0000-0000-0000-000000000143", + "id": "00000000-0000-0000-0000-000000000144", "views": undefined, }, "dashboard": { "fields": { "attachments": { - "id": "00000000-0000-0000-0000-000000000155", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000145", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000151", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000147", - }, - "favorites": { - "id": "00000000-0000-0000-0000-000000000154", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000144", - }, - "pageLayoutId": { - "id": "00000000-0000-0000-0000-000000000150", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000149", - }, - "searchVector": { "id": "00000000-0000-0000-0000-000000000156", }, - "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000153", - }, - "title": { - "id": "00000000-0000-0000-0000-000000000148", - }, - "updatedAt": { + "createdAt": { "id": "00000000-0000-0000-0000-000000000146", }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000152", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000148", + }, + "favorites": { + "id": "00000000-0000-0000-0000-000000000155", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000145", + }, + "pageLayoutId": { + "id": "00000000-0000-0000-0000-000000000151", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000150", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000157", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000154", + }, + "title": { + "id": "00000000-0000-0000-0000-000000000149", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000147", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000153", + }, }, - "id": "00000000-0000-0000-0000-000000000162", + "id": "00000000-0000-0000-0000-000000000163", "views": { "allDashboards": { - "id": "00000000-0000-0000-0000-000000000161", + "id": "00000000-0000-0000-0000-000000000162", "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000159", + "id": "00000000-0000-0000-0000-000000000160", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000158", + "id": "00000000-0000-0000-0000-000000000159", }, "title": { - "id": "00000000-0000-0000-0000-000000000157", + "id": "00000000-0000-0000-0000-000000000158", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000160", + "id": "00000000-0000-0000-0000-000000000161", }, }, "viewGroups": {}, @@ -530,151 +533,151 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "favorite": { "fields": { "company": { - "id": "00000000-0000-0000-0000-000000000170", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000164", - }, - "dashboard": { - "id": "00000000-0000-0000-0000-000000000179", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000166", - }, - "favoriteFolder": { - "id": "00000000-0000-0000-0000-000000000178", - }, - "forWorkspaceMember": { - "id": "00000000-0000-0000-0000-000000000168", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000163", - }, - "note": { - "id": "00000000-0000-0000-0000-000000000176", - }, - "opportunity": { "id": "00000000-0000-0000-0000-000000000171", }, - "person": { - "id": "00000000-0000-0000-0000-000000000169", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000167", - }, - "task": { - "id": "00000000-0000-0000-0000-000000000175", - }, - "updatedAt": { + "createdAt": { "id": "00000000-0000-0000-0000-000000000165", }, - "viewId": { + "dashboard": { + "id": "00000000-0000-0000-0000-000000000180", + }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000167", + }, + "favoriteFolder": { + "id": "00000000-0000-0000-0000-000000000179", + }, + "forWorkspaceMember": { + "id": "00000000-0000-0000-0000-000000000169", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000164", + }, + "note": { "id": "00000000-0000-0000-0000-000000000177", }, - "workflow": { + "opportunity": { "id": "00000000-0000-0000-0000-000000000172", }, - "workflowRun": { - "id": "00000000-0000-0000-0000-000000000174", + "person": { + "id": "00000000-0000-0000-0000-000000000170", }, - "workflowVersion": { + "position": { + "id": "00000000-0000-0000-0000-000000000168", + }, + "task": { + "id": "00000000-0000-0000-0000-000000000176", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000166", + }, + "viewId": { + "id": "00000000-0000-0000-0000-000000000178", + }, + "workflow": { "id": "00000000-0000-0000-0000-000000000173", }, + "workflowRun": { + "id": "00000000-0000-0000-0000-000000000175", + }, + "workflowVersion": { + "id": "00000000-0000-0000-0000-000000000174", + }, }, - "id": "00000000-0000-0000-0000-000000000180", + "id": "00000000-0000-0000-0000-000000000181", "views": undefined, }, "favoriteFolder": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000182", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000184", - }, - "favorites": { - "id": "00000000-0000-0000-0000-000000000187", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000181", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000186", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000185", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000183", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000185", + }, + "favorites": { + "id": "00000000-0000-0000-0000-000000000188", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000182", + }, + "name": { + "id": "00000000-0000-0000-0000-000000000187", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000186", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000184", + }, }, - "id": "00000000-0000-0000-0000-000000000188", + "id": "00000000-0000-0000-0000-000000000189", "views": undefined, }, "message": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000259", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000261", - }, - "direction": { - "id": "00000000-0000-0000-0000-000000000264", - }, - "headerMessageId": { - "id": "00000000-0000-0000-0000-000000000262", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000258", - }, - "messageChannelMessageAssociations": { - "id": "00000000-0000-0000-0000-000000000269", - }, - "messageParticipants": { - "id": "00000000-0000-0000-0000-000000000268", - }, - "messageThread": { - "id": "00000000-0000-0000-0000-000000000263", - }, - "receivedAt": { - "id": "00000000-0000-0000-0000-000000000267", - }, - "subject": { - "id": "00000000-0000-0000-0000-000000000265", - }, - "text": { - "id": "00000000-0000-0000-0000-000000000266", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000260", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000262", + }, + "direction": { + "id": "00000000-0000-0000-0000-000000000265", + }, + "headerMessageId": { + "id": "00000000-0000-0000-0000-000000000263", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000259", + }, + "messageChannelMessageAssociations": { + "id": "00000000-0000-0000-0000-000000000270", + }, + "messageParticipants": { + "id": "00000000-0000-0000-0000-000000000269", + }, + "messageThread": { + "id": "00000000-0000-0000-0000-000000000264", + }, + "receivedAt": { + "id": "00000000-0000-0000-0000-000000000268", + }, + "subject": { + "id": "00000000-0000-0000-0000-000000000266", + }, + "text": { + "id": "00000000-0000-0000-0000-000000000267", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000261", + }, }, - "id": "00000000-0000-0000-0000-000000000278", + "id": "00000000-0000-0000-0000-000000000279", "views": { "allMessages": { - "id": "00000000-0000-0000-0000-000000000277", + "id": "00000000-0000-0000-0000-000000000278", "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000276", + "id": "00000000-0000-0000-0000-000000000277", }, "headerMessageId": { - "id": "00000000-0000-0000-0000-000000000274", + "id": "00000000-0000-0000-0000-000000000275", }, "messageParticipants": { - "id": "00000000-0000-0000-0000-000000000272", - }, - "messageThread": { - "id": "00000000-0000-0000-0000-000000000271", - }, - "receivedAt": { "id": "00000000-0000-0000-0000-000000000273", }, + "messageThread": { + "id": "00000000-0000-0000-0000-000000000272", + }, + "receivedAt": { + "id": "00000000-0000-0000-0000-000000000274", + }, "subject": { - "id": "00000000-0000-0000-0000-000000000270", + "id": "00000000-0000-0000-0000-000000000271", }, "text": { - "id": "00000000-0000-0000-0000-000000000275", + "id": "00000000-0000-0000-0000-000000000276", }, }, "viewGroups": {}, @@ -684,223 +687,223 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "messageChannel": { "fields": { "connectedAccount": { - "id": "00000000-0000-0000-0000-000000000206", - }, - "contactAutoCreationPolicy": { - "id": "00000000-0000-0000-0000-000000000209", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000201", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000203", - }, - "excludeGroupEmails": { - "id": "00000000-0000-0000-0000-000000000211", - }, - "excludeNonProfessionalEmails": { - "id": "00000000-0000-0000-0000-000000000210", - }, - "handle": { - "id": "00000000-0000-0000-0000-000000000205", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000200", - }, - "isContactAutoCreationEnabled": { - "id": "00000000-0000-0000-0000-000000000208", - }, - "isSyncEnabled": { - "id": "00000000-0000-0000-0000-000000000216", - }, - "messageChannelMessageAssociations": { - "id": "00000000-0000-0000-0000-000000000212", - }, - "messageFolderImportPolicy": { - "id": "00000000-0000-0000-0000-000000000214", - }, - "messageFolders": { - "id": "00000000-0000-0000-0000-000000000213", - }, - "pendingGroupEmailsAction": { - "id": "00000000-0000-0000-0000-000000000215", - }, - "syncCursor": { - "id": "00000000-0000-0000-0000-000000000217", - }, - "syncStage": { - "id": "00000000-0000-0000-0000-000000000220", - }, - "syncStageStartedAt": { - "id": "00000000-0000-0000-0000-000000000221", - }, - "syncStatus": { - "id": "00000000-0000-0000-0000-000000000219", - }, - "syncedAt": { - "id": "00000000-0000-0000-0000-000000000218", - }, - "throttleFailureCount": { - "id": "00000000-0000-0000-0000-000000000222", - }, - "type": { "id": "00000000-0000-0000-0000-000000000207", }, - "updatedAt": { + "contactAutoCreationPolicy": { + "id": "00000000-0000-0000-0000-000000000210", + }, + "createdAt": { "id": "00000000-0000-0000-0000-000000000202", }, - "visibility": { + "deletedAt": { "id": "00000000-0000-0000-0000-000000000204", }, + "excludeGroupEmails": { + "id": "00000000-0000-0000-0000-000000000212", + }, + "excludeNonProfessionalEmails": { + "id": "00000000-0000-0000-0000-000000000211", + }, + "handle": { + "id": "00000000-0000-0000-0000-000000000206", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000201", + }, + "isContactAutoCreationEnabled": { + "id": "00000000-0000-0000-0000-000000000209", + }, + "isSyncEnabled": { + "id": "00000000-0000-0000-0000-000000000217", + }, + "messageChannelMessageAssociations": { + "id": "00000000-0000-0000-0000-000000000213", + }, + "messageFolderImportPolicy": { + "id": "00000000-0000-0000-0000-000000000215", + }, + "messageFolders": { + "id": "00000000-0000-0000-0000-000000000214", + }, + "pendingGroupEmailsAction": { + "id": "00000000-0000-0000-0000-000000000216", + }, + "syncCursor": { + "id": "00000000-0000-0000-0000-000000000218", + }, + "syncStage": { + "id": "00000000-0000-0000-0000-000000000221", + }, + "syncStageStartedAt": { + "id": "00000000-0000-0000-0000-000000000222", + }, + "syncStatus": { + "id": "00000000-0000-0000-0000-000000000220", + }, + "syncedAt": { + "id": "00000000-0000-0000-0000-000000000219", + }, + "throttleFailureCount": { + "id": "00000000-0000-0000-0000-000000000223", + }, + "type": { + "id": "00000000-0000-0000-0000-000000000208", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000203", + }, + "visibility": { + "id": "00000000-0000-0000-0000-000000000205", + }, }, - "id": "00000000-0000-0000-0000-000000000223", + "id": "00000000-0000-0000-0000-000000000224", "views": undefined, }, "messageChannelMessageAssociation": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000190", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000192", - }, - "direction": { - "id": "00000000-0000-0000-0000-000000000198", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000189", - }, - "message": { - "id": "00000000-0000-0000-0000-000000000194", - }, - "messageChannel": { - "id": "00000000-0000-0000-0000-000000000193", - }, - "messageExternalId": { - "id": "00000000-0000-0000-0000-000000000195", - }, - "messageThread": { - "id": "00000000-0000-0000-0000-000000000196", - }, - "messageThreadExternalId": { - "id": "00000000-0000-0000-0000-000000000197", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000191", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000193", + }, + "direction": { + "id": "00000000-0000-0000-0000-000000000199", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000190", + }, + "message": { + "id": "00000000-0000-0000-0000-000000000195", + }, + "messageChannel": { + "id": "00000000-0000-0000-0000-000000000194", + }, + "messageExternalId": { + "id": "00000000-0000-0000-0000-000000000196", + }, + "messageThread": { + "id": "00000000-0000-0000-0000-000000000197", + }, + "messageThreadExternalId": { + "id": "00000000-0000-0000-0000-000000000198", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000192", + }, }, - "id": "00000000-0000-0000-0000-000000000199", + "id": "00000000-0000-0000-0000-000000000200", "views": undefined, }, "messageFolder": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000225", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000227", - }, - "externalId": { - "id": "00000000-0000-0000-0000-000000000234", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000224", - }, - "isSentFolder": { - "id": "00000000-0000-0000-0000-000000000232", - }, - "isSynced": { - "id": "00000000-0000-0000-0000-000000000233", - }, - "messageChannel": { - "id": "00000000-0000-0000-0000-000000000230", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000228", - }, - "parentFolderId": { - "id": "00000000-0000-0000-0000-000000000229", - }, - "pendingSyncAction": { - "id": "00000000-0000-0000-0000-000000000235", - }, - "syncCursor": { - "id": "00000000-0000-0000-0000-000000000231", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000226", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000228", + }, + "externalId": { + "id": "00000000-0000-0000-0000-000000000235", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000225", + }, + "isSentFolder": { + "id": "00000000-0000-0000-0000-000000000233", + }, + "isSynced": { + "id": "00000000-0000-0000-0000-000000000234", + }, + "messageChannel": { + "id": "00000000-0000-0000-0000-000000000231", + }, + "name": { + "id": "00000000-0000-0000-0000-000000000229", + }, + "parentFolderId": { + "id": "00000000-0000-0000-0000-000000000230", + }, + "pendingSyncAction": { + "id": "00000000-0000-0000-0000-000000000236", + }, + "syncCursor": { + "id": "00000000-0000-0000-0000-000000000232", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000227", + }, }, - "id": "00000000-0000-0000-0000-000000000236", + "id": "00000000-0000-0000-0000-000000000237", "views": undefined, }, "messageParticipant": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000238", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000240", - }, - "displayName": { - "id": "00000000-0000-0000-0000-000000000244", - }, - "handle": { - "id": "00000000-0000-0000-0000-000000000243", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000237", - }, - "message": { - "id": "00000000-0000-0000-0000-000000000241", - }, - "person": { - "id": "00000000-0000-0000-0000-000000000245", - }, - "role": { - "id": "00000000-0000-0000-0000-000000000242", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000239", }, - "workspaceMember": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000241", + }, + "displayName": { + "id": "00000000-0000-0000-0000-000000000245", + }, + "handle": { + "id": "00000000-0000-0000-0000-000000000244", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000238", + }, + "message": { + "id": "00000000-0000-0000-0000-000000000242", + }, + "person": { "id": "00000000-0000-0000-0000-000000000246", }, + "role": { + "id": "00000000-0000-0000-0000-000000000243", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000240", + }, + "workspaceMember": { + "id": "00000000-0000-0000-0000-000000000247", + }, }, - "id": "00000000-0000-0000-0000-000000000247", + "id": "00000000-0000-0000-0000-000000000248", "views": undefined, }, "messageThread": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000249", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000251", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000248", - }, - "messageChannelMessageAssociations": { - "id": "00000000-0000-0000-0000-000000000253", - }, - "messages": { - "id": "00000000-0000-0000-0000-000000000252", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000250", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000252", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000249", + }, + "messageChannelMessageAssociations": { + "id": "00000000-0000-0000-0000-000000000254", + }, + "messages": { + "id": "00000000-0000-0000-0000-000000000253", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000251", + }, }, - "id": "00000000-0000-0000-0000-000000000257", + "id": "00000000-0000-0000-0000-000000000258", "views": { "allMessageThreads": { - "id": "00000000-0000-0000-0000-000000000256", + "id": "00000000-0000-0000-0000-000000000257", "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000255", + "id": "00000000-0000-0000-0000-000000000256", }, "messages": { - "id": "00000000-0000-0000-0000-000000000254", + "id": "00000000-0000-0000-0000-000000000255", }, }, "viewGroups": {}, @@ -910,67 +913,67 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "note": { "fields": { "attachments": { - "id": "00000000-0000-0000-0000-000000000289", - }, - "bodyV2": { - "id": "00000000-0000-0000-0000-000000000285", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000280", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000286", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000282", - }, - "favorites": { - "id": "00000000-0000-0000-0000-000000000291", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000279", - }, - "noteTargets": { - "id": "00000000-0000-0000-0000-000000000288", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000283", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000292", - }, - "timelineActivities": { "id": "00000000-0000-0000-0000-000000000290", }, - "title": { - "id": "00000000-0000-0000-0000-000000000284", + "bodyV2": { + "id": "00000000-0000-0000-0000-000000000286", }, - "updatedAt": { + "createdAt": { "id": "00000000-0000-0000-0000-000000000281", }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000287", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000283", + }, + "favorites": { + "id": "00000000-0000-0000-0000-000000000292", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000280", + }, + "noteTargets": { + "id": "00000000-0000-0000-0000-000000000289", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000284", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000293", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000291", + }, + "title": { + "id": "00000000-0000-0000-0000-000000000285", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000282", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000288", + }, }, - "id": "00000000-0000-0000-0000-000000000299", + "id": "00000000-0000-0000-0000-000000000300", "views": { "allNotes": { - "id": "00000000-0000-0000-0000-000000000298", + "id": "00000000-0000-0000-0000-000000000299", "viewFields": { "bodyV2": { - "id": "00000000-0000-0000-0000-000000000295", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000297", - }, - "createdBy": { "id": "00000000-0000-0000-0000-000000000296", }, + "createdAt": { + "id": "00000000-0000-0000-0000-000000000298", + }, + "createdBy": { + "id": "00000000-0000-0000-0000-000000000297", + }, "noteTargets": { - "id": "00000000-0000-0000-0000-000000000294", + "id": "00000000-0000-0000-0000-000000000295", }, "title": { - "id": "00000000-0000-0000-0000-000000000293", + "id": "00000000-0000-0000-0000-000000000294", }, }, "viewGroups": {}, @@ -980,160 +983,160 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "noteTarget": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000301", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000303", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000300", - }, - "note": { - "id": "00000000-0000-0000-0000-000000000304", - }, - "targetCompany": { - "id": "00000000-0000-0000-0000-000000000306", - }, - "targetOpportunity": { - "id": "00000000-0000-0000-0000-000000000307", - }, - "targetPerson": { - "id": "00000000-0000-0000-0000-000000000305", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000302", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000304", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000301", + }, + "note": { + "id": "00000000-0000-0000-0000-000000000305", + }, + "targetCompany": { + "id": "00000000-0000-0000-0000-000000000307", + }, + "targetOpportunity": { + "id": "00000000-0000-0000-0000-000000000308", + }, + "targetPerson": { + "id": "00000000-0000-0000-0000-000000000306", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000303", + }, }, - "id": "00000000-0000-0000-0000-000000000308", + "id": "00000000-0000-0000-0000-000000000309", "views": undefined, }, "opportunity": { "fields": { "amount": { - "id": "00000000-0000-0000-0000-000000000314", - }, - "attachments": { - "id": "00000000-0000-0000-0000-000000000326", - }, - "closeDate": { "id": "00000000-0000-0000-0000-000000000315", }, - "company": { - "id": "00000000-0000-0000-0000-000000000321", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000310", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000318", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000312", - }, - "favorites": { - "id": "00000000-0000-0000-0000-000000000323", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000309", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000313", - }, - "noteTargets": { - "id": "00000000-0000-0000-0000-000000000325", - }, - "owner": { - "id": "00000000-0000-0000-0000-000000000322", - }, - "pointOfContact": { - "id": "00000000-0000-0000-0000-000000000320", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000317", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000328", - }, - "stage": { - "id": "00000000-0000-0000-0000-000000000316", - }, - "taskTargets": { - "id": "00000000-0000-0000-0000-000000000324", - }, - "timelineActivities": { + "attachments": { "id": "00000000-0000-0000-0000-000000000327", }, - "updatedAt": { + "closeDate": { + "id": "00000000-0000-0000-0000-000000000316", + }, + "company": { + "id": "00000000-0000-0000-0000-000000000322", + }, + "createdAt": { "id": "00000000-0000-0000-0000-000000000311", }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000319", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000313", + }, + "favorites": { + "id": "00000000-0000-0000-0000-000000000324", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000310", + }, + "name": { + "id": "00000000-0000-0000-0000-000000000314", + }, + "noteTargets": { + "id": "00000000-0000-0000-0000-000000000326", + }, + "owner": { + "id": "00000000-0000-0000-0000-000000000323", + }, + "pointOfContact": { + "id": "00000000-0000-0000-0000-000000000321", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000318", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000329", + }, + "stage": { + "id": "00000000-0000-0000-0000-000000000317", + }, + "taskTargets": { + "id": "00000000-0000-0000-0000-000000000325", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000328", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000312", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000320", + }, }, - "id": "00000000-0000-0000-0000-000000000348", + "id": "00000000-0000-0000-0000-000000000349", "views": { "allOpportunities": { - "id": "00000000-0000-0000-0000-000000000335", + "id": "00000000-0000-0000-0000-000000000336", "viewFields": { "amount": { - "id": "00000000-0000-0000-0000-000000000330", - }, - "closeDate": { - "id": "00000000-0000-0000-0000-000000000332", - }, - "company": { - "id": "00000000-0000-0000-0000-000000000333", - }, - "createdBy": { "id": "00000000-0000-0000-0000-000000000331", }, + "closeDate": { + "id": "00000000-0000-0000-0000-000000000333", + }, + "company": { + "id": "00000000-0000-0000-0000-000000000334", + }, + "createdBy": { + "id": "00000000-0000-0000-0000-000000000332", + }, "name": { - "id": "00000000-0000-0000-0000-000000000329", + "id": "00000000-0000-0000-0000-000000000330", }, "pointOfContact": { - "id": "00000000-0000-0000-0000-000000000334", + "id": "00000000-0000-0000-0000-000000000335", }, }, "viewGroups": {}, }, "byStage": { - "id": "00000000-0000-0000-0000-000000000347", + "id": "00000000-0000-0000-0000-000000000348", "viewFields": { "amount": { - "id": "00000000-0000-0000-0000-000000000337", - }, - "closeDate": { - "id": "00000000-0000-0000-0000-000000000339", - }, - "company": { - "id": "00000000-0000-0000-0000-000000000340", - }, - "createdBy": { "id": "00000000-0000-0000-0000-000000000338", }, + "closeDate": { + "id": "00000000-0000-0000-0000-000000000340", + }, + "company": { + "id": "00000000-0000-0000-0000-000000000341", + }, + "createdBy": { + "id": "00000000-0000-0000-0000-000000000339", + }, "name": { - "id": "00000000-0000-0000-0000-000000000336", + "id": "00000000-0000-0000-0000-000000000337", }, "pointOfContact": { - "id": "00000000-0000-0000-0000-000000000341", + "id": "00000000-0000-0000-0000-000000000342", }, }, "viewGroups": { "customer": { - "id": "00000000-0000-0000-0000-000000000346", + "id": "00000000-0000-0000-0000-000000000347", }, "meeting": { - "id": "00000000-0000-0000-0000-000000000344", - }, - "new": { - "id": "00000000-0000-0000-0000-000000000342", - }, - "proposal": { "id": "00000000-0000-0000-0000-000000000345", }, - "screening": { + "new": { "id": "00000000-0000-0000-0000-000000000343", }, + "proposal": { + "id": "00000000-0000-0000-0000-000000000346", + }, + "screening": { + "id": "00000000-0000-0000-0000-000000000344", + }, }, }, }, @@ -1141,116 +1144,116 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "person": { "fields": { "attachments": { - "id": "00000000-0000-0000-0000-000000000369", - }, - "avatarUrl": { - "id": "00000000-0000-0000-0000-000000000360", - }, - "calendarEventParticipants": { - "id": "00000000-0000-0000-0000-000000000371", - }, - "city": { - "id": "00000000-0000-0000-0000-000000000359", - }, - "company": { - "id": "00000000-0000-0000-0000-000000000364", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000350", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000362", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000352", - }, - "emails": { - "id": "00000000-0000-0000-0000-000000000354", - }, - "favorites": { - "id": "00000000-0000-0000-0000-000000000368", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000349", - }, - "jobTitle": { - "id": "00000000-0000-0000-0000-000000000357", - }, - "linkedinLink": { - "id": "00000000-0000-0000-0000-000000000355", - }, - "messageParticipants": { "id": "00000000-0000-0000-0000-000000000370", }, - "name": { - "id": "00000000-0000-0000-0000-000000000353", - }, - "noteTargets": { - "id": "00000000-0000-0000-0000-000000000367", - }, - "phones": { - "id": "00000000-0000-0000-0000-000000000358", - }, - "pointOfContactForOpportunities": { - "id": "00000000-0000-0000-0000-000000000365", - }, - "position": { + "avatarUrl": { "id": "00000000-0000-0000-0000-000000000361", }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000373", - }, - "taskTargets": { - "id": "00000000-0000-0000-0000-000000000366", - }, - "timelineActivities": { + "calendarEventParticipants": { "id": "00000000-0000-0000-0000-000000000372", }, - "updatedAt": { + "city": { + "id": "00000000-0000-0000-0000-000000000360", + }, + "company": { + "id": "00000000-0000-0000-0000-000000000365", + }, + "createdAt": { "id": "00000000-0000-0000-0000-000000000351", }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000363", }, - "xLink": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000353", + }, + "emails": { + "id": "00000000-0000-0000-0000-000000000355", + }, + "favorites": { + "id": "00000000-0000-0000-0000-000000000369", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000350", + }, + "jobTitle": { + "id": "00000000-0000-0000-0000-000000000358", + }, + "linkedinLink": { "id": "00000000-0000-0000-0000-000000000356", }, + "messageParticipants": { + "id": "00000000-0000-0000-0000-000000000371", + }, + "name": { + "id": "00000000-0000-0000-0000-000000000354", + }, + "noteTargets": { + "id": "00000000-0000-0000-0000-000000000368", + }, + "phones": { + "id": "00000000-0000-0000-0000-000000000359", + }, + "pointOfContactForOpportunities": { + "id": "00000000-0000-0000-0000-000000000366", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000362", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000374", + }, + "taskTargets": { + "id": "00000000-0000-0000-0000-000000000367", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000373", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000352", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000364", + }, + "xLink": { + "id": "00000000-0000-0000-0000-000000000357", + }, }, - "id": "00000000-0000-0000-0000-000000000385", + "id": "00000000-0000-0000-0000-000000000386", "views": { "allPeople": { - "id": "00000000-0000-0000-0000-000000000384", + "id": "00000000-0000-0000-0000-000000000385", "viewFields": { "city": { - "id": "00000000-0000-0000-0000-000000000380", - }, - "company": { - "id": "00000000-0000-0000-0000-000000000377", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000379", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000376", - }, - "emails": { - "id": "00000000-0000-0000-0000-000000000375", - }, - "jobTitle": { "id": "00000000-0000-0000-0000-000000000381", }, - "linkedinLink": { - "id": "00000000-0000-0000-0000-000000000382", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000374", - }, - "phones": { + "company": { "id": "00000000-0000-0000-0000-000000000378", }, - "xLink": { + "createdAt": { + "id": "00000000-0000-0000-0000-000000000380", + }, + "createdBy": { + "id": "00000000-0000-0000-0000-000000000377", + }, + "emails": { + "id": "00000000-0000-0000-0000-000000000376", + }, + "jobTitle": { + "id": "00000000-0000-0000-0000-000000000382", + }, + "linkedinLink": { "id": "00000000-0000-0000-0000-000000000383", }, + "name": { + "id": "00000000-0000-0000-0000-000000000375", + }, + "phones": { + "id": "00000000-0000-0000-0000-000000000379", + }, + "xLink": { + "id": "00000000-0000-0000-0000-000000000384", + }, }, "viewGroups": {}, }, @@ -1259,157 +1262,157 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "task": { "fields": { "assignee": { - "id": "00000000-0000-0000-0000-000000000399", - }, - "attachments": { - "id": "00000000-0000-0000-0000-000000000398", - }, - "bodyV2": { - "id": "00000000-0000-0000-0000-000000000392", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000387", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000395", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000389", - }, - "dueAt": { - "id": "00000000-0000-0000-0000-000000000393", - }, - "favorites": { - "id": "00000000-0000-0000-0000-000000000401", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000386", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000390", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000402", - }, - "status": { - "id": "00000000-0000-0000-0000-000000000394", - }, - "taskTargets": { - "id": "00000000-0000-0000-0000-000000000397", - }, - "timelineActivities": { "id": "00000000-0000-0000-0000-000000000400", }, - "title": { - "id": "00000000-0000-0000-0000-000000000391", + "attachments": { + "id": "00000000-0000-0000-0000-000000000399", }, - "updatedAt": { + "bodyV2": { + "id": "00000000-0000-0000-0000-000000000393", + }, + "createdAt": { "id": "00000000-0000-0000-0000-000000000388", }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000396", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000390", + }, + "dueAt": { + "id": "00000000-0000-0000-0000-000000000394", + }, + "favorites": { + "id": "00000000-0000-0000-0000-000000000402", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000387", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000391", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000403", + }, + "status": { + "id": "00000000-0000-0000-0000-000000000395", + }, + "taskTargets": { + "id": "00000000-0000-0000-0000-000000000398", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000401", + }, + "title": { + "id": "00000000-0000-0000-0000-000000000392", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000389", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000397", + }, }, - "id": "00000000-0000-0000-0000-000000000433", + "id": "00000000-0000-0000-0000-000000000434", "views": { "allTasks": { - "id": "00000000-0000-0000-0000-000000000411", + "id": "00000000-0000-0000-0000-000000000412", "viewFields": { "assignee": { - "id": "00000000-0000-0000-0000-000000000408", - }, - "bodyV2": { "id": "00000000-0000-0000-0000-000000000409", }, - "createdAt": { + "bodyV2": { "id": "00000000-0000-0000-0000-000000000410", }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000406", + "createdAt": { + "id": "00000000-0000-0000-0000-000000000411", }, - "dueAt": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000407", }, - "status": { - "id": "00000000-0000-0000-0000-000000000404", + "dueAt": { + "id": "00000000-0000-0000-0000-000000000408", }, - "taskTargets": { + "status": { "id": "00000000-0000-0000-0000-000000000405", }, + "taskTargets": { + "id": "00000000-0000-0000-0000-000000000406", + }, "title": { - "id": "00000000-0000-0000-0000-000000000403", + "id": "00000000-0000-0000-0000-000000000404", }, }, "viewGroups": {}, }, "assignedToMe": { - "id": "00000000-0000-0000-0000-000000000423", + "id": "00000000-0000-0000-0000-000000000424", "viewFields": { "assignee": { - "id": "00000000-0000-0000-0000-000000000416", - }, - "bodyV2": { "id": "00000000-0000-0000-0000-000000000417", }, - "createdAt": { + "bodyV2": { "id": "00000000-0000-0000-0000-000000000418", }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000414", + "createdAt": { + "id": "00000000-0000-0000-0000-000000000419", }, - "dueAt": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000415", }, + "dueAt": { + "id": "00000000-0000-0000-0000-000000000416", + }, "taskTargets": { - "id": "00000000-0000-0000-0000-000000000413", + "id": "00000000-0000-0000-0000-000000000414", }, "title": { - "id": "00000000-0000-0000-0000-000000000412", + "id": "00000000-0000-0000-0000-000000000413", }, }, "viewGroups": { "done": { - "id": "00000000-0000-0000-0000-000000000421", - }, - "empty": { "id": "00000000-0000-0000-0000-000000000422", }, + "empty": { + "id": "00000000-0000-0000-0000-000000000423", + }, "inProgress": { - "id": "00000000-0000-0000-0000-000000000420", + "id": "00000000-0000-0000-0000-000000000421", }, "todo": { - "id": "00000000-0000-0000-0000-000000000419", + "id": "00000000-0000-0000-0000-000000000420", }, }, }, "byStatus": { - "id": "00000000-0000-0000-0000-000000000432", + "id": "00000000-0000-0000-0000-000000000433", "viewFields": { "assignee": { - "id": "00000000-0000-0000-0000-000000000427", - }, - "createdAt": { "id": "00000000-0000-0000-0000-000000000428", }, + "createdAt": { + "id": "00000000-0000-0000-0000-000000000429", + }, "dueAt": { - "id": "00000000-0000-0000-0000-000000000426", + "id": "00000000-0000-0000-0000-000000000427", }, "status": { - "id": "00000000-0000-0000-0000-000000000425", + "id": "00000000-0000-0000-0000-000000000426", }, "title": { - "id": "00000000-0000-0000-0000-000000000424", + "id": "00000000-0000-0000-0000-000000000425", }, }, "viewGroups": { "done": { - "id": "00000000-0000-0000-0000-000000000431", + "id": "00000000-0000-0000-0000-000000000432", }, "inProgress": { - "id": "00000000-0000-0000-0000-000000000430", + "id": "00000000-0000-0000-0000-000000000431", }, "todo": { - "id": "00000000-0000-0000-0000-000000000429", + "id": "00000000-0000-0000-0000-000000000430", }, }, }, @@ -1418,116 +1421,116 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "taskTarget": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000435", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000437", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000434", - }, - "targetCompany": { - "id": "00000000-0000-0000-0000-000000000440", - }, - "targetOpportunity": { - "id": "00000000-0000-0000-0000-000000000441", - }, - "targetPerson": { - "id": "00000000-0000-0000-0000-000000000439", - }, - "task": { - "id": "00000000-0000-0000-0000-000000000438", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000436", }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000438", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000435", + }, + "targetCompany": { + "id": "00000000-0000-0000-0000-000000000441", + }, + "targetOpportunity": { + "id": "00000000-0000-0000-0000-000000000442", + }, + "targetPerson": { + "id": "00000000-0000-0000-0000-000000000440", + }, + "task": { + "id": "00000000-0000-0000-0000-000000000439", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000437", + }, }, - "id": "00000000-0000-0000-0000-000000000442", + "id": "00000000-0000-0000-0000-000000000443", "views": undefined, }, "timelineActivity": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000444", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000446", - }, - "happensAt": { - "id": "00000000-0000-0000-0000-000000000447", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000443", - }, - "linkedObjectMetadataId": { - "id": "00000000-0000-0000-0000-000000000462", - }, - "linkedRecordCachedName": { - "id": "00000000-0000-0000-0000-000000000460", - }, - "linkedRecordId": { - "id": "00000000-0000-0000-0000-000000000461", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000448", - }, - "properties": { - "id": "00000000-0000-0000-0000-000000000449", - }, - "targetCompany": { - "id": "00000000-0000-0000-0000-000000000452", - }, - "targetDashboard": { - "id": "00000000-0000-0000-0000-000000000459", - }, - "targetNote": { - "id": "00000000-0000-0000-0000-000000000455", - }, - "targetOpportunity": { - "id": "00000000-0000-0000-0000-000000000453", - }, - "targetPerson": { - "id": "00000000-0000-0000-0000-000000000451", - }, - "targetTask": { - "id": "00000000-0000-0000-0000-000000000454", - }, - "targetWorkflow": { - "id": "00000000-0000-0000-0000-000000000456", - }, - "targetWorkflowRun": { - "id": "00000000-0000-0000-0000-000000000458", - }, - "targetWorkflowVersion": { - "id": "00000000-0000-0000-0000-000000000457", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000445", }, - "workspaceMember": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000447", + }, + "happensAt": { + "id": "00000000-0000-0000-0000-000000000448", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000444", + }, + "linkedObjectMetadataId": { + "id": "00000000-0000-0000-0000-000000000463", + }, + "linkedRecordCachedName": { + "id": "00000000-0000-0000-0000-000000000461", + }, + "linkedRecordId": { + "id": "00000000-0000-0000-0000-000000000462", + }, + "name": { + "id": "00000000-0000-0000-0000-000000000449", + }, + "properties": { "id": "00000000-0000-0000-0000-000000000450", }, + "targetCompany": { + "id": "00000000-0000-0000-0000-000000000453", + }, + "targetDashboard": { + "id": "00000000-0000-0000-0000-000000000460", + }, + "targetNote": { + "id": "00000000-0000-0000-0000-000000000456", + }, + "targetOpportunity": { + "id": "00000000-0000-0000-0000-000000000454", + }, + "targetPerson": { + "id": "00000000-0000-0000-0000-000000000452", + }, + "targetTask": { + "id": "00000000-0000-0000-0000-000000000455", + }, + "targetWorkflow": { + "id": "00000000-0000-0000-0000-000000000457", + }, + "targetWorkflowRun": { + "id": "00000000-0000-0000-0000-000000000459", + }, + "targetWorkflowVersion": { + "id": "00000000-0000-0000-0000-000000000458", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000446", + }, + "workspaceMember": { + "id": "00000000-0000-0000-0000-000000000451", + }, }, - "id": "00000000-0000-0000-0000-000000000469", + "id": "00000000-0000-0000-0000-000000000470", "views": { "allTimelineActivities": { - "id": "00000000-0000-0000-0000-000000000468", + "id": "00000000-0000-0000-0000-000000000469", "viewFields": { "happensAt": { - "id": "00000000-0000-0000-0000-000000000464", - }, - "linkedRecordCachedName": { - "id": "00000000-0000-0000-0000-000000000467", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000463", - }, - "properties": { "id": "00000000-0000-0000-0000-000000000465", }, - "workspaceMember": { + "linkedRecordCachedName": { + "id": "00000000-0000-0000-0000-000000000468", + }, + "name": { + "id": "00000000-0000-0000-0000-000000000464", + }, + "properties": { "id": "00000000-0000-0000-0000-000000000466", }, + "workspaceMember": { + "id": "00000000-0000-0000-0000-000000000467", + }, }, "viewGroups": {}, }, @@ -1536,79 +1539,79 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workflow": { "fields": { "attachments": { - "id": "00000000-0000-0000-0000-000000000483", - }, - "automatedTriggers": { - "id": "00000000-0000-0000-0000-000000000480", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000471", - }, - "createdBy": { "id": "00000000-0000-0000-0000-000000000484", }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000473", - }, - "favorites": { + "automatedTriggers": { "id": "00000000-0000-0000-0000-000000000481", }, - "id": { - "id": "00000000-0000-0000-0000-000000000470", - }, - "lastPublishedVersionId": { - "id": "00000000-0000-0000-0000-000000000475", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000474", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000477", - }, - "runs": { - "id": "00000000-0000-0000-0000-000000000479", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000486", - }, - "statuses": { - "id": "00000000-0000-0000-0000-000000000476", - }, - "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000482", - }, - "updatedAt": { + "createdAt": { "id": "00000000-0000-0000-0000-000000000472", }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000485", }, - "versions": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000474", + }, + "favorites": { + "id": "00000000-0000-0000-0000-000000000482", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000471", + }, + "lastPublishedVersionId": { + "id": "00000000-0000-0000-0000-000000000476", + }, + "name": { + "id": "00000000-0000-0000-0000-000000000475", + }, + "position": { "id": "00000000-0000-0000-0000-000000000478", }, + "runs": { + "id": "00000000-0000-0000-0000-000000000480", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000487", + }, + "statuses": { + "id": "00000000-0000-0000-0000-000000000477", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000483", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000473", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000486", + }, + "versions": { + "id": "00000000-0000-0000-0000-000000000479", + }, }, - "id": "00000000-0000-0000-0000-000000000494", + "id": "00000000-0000-0000-0000-000000000495", "views": { "allWorkflows": { - "id": "00000000-0000-0000-0000-000000000493", + "id": "00000000-0000-0000-0000-000000000494", "viewFields": { "createdBy": { - "id": "00000000-0000-0000-0000-000000000490", + "id": "00000000-0000-0000-0000-000000000491", }, "name": { - "id": "00000000-0000-0000-0000-000000000487", - }, - "runs": { - "id": "00000000-0000-0000-0000-000000000492", - }, - "statuses": { "id": "00000000-0000-0000-0000-000000000488", }, - "updatedAt": { + "runs": { + "id": "00000000-0000-0000-0000-000000000493", + }, + "statuses": { "id": "00000000-0000-0000-0000-000000000489", }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000490", + }, "versions": { - "id": "00000000-0000-0000-0000-000000000491", + "id": "00000000-0000-0000-0000-000000000492", }, }, "viewGroups": {}, @@ -1618,115 +1621,115 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workflowAutomatedTrigger": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000496", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000498", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000495", - }, - "settings": { - "id": "00000000-0000-0000-0000-000000000500", - }, - "type": { - "id": "00000000-0000-0000-0000-000000000499", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000497", }, - "workflow": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000499", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000496", + }, + "settings": { "id": "00000000-0000-0000-0000-000000000501", }, + "type": { + "id": "00000000-0000-0000-0000-000000000500", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000498", + }, + "workflow": { + "id": "00000000-0000-0000-0000-000000000502", + }, }, - "id": "00000000-0000-0000-0000-000000000502", + "id": "00000000-0000-0000-0000-000000000503", "views": undefined, }, "workflowRun": { "fields": { "context": { - "id": "00000000-0000-0000-0000-000000000518", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000504", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000515", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000506", - }, - "endedAt": { - "id": "00000000-0000-0000-0000-000000000512", - }, - "enqueuedAt": { - "id": "00000000-0000-0000-0000-000000000510", - }, - "favorites": { - "id": "00000000-0000-0000-0000-000000000520", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000503", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000507", - }, - "output": { - "id": "00000000-0000-0000-0000-000000000517", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000514", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000522", - }, - "startedAt": { - "id": "00000000-0000-0000-0000-000000000511", - }, - "state": { "id": "00000000-0000-0000-0000-000000000519", }, - "status": { - "id": "00000000-0000-0000-0000-000000000513", - }, - "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000521", - }, - "updatedAt": { + "createdAt": { "id": "00000000-0000-0000-0000-000000000505", }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000516", }, - "workflow": { - "id": "00000000-0000-0000-0000-000000000509", + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000507", }, - "workflowVersion": { + "endedAt": { + "id": "00000000-0000-0000-0000-000000000513", + }, + "enqueuedAt": { + "id": "00000000-0000-0000-0000-000000000511", + }, + "favorites": { + "id": "00000000-0000-0000-0000-000000000521", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000504", + }, + "name": { "id": "00000000-0000-0000-0000-000000000508", }, + "output": { + "id": "00000000-0000-0000-0000-000000000518", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000515", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000523", + }, + "startedAt": { + "id": "00000000-0000-0000-0000-000000000512", + }, + "state": { + "id": "00000000-0000-0000-0000-000000000520", + }, + "status": { + "id": "00000000-0000-0000-0000-000000000514", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000522", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000506", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000517", + }, + "workflow": { + "id": "00000000-0000-0000-0000-000000000510", + }, + "workflowVersion": { + "id": "00000000-0000-0000-0000-000000000509", + }, }, - "id": "00000000-0000-0000-0000-000000000530", + "id": "00000000-0000-0000-0000-000000000531", "views": { "allWorkflowRuns": { - "id": "00000000-0000-0000-0000-000000000529", + "id": "00000000-0000-0000-0000-000000000530", "viewFields": { "createdBy": { - "id": "00000000-0000-0000-0000-000000000527", + "id": "00000000-0000-0000-0000-000000000528", }, "name": { - "id": "00000000-0000-0000-0000-000000000523", - }, - "startedAt": { - "id": "00000000-0000-0000-0000-000000000526", - }, - "status": { - "id": "00000000-0000-0000-0000-000000000525", - }, - "workflow": { "id": "00000000-0000-0000-0000-000000000524", }, + "startedAt": { + "id": "00000000-0000-0000-0000-000000000527", + }, + "status": { + "id": "00000000-0000-0000-0000-000000000526", + }, + "workflow": { + "id": "00000000-0000-0000-0000-000000000525", + }, "workflowVersion": { - "id": "00000000-0000-0000-0000-000000000528", + "id": "00000000-0000-0000-0000-000000000529", }, }, "viewGroups": {}, @@ -1736,67 +1739,67 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workflowVersion": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000532", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000534", - }, - "favorites": { - "id": "00000000-0000-0000-0000-000000000542", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000531", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000535", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000539", - }, - "runs": { - "id": "00000000-0000-0000-0000-000000000540", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000544", - }, - "status": { - "id": "00000000-0000-0000-0000-000000000538", - }, - "steps": { - "id": "00000000-0000-0000-0000-000000000541", - }, - "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000543", - }, - "trigger": { - "id": "00000000-0000-0000-0000-000000000537", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000533", }, - "workflow": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000535", + }, + "favorites": { + "id": "00000000-0000-0000-0000-000000000543", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000532", + }, + "name": { "id": "00000000-0000-0000-0000-000000000536", }, + "position": { + "id": "00000000-0000-0000-0000-000000000540", + }, + "runs": { + "id": "00000000-0000-0000-0000-000000000541", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000545", + }, + "status": { + "id": "00000000-0000-0000-0000-000000000539", + }, + "steps": { + "id": "00000000-0000-0000-0000-000000000542", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000544", + }, + "trigger": { + "id": "00000000-0000-0000-0000-000000000538", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000534", + }, + "workflow": { + "id": "00000000-0000-0000-0000-000000000537", + }, }, - "id": "00000000-0000-0000-0000-000000000551", + "id": "00000000-0000-0000-0000-000000000552", "views": { "allWorkflowVersions": { - "id": "00000000-0000-0000-0000-000000000550", + "id": "00000000-0000-0000-0000-000000000551", "viewFields": { "name": { - "id": "00000000-0000-0000-0000-000000000545", + "id": "00000000-0000-0000-0000-000000000546", }, "runs": { - "id": "00000000-0000-0000-0000-000000000549", + "id": "00000000-0000-0000-0000-000000000550", }, "status": { - "id": "00000000-0000-0000-0000-000000000547", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000548", }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000549", + }, "workflow": { - "id": "00000000-0000-0000-0000-000000000546", + "id": "00000000-0000-0000-0000-000000000547", }, }, "viewGroups": {}, @@ -1806,116 +1809,116 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workspaceMember": { "fields": { "accountOwnerForCompanies": { - "id": "00000000-0000-0000-0000-000000000566", - }, - "assignedTasks": { - "id": "00000000-0000-0000-0000-000000000563", - }, - "avatarUrl": { - "id": "00000000-0000-0000-0000-000000000560", - }, - "blocklist": { - "id": "00000000-0000-0000-0000-000000000569", - }, - "calendarEventParticipants": { - "id": "00000000-0000-0000-0000-000000000570", - }, - "calendarStartDay": { - "id": "00000000-0000-0000-0000-000000000576", - }, - "colorScheme": { - "id": "00000000-0000-0000-0000-000000000558", - }, - "connectedAccounts": { "id": "00000000-0000-0000-0000-000000000567", }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000553", - }, - "dateFormat": { - "id": "00000000-0000-0000-0000-000000000573", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000555", - }, - "favorites": { - "id": "00000000-0000-0000-0000-000000000565", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000552", - }, - "locale": { - "id": "00000000-0000-0000-0000-000000000559", - }, - "messageParticipants": { - "id": "00000000-0000-0000-0000-000000000568", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000557", - }, - "numberFormat": { - "id": "00000000-0000-0000-0000-000000000577", - }, - "ownedOpportunities": { + "assignedTasks": { "id": "00000000-0000-0000-0000-000000000564", }, - "position": { - "id": "00000000-0000-0000-0000-000000000556", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000575", - }, - "timeFormat": { - "id": "00000000-0000-0000-0000-000000000574", - }, - "timeZone": { - "id": "00000000-0000-0000-0000-000000000572", - }, - "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000571", - }, - "updatedAt": { - "id": "00000000-0000-0000-0000-000000000554", - }, - "userEmail": { + "avatarUrl": { "id": "00000000-0000-0000-0000-000000000561", }, - "userId": { + "blocklist": { + "id": "00000000-0000-0000-0000-000000000570", + }, + "calendarEventParticipants": { + "id": "00000000-0000-0000-0000-000000000571", + }, + "calendarStartDay": { + "id": "00000000-0000-0000-0000-000000000577", + }, + "colorScheme": { + "id": "00000000-0000-0000-0000-000000000559", + }, + "connectedAccounts": { + "id": "00000000-0000-0000-0000-000000000568", + }, + "createdAt": { + "id": "00000000-0000-0000-0000-000000000554", + }, + "dateFormat": { + "id": "00000000-0000-0000-0000-000000000574", + }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000556", + }, + "favorites": { + "id": "00000000-0000-0000-0000-000000000566", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000553", + }, + "locale": { + "id": "00000000-0000-0000-0000-000000000560", + }, + "messageParticipants": { + "id": "00000000-0000-0000-0000-000000000569", + }, + "name": { + "id": "00000000-0000-0000-0000-000000000558", + }, + "numberFormat": { + "id": "00000000-0000-0000-0000-000000000578", + }, + "ownedOpportunities": { + "id": "00000000-0000-0000-0000-000000000565", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000557", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000576", + }, + "timeFormat": { + "id": "00000000-0000-0000-0000-000000000575", + }, + "timeZone": { + "id": "00000000-0000-0000-0000-000000000573", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000572", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000555", + }, + "userEmail": { "id": "00000000-0000-0000-0000-000000000562", }, + "userId": { + "id": "00000000-0000-0000-0000-000000000563", + }, }, - "id": "00000000-0000-0000-0000-000000000588", + "id": "00000000-0000-0000-0000-000000000589", "views": { "allWorkspaceMembers": { - "id": "00000000-0000-0000-0000-000000000587", + "id": "00000000-0000-0000-0000-000000000588", "viewFields": { "avatarUrl": { - "id": "00000000-0000-0000-0000-000000000580", - }, - "colorScheme": { "id": "00000000-0000-0000-0000-000000000581", }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000586", - }, - "dateFormat": { - "id": "00000000-0000-0000-0000-000000000584", - }, - "locale": { + "colorScheme": { "id": "00000000-0000-0000-0000-000000000582", }, - "name": { - "id": "00000000-0000-0000-0000-000000000578", + "createdAt": { + "id": "00000000-0000-0000-0000-000000000587", }, - "timeFormat": { + "dateFormat": { "id": "00000000-0000-0000-0000-000000000585", }, - "timeZone": { + "locale": { "id": "00000000-0000-0000-0000-000000000583", }, - "userEmail": { + "name": { "id": "00000000-0000-0000-0000-000000000579", }, + "timeFormat": { + "id": "00000000-0000-0000-0000-000000000586", + }, + "timeZone": { + "id": "00000000-0000-0000-0000-000000000584", + }, + "userEmail": { + "id": "00000000-0000-0000-0000-000000000580", + }, }, "viewGroups": {}, }, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-attachment-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-attachment-standard-flat-field-metadata.util.ts index a3a1dbaf69..065052cb11 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-attachment-standard-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-attachment-standard-flat-field-metadata.util.ts @@ -1,10 +1,10 @@ +import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; import { DateDisplayFormat, FieldMetadataType, RelationOnDeleteAction, RelationType, } from 'twenty-shared/types'; -import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; @@ -126,6 +126,27 @@ export const buildAttachmentStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), + file: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'file', + type: FieldMetadataType.FILES, + label: 'File', + description: 'Attachment file', + icon: 'IconFileUpload', + isNullable: true, + isUIReadOnly: true, + settings: { + maxNumberOfValues: 1, + }, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + //deprecated fullPath: createStandardFieldFlatMetadata({ objectName, workspaceId, @@ -143,6 +164,7 @@ export const buildAttachmentStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), + //deprecated fileCategory: createStandardFieldFlatMetadata({ objectName, workspaceId, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-field-ids.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-field-ids.ts index fffc3b0f4f..04913f104f 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-field-ids.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-field-ids.ts @@ -33,6 +33,7 @@ export const ATTACHMENT_STANDARD_FIELD_IDS = { name: '20202020-87a5-48f8-bbf7-ade388825a57', fullPath: '20202020-0d19-453d-8e8d-fbcda8ca3747', type: '20202020-a417-49b8-a40b-f6a7874caa0d', + file: '20202020-15db-460e-8166-c7b5d87ad4be', fileCategory: '20202020-8c3f-4d9e-9a1b-2e5f7a8c9d0e', createdBy: '395be3bd-a5c9-463d-aafe-9bc3bbec3f15', updatedBy: '376239d1-3e65-4cb6-b5d8-e0917d43cc93', diff --git a/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts b/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts index 34200a08a7..94017b7c64 100644 --- a/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts +++ b/packages/twenty-server/src/modules/attachment/standard-objects/attachment.workspace-entity.ts @@ -1,5 +1,6 @@ import { type ActorMetadata } from 'twenty-shared/types'; +import { type FileOutput } from 'src/engine/api/common/common-args-processors/data-arg-processor/types/file-item.type'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; import { type CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity'; import { type EntityRelation } from 'src/engine/workspace-manager/workspace-migration/types/entity-relation.interface'; @@ -13,10 +14,14 @@ import { type WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standa import { type WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity { + /** @deprecated Use `file[0].label` field instead */ name: string | null; + file: FileOutput[] | null; + /** @deprecated Use `file[0].fileId` field instead */ fullPath: string | null; /** @deprecated Use `fileCategory` field instead */ type: string | null; + /** @deprecated Use `file[0].extension` field instead */ fileCategory: string; createdBy: ActorMetadata; updatedBy: ActorMetadata; diff --git a/packages/twenty-server/test/integration/graphql/suites/files-field/files-field-download.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/files-field/files-field-download.integration-spec.ts index 71eb9100ff..24d6a9b962 100644 --- a/packages/twenty-server/test/integration/graphql/suites/files-field/files-field-download.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/files-field/files-field-download.integration-spec.ts @@ -2,23 +2,13 @@ import gql from 'graphql-tag'; import request from 'supertest'; import { makeGraphqlAPIRequestWithFileUpload } from 'test/integration/graphql/utils/make-graphql-api-request-with-file-upload.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { uploadFilesFieldFileMutation } from 'test/integration/graphql/utils/upload-files-field-file-mutation.util'; import { createOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata.util'; import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util'; import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util'; import { updateOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/update-one-object-metadata.util'; import { FieldMetadataType } from 'twenty-shared/types'; -const uploadWorkspaceFieldFileMutation = gql` - mutation UploadFilesFieldFile($file: Upload!) { - uploadFilesFieldFile(file: $file) { - id - path - size - createdAt - } - } -`; - const deleteFileMutation = gql` mutation DeleteFile($fileId: UUID!) { deleteFile(fileId: $fileId) { @@ -59,33 +49,6 @@ type UploadedFile = { content: string; }; -const uploadFile = async ( - filename: string, - content: string, - contentType: string, -): Promise => { - const response = await makeGraphqlAPIRequestWithFileUpload( - { - query: uploadWorkspaceFieldFileMutation, - variables: { file: null }, - }, - { - field: 'file', - buffer: Buffer.from(content), - filename, - contentType, - }, - ); - - expect(response.body.errors).toBeUndefined(); - - return { - id: response.body.data.uploadFilesFieldFile.id, - contentType, - content, - }; -}; - const deleteFile = async (fileId: string): Promise => { await makeGraphqlAPIRequest({ query: deleteFileMutation, @@ -95,8 +58,36 @@ const deleteFile = async (fileId: string): Promise => { describe('files-field.controller - GET /files-field/:id', () => { let createdObjectMetadataId = ''; + let createdFieldMetadataId = ''; let uploadedFiles: UploadedFile[] = []; + const uploadFile = async ( + filename: string, + content: string, + contentType: string, + ): Promise => { + const response = await makeGraphqlAPIRequestWithFileUpload( + { + query: uploadFilesFieldFileMutation, + variables: { file: null, fieldMetadataId: createdFieldMetadataId }, + }, + { + field: 'file', + buffer: Buffer.from(content), + filename, + contentType, + }, + ); + + expect(response.body.errors).toBeUndefined(); + + return { + id: response.body.data.uploadFilesFieldFile.id, + contentType, + content, + }; + }; + beforeAll(async () => { jest.useRealTimers(); @@ -116,7 +107,9 @@ describe('files-field.controller - GET /files-field/:id', () => { createdObjectMetadataId = objectMetadataId; - await createOneFieldMetadata({ + const { + data: { createOneField: createdFieldMetadata }, + } = await createOneFieldMetadata({ input: { name: 'filesField', label: 'Files Field', @@ -131,6 +124,8 @@ describe('files-field.controller - GET /files-field/:id', () => { type `, }); + + createdFieldMetadataId = createdFieldMetadata.id; }); afterEach(async () => { diff --git a/packages/twenty-server/test/integration/graphql/suites/files-field/files-field-sync.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/files-field/files-field-sync.integration-spec.ts index 463dd8fcdf..63f87eda4b 100644 --- a/packages/twenty-server/test/integration/graphql/suites/files-field/files-field-sync.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/files-field/files-field-sync.integration-spec.ts @@ -1,23 +1,13 @@ import gql from 'graphql-tag'; import { makeGraphqlAPIRequestWithFileUpload } from 'test/integration/graphql/utils/make-graphql-api-request-with-file-upload.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { uploadFilesFieldFileMutation } from 'test/integration/graphql/utils/upload-files-field-file-mutation.util'; import { createOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata.util'; import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util'; import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util'; import { updateOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/update-one-object-metadata.util'; import { FieldMetadataType } from 'twenty-shared/types'; -const uploadWorkspaceFieldFileMutation = gql` - mutation UploadFilesFieldFile($file: Upload!) { - uploadFilesFieldFile(file: $file) { - id - path - size - createdAt - } - } -`; - const deleteFileMutation = gql` mutation DeleteFile($fileId: UUID!) { deleteFile(fileId: $fileId) { @@ -75,32 +65,6 @@ type UploadedFile = { contentType: string; }; -const uploadFile = async ( - filename: string, - content: string, - contentType: string, -): Promise => { - const response = await makeGraphqlAPIRequestWithFileUpload( - { - query: uploadWorkspaceFieldFileMutation, - variables: { file: null }, - }, - { - field: 'file', - buffer: Buffer.from(content), - filename, - contentType, - }, - ); - - expect(response.body.errors).toBeUndefined(); - - return { - id: response.body.data.uploadFilesFieldFile.id, - contentType, - }; -}; - const deleteFile = async (fileId: string): Promise => { await makeGraphqlAPIRequest({ query: deleteFileMutation, @@ -110,8 +74,35 @@ const deleteFile = async (fileId: string): Promise => { describe('fileFieldSync - FILES field <> files sync', () => { let createdObjectMetadataId = ''; + let createdFieldMetadataId = ''; let uploadedFiles: UploadedFile[] = []; + const uploadFile = async ( + filename: string, + content: string, + contentType: string, + ): Promise => { + const response = await makeGraphqlAPIRequestWithFileUpload( + { + query: uploadFilesFieldFileMutation, + variables: { file: null, fieldMetadataId: createdFieldMetadataId }, + }, + { + field: 'file', + buffer: Buffer.from(content), + filename, + contentType, + }, + ); + + expect(response.body.errors).toBeUndefined(); + + return { + id: response.body.data.uploadFilesFieldFile.id, + contentType, + }; + }; + const checkFileExistsInDB = async (fileId: string): Promise => { const result = await global.testDataSource.query( 'SELECT id FROM core."file" WHERE id = $1 AND "deletedAt" IS NULL', @@ -168,7 +159,11 @@ describe('fileFieldSync - FILES field <> files sync', () => { createdObjectMetadataId = objectMetadataId; - await createOneFieldMetadata({ + const { + data: { + createOneField: { id: fieldMetadataId }, + }, + } = await createOneFieldMetadata({ input: { name: 'filesField', label: 'Files Field', @@ -183,6 +178,8 @@ describe('fileFieldSync - FILES field <> files sync', () => { type `, }); + + createdFieldMetadataId = fieldMetadataId; }); afterEach(async () => { diff --git a/packages/twenty-server/test/integration/graphql/suites/files-field/upload-files-field-file.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/files-field/upload-files-field-file.integration-spec.ts index 4e0c0f9333..e69ba651b6 100644 --- a/packages/twenty-server/test/integration/graphql/suites/files-field/upload-files-field-file.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/files-field/upload-files-field-file.integration-spec.ts @@ -1,18 +1,12 @@ import gql from 'graphql-tag'; import { makeGraphqlAPIRequestWithFileUpload } from 'test/integration/graphql/utils/make-graphql-api-request-with-file-upload.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { FileFolder } from 'twenty-shared/types'; - -const uploadFilesFieldFileMutation = gql` - mutation uploadFilesFieldFile($file: Upload!) { - uploadFilesFieldFile(file: $file) { - id - path - size - createdAt - } - } -`; +import { uploadFilesFieldFileMutation } from 'test/integration/graphql/utils/upload-files-field-file-mutation.util'; +import { createOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata.util'; +import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util'; +import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util'; +import { updateOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/update-one-object-metadata.util'; +import { FieldMetadataType, FileFolder } from 'twenty-shared/types'; const deleteFileMutation = gql` mutation DeleteFile($fileId: UUID!) { @@ -23,10 +17,61 @@ const deleteFileMutation = gql` `; describe('uploadFilesFieldFile', () => { + let createdObjectMetadataId: string; + let createdFieldMetadataId: string; let uploadedFileId: string | null = null; - beforeAll(() => { + const getFieldMetadataUniversalIdentifier = async ( + fieldMetadataId: string, + ): Promise => { + const result = await global.testDataSource.query( + 'SELECT "universalIdentifier" FROM core."fieldMetadata" WHERE id = $1', + [fieldMetadataId], + ); + + return result[0].universalIdentifier; + }; + + beforeAll(async () => { jest.useRealTimers(); + + const { + data: { + createOneObject: { id: objectMetadataId }, + }, + } = await createOneObjectMetadata({ + input: { + nameSingular: 'uploadTestObject', + namePlural: 'uploadTestObjects', + labelSingular: 'Upload Test Object', + labelPlural: 'Upload Test Objects', + icon: 'IconFile', + }, + }); + + createdObjectMetadataId = objectMetadataId; + + const { + data: { + createOneField: { id: fieldMetadataId }, + }, + } = await createOneFieldMetadata({ + input: { + name: 'filesField', + label: 'Files Field', + type: FieldMetadataType.FILES, + objectMetadataId: createdObjectMetadataId, + settings: { maxNumberOfValues: 5 }, + }, + gqlFields: ` + id + name + label + type + `, + }); + + createdFieldMetadataId = fieldMetadataId; }); afterAll(async () => { @@ -36,6 +81,20 @@ describe('uploadFilesFieldFile', () => { variables: { fileId: uploadedFileId }, }); } + + await updateOneObjectMetadata({ + expectToFail: false, + input: { + idToUpdate: createdObjectMetadataId, + updatePayload: { + isActive: false, + }, + }, + }); + await deleteOneObjectMetadata({ + input: { idToDelete: createdObjectMetadataId }, + }); + jest.useFakeTimers(); }); @@ -47,7 +106,10 @@ describe('uploadFilesFieldFile', () => { const response = await makeGraphqlAPIRequestWithFileUpload( { query: uploadFilesFieldFileMutation, - variables: { file: null }, + variables: { + file: null, + fieldMetadataId: createdFieldMetadataId, + }, }, { field: 'file', @@ -69,6 +131,12 @@ describe('uploadFilesFieldFile', () => { expect(fileResult.path).toBeDefined(); expect(typeof fileResult.path).toBe('string'); expect(fileResult.path).toContain(FileFolder.FilesField); + + const fieldUniversalIdentifier = await getFieldMetadataUniversalIdentifier( + createdFieldMetadataId, + ); + + expect(fileResult.path).toContain(fieldUniversalIdentifier); expect(fileResult.size).toBe(testFileContent.length); expect(fileResult.createdAt).toBeDefined(); diff --git a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util.ts b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util.ts index 726420ca6a..5c01ba6dd8 100644 --- a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util.ts +++ b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util.ts @@ -1,11 +1,11 @@ -import gql from 'graphql-tag'; import { getFieldMetadataCreationInputs } from 'test/integration/graphql/suites/inputs-validation/utils/get-field-metadata-creation-inputs.util'; import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; import { makeGraphqlAPIRequestWithFileUpload } from 'test/integration/graphql/utils/make-graphql-api-request-with-file-upload.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { uploadFilesFieldFileMutation } from 'test/integration/graphql/utils/upload-files-field-file-mutation.util'; import { createOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata.util'; import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util'; -import { RelationType } from 'twenty-shared/types'; +import { FieldMetadataType, RelationType } from 'twenty-shared/types'; import { computeMorphRelationFieldName } from 'twenty-shared/utils'; import { v4 } from 'uuid'; @@ -28,17 +28,6 @@ export const TEST_UUID_FIELD_VALUE = '20202020-b21e-4ec2-873b-de4264d89025'; export const TEST_TARGET_OBJECT_RECORD_ID_FIELD_VALUE = '20202020-b21e-4ec2-873b-de4264d89021'; -const uploadFilesFieldFileMutation = gql` - mutation UploadFilesFieldFile($file: Upload!) { - uploadFilesFieldFile(file: $file) { - id - path - size - createdAt - } - } -`; - export const joinColumnNameForManyToOneMorphRelationField1 = computeMorphRelationFieldName({ fieldName: 'manyToOneMorphRelationField', @@ -91,10 +80,17 @@ export const setupTestObjectsWithAllFieldTypes = async ( targetObjectMetadata2Id, ); + let filesFieldMetadataId: string | undefined; + for (const input of fieldMetadataCreationInputs) { - await createOneFieldMetadata({ + const result = await createOneFieldMetadata({ input, + gqlFields: 'id name type', }); + + if (input.type === FieldMetadataType.FILES) { + filesFieldMetadataId = result.data.createOneField.id; + } } await makeGraphqlAPIRequest( @@ -115,6 +111,10 @@ export const setupTestObjectsWithAllFieldTypes = async ( if (withFilesField) { jest.useRealTimers(); + if (!filesFieldMetadataId) { + throw new Error('FILES field metadata was not created'); + } + const testFileContent = 'Test document content'; const testFileName = 'Document.pdf'; const testMimeType = 'application/pdf'; @@ -122,7 +122,7 @@ export const setupTestObjectsWithAllFieldTypes = async ( const uploadResponse = await makeGraphqlAPIRequestWithFileUpload( { query: uploadFilesFieldFileMutation, - variables: { file: null }, + variables: { file: null, fieldMetadataId: filesFieldMetadataId }, }, { field: 'file', diff --git a/packages/twenty-server/test/integration/graphql/utils/upload-files-field-file-mutation.util.ts b/packages/twenty-server/test/integration/graphql/utils/upload-files-field-file-mutation.util.ts new file mode 100644 index 0000000000..6ee1e02c27 --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/utils/upload-files-field-file-mutation.util.ts @@ -0,0 +1,12 @@ +import gql from 'graphql-tag'; + +export const uploadFilesFieldFileMutation = gql` + mutation UploadFilesFieldFile($file: Upload!, $fieldMetadataId: String!) { + uploadFilesFieldFile(file: $file, fieldMetadataId: $fieldMetadataId) { + id + path + size + createdAt + } + } +`; diff --git a/packages/twenty-shared/src/metadata/standard-object.constant.ts b/packages/twenty-shared/src/metadata/standard-object.constant.ts index af586c862b..8f1effab62 100644 --- a/packages/twenty-shared/src/metadata/standard-object.constant.ts +++ b/packages/twenty-shared/src/metadata/standard-object.constant.ts @@ -19,7 +19,10 @@ export const STANDARD_OBJECTS = { universalIdentifier: '20202020-a01d-4004-9d04-4f8fb16eae5d', }, name: { universalIdentifier: '20202020-87a5-48f8-bbf7-ade388825a57' }, + file: { universalIdentifier: '20202020-15db-460e-8166-c7b5d87ad4be' }, + //deprecated fullPath: { universalIdentifier: '20202020-0d19-453d-8e8d-fbcda8ca3747' }, + //deprecated fileCategory: { universalIdentifier: '20202020-8c3f-4d9e-9a1b-2e5f7a8c9d0e', }, diff --git a/packages/twenty-ui/src/assets/icons/illustration-file.svg b/packages/twenty-ui/src/assets/icons/illustration-file.svg index 5005f2d576..bd8988c7e5 100644 --- a/packages/twenty-ui/src/assets/icons/illustration-file.svg +++ b/packages/twenty-ui/src/assets/icons/illustration-file.svg @@ -1,4 +1,5 @@ - - - + + + +