Feat/email composer improvements (#23188)
- Move composer to dedicated page - Add test email option - Auto saved as draft can be revisited from `objects/messageCampaigns` later - Campaign stats component https://github.com/user-attachments/assets/9e523116-e79b-496d-9c9d-3887e0c9213f <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/23188?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
+2
@@ -51,6 +51,8 @@ export enum EngineComponentKey {
|
||||
REPLY_TO_EMAIL_THREAD = 'REPLY_TO_EMAIL_THREAD',
|
||||
COMPOSE_EMAIL = 'COMPOSE_EMAIL',
|
||||
COMPOSE_CAMPAIGN = 'COMPOSE_CAMPAIGN',
|
||||
SEND_MESSAGE_CAMPAIGN = 'SEND_MESSAGE_CAMPAIGN',
|
||||
SEND_MESSAGE_CAMPAIGN_TEST = 'SEND_MESSAGE_CAMPAIGN_TEST',
|
||||
|
||||
// TODO: Remove deprecated keys once upgrade:1-21:refactor-navigation-commands has run on all workspaces
|
||||
// Deprecated: replaced by NAVIGATION engine key with payload
|
||||
|
||||
+12
@@ -95,6 +95,12 @@ export class FlatPageLayoutWidgetTypeValidatorService {
|
||||
EMAIL_THREAD: validateSimpleRecordPageWidgetForCreation(
|
||||
WidgetConfigurationType.EMAIL_THREAD,
|
||||
),
|
||||
MESSAGE_CAMPAIGN_BODY: validateSimpleRecordPageWidgetForCreation(
|
||||
WidgetConfigurationType.MESSAGE_CAMPAIGN_BODY,
|
||||
),
|
||||
MESSAGE_CAMPAIGN_DETAILS: validateSimpleRecordPageWidgetForCreation(
|
||||
WidgetConfigurationType.MESSAGE_CAMPAIGN_DETAILS,
|
||||
),
|
||||
};
|
||||
|
||||
private readonly PAGE_LAYOUT_WIDGET_TYPE_VALIDATOR_FOR_UPDATE_HASHMAP: FlatPageLayoutWidgetTypeValidatorForUpdate =
|
||||
@@ -149,6 +155,12 @@ export class FlatPageLayoutWidgetTypeValidatorService {
|
||||
EMAIL_THREAD: validateSimpleRecordPageWidgetForUpdate(
|
||||
WidgetConfigurationType.EMAIL_THREAD,
|
||||
),
|
||||
MESSAGE_CAMPAIGN_BODY: validateSimpleRecordPageWidgetForUpdate(
|
||||
WidgetConfigurationType.MESSAGE_CAMPAIGN_BODY,
|
||||
),
|
||||
MESSAGE_CAMPAIGN_DETAILS: validateSimpleRecordPageWidgetForUpdate(
|
||||
WidgetConfigurationType.MESSAGE_CAMPAIGN_DETAILS,
|
||||
),
|
||||
};
|
||||
|
||||
public validateFlatPageLayoutWidgetTypeSpecificitiesForCreation(
|
||||
|
||||
+2
@@ -376,6 +376,8 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
|
||||
case WidgetConfigurationType.IFRAME:
|
||||
case WidgetConfigurationType.STANDALONE_RICH_TEXT:
|
||||
case WidgetConfigurationType.EMAIL_THREAD:
|
||||
case WidgetConfigurationType.MESSAGE_CAMPAIGN_BODY:
|
||||
case WidgetConfigurationType.MESSAGE_CAMPAIGN_DETAILS:
|
||||
return configuration;
|
||||
}
|
||||
};
|
||||
|
||||
+5
-3
@@ -2,6 +2,7 @@ import { UseGuards, UseInterceptors } from '@nestjs/common';
|
||||
import { Args, Mutation, Parent, Query, ResolveField } from '@nestjs/graphql';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { Not, Repository } from 'typeorm';
|
||||
@@ -13,6 +14,7 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
|
||||
import { AuthUserWorkspaceId } from 'src/engine/decorators/auth/auth-user-workspace-id.decorator';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
|
||||
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { ConnectedAccountMetadataService } from 'src/engine/metadata-modules/connected-account/connected-account-metadata.service';
|
||||
import { ConnectedAccountPublicDTO } from 'src/engine/metadata-modules/connected-account/dtos/connected-account-public.dto';
|
||||
@@ -167,7 +169,7 @@ export class MessageChannelResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => CreateEmailGroupChannelOutput)
|
||||
@UseGuards(NoPermissionGuard)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.WORKSPACE))
|
||||
async createEmailGroupChannel(
|
||||
@Args('input') input: CreateEmailGroupChannelInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
@@ -182,7 +184,7 @@ export class MessageChannelResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => MessageChannelDTO)
|
||||
@UseGuards(NoPermissionGuard)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.WORKSPACE))
|
||||
async updateEmailGroupChannel(
|
||||
@Args('input') input: UpdateEmailGroupChannelInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
@@ -197,7 +199,7 @@ export class MessageChannelResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => MessageChannelDTO)
|
||||
@UseGuards(NoPermissionGuard)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.WORKSPACE))
|
||||
async deleteEmailGroupChannel(
|
||||
@Args('id', { type: () => UUIDScalarType }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
|
||||
+9
@@ -41,6 +41,15 @@ export const messageChannelGraphqlApiExceptionHandler = (error: Error) => {
|
||||
switch (error.code) {
|
||||
case EmailingDomainExceptionCode.EMAILING_DOMAIN_ALREADY_REGISTERED:
|
||||
throw new ConflictError(error);
|
||||
case EmailingDomainExceptionCode.MESSAGE_SUPPRESSION_NOT_FOUND:
|
||||
throw new NotFoundError(error);
|
||||
case EmailingDomainExceptionCode.MESSAGE_SUPPRESSION_NOT_REMOVABLE:
|
||||
throw new ForbiddenError(error);
|
||||
case EmailingDomainExceptionCode.MESSAGE_CAMPAIGN_NOT_FOUND:
|
||||
throw new NotFoundError(error);
|
||||
case EmailingDomainExceptionCode.MESSAGE_CAMPAIGN_NOT_SENDABLE:
|
||||
case EmailingDomainExceptionCode.EMAILING_DOMAIN_NOT_VERIFIED:
|
||||
throw new UserInputError(error);
|
||||
default: {
|
||||
return assertUnreachable(error.code);
|
||||
}
|
||||
|
||||
+4
@@ -1,5 +1,7 @@
|
||||
import { AggregateChartConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/aggregate-chart-configuration.dto';
|
||||
import { EmailThreadConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/email-thread-configuration.dto';
|
||||
import { MessageCampaignBodyConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/message-campaign-body-configuration.dto';
|
||||
import { MessageCampaignDetailsConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/message-campaign-details-configuration.dto';
|
||||
import { BarChartConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/bar-chart-configuration.dto';
|
||||
import { CalendarConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/calendar-configuration.dto';
|
||||
import { EmailsConfigurationDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/emails-configuration.dto';
|
||||
@@ -35,6 +37,8 @@ export const ALL_WIDGET_CONFIGURATION_TYPE_VALIDATOR_BY_WIDGET_CONFIGURATION_TYP
|
||||
FRONT_COMPONENT: FrontComponentConfigurationDTO,
|
||||
EMAILS: EmailsConfigurationDTO,
|
||||
EMAIL_THREAD: EmailThreadConfigurationDTO,
|
||||
MESSAGE_CAMPAIGN_BODY: MessageCampaignBodyConfigurationDTO,
|
||||
MESSAGE_CAMPAIGN_DETAILS: MessageCampaignDetailsConfigurationDTO,
|
||||
FIELD: FieldConfigurationDTO,
|
||||
FIELD_RICH_TEXT: FieldRichTextConfigurationDTO,
|
||||
FIELDS: FieldsConfigurationDTO,
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { IsIn, IsNotEmpty } from 'class-validator';
|
||||
import { type MessageCampaignBodyConfiguration } from 'twenty-shared/types';
|
||||
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
|
||||
@ObjectType('MessageCampaignBodyConfiguration')
|
||||
export class MessageCampaignBodyConfigurationDTO implements MessageCampaignBodyConfiguration {
|
||||
@Field(() => WidgetConfigurationType)
|
||||
@IsIn([WidgetConfigurationType.MESSAGE_CAMPAIGN_BODY])
|
||||
@IsNotEmpty()
|
||||
configurationType: WidgetConfigurationType.MESSAGE_CAMPAIGN_BODY;
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { IsIn, IsNotEmpty } from 'class-validator';
|
||||
import { type MessageCampaignDetailsConfiguration } from 'twenty-shared/types';
|
||||
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
|
||||
@ObjectType('MessageCampaignDetailsConfiguration')
|
||||
export class MessageCampaignDetailsConfigurationDTO implements MessageCampaignDetailsConfiguration {
|
||||
@Field(() => WidgetConfigurationType)
|
||||
@IsIn([WidgetConfigurationType.MESSAGE_CAMPAIGN_DETAILS])
|
||||
@IsNotEmpty()
|
||||
configurationType: WidgetConfigurationType.MESSAGE_CAMPAIGN_DETAILS;
|
||||
}
|
||||
+2
@@ -27,6 +27,8 @@ export enum WidgetConfigurationType {
|
||||
FRONT_COMPONENT = 'FRONT_COMPONENT',
|
||||
RECORD_TABLE = 'RECORD_TABLE',
|
||||
EMAIL_THREAD = 'EMAIL_THREAD',
|
||||
MESSAGE_CAMPAIGN_BODY = 'MESSAGE_CAMPAIGN_BODY',
|
||||
MESSAGE_CAMPAIGN_DETAILS = 'MESSAGE_CAMPAIGN_DETAILS',
|
||||
}
|
||||
export type AllGraphWidgetConfigurationType =
|
||||
| WidgetConfigurationType.AGGREGATE_CHART
|
||||
|
||||
+2
@@ -18,4 +18,6 @@ export enum WidgetType {
|
||||
FRONT_COMPONENT = 'FRONT_COMPONENT',
|
||||
RECORD_TABLE = 'RECORD_TABLE',
|
||||
EMAIL_THREAD = 'EMAIL_THREAD',
|
||||
MESSAGE_CAMPAIGN_BODY = 'MESSAGE_CAMPAIGN_BODY',
|
||||
MESSAGE_CAMPAIGN_DETAILS = 'MESSAGE_CAMPAIGN_DETAILS',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user