Few fixes before release 1.3.0 (#13791)
This commit is contained in:
+2
@@ -17,7 +17,9 @@ type SettingsOptionCardContentSelectProps = {
|
||||
};
|
||||
|
||||
const StyledSelectContainer = styled.div`
|
||||
justify-content: flex-end;
|
||||
margin-left: auto;
|
||||
max-width: 120px;
|
||||
`;
|
||||
|
||||
export const SettingsOptionCardContentSelect = ({
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ export const SettingsDataModelFieldIsUniqueForm = ({
|
||||
<SettingsOptionCardContentSelect
|
||||
Icon={IconKey}
|
||||
title={t`Unique`}
|
||||
description={t`Prevent users from assigining the same value to different records`}
|
||||
description={t`Prevent from assigining the same value to different records`}
|
||||
>
|
||||
<Toggle
|
||||
toggleSize="small"
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import {
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
const isUniqueFieldFormSchema = z.object({
|
||||
isUnique: z.boolean().nullable().optional(),
|
||||
isUnique: z.boolean().nullable().default(false),
|
||||
});
|
||||
|
||||
const booleanFieldFormSchema = z
|
||||
|
||||
-4
@@ -4,7 +4,6 @@ import { z } from 'zod';
|
||||
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/components/SettingsDataModelPreviewFormCard';
|
||||
import { SettingsDataModelFieldIsUniqueForm } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldIsUniqueForm';
|
||||
import {
|
||||
settingsDataModelFieldMultiSelectFormSchema,
|
||||
SettingsDataModelFieldSelectForm,
|
||||
@@ -68,9 +67,6 @@ export const SettingsDataModelFieldSelectSettingsFormCard = ({
|
||||
<SettingsDataModelFieldSelectForm
|
||||
fieldMetadataItem={fieldMetadataItem}
|
||||
/>
|
||||
<SettingsDataModelFieldIsUniqueForm
|
||||
fieldMetadataItem={fieldMetadataItem}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
+4
@@ -6,6 +6,10 @@ import { FieldMetadataType } from 'twenty-shared/types';
|
||||
export const canBeUnique = (
|
||||
field: Pick<FieldMetadataItem, 'type' | 'isCustom'>,
|
||||
) => {
|
||||
if (field.isCustom === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
[FieldMetadataType.MORPH_RELATION, FieldMetadataType.RELATION].includes(
|
||||
field.type,
|
||||
|
||||
+1
@@ -6,6 +6,7 @@ export const fetchMetadataFields = (
|
||||
selector: Selectors,
|
||||
) => {
|
||||
const defaultFields = `
|
||||
id
|
||||
type
|
||||
name
|
||||
label
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import {
|
||||
type BeforeUpdateOneHook,
|
||||
type UpdateOneInputType,
|
||||
} from '@ptc-org/nestjs-query-graphql';
|
||||
import { type APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
import { SOURCE_LOCALE, type APP_LOCALES } from 'twenty-shared/translations';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import {
|
||||
|
||||
+6
@@ -188,6 +188,9 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
throw new FieldMetadataException(
|
||||
'Unique field cannot have a default value',
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
{
|
||||
userFriendlyMessage: t`Unique field cannot have a default value`,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -832,6 +835,9 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
throw new FieldMetadataException(
|
||||
'Unique field cannot have a default value',
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
{
|
||||
userFriendlyMessage: t`Unique field cannot have a default value`,
|
||||
},
|
||||
);
|
||||
|
||||
if (fieldMetadataInput.isUnique !== true) return;
|
||||
|
||||
@@ -34,7 +34,7 @@ export function formatData<T>(
|
||||
|
||||
if (!fieldMetadata) {
|
||||
throw new Error(
|
||||
`Field metadata for field "${key}" is missing in object metadata`,
|
||||
`Field metadata for field "${key}" is missing in object metadata ${objectMetadataItemWithFieldMaps.nameSingular}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+9
-1
@@ -1,4 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { type gmail_v1 as gmailV1 } from 'googleapis';
|
||||
@@ -24,6 +24,7 @@ import { assertNotNull } from 'src/utils/assert';
|
||||
|
||||
@Injectable()
|
||||
export class GmailGetMessageListService {
|
||||
private readonly logger = new Logger(GmailGetMessageListService.name);
|
||||
constructor(
|
||||
private readonly gmailClientProvider: GmailClientProvider,
|
||||
private readonly gmailGetHistoryService: GmailGetHistoryService,
|
||||
@@ -55,6 +56,13 @@ export class GmailGetMessageListService {
|
||||
q: computeGmailCategoryExcludeSearchFilter(excludedCategories),
|
||||
})
|
||||
.catch((error) => {
|
||||
this.logger.error(
|
||||
`Connected account ${connectedAccount.id}: Error fetching message list: ${error.message}`,
|
||||
);
|
||||
this.logger.error(
|
||||
`Connected account ${connectedAccount.id}: Error fetching message list: ${JSON.stringify(error)}`,
|
||||
);
|
||||
|
||||
this.gmailHandleErrorService.handleGmailMessageListFetchError(error);
|
||||
|
||||
return {
|
||||
|
||||
+6
-2
@@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
type PageCollection,
|
||||
PageIterator,
|
||||
type PageCollection,
|
||||
type PageIteratorCallback,
|
||||
} from '@microsoft/microsoft-graph-client';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
@@ -30,6 +30,7 @@ const MESSAGING_MICROSOFT_USERS_MESSAGES_LIST_MAX_RESULT = 999;
|
||||
|
||||
@Injectable()
|
||||
export class MicrosoftGetMessageListService {
|
||||
private readonly logger = new Logger(MicrosoftGetMessageListService.name);
|
||||
constructor(
|
||||
private readonly microsoftClientProvider: MicrosoftClientProvider,
|
||||
private readonly microsoftHandleErrorService: MicrosoftHandleErrorService,
|
||||
@@ -123,6 +124,9 @@ export class MicrosoftGetMessageListService {
|
||||
})
|
||||
.get()
|
||||
.catch((error) => {
|
||||
this.logger.error(
|
||||
`Connected account ${connectedAccount.id}: Error fetching message list: ${JSON.stringify(error)}`,
|
||||
);
|
||||
if (isAccessTokenRefreshingError(error?.body)) {
|
||||
throw new MessageImportDriverException(
|
||||
error.message,
|
||||
|
||||
+61
-66
@@ -45,76 +45,71 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService {
|
||||
|
||||
const workspaceDataSource = await this.twentyORMManager.getDatasource();
|
||||
|
||||
const createdMessagesWithParticipants =
|
||||
await workspaceDataSource?.transaction(
|
||||
async (transactionManager: WorkspaceEntityManager) => {
|
||||
const { messageExternalIdsAndIdsMap, createdMessages } =
|
||||
await this.messageService.saveMessagesWithinTransaction(
|
||||
messagesToSave,
|
||||
messageChannel.id,
|
||||
transactionManager,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
const participantsWithMessageId: (ParticipantWithMessageId & {
|
||||
shouldCreateContact: boolean;
|
||||
})[] = messagesToSave.flatMap((message) => {
|
||||
const messageId = messageExternalIdsAndIdsMap.get(
|
||||
message.externalId,
|
||||
);
|
||||
|
||||
return messageId
|
||||
? message.participants.map((participant: Participant) => {
|
||||
const fromHandle =
|
||||
message.participants.find((p) => p.role === 'from')
|
||||
?.handle || '';
|
||||
|
||||
const isMessageSentByConnectedAccount =
|
||||
handleAliases.includes(fromHandle) ||
|
||||
fromHandle === connectedAccount.handle;
|
||||
|
||||
const isParticipantConnectedAccount =
|
||||
handleAliases.includes(participant.handle) ||
|
||||
participant.handle === connectedAccount.handle;
|
||||
|
||||
const isExcludedByNonProfessionalEmails =
|
||||
messageChannel.excludeNonProfessionalEmails &&
|
||||
!isWorkEmail(participant.handle);
|
||||
|
||||
const isExcludedByGroupEmails =
|
||||
messageChannel.excludeGroupEmails &&
|
||||
isGroupEmail(participant.handle);
|
||||
|
||||
const shouldCreateContact =
|
||||
!!participant.handle &&
|
||||
!isParticipantConnectedAccount &&
|
||||
!isExcludedByNonProfessionalEmails &&
|
||||
!isExcludedByGroupEmails &&
|
||||
(messageChannel.contactAutoCreationPolicy ===
|
||||
MessageChannelContactAutoCreationPolicy.SENT_AND_RECEIVED ||
|
||||
(messageChannel.contactAutoCreationPolicy ===
|
||||
MessageChannelContactAutoCreationPolicy.SENT &&
|
||||
isMessageSentByConnectedAccount));
|
||||
|
||||
return {
|
||||
...participant,
|
||||
messageId,
|
||||
shouldCreateContact,
|
||||
};
|
||||
})
|
||||
: [];
|
||||
});
|
||||
|
||||
await this.messageParticipantService.saveMessageParticipants(
|
||||
participantsWithMessageId,
|
||||
const participantsWithMessageId = await workspaceDataSource?.transaction(
|
||||
async (transactionManager: WorkspaceEntityManager) => {
|
||||
const { messageExternalIdsAndIdsMap } =
|
||||
await this.messageService.saveMessagesWithinTransaction(
|
||||
messagesToSave,
|
||||
messageChannel.id,
|
||||
transactionManager,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
return { participantsWithMessageId, createdMessages };
|
||||
},
|
||||
);
|
||||
const participantsWithMessageId: (ParticipantWithMessageId & {
|
||||
shouldCreateContact: boolean;
|
||||
})[] = messagesToSave.flatMap((message) => {
|
||||
const messageId = messageExternalIdsAndIdsMap.get(message.externalId);
|
||||
|
||||
const { participantsWithMessageId } = createdMessagesWithParticipants;
|
||||
return messageId
|
||||
? message.participants.map((participant: Participant) => {
|
||||
const fromHandle =
|
||||
message.participants.find((p) => p.role === 'from')?.handle ||
|
||||
'';
|
||||
|
||||
const isMessageSentByConnectedAccount =
|
||||
handleAliases.includes(fromHandle) ||
|
||||
fromHandle === connectedAccount.handle;
|
||||
|
||||
const isParticipantConnectedAccount =
|
||||
handleAliases.includes(participant.handle) ||
|
||||
participant.handle === connectedAccount.handle;
|
||||
|
||||
const isExcludedByNonProfessionalEmails =
|
||||
messageChannel.excludeNonProfessionalEmails &&
|
||||
!isWorkEmail(participant.handle);
|
||||
|
||||
const isExcludedByGroupEmails =
|
||||
messageChannel.excludeGroupEmails &&
|
||||
isGroupEmail(participant.handle);
|
||||
|
||||
const shouldCreateContact =
|
||||
!!participant.handle &&
|
||||
!isParticipantConnectedAccount &&
|
||||
!isExcludedByNonProfessionalEmails &&
|
||||
!isExcludedByGroupEmails &&
|
||||
(messageChannel.contactAutoCreationPolicy ===
|
||||
MessageChannelContactAutoCreationPolicy.SENT_AND_RECEIVED ||
|
||||
(messageChannel.contactAutoCreationPolicy ===
|
||||
MessageChannelContactAutoCreationPolicy.SENT &&
|
||||
isMessageSentByConnectedAccount));
|
||||
|
||||
return {
|
||||
...participant,
|
||||
messageId,
|
||||
shouldCreateContact,
|
||||
};
|
||||
})
|
||||
: [];
|
||||
});
|
||||
|
||||
await this.messageParticipantService.saveMessageParticipants(
|
||||
participantsWithMessageId,
|
||||
transactionManager,
|
||||
);
|
||||
|
||||
return participantsWithMessageId;
|
||||
},
|
||||
);
|
||||
|
||||
if (messageChannel.isContactAutoCreationEnabled) {
|
||||
const contactsToCreate = participantsWithMessageId.filter(
|
||||
|
||||
+13
-8
@@ -68,15 +68,20 @@ const filterOutInternals = (
|
||||
}
|
||||
|
||||
const primaryHandleDomain = getDomainNameByEmail(primaryHandle);
|
||||
const isAllHandlesFromSameDomain = message.participants
|
||||
.filter((participant) => !!participant.handle)
|
||||
.every(
|
||||
(participant) =>
|
||||
getDomainNameByEmail(participant.handle) === primaryHandleDomain,
|
||||
);
|
||||
|
||||
if (isAllHandlesFromSameDomain) {
|
||||
return false;
|
||||
try {
|
||||
const isAllHandlesFromSameDomain = message.participants
|
||||
.filter((participant) => !!participant.handle)
|
||||
.every(
|
||||
(participant) =>
|
||||
getDomainNameByEmail(participant.handle) === primaryHandleDomain,
|
||||
);
|
||||
|
||||
if (isAllHandlesFromSameDomain) {
|
||||
return false;
|
||||
}
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user