Compare commits

...

4 Commits

Author SHA1 Message Date
Etienne fe371eb4c4 fix on field relation preview (#11926)
To reproduce : 
Modify object destination to an object with a 'simple' field as
labelIdentifier from data model settings, during creation of a relation
field from an object which has a composite field as labelIdentifier +
Relation type 'has many'

Fix : 
fieldValue and fieldDefinition does not update at the same time (when
object destination is modified) in RelationToManyFieldDisplay component.
Need to better define recordId to be sure fieldValue doesn't point on
previous record.

Tested : 
Relation field creation from Person with switch on relationType and
objectDestination (company/workspaceMember)
Relation field creation from Company with switch on relationType and
objectDestination (pet/person)
closes https://github.com/twentyhq/twenty/issues/11826
2025-05-07 17:10:41 +02:00
Guillim 1db92ce662 Critical email sync bug (#11885)
Removing the upsert to avoid the ON CONFLICT
2025-05-06 11:22:09 +02:00
prastoin 6bb0212a70 fix(server): upgrade command 2025-05-05 16:48:10 +02:00
Etienne 4a543a0e0a fix relation creation bug (#11848)
Context : In `RelationToOneFieldDisplay`, the `objectNameSingular` used
for the chip calculation was incorrect - it was using the value from the
opposite side of the relationship. Then, labelIdentifier based on
composite fields were causing errors (People and WorkspaceMembers with
name)


<img width="300" alt="Screenshot 2025-05-03 at 08 03 46"
src="https://github.com/user-attachments/assets/8d034700-5244-4b1b-978e-f77ae78b6ceb"
/>


Tested everywhere FieldDisplay is used. 
Tested for each both relation type. 

closes https://github.com/twentyhq/twenty/issues/11826
2025-05-03 08:57:53 +02:00
6 changed files with 52 additions and 30 deletions
@@ -13,7 +13,8 @@ import { isDefined } from 'twenty-shared/utils';
import { pascalCase } from '~/utils/string/pascalCase';
export const RelationFromManyFieldDisplay = () => {
const { fieldValue, fieldDefinition } = useRelationFromManyFieldDisplay();
const { fieldValue, fieldDefinition, generateRecordChipData } =
useRelationFromManyFieldDisplay();
const { isFocused } = useFieldFocus();
const { disableChipClick } = useContext(FieldContext);
@@ -99,14 +100,17 @@ export const RelationFromManyFieldDisplay = () => {
} else {
return (
<ExpandableList isChipCountDisplayed={isFocused}>
{fieldValue.filter(isDefined).map((record) => (
<RecordChip
key={record.id}
objectNameSingular={objectNameSingular}
record={record}
forceDisableClick={disableChipClick}
/>
))}
{fieldValue.filter(isDefined).map((record) => {
const recordChipData = generateRecordChipData(record);
return (
<RecordChip
key={recordChipData.recordId}
objectNameSingular={recordChipData.objectNameSingular}
record={record}
forceDisableClick={disableChipClick}
/>
);
})}
</ExpandableList>
);
}
@@ -60,9 +60,8 @@ export const useRelationFromManyFieldDisplay = () => {
: (record: ObjectRecord) =>
generateDefaultRecordChipData({
record,
// @ts-expect-error Above assertions does not infer that fieldDefinition.metadata.objectMetadataNameSingular always defined
objectNameSingular:
fieldDefinition.metadata.objectMetadataNameSingular,
fieldDefinition.metadata.relationObjectMetadataNameSingular,
});
return {
@@ -60,9 +60,8 @@ export const useRelationToOneFieldDisplay = () => {
: (record: ObjectRecord) =>
generateDefaultRecordChipData({
record,
// @ts-expect-error Above assertions does not infer that fieldDefinition.metadata.objectMetadataNameSingular always defined
objectNameSingular:
fieldDefinition.metadata.objectMetadataNameSingular,
fieldDefinition.metadata.relationObjectMetadataNameSingular,
});
return {
@@ -102,7 +102,7 @@ export const SettingsDataModelFieldPreview = ({
fieldMetadataItem.name || `${fieldMetadataItem.type}-new-field`;
const recordId =
previewRecord?.id ??
`${objectMetadataItem.nameSingular}-${fieldName}-${fieldMetadataItem.relationDefinition?.direction}-preview`;
`${objectMetadataItem.nameSingular}-${fieldName}-${fieldMetadataItem.relationDefinition?.direction}-${relationObjectMetadataItem?.nameSingular}-preview`;
return (
<>
@@ -19,11 +19,11 @@ import { UpdateViewAggregateOperationsCommand } from 'src/database/commands/upgr
import { UpgradeCreatedByEnumCommand } from 'src/database/commands/upgrade-version-command/0-51/0-51-update-workflow-trigger-type-enum.command';
import { MigrateRelationsToFieldMetadataCommand } from 'src/database/commands/upgrade-version-command/0-52/0-52-migrate-relations-to-field-metadata.command';
import { UpgradeDateAndDateTimeFieldsSettingsJsonCommand } from 'src/database/commands/upgrade-version-command/0-52/0-52-upgrade-settings-field';
import { MigrateWorkflowEventListenersToAutomatedTriggersCommand } from 'src/database/commands/upgrade-version-command/0-53/0-53-migrate-workflow-event-listeners-to-automated-triggers.command';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { SyncWorkspaceMetadataCommand } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/sync-workspace-metadata.command';
import { MigrateWorkflowEventListenersToAutomatedTriggersCommand } from 'src/database/commands/upgrade-version-command/0-53/0-53-migrate-workflow-event-listeners-to-automated-triggers.command';
type VersionCommands = {
beforeSyncMetadata: ActiveOrSuspendedWorkspacesMigrationCommandRunner[];
@@ -34,7 +34,7 @@ type VersionCommands = {
description: 'Upgrade workspaces to the latest version',
})
export class UpgradeCommand extends UpgradeCommandRunner {
fromWorkspaceVersion = new SemVer('0.50.0');
fromWorkspaceVersion = new SemVer('0.51.0');
private commands: VersionCommands;
constructor(
@@ -117,7 +117,7 @@ export class UpgradeCommand extends UpgradeCommandRunner {
],
};
this.commands = commands_053;
this.commands = _commands_052;
}
override async runBeforeSyncMetadata(args: RunOnWorkspaceArgs) {
@@ -62,19 +62,39 @@ export class MessagingMessageService {
});
if (existingMessage) {
await messageChannelMessageAssociationRepository.upsert(
{
messageChannelId,
messageId: existingMessage.id,
messageExternalId: message.externalId,
messageThreadExternalId: message.messageThreadExternalId,
},
{
conflictPaths: ['messageChannelId', 'messageId'],
indexPredicate: '"deletedAt" IS NULL',
},
transactionManager,
);
const existingAssociation =
await messageChannelMessageAssociationRepository.findOne(
{
where: {
messageChannelId,
messageId: existingMessage.id,
},
},
transactionManager,
);
if (existingAssociation) {
await messageChannelMessageAssociationRepository.update(
{
id: existingAssociation.id,
},
{
messageExternalId: message.externalId,
messageThreadExternalId: message.messageThreadExternalId,
},
transactionManager,
);
} else {
await messageChannelMessageAssociationRepository.insert(
{
messageChannelId,
messageId: existingMessage.id,
messageExternalId: message.externalId,
messageThreadExternalId: message.messageThreadExternalId,
},
transactionManager,
);
}
continue;
}