Revert "feat(messaging): message campaign delivery stats + views
(#22452)"
This reverts commit 2e1117d442.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22627?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. -->
This commit is contained in:
+6
@@ -4,13 +4,16 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { WorkspaceIteratorModule } from 'src/database/commands/command-runners/workspace-iterator.module';
|
||||
import { BackfillWorkspaceCustomApplicationRegistrationCommand } from 'src/database/commands/upgrade-version-command/2-19/2-19-workspace-command-1782853718000-backfill-workspace-custom-application-registration.command';
|
||||
import { BackfillSystemUniqueIndexUniversalIdentifierCommand } from 'src/database/commands/upgrade-version-command/2-19/2-19-workspace-command-1783093620000-backfill-system-unique-index-universal-identifier.command';
|
||||
import { BackfillDeterministicFieldUniversalIdentifiersCommand } from 'src/database/commands/upgrade-version-command/2-19/2-19-workspace-command-1783100000000-backfill-deterministic-field-universal-identifiers.command';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
|
||||
import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/workspace-migration-runner.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -18,16 +21,19 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
|
||||
TypeOrmModule.forFeature([
|
||||
WorkspaceEntity,
|
||||
ApplicationEntity,
|
||||
FieldMetadataEntity,
|
||||
IndexMetadataEntity,
|
||||
]),
|
||||
WorkspaceIteratorModule,
|
||||
WorkspaceCacheModule,
|
||||
WorkspaceMetadataVersionModule,
|
||||
WorkspaceMigrationModule,
|
||||
WorkspaceMigrationRunnerModule,
|
||||
],
|
||||
providers: [
|
||||
BackfillWorkspaceCustomApplicationRegistrationCommand,
|
||||
BackfillSystemUniqueIndexUniversalIdentifierCommand,
|
||||
BackfillDeterministicFieldUniversalIdentifiersCommand,
|
||||
],
|
||||
})
|
||||
export class V2_19_UpgradeVersionCommandModule {}
|
||||
|
||||
+2
-2
@@ -87,9 +87,9 @@ const isMorphOrRelationFieldMetadataType = (type: FieldMetadataType) =>
|
||||
type === FieldMetadataType.RELATION ||
|
||||
type === FieldMetadataType.MORPH_RELATION;
|
||||
|
||||
@RegisteredWorkspaceCommand('2.20.0', 1783100000000)
|
||||
@RegisteredWorkspaceCommand('2.19.0', 1783100000000)
|
||||
@Command({
|
||||
name: 'upgrade:2-20:backfill-deterministic-field-universal-identifiers',
|
||||
name: 'upgrade:2-19:backfill-deterministic-field-universal-identifiers',
|
||||
description:
|
||||
'Recompute the universal identifier of auto-provisioned field metadata (system fields and default relation fields) to the deterministic getFieldUniversalIdentifier derivation.',
|
||||
})
|
||||
+1
-1
@@ -8,7 +8,7 @@ import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/
|
||||
// (the sequence only runs previous + current versions). down() restores it.
|
||||
const TABLES = ['objectMetadata', 'fieldMetadata'] as const;
|
||||
|
||||
@RegisteredInstanceCommand('2.20.0', 1782991100000)
|
||||
@RegisteredInstanceCommand('2.20.0', 1825000000000)
|
||||
export class DropMetadataStandardOverridesColumnFastInstanceCommand
|
||||
implements FastInstanceCommand
|
||||
{
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { WorkspaceIteratorModule } from 'src/database/commands/command-runners/workspace-iterator.module';
|
||||
import { AddMessageCampaignStatFieldsCommand } from 'src/database/commands/upgrade-version-command/2-20/2-20-workspace-command-1783083423000-add-message-campaign-stat-fields.command';
|
||||
import { CreateMessageListViewCommand } from 'src/database/commands/upgrade-version-command/2-20/2-20-workspace-command-1783083423001-create-message-list-view.command';
|
||||
import { BackfillDeterministicFieldUniversalIdentifiersCommand } from 'src/database/commands/upgrade-version-command/2-20/2-20-workspace-command-1783100000000-backfill-deterministic-field-universal-identifiers.command';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
|
||||
import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/workspace-migration-runner.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ApplicationModule,
|
||||
TypeOrmModule.forFeature([ApplicationEntity, FieldMetadataEntity]),
|
||||
WorkspaceIteratorModule,
|
||||
WorkspaceCacheModule,
|
||||
WorkspaceMigrationModule,
|
||||
WorkspaceMigrationRunnerModule,
|
||||
],
|
||||
providers: [
|
||||
AddMessageCampaignStatFieldsCommand,
|
||||
CreateMessageListViewCommand,
|
||||
BackfillDeterministicFieldUniversalIdentifiersCommand,
|
||||
],
|
||||
})
|
||||
export class V2_20_UpgradeVersionCommandModule {}
|
||||
-231
@@ -1,231 +0,0 @@
|
||||
import { Command } from 'nest-commander';
|
||||
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ActiveOrSuspendedWorkspaceCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspace.command-runner';
|
||||
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||
import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspace.command-runner';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { RegisteredWorkspaceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-workspace-command.decorator';
|
||||
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { type TwentyStandardAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/types/twenty-standard-all-flat-entity-maps.type';
|
||||
import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant';
|
||||
import { type WorkspaceCacheDataMap } from 'src/engine/workspace-cache/types/workspace-cache-key.type';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
const CAMPAIGN = STANDARD_OBJECTS.messageCampaign;
|
||||
|
||||
const STAT_FIELD_UNIVERSAL_IDENTIFIERS = [
|
||||
CAMPAIGN.fields.sentCount.universalIdentifier,
|
||||
CAMPAIGN.fields.failedCount.universalIdentifier,
|
||||
CAMPAIGN.fields.bouncedCount.universalIdentifier,
|
||||
CAMPAIGN.fields.complainedCount.universalIdentifier,
|
||||
];
|
||||
|
||||
// The allMessageCampaigns view is introduced by this feature, so existing
|
||||
// workspaces have no messageCampaign view at all. Create the view and every one
|
||||
// of its columns (not just the stat columns) so it materializes end to end.
|
||||
const CAMPAIGN_VIEW_UNIVERSAL_IDENTIFIER =
|
||||
CAMPAIGN.views.allMessageCampaigns.universalIdentifier;
|
||||
|
||||
const CAMPAIGN_VIEW_FIELD_UNIVERSAL_IDENTIFIERS = Object.values(
|
||||
CAMPAIGN.views.allMessageCampaigns.viewFields,
|
||||
).map((viewField) => viewField.universalIdentifier);
|
||||
|
||||
@RegisteredWorkspaceCommand('2.20.0', 1783083423000)
|
||||
@Command({
|
||||
name: 'upgrade:2-20:add-message-campaign-stat-fields',
|
||||
description:
|
||||
'Add the MessageCampaign delivery-stat fields (sent/failed/bounced/complained) and their view columns on existing workspaces',
|
||||
})
|
||||
export class AddMessageCampaignStatFieldsCommand extends ActiveOrSuspendedWorkspaceCommandRunner {
|
||||
constructor(
|
||||
protected readonly workspaceIteratorService: WorkspaceIteratorService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
) {
|
||||
super(workspaceIteratorService);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
const isDryRun = options.dryRun ?? false;
|
||||
|
||||
const {
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatViewMaps,
|
||||
flatViewFieldMaps,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatFieldMetadataMaps',
|
||||
'flatObjectMetadataMaps',
|
||||
'flatViewMaps',
|
||||
'flatViewFieldMaps',
|
||||
]);
|
||||
|
||||
const campaignObjectMetadata =
|
||||
findFlatEntityByUniversalIdentifier<FlatObjectMetadata>({
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
universalIdentifier: CAMPAIGN.universalIdentifier,
|
||||
});
|
||||
|
||||
if (!isDefined(campaignObjectMetadata)) {
|
||||
this.logger.log(
|
||||
`messageCampaign object does not exist for workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const { twentyStandardFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
const { allFlatEntityMaps: standardAllFlatEntityMaps } =
|
||||
computeTwentyStandardApplicationAllFlatEntityMaps({
|
||||
now: new Date().toISOString(),
|
||||
workspaceId,
|
||||
twentyStandardApplicationId: twentyStandardFlatApplication.id,
|
||||
});
|
||||
|
||||
const fieldsToCreate = STAT_FIELD_UNIVERSAL_IDENTIFIERS.filter(
|
||||
(universalIdentifier) =>
|
||||
!isDefined(
|
||||
flatFieldMetadataMaps.byUniversalIdentifier[universalIdentifier],
|
||||
),
|
||||
).map((universalIdentifier) => {
|
||||
const standardField =
|
||||
findFlatEntityByUniversalIdentifier<FlatFieldMetadata>({
|
||||
flatEntityMaps: standardAllFlatEntityMaps.flatFieldMetadataMaps,
|
||||
universalIdentifier,
|
||||
});
|
||||
|
||||
if (!isDefined(standardField)) {
|
||||
throw new Error(
|
||||
`Standard application is missing messageCampaign field ${universalIdentifier}`,
|
||||
);
|
||||
}
|
||||
|
||||
return standardField;
|
||||
});
|
||||
|
||||
const viewsToCreate = this.resolveViewsToCreate({
|
||||
flatViewMaps,
|
||||
standardAllFlatEntityMaps,
|
||||
});
|
||||
|
||||
const viewFieldsToCreate = CAMPAIGN_VIEW_FIELD_UNIVERSAL_IDENTIFIERS.filter(
|
||||
(universalIdentifier) =>
|
||||
!isDefined(flatViewFieldMaps.byUniversalIdentifier[universalIdentifier]),
|
||||
).map((universalIdentifier) => {
|
||||
const standardViewField = findFlatEntityByUniversalIdentifier<FlatViewField>(
|
||||
{
|
||||
flatEntityMaps: standardAllFlatEntityMaps.flatViewFieldMaps,
|
||||
universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (!isDefined(standardViewField)) {
|
||||
throw new Error(
|
||||
`Standard application is missing messageCampaign view column ${universalIdentifier}`,
|
||||
);
|
||||
}
|
||||
|
||||
return standardViewField;
|
||||
});
|
||||
|
||||
const hasMetadataChanges =
|
||||
fieldsToCreate.length > 0 ||
|
||||
viewsToCreate.length > 0 ||
|
||||
viewFieldsToCreate.length > 0;
|
||||
|
||||
if (isDryRun) {
|
||||
this.logger.log(
|
||||
`[DRY RUN] Workspace ${workspaceId}: ${fieldsToCreate.length} field(s), ${viewsToCreate.length} view(s), ${viewFieldsToCreate.length} view column(s)`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasMetadataChanges) {
|
||||
const result =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
isSystemBuild: true,
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
fieldMetadata: {
|
||||
flatEntityToCreate: fieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
view: {
|
||||
flatEntityToCreate: viewsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: viewFieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (result.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to add messageCampaign stat fields:\n${JSON.stringify(result, null, 2)}`,
|
||||
);
|
||||
|
||||
throw new Error(
|
||||
`Failed to add messageCampaign stat fields for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Applied messageCampaign stat fields for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
private resolveViewsToCreate({
|
||||
flatViewMaps,
|
||||
standardAllFlatEntityMaps,
|
||||
}: {
|
||||
flatViewMaps: WorkspaceCacheDataMap['flatViewMaps'];
|
||||
standardAllFlatEntityMaps: TwentyStandardAllFlatEntityMaps;
|
||||
}): FlatView[] {
|
||||
if (
|
||||
isDefined(
|
||||
flatViewMaps.byUniversalIdentifier[CAMPAIGN_VIEW_UNIVERSAL_IDENTIFIER],
|
||||
)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const standardView = findFlatEntityByUniversalIdentifier<FlatView>({
|
||||
flatEntityMaps: standardAllFlatEntityMaps.flatViewMaps,
|
||||
universalIdentifier: CAMPAIGN_VIEW_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
if (!isDefined(standardView)) {
|
||||
throw new Error(
|
||||
`Standard application is missing messageCampaign view ${CAMPAIGN_VIEW_UNIVERSAL_IDENTIFIER}`,
|
||||
);
|
||||
}
|
||||
|
||||
return [standardView];
|
||||
}
|
||||
}
|
||||
-187
@@ -1,187 +0,0 @@
|
||||
import { Command } from 'nest-commander';
|
||||
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ActiveOrSuspendedWorkspaceCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspace.command-runner';
|
||||
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||
import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspace.command-runner';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { RegisteredWorkspaceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-workspace-command.decorator';
|
||||
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { type TwentyStandardAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/types/twenty-standard-all-flat-entity-maps.type';
|
||||
import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant';
|
||||
import { type WorkspaceCacheDataMap } from 'src/engine/workspace-cache/types/workspace-cache-key.type';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
const LIST = STANDARD_OBJECTS.messageList;
|
||||
|
||||
const LIST_VIEW_UNIVERSAL_IDENTIFIER =
|
||||
LIST.views.allMessageLists.universalIdentifier;
|
||||
|
||||
const LIST_VIEW_FIELD_UNIVERSAL_IDENTIFIERS = Object.values(
|
||||
LIST.views.allMessageLists.viewFields,
|
||||
).map((viewField) => viewField.universalIdentifier);
|
||||
|
||||
@RegisteredWorkspaceCommand('2.20.0', 1783083423001)
|
||||
@Command({
|
||||
name: 'upgrade:2-20:create-message-list-view',
|
||||
description:
|
||||
'Create the MessageList standard view and its columns on existing workspaces',
|
||||
})
|
||||
export class CreateMessageListViewCommand extends ActiveOrSuspendedWorkspaceCommandRunner {
|
||||
constructor(
|
||||
protected readonly workspaceIteratorService: WorkspaceIteratorService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
) {
|
||||
super(workspaceIteratorService);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
const isDryRun = options.dryRun ?? false;
|
||||
|
||||
const { flatObjectMetadataMaps, flatViewMaps, flatViewFieldMaps } =
|
||||
await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatViewMaps',
|
||||
'flatViewFieldMaps',
|
||||
]);
|
||||
|
||||
const listObjectMetadata =
|
||||
findFlatEntityByUniversalIdentifier<FlatObjectMetadata>({
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
universalIdentifier: LIST.universalIdentifier,
|
||||
});
|
||||
|
||||
if (!isDefined(listObjectMetadata)) {
|
||||
this.logger.log(
|
||||
`messageList object does not exist for workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const { twentyStandardFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
const { allFlatEntityMaps: standardAllFlatEntityMaps } =
|
||||
computeTwentyStandardApplicationAllFlatEntityMaps({
|
||||
now: new Date().toISOString(),
|
||||
workspaceId,
|
||||
twentyStandardApplicationId: twentyStandardFlatApplication.id,
|
||||
});
|
||||
|
||||
const viewsToCreate = this.resolveViewsToCreate({
|
||||
flatViewMaps,
|
||||
standardAllFlatEntityMaps,
|
||||
});
|
||||
|
||||
const viewFieldsToCreate = LIST_VIEW_FIELD_UNIVERSAL_IDENTIFIERS.filter(
|
||||
(universalIdentifier) =>
|
||||
!isDefined(flatViewFieldMaps.byUniversalIdentifier[universalIdentifier]),
|
||||
).map((universalIdentifier) => {
|
||||
const standardViewField =
|
||||
findFlatEntityByUniversalIdentifier<FlatViewField>({
|
||||
flatEntityMaps: standardAllFlatEntityMaps.flatViewFieldMaps,
|
||||
universalIdentifier,
|
||||
});
|
||||
|
||||
if (!isDefined(standardViewField)) {
|
||||
throw new Error(
|
||||
`Standard application is missing messageList view column ${universalIdentifier}`,
|
||||
);
|
||||
}
|
||||
|
||||
return standardViewField;
|
||||
});
|
||||
|
||||
if (viewsToCreate.length === 0 && viewFieldsToCreate.length === 0) {
|
||||
this.logger.log(
|
||||
`messageList view already exists for workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDryRun) {
|
||||
this.logger.log(
|
||||
`[DRY RUN] Workspace ${workspaceId}: ${viewsToCreate.length} view(s), ${viewFieldsToCreate.length} view column(s)`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const result =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
isSystemBuild: true,
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
view: {
|
||||
flatEntityToCreate: viewsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: viewFieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (result.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to create messageList view:\n${JSON.stringify(result, null, 2)}`,
|
||||
);
|
||||
|
||||
throw new Error(
|
||||
`Failed to create messageList view for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(`Created messageList view for workspace ${workspaceId}`);
|
||||
}
|
||||
|
||||
private resolveViewsToCreate({
|
||||
flatViewMaps,
|
||||
standardAllFlatEntityMaps,
|
||||
}: {
|
||||
flatViewMaps: WorkspaceCacheDataMap['flatViewMaps'];
|
||||
standardAllFlatEntityMaps: TwentyStandardAllFlatEntityMaps;
|
||||
}): FlatView[] {
|
||||
if (
|
||||
isDefined(
|
||||
flatViewMaps.byUniversalIdentifier[LIST_VIEW_UNIVERSAL_IDENTIFIER],
|
||||
)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const standardView = findFlatEntityByUniversalIdentifier<FlatView>({
|
||||
flatEntityMaps: standardAllFlatEntityMaps.flatViewMaps,
|
||||
universalIdentifier: LIST_VIEW_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
if (!isDefined(standardView)) {
|
||||
throw new Error(
|
||||
`Standard application is missing messageList view ${LIST_VIEW_UNIVERSAL_IDENTIFIER}`,
|
||||
);
|
||||
}
|
||||
|
||||
return [standardView];
|
||||
}
|
||||
}
|
||||
-234
@@ -1,234 +0,0 @@
|
||||
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
|
||||
import { type WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||
import { AddMessageCampaignStatFieldsCommand } from 'src/database/commands/upgrade-version-command/2-20/2-20-workspace-command-1783083423000-add-message-campaign-stat-fields.command';
|
||||
import { type ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant';
|
||||
import { type WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { type WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
jest.mock(
|
||||
'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant',
|
||||
);
|
||||
|
||||
const computeTwentyStandardApplicationAllFlatEntityMapsMock =
|
||||
computeTwentyStandardApplicationAllFlatEntityMaps as jest.Mock;
|
||||
|
||||
const WORKSPACE_ID = '20202020-0000-0000-0000-000000000001';
|
||||
const STANDARD_APPLICATION = {
|
||||
id: '20202020-0000-0000-0000-0000000000aa',
|
||||
universalIdentifier: '20202020-0000-0000-0000-0000000000bb',
|
||||
};
|
||||
|
||||
const CAMPAIGN = STANDARD_OBJECTS.messageCampaign;
|
||||
const STAT_FIELD_UNIVERSAL_IDENTIFIERS = [
|
||||
CAMPAIGN.fields.sentCount.universalIdentifier,
|
||||
CAMPAIGN.fields.failedCount.universalIdentifier,
|
||||
CAMPAIGN.fields.bouncedCount.universalIdentifier,
|
||||
CAMPAIGN.fields.complainedCount.universalIdentifier,
|
||||
];
|
||||
const CAMPAIGN_VIEW_UNIVERSAL_IDENTIFIER =
|
||||
CAMPAIGN.views.allMessageCampaigns.universalIdentifier;
|
||||
const CAMPAIGN_VIEW_FIELD_UNIVERSAL_IDENTIFIERS = Object.values(
|
||||
CAMPAIGN.views.allMessageCampaigns.viewFields,
|
||||
).map((viewField) => viewField.universalIdentifier);
|
||||
|
||||
const buildByUniversalIdentifierMap = (universalIdentifiers: string[]) => ({
|
||||
byUniversalIdentifier: Object.fromEntries(
|
||||
universalIdentifiers.map((universalIdentifier) => [
|
||||
universalIdentifier,
|
||||
{ universalIdentifier },
|
||||
]),
|
||||
),
|
||||
});
|
||||
|
||||
describe('AddMessageCampaignStatFieldsCommand', () => {
|
||||
let command: AddMessageCampaignStatFieldsCommand;
|
||||
let findApplicationMock: jest.Mock;
|
||||
let getOrRecomputeMock: jest.Mock;
|
||||
let validateBuildAndRunWorkspaceMigrationMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
findApplicationMock = jest.fn().mockResolvedValue({
|
||||
twentyStandardFlatApplication: STANDARD_APPLICATION,
|
||||
});
|
||||
getOrRecomputeMock = jest.fn();
|
||||
validateBuildAndRunWorkspaceMigrationMock = jest
|
||||
.fn()
|
||||
.mockResolvedValue({ status: 'success' });
|
||||
|
||||
computeTwentyStandardApplicationAllFlatEntityMapsMock.mockReturnValue({
|
||||
allFlatEntityMaps: {
|
||||
flatFieldMetadataMaps: buildByUniversalIdentifierMap(
|
||||
STAT_FIELD_UNIVERSAL_IDENTIFIERS,
|
||||
),
|
||||
flatViewMaps: buildByUniversalIdentifierMap([
|
||||
CAMPAIGN_VIEW_UNIVERSAL_IDENTIFIER,
|
||||
]),
|
||||
flatViewFieldMaps: buildByUniversalIdentifierMap(
|
||||
CAMPAIGN_VIEW_FIELD_UNIVERSAL_IDENTIFIERS,
|
||||
),
|
||||
},
|
||||
});
|
||||
|
||||
command = new AddMessageCampaignStatFieldsCommand(
|
||||
{} as WorkspaceIteratorService,
|
||||
{
|
||||
findWorkspaceTwentyStandardAndCustomApplicationOrThrow:
|
||||
findApplicationMock,
|
||||
} as unknown as ApplicationService,
|
||||
{
|
||||
getOrRecompute: getOrRecomputeMock,
|
||||
} as unknown as WorkspaceCacheService,
|
||||
{
|
||||
validateBuildAndRunWorkspaceMigration:
|
||||
validateBuildAndRunWorkspaceMigrationMock,
|
||||
} as unknown as WorkspaceMigrationValidateBuildAndRunService,
|
||||
);
|
||||
});
|
||||
|
||||
const runOnWorkspace = (dryRun = false) =>
|
||||
command.runOnWorkspace({
|
||||
workspaceId: WORKSPACE_ID,
|
||||
options: { dryRun },
|
||||
index: 0,
|
||||
total: 1,
|
||||
});
|
||||
|
||||
const mockWorkspaceCache = ({
|
||||
existingFields = [],
|
||||
existingViews = [],
|
||||
existingViewFields = [],
|
||||
}: {
|
||||
existingFields?: string[];
|
||||
existingViews?: string[];
|
||||
existingViewFields?: string[];
|
||||
}) => {
|
||||
getOrRecomputeMock.mockResolvedValue({
|
||||
flatObjectMetadataMaps: buildByUniversalIdentifierMap([
|
||||
CAMPAIGN.universalIdentifier,
|
||||
]),
|
||||
flatFieldMetadataMaps: buildByUniversalIdentifierMap(existingFields),
|
||||
flatViewMaps: buildByUniversalIdentifierMap(existingViews),
|
||||
flatViewFieldMaps: buildByUniversalIdentifierMap(existingViewFields),
|
||||
});
|
||||
};
|
||||
|
||||
it('creates missing stat fields, the campaign view, and all campaign view fields', async () => {
|
||||
mockWorkspaceCache({});
|
||||
|
||||
await runOnWorkspace();
|
||||
|
||||
expect(validateBuildAndRunWorkspaceMigrationMock).toHaveBeenCalledWith({
|
||||
isSystemBuild: true,
|
||||
workspaceId: WORKSPACE_ID,
|
||||
applicationUniversalIdentifier: STANDARD_APPLICATION.universalIdentifier,
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
fieldMetadata: {
|
||||
flatEntityToCreate: expect.arrayContaining(
|
||||
STAT_FIELD_UNIVERSAL_IDENTIFIERS.map((universalIdentifier) =>
|
||||
expect.objectContaining({ universalIdentifier }),
|
||||
),
|
||||
),
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
view: {
|
||||
flatEntityToCreate: [
|
||||
expect.objectContaining({
|
||||
universalIdentifier: CAMPAIGN_VIEW_UNIVERSAL_IDENTIFIER,
|
||||
}),
|
||||
],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: expect.arrayContaining(
|
||||
CAMPAIGN_VIEW_FIELD_UNIVERSAL_IDENTIFIERS.map(
|
||||
(universalIdentifier) =>
|
||||
expect.objectContaining({ universalIdentifier }),
|
||||
),
|
||||
),
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
validateBuildAndRunWorkspaceMigrationMock.mock.calls[0][0]
|
||||
.allFlatEntityOperationByMetadataName.fieldMetadata.flatEntityToCreate,
|
||||
).toHaveLength(STAT_FIELD_UNIVERSAL_IDENTIFIERS.length);
|
||||
expect(
|
||||
validateBuildAndRunWorkspaceMigrationMock.mock.calls[0][0]
|
||||
.allFlatEntityOperationByMetadataName.viewField.flatEntityToCreate,
|
||||
).toHaveLength(CAMPAIGN_VIEW_FIELD_UNIVERSAL_IDENTIFIERS.length);
|
||||
});
|
||||
|
||||
it('creates only missing pieces when rerun against a partially migrated workspace', async () => {
|
||||
mockWorkspaceCache({
|
||||
existingFields: [CAMPAIGN.fields.sentCount.universalIdentifier],
|
||||
existingViews: [CAMPAIGN_VIEW_UNIVERSAL_IDENTIFIER],
|
||||
existingViewFields: [
|
||||
CAMPAIGN.views.allMessageCampaigns.viewFields.subject
|
||||
.universalIdentifier,
|
||||
],
|
||||
});
|
||||
|
||||
await runOnWorkspace();
|
||||
|
||||
const payload =
|
||||
validateBuildAndRunWorkspaceMigrationMock.mock.calls[0][0]
|
||||
.allFlatEntityOperationByMetadataName;
|
||||
|
||||
expect(payload.fieldMetadata.flatEntityToCreate).toEqual(
|
||||
expect.arrayContaining(
|
||||
STAT_FIELD_UNIVERSAL_IDENTIFIERS.slice(1).map((universalIdentifier) =>
|
||||
expect.objectContaining({ universalIdentifier }),
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(payload.fieldMetadata.flatEntityToCreate).toHaveLength(
|
||||
STAT_FIELD_UNIVERSAL_IDENTIFIERS.length - 1,
|
||||
);
|
||||
expect(payload.view.flatEntityToCreate).toEqual([]);
|
||||
expect(payload.viewField.flatEntityToCreate).toHaveLength(
|
||||
CAMPAIGN_VIEW_FIELD_UNIVERSAL_IDENTIFIERS.length - 1,
|
||||
);
|
||||
});
|
||||
|
||||
it('skips the metadata migration when everything already exists', async () => {
|
||||
mockWorkspaceCache({
|
||||
existingFields: STAT_FIELD_UNIVERSAL_IDENTIFIERS,
|
||||
existingViews: [CAMPAIGN_VIEW_UNIVERSAL_IDENTIFIER],
|
||||
existingViewFields: CAMPAIGN_VIEW_FIELD_UNIVERSAL_IDENTIFIERS,
|
||||
});
|
||||
|
||||
await runOnWorkspace();
|
||||
|
||||
expect(validateBuildAndRunWorkspaceMigrationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not write metadata in dry-run mode', async () => {
|
||||
mockWorkspaceCache({});
|
||||
|
||||
await runOnWorkspace(true);
|
||||
|
||||
expect(validateBuildAndRunWorkspaceMigrationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('skips workspaces where the messageCampaign object is absent', async () => {
|
||||
getOrRecomputeMock.mockResolvedValue({
|
||||
flatObjectMetadataMaps: buildByUniversalIdentifierMap([]),
|
||||
flatFieldMetadataMaps: buildByUniversalIdentifierMap([]),
|
||||
flatViewMaps: buildByUniversalIdentifierMap([]),
|
||||
flatViewFieldMaps: buildByUniversalIdentifierMap([]),
|
||||
});
|
||||
|
||||
await runOnWorkspace();
|
||||
|
||||
expect(findApplicationMock).not.toHaveBeenCalled();
|
||||
expect(validateBuildAndRunWorkspaceMigrationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
|
||||
import { type WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||
import { CreateMessageListViewCommand } from 'src/database/commands/upgrade-version-command/2-20/2-20-workspace-command-1783083423001-create-message-list-view.command';
|
||||
import { type ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant';
|
||||
import { type WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { type WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
jest.mock(
|
||||
'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant',
|
||||
);
|
||||
|
||||
const computeTwentyStandardApplicationAllFlatEntityMapsMock =
|
||||
computeTwentyStandardApplicationAllFlatEntityMaps as jest.Mock;
|
||||
|
||||
const WORKSPACE_ID = '20202020-0000-0000-0000-000000000001';
|
||||
const STANDARD_APPLICATION = {
|
||||
id: '20202020-0000-0000-0000-0000000000aa',
|
||||
universalIdentifier: '20202020-0000-0000-0000-0000000000bb',
|
||||
};
|
||||
|
||||
const LIST = STANDARD_OBJECTS.messageList;
|
||||
const LIST_VIEW_UNIVERSAL_IDENTIFIER =
|
||||
LIST.views.allMessageLists.universalIdentifier;
|
||||
const LIST_VIEW_FIELD_UNIVERSAL_IDENTIFIERS = Object.values(
|
||||
LIST.views.allMessageLists.viewFields,
|
||||
).map((viewField) => viewField.universalIdentifier);
|
||||
|
||||
const buildByUniversalIdentifierMap = (universalIdentifiers: string[]) => ({
|
||||
byUniversalIdentifier: Object.fromEntries(
|
||||
universalIdentifiers.map((universalIdentifier) => [
|
||||
universalIdentifier,
|
||||
{ universalIdentifier },
|
||||
]),
|
||||
),
|
||||
});
|
||||
|
||||
describe('CreateMessageListViewCommand', () => {
|
||||
let command: CreateMessageListViewCommand;
|
||||
let findApplicationMock: jest.Mock;
|
||||
let getOrRecomputeMock: jest.Mock;
|
||||
let validateBuildAndRunWorkspaceMigrationMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
findApplicationMock = jest.fn().mockResolvedValue({
|
||||
twentyStandardFlatApplication: STANDARD_APPLICATION,
|
||||
});
|
||||
getOrRecomputeMock = jest.fn();
|
||||
validateBuildAndRunWorkspaceMigrationMock = jest
|
||||
.fn()
|
||||
.mockResolvedValue({ status: 'success' });
|
||||
|
||||
computeTwentyStandardApplicationAllFlatEntityMapsMock.mockReturnValue({
|
||||
allFlatEntityMaps: {
|
||||
flatViewMaps: buildByUniversalIdentifierMap([
|
||||
LIST_VIEW_UNIVERSAL_IDENTIFIER,
|
||||
]),
|
||||
flatViewFieldMaps: buildByUniversalIdentifierMap(
|
||||
LIST_VIEW_FIELD_UNIVERSAL_IDENTIFIERS,
|
||||
),
|
||||
},
|
||||
});
|
||||
|
||||
command = new CreateMessageListViewCommand(
|
||||
{} as WorkspaceIteratorService,
|
||||
{
|
||||
findWorkspaceTwentyStandardAndCustomApplicationOrThrow:
|
||||
findApplicationMock,
|
||||
} as unknown as ApplicationService,
|
||||
{
|
||||
getOrRecompute: getOrRecomputeMock,
|
||||
} as unknown as WorkspaceCacheService,
|
||||
{
|
||||
validateBuildAndRunWorkspaceMigration:
|
||||
validateBuildAndRunWorkspaceMigrationMock,
|
||||
} as unknown as WorkspaceMigrationValidateBuildAndRunService,
|
||||
);
|
||||
});
|
||||
|
||||
const runOnWorkspace = (dryRun = false) =>
|
||||
command.runOnWorkspace({
|
||||
workspaceId: WORKSPACE_ID,
|
||||
options: { dryRun },
|
||||
index: 0,
|
||||
total: 1,
|
||||
});
|
||||
|
||||
const mockWorkspaceCache = ({
|
||||
existingViews = [],
|
||||
existingViewFields = [],
|
||||
}: {
|
||||
existingViews?: string[];
|
||||
existingViewFields?: string[];
|
||||
}) => {
|
||||
getOrRecomputeMock.mockResolvedValue({
|
||||
flatObjectMetadataMaps: buildByUniversalIdentifierMap([
|
||||
LIST.universalIdentifier,
|
||||
]),
|
||||
flatViewMaps: buildByUniversalIdentifierMap(existingViews),
|
||||
flatViewFieldMaps: buildByUniversalIdentifierMap(existingViewFields),
|
||||
});
|
||||
};
|
||||
|
||||
it('creates the message list view and all view fields when missing', async () => {
|
||||
mockWorkspaceCache({});
|
||||
|
||||
await runOnWorkspace();
|
||||
|
||||
expect(validateBuildAndRunWorkspaceMigrationMock).toHaveBeenCalledWith({
|
||||
isSystemBuild: true,
|
||||
workspaceId: WORKSPACE_ID,
|
||||
applicationUniversalIdentifier: STANDARD_APPLICATION.universalIdentifier,
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
view: {
|
||||
flatEntityToCreate: [
|
||||
expect.objectContaining({
|
||||
universalIdentifier: LIST_VIEW_UNIVERSAL_IDENTIFIER,
|
||||
}),
|
||||
],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: expect.arrayContaining(
|
||||
LIST_VIEW_FIELD_UNIVERSAL_IDENTIFIERS.map((universalIdentifier) =>
|
||||
expect.objectContaining({ universalIdentifier }),
|
||||
),
|
||||
),
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
validateBuildAndRunWorkspaceMigrationMock.mock.calls[0][0]
|
||||
.allFlatEntityOperationByMetadataName.viewField.flatEntityToCreate,
|
||||
).toHaveLength(LIST_VIEW_FIELD_UNIVERSAL_IDENTIFIERS.length);
|
||||
});
|
||||
|
||||
it('creates missing view fields when the view already exists', async () => {
|
||||
mockWorkspaceCache({
|
||||
existingViews: [LIST_VIEW_UNIVERSAL_IDENTIFIER],
|
||||
existingViewFields: [
|
||||
LIST.views.allMessageLists.viewFields.name.universalIdentifier,
|
||||
],
|
||||
});
|
||||
|
||||
await runOnWorkspace();
|
||||
|
||||
const payload =
|
||||
validateBuildAndRunWorkspaceMigrationMock.mock.calls[0][0]
|
||||
.allFlatEntityOperationByMetadataName;
|
||||
|
||||
expect(payload.view.flatEntityToCreate).toEqual([]);
|
||||
expect(payload.viewField.flatEntityToCreate).toEqual(
|
||||
expect.arrayContaining(
|
||||
LIST_VIEW_FIELD_UNIVERSAL_IDENTIFIERS.slice(1).map(
|
||||
(universalIdentifier) =>
|
||||
expect.objectContaining({ universalIdentifier }),
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(payload.viewField.flatEntityToCreate).toHaveLength(
|
||||
LIST_VIEW_FIELD_UNIVERSAL_IDENTIFIERS.length - 1,
|
||||
);
|
||||
});
|
||||
|
||||
it('does nothing when the view and view fields already exist', async () => {
|
||||
mockWorkspaceCache({
|
||||
existingViews: [LIST_VIEW_UNIVERSAL_IDENTIFIER],
|
||||
existingViewFields: LIST_VIEW_FIELD_UNIVERSAL_IDENTIFIERS,
|
||||
});
|
||||
|
||||
await runOnWorkspace();
|
||||
|
||||
expect(validateBuildAndRunWorkspaceMigrationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not write metadata in dry-run mode', async () => {
|
||||
mockWorkspaceCache({});
|
||||
|
||||
await runOnWorkspace(true);
|
||||
|
||||
expect(validateBuildAndRunWorkspaceMigrationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('skips workspaces where the messageList object is absent', async () => {
|
||||
getOrRecomputeMock.mockResolvedValue({
|
||||
flatObjectMetadataMaps: buildByUniversalIdentifierMap([]),
|
||||
flatViewMaps: buildByUniversalIdentifierMap([]),
|
||||
flatViewFieldMaps: buildByUniversalIdentifierMap([]),
|
||||
});
|
||||
|
||||
await runOnWorkspace();
|
||||
|
||||
expect(findApplicationMock).not.toHaveBeenCalled();
|
||||
expect(validateBuildAndRunWorkspaceMigrationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { type QueryRunner } from 'typeorm';
|
||||
|
||||
import { DropMetadataStandardOverridesColumnFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-20/2-20-instance-command-fast-1782991100000-drop-metadata-standard-overrides-column';
|
||||
import { DropMetadataStandardOverridesColumnFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-20/2-20-instance-command-fast-1825000000000-drop-metadata-standard-overrides-column';
|
||||
import { DROP_METADATA_STANDARD_OVERRIDES_COLUMN_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-20/drop-metadata-standard-overrides-column-upgrade-command-name.constant';
|
||||
import { getRegisteredInstanceCommandMetadata } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
|
||||
|
||||
@@ -19,7 +19,7 @@ describe('DropMetadataStandardOverridesColumnFastInstanceCommand', () => {
|
||||
|
||||
expect(metadata).toEqual({
|
||||
version: '2.20.0',
|
||||
timestamp: 1782991100000,
|
||||
timestamp: 1825000000000,
|
||||
type: 'fast',
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Registered name of the 2.20 drop command. Wire to @WasRemovedInUpgrade on the
|
||||
// standardOverrides columns once 2.20 is current.
|
||||
export const DROP_METADATA_STANDARD_OVERRIDES_COLUMN_UPGRADE_COMMAND_NAME =
|
||||
'2.20.0_DropMetadataStandardOverridesColumnFastInstanceCommand_1782991100000';
|
||||
'2.20.0_DropMetadataStandardOverridesColumnFastInstanceCommand_1825000000000';
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ import { AddPendingQuestionMessageIdToAgentChatThreadFastInstanceCommand } from
|
||||
import { AddWorkspaceDiscoverabilityToWorkspaceFastInstanceCommand } from './2-19/2-19-instance-command-fast-1783004140000-add-workspace-discoverability-to-workspace';
|
||||
import { AddStatusToFileFastInstanceCommand } from './2-19/2-19-instance-command-fast-1783082964705-add-status-to-file';
|
||||
import { AddPendingMimeCheckToFileFastInstanceCommand } from './2-19/2-19-instance-command-fast-1783094691548-add-pending-mime-check-to-file';
|
||||
import { DropMetadataStandardOverridesColumnFastInstanceCommand } from './2-20/2-20-instance-command-fast-1782991100000-drop-metadata-standard-overrides-column';
|
||||
import { DropMetadataStandardOverridesColumnFastInstanceCommand } from './2-20/2-20-instance-command-fast-1825000000000-drop-metadata-standard-overrides-column';
|
||||
import { AddLogoToApplicationRegistrationFastInstanceCommand } from './2-19/2-19-instance-command-fast-1783069672191-add-logo-to-application-registration';
|
||||
import { BackfillLogoOnApplicationRegistrationSlowInstanceCommand } from './2-19/2-19-instance-command-slow-1783069673191-backfill-logo-on-application-registration';
|
||||
import { AddDisplayFieldsToApplicationRegistrationFastInstanceCommand } from './2-19/2-19-instance-command-fast-1783073776590-add-display-fields-to-application-registration';
|
||||
|
||||
-2
@@ -20,7 +20,6 @@ import { V2_16_UpgradeVersionCommandModule } from 'src/database/commands/upgrade
|
||||
import { V2_17_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/2-17/2-17-upgrade-version-command.module';
|
||||
import { V2_18_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/2-18/2-18-upgrade-version-command.module';
|
||||
import { V2_19_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/2-19/2-19-upgrade-version-command.module';
|
||||
import { V2_20_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/2-20/2-20-upgrade-version-command.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -44,7 +43,6 @@ import { V2_20_UpgradeVersionCommandModule } from 'src/database/commands/upgrade
|
||||
V2_17_UpgradeVersionCommandModule,
|
||||
V2_18_UpgradeVersionCommandModule,
|
||||
V2_19_UpgradeVersionCommandModule,
|
||||
V2_20_UpgradeVersionCommandModule,
|
||||
],
|
||||
})
|
||||
export class WorkspaceCommandProviderModule {}
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
export enum CacheStorageNamespace {
|
||||
ModuleMessaging = 'module:messaging',
|
||||
ModuleEmailing = 'module:emailing',
|
||||
ModuleCalendar = 'module:calendar',
|
||||
ModuleWorkflow = 'module:workflow',
|
||||
EngineWorkspace = 'engine:workspace',
|
||||
|
||||
-5
@@ -17,11 +17,6 @@ export const CAMPAIGN_STATUS = {
|
||||
|
||||
export const MATERIALIZE_CAMPAIGN_JOB = 'MaterializeCampaignJob';
|
||||
export const SEND_CAMPAIGN_EMAIL_JOB = 'SendCampaignEmailJob';
|
||||
export const REFRESH_CAMPAIGN_STATS_JOB = 'RefreshCampaignStatsJob';
|
||||
|
||||
export const CAMPAIGN_STATS_REFRESH_DEBOUNCE_MS = 10_000;
|
||||
export const CAMPAIGN_STATS_REFRESH_DELAY_MS =
|
||||
CAMPAIGN_STATS_REFRESH_DEBOUNCE_MS + 2_000;
|
||||
|
||||
export const MAX_CAMPAIGN_RECIPIENTS = 10000;
|
||||
|
||||
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
export type RefreshCampaignStatsJobData = {
|
||||
workspaceId: string;
|
||||
campaignId: string;
|
||||
};
|
||||
@@ -22,7 +22,6 @@ import { EmailSenderJob } from 'src/engine/core-modules/email/email-sender.job';
|
||||
import { EmailModule } from 'src/engine/core-modules/email/email.module';
|
||||
import { EmailingModule } from 'src/modules/emailing/emailing.module';
|
||||
import { MaterializeCampaignJob } from 'src/modules/emailing/jobs/materialize-campaign.job';
|
||||
import { RefreshCampaignStatsJob } from 'src/modules/emailing/jobs/refresh-campaign-stats.job';
|
||||
import { SendCampaignEmailJob } from 'src/modules/emailing/jobs/send-campaign-email.job';
|
||||
import { EnterpriseModule } from 'src/engine/core-modules/enterprise/enterprise.module';
|
||||
import { EventLogIngestionModule } from 'src/engine/core-modules/event-logs/ingest/event-log-ingestion.module';
|
||||
@@ -105,7 +104,6 @@ import { WorkflowModule } from 'src/modules/workflow/workflow.module';
|
||||
EmailSenderJob,
|
||||
SendCampaignEmailJob,
|
||||
MaterializeCampaignJob,
|
||||
RefreshCampaignStatsJob,
|
||||
UpdateSubscriptionQuantityJob,
|
||||
HandleWorkspaceMemberDeletedJob,
|
||||
CleanWorkspaceDeletionWarningUserVarsJob,
|
||||
|
||||
+707
-780
File diff suppressed because it is too large
Load Diff
-52
@@ -261,58 +261,6 @@ export const buildMessageCampaignStandardFlatFieldMetadatas = ({
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
},
|
||||
}),
|
||||
sentCount: createStandardFieldFlatMetadata({
|
||||
...base,
|
||||
context: {
|
||||
fieldName: 'sentCount',
|
||||
type: FieldMetadataType.NUMBER,
|
||||
label: i18nLabel(msg`Sent count`),
|
||||
description: i18nLabel(msg`Number of emails sent`),
|
||||
icon: 'IconMailFast',
|
||||
isNullable: false,
|
||||
isUIEditable: false,
|
||||
defaultValue: 0,
|
||||
},
|
||||
}),
|
||||
failedCount: createStandardFieldFlatMetadata({
|
||||
...base,
|
||||
context: {
|
||||
fieldName: 'failedCount',
|
||||
type: FieldMetadataType.NUMBER,
|
||||
label: i18nLabel(msg`Failed count`),
|
||||
description: i18nLabel(msg`Number of emails that failed to send`),
|
||||
icon: 'IconMailX',
|
||||
isNullable: false,
|
||||
isUIEditable: false,
|
||||
defaultValue: 0,
|
||||
},
|
||||
}),
|
||||
bouncedCount: createStandardFieldFlatMetadata({
|
||||
...base,
|
||||
context: {
|
||||
fieldName: 'bouncedCount',
|
||||
type: FieldMetadataType.NUMBER,
|
||||
label: i18nLabel(msg`Bounced count`),
|
||||
description: i18nLabel(msg`Number of emails that bounced`),
|
||||
icon: 'IconMailOff',
|
||||
isNullable: false,
|
||||
isUIEditable: false,
|
||||
defaultValue: 0,
|
||||
},
|
||||
}),
|
||||
complainedCount: createStandardFieldFlatMetadata({
|
||||
...base,
|
||||
context: {
|
||||
fieldName: 'complainedCount',
|
||||
type: FieldMetadataType.NUMBER,
|
||||
label: i18nLabel(msg`Complained count`),
|
||||
description: i18nLabel(msg`Number of spam complaints received`),
|
||||
icon: 'IconMoodSad',
|
||||
isNullable: false,
|
||||
isUIEditable: false,
|
||||
defaultValue: 0,
|
||||
},
|
||||
}),
|
||||
unsubscribeTopicId: createStandardFieldFlatMetadata({
|
||||
...base,
|
||||
context: {
|
||||
|
||||
-4
@@ -11,10 +11,8 @@ import { computeStandardCalendarEventViewFields } from 'src/engine/workspace-man
|
||||
import { computeStandardCallRecordingViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-call-recording-view-fields.util';
|
||||
import { computeStandardCompanyViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-company-view-fields.util';
|
||||
import { computeStandardDashboardViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-dashboard-view-fields.util';
|
||||
import { computeStandardMessageCampaignViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-message-campaign-view-fields.util';
|
||||
import { computeStandardMessageChannelMessageAssociationMessageFolderViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-message-channel-message-association-message-folder-view-fields.util';
|
||||
import { computeStandardMessageChannelMessageAssociationViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-message-channel-message-association-view-fields.util';
|
||||
import { computeStandardMessageListViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-message-list-view-fields.util';
|
||||
import { computeStandardMessageParticipantViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-message-participant-view-fields.util';
|
||||
import { computeStandardMessageThreadViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-message-thread-view-fields.util';
|
||||
import { computeStandardMessageViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-message-view-fields.util';
|
||||
@@ -47,12 +45,10 @@ const STANDARD_FLAT_VIEW_FIELD_METADATA_BUILDERS_BY_OBJECT_NAME = {
|
||||
company: computeStandardCompanyViewFields,
|
||||
dashboard: computeStandardDashboardViewFields,
|
||||
message: computeStandardMessageViewFields,
|
||||
messageCampaign: computeStandardMessageCampaignViewFields,
|
||||
messageChannelMessageAssociation:
|
||||
computeStandardMessageChannelMessageAssociationViewFields,
|
||||
messageChannelMessageAssociationMessageFolder:
|
||||
computeStandardMessageChannelMessageAssociationMessageFolderViewFields,
|
||||
messageList: computeStandardMessageListViewFields,
|
||||
messageParticipant: computeStandardMessageParticipantViewFields,
|
||||
messageThread: computeStandardMessageThreadViewFields,
|
||||
note: computeStandardNoteViewFields,
|
||||
|
||||
-144
@@ -1,144 +0,0 @@
|
||||
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
|
||||
import {
|
||||
createStandardViewFieldFlatMetadata,
|
||||
type CreateStandardViewFieldArgs,
|
||||
} from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/create-standard-view-field-flat-metadata.util';
|
||||
|
||||
export const computeStandardMessageCampaignViewFields = (
|
||||
args: Omit<CreateStandardViewFieldArgs<'messageCampaign'>, 'context'>,
|
||||
): Record<string, FlatViewField> => {
|
||||
return {
|
||||
allMessageCampaignsSubject: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
viewFieldName: 'subject',
|
||||
fieldName: 'subject',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 300,
|
||||
},
|
||||
}),
|
||||
allMessageCampaignsStatus: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
viewFieldName: 'status',
|
||||
fieldName: 'status',
|
||||
position: 1,
|
||||
isVisible: true,
|
||||
size: 120,
|
||||
},
|
||||
}),
|
||||
allMessageCampaignsList: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
viewFieldName: 'list',
|
||||
fieldName: 'list',
|
||||
position: 2,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
},
|
||||
}),
|
||||
allMessageCampaignsFromAddress: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
viewFieldName: 'fromAddress',
|
||||
fieldName: 'fromAddress',
|
||||
position: 3,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
},
|
||||
}),
|
||||
allMessageCampaignsSentAt: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
viewFieldName: 'sentAt',
|
||||
fieldName: 'sentAt',
|
||||
position: 4,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
},
|
||||
}),
|
||||
allMessageCampaignsSentCount: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
viewFieldName: 'sentCount',
|
||||
fieldName: 'sentCount',
|
||||
position: 5,
|
||||
isVisible: true,
|
||||
size: 100,
|
||||
},
|
||||
}),
|
||||
allMessageCampaignsFailedCount: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
viewFieldName: 'failedCount',
|
||||
fieldName: 'failedCount',
|
||||
position: 6,
|
||||
isVisible: true,
|
||||
size: 100,
|
||||
},
|
||||
}),
|
||||
allMessageCampaignsBouncedCount: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
viewFieldName: 'bouncedCount',
|
||||
fieldName: 'bouncedCount',
|
||||
position: 7,
|
||||
isVisible: true,
|
||||
size: 100,
|
||||
},
|
||||
}),
|
||||
allMessageCampaignsComplainedCount: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
viewFieldName: 'complainedCount',
|
||||
fieldName: 'complainedCount',
|
||||
position: 8,
|
||||
isVisible: true,
|
||||
size: 120,
|
||||
},
|
||||
}),
|
||||
allMessageCampaignsRecipients: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
viewFieldName: 'recipients',
|
||||
fieldName: 'recipients',
|
||||
position: 9,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
},
|
||||
}),
|
||||
allMessageCampaignsCreatedAt: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
viewFieldName: 'createdAt',
|
||||
fieldName: 'createdAt',
|
||||
position: 10,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
|
||||
import {
|
||||
createStandardViewFieldFlatMetadata,
|
||||
type CreateStandardViewFieldArgs,
|
||||
} from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/create-standard-view-field-flat-metadata.util';
|
||||
|
||||
export const computeStandardMessageListViewFields = (
|
||||
args: Omit<CreateStandardViewFieldArgs<'messageList'>, 'context'>,
|
||||
): Record<string, FlatViewField> => {
|
||||
return {
|
||||
allMessageListsName: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageList',
|
||||
context: {
|
||||
viewName: 'allMessageLists',
|
||||
viewFieldName: 'name',
|
||||
fieldName: 'name',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 300,
|
||||
},
|
||||
}),
|
||||
allMessageListsMembers: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageList',
|
||||
context: {
|
||||
viewName: 'allMessageLists',
|
||||
viewFieldName: 'members',
|
||||
fieldName: 'members',
|
||||
position: 1,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
},
|
||||
}),
|
||||
allMessageListsCampaigns: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageList',
|
||||
context: {
|
||||
viewName: 'allMessageLists',
|
||||
viewFieldName: 'campaigns',
|
||||
fieldName: 'campaigns',
|
||||
position: 2,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
},
|
||||
}),
|
||||
allMessageListsCreatedAt: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageList',
|
||||
context: {
|
||||
viewName: 'allMessageLists',
|
||||
viewFieldName: 'createdAt',
|
||||
fieldName: 'createdAt',
|
||||
position: 3,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
-4
@@ -11,10 +11,8 @@ import { computeStandardCalendarEventViews } from 'src/engine/workspace-manager/
|
||||
import { computeStandardCallRecordingViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-call-recording-views.util';
|
||||
import { computeStandardCompanyViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-company-views.util';
|
||||
import { computeStandardDashboardViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-dashboard-views.util';
|
||||
import { computeStandardMessageCampaignViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-message-campaign-views.util';
|
||||
import { computeStandardMessageChannelMessageAssociationMessageFolderViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-message-channel-message-association-message-folder-views.util';
|
||||
import { computeStandardMessageChannelMessageAssociationViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-message-channel-message-association-views.util';
|
||||
import { computeStandardMessageListViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-message-list-views.util';
|
||||
import { computeStandardMessageParticipantViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-message-participant-views.util';
|
||||
import { computeStandardMessageThreadViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-message-thread-views.util';
|
||||
import { computeStandardMessageViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-message-views.util';
|
||||
@@ -47,12 +45,10 @@ const STANDARD_FLAT_VIEW_METADATA_BUILDERS_BY_OBJECT_NAME = {
|
||||
company: computeStandardCompanyViews,
|
||||
dashboard: computeStandardDashboardViews,
|
||||
message: computeStandardMessageViews,
|
||||
messageCampaign: computeStandardMessageCampaignViews,
|
||||
messageChannelMessageAssociation:
|
||||
computeStandardMessageChannelMessageAssociationViews,
|
||||
messageChannelMessageAssociationMessageFolder:
|
||||
computeStandardMessageChannelMessageAssociationMessageFolderViews,
|
||||
messageList: computeStandardMessageListViews,
|
||||
messageParticipant: computeStandardMessageParticipantViews,
|
||||
messageThread: computeStandardMessageThreadViews,
|
||||
note: computeStandardNoteViews,
|
||||
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
import { ViewType, ViewKey } from 'twenty-shared/types';
|
||||
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import {
|
||||
createStandardViewFlatMetadata,
|
||||
type CreateStandardViewArgs,
|
||||
} from 'src/engine/workspace-manager/twenty-standard-application/utils/view/create-standard-view-flat-metadata.util';
|
||||
|
||||
export const computeStandardMessageCampaignViews = (
|
||||
args: Omit<CreateStandardViewArgs<'messageCampaign'>, 'context'>,
|
||||
): Record<string, FlatView> => {
|
||||
return {
|
||||
allMessageCampaigns: createStandardViewFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageCampaign',
|
||||
context: {
|
||||
viewName: 'allMessageCampaigns',
|
||||
name: 'All {objectLabelPlural}',
|
||||
type: ViewType.TABLE,
|
||||
key: ViewKey.INDEX,
|
||||
position: 0,
|
||||
icon: 'IconSend',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
import { ViewType, ViewKey } from 'twenty-shared/types';
|
||||
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import {
|
||||
createStandardViewFlatMetadata,
|
||||
type CreateStandardViewArgs,
|
||||
} from 'src/engine/workspace-manager/twenty-standard-application/utils/view/create-standard-view-flat-metadata.util';
|
||||
|
||||
export const computeStandardMessageListViews = (
|
||||
args: Omit<CreateStandardViewArgs<'messageList'>, 'context'>,
|
||||
): Record<string, FlatView> => {
|
||||
return {
|
||||
allMessageLists: createStandardViewFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageList',
|
||||
context: {
|
||||
viewName: 'allMessageLists',
|
||||
name: 'All {objectLabelPlural}',
|
||||
type: ViewType.TABLE,
|
||||
key: ViewKey.INDEX,
|
||||
position: 0,
|
||||
icon: 'IconList',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
@@ -10,7 +10,6 @@ import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-
|
||||
import { MessageChannelEntity } from 'src/engine/metadata-modules/message-channel/entities/message-channel.entity';
|
||||
import { MessageChannelMetadataModule } from 'src/engine/metadata-modules/message-channel/message-channel-metadata.module';
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
|
||||
import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
import { WorkspaceEventEmitterModule } from 'src/engine/workspace-event-emitter/workspace-event-emitter.module';
|
||||
@@ -19,7 +18,6 @@ import { EmailingSendResolver } from 'src/modules/emailing/resolvers/emailing-se
|
||||
import { UnsubscribeTopicResolver } from 'src/modules/emailing/resolvers/unsubscribe-topic.resolver';
|
||||
import { EmailBillingService } from 'src/modules/emailing/services/email-billing.service';
|
||||
import { EmailingDomainSenderService } from 'src/modules/emailing/services/emailing-domain-sender.service';
|
||||
import { MessageCampaignStatisticsService } from 'src/modules/emailing/services/message-campaign-statistics.service';
|
||||
import { MessageCampaignService } from 'src/modules/emailing/services/message-campaign.service';
|
||||
import { MessageSuppressionService } from 'src/modules/emailing/services/message-suppression.service';
|
||||
import { UnsubscribeTopicService } from 'src/modules/emailing/services/unsubscribe-topic.service';
|
||||
@@ -30,7 +28,6 @@ import { UnsubscribeTopicService } from 'src/modules/emailing/services/unsubscri
|
||||
MessageChannelMetadataModule,
|
||||
FeatureFlagModule,
|
||||
PermissionsModule,
|
||||
UserRoleModule,
|
||||
BillingModule,
|
||||
WorkspaceEventEmitterModule,
|
||||
WorkspaceCacheModule,
|
||||
@@ -45,7 +42,6 @@ import { UnsubscribeTopicService } from 'src/modules/emailing/services/unsubscri
|
||||
providers: [
|
||||
EmailBillingService,
|
||||
MessageCampaignService,
|
||||
MessageCampaignStatisticsService,
|
||||
MessageSuppressionService,
|
||||
UnsubscribeTopicService,
|
||||
EmailingDomainSenderService,
|
||||
@@ -58,7 +54,6 @@ import { UnsubscribeTopicService } from 'src/modules/emailing/services/unsubscri
|
||||
exports: [
|
||||
EmailingDomainSenderService,
|
||||
MessageCampaignService,
|
||||
MessageCampaignStatisticsService,
|
||||
MessageSuppressionService,
|
||||
UnsubscribeTopicService,
|
||||
],
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { REFRESH_CAMPAIGN_STATS_JOB } from 'src/engine/core-modules/emailing-domain/constants/campaign.constant';
|
||||
import { type RefreshCampaignStatsJobData } from 'src/engine/core-modules/emailing-domain/types/refresh-campaign-stats-job-data.type';
|
||||
import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator';
|
||||
import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator';
|
||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||
import { MessageCampaignStatisticsService } from 'src/modules/emailing/services/message-campaign-statistics.service';
|
||||
|
||||
@Processor(MessageQueue.emailQueue)
|
||||
export class RefreshCampaignStatsJob {
|
||||
constructor(
|
||||
private readonly messageCampaignStatisticsService: MessageCampaignStatisticsService,
|
||||
) {}
|
||||
|
||||
@Process(REFRESH_CAMPAIGN_STATS_JOB)
|
||||
async handle(data: RefreshCampaignStatsJobData): Promise<void> {
|
||||
await this.messageCampaignStatisticsService.refreshCampaignCounts({
|
||||
workspaceId: data.workspaceId,
|
||||
campaignId: data.campaignId,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -97,13 +97,11 @@ export class EmailingSendResolver {
|
||||
async previewMessageCampaignAudience(
|
||||
@Args('input') input: PreviewMessageCampaignAudienceInput,
|
||||
@AuthWorkspace() currentWorkspace: WorkspaceEntity,
|
||||
@AuthUserWorkspaceId() userWorkspaceId: string,
|
||||
): Promise<CampaignAudiencePreviewDTO> {
|
||||
this.emailGroupAccessService.validateEmailGroupAccessOrThrow();
|
||||
|
||||
return this.messageCampaignService.previewAudience({
|
||||
workspaceId: currentWorkspace.id,
|
||||
userWorkspaceId,
|
||||
listId: input.listId,
|
||||
unsubscribeTopicId: input.unsubscribeTopicId,
|
||||
});
|
||||
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { CAMPAIGN_MESSAGE_DELIVERY_STATUS } from 'src/engine/core-modules/emailing-domain/constants/campaign.constant';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import { MessageCampaignWorkspaceEntity } from 'src/modules/emailing/standard-objects/message-campaign.workspace-entity';
|
||||
import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
|
||||
|
||||
type DeliveryStatusCountRow = {
|
||||
deliveryStatus: string | null;
|
||||
count: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class MessageCampaignStatisticsService {
|
||||
constructor(
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
) {}
|
||||
|
||||
async refreshCampaignCounts({
|
||||
workspaceId,
|
||||
campaignId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
campaignId: string;
|
||||
}): Promise<void> {
|
||||
await this.globalWorkspaceOrmManager.executeInWorkspaceContext(async () => {
|
||||
const messageRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository(
|
||||
workspaceId,
|
||||
MessageWorkspaceEntity,
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
const deliveryStatusCountRows = await messageRepository
|
||||
.createQueryBuilder('message')
|
||||
.select('message.deliveryStatus', 'deliveryStatus')
|
||||
.addSelect('COUNT(*)', 'count')
|
||||
.where('message.messageCampaignId = :campaignId', { campaignId })
|
||||
.groupBy('message.deliveryStatus')
|
||||
.getRawMany<DeliveryStatusCountRow>();
|
||||
|
||||
const countByDeliveryStatus = new Map(
|
||||
deliveryStatusCountRows.map((row) => [
|
||||
row.deliveryStatus,
|
||||
Number(row.count),
|
||||
]),
|
||||
);
|
||||
|
||||
const sentCount =
|
||||
countByDeliveryStatus.get(CAMPAIGN_MESSAGE_DELIVERY_STATUS.SENT) ?? 0;
|
||||
const failedCount =
|
||||
countByDeliveryStatus.get(CAMPAIGN_MESSAGE_DELIVERY_STATUS.FAILED) ?? 0;
|
||||
const bouncedCount =
|
||||
countByDeliveryStatus.get(CAMPAIGN_MESSAGE_DELIVERY_STATUS.BOUNCED) ??
|
||||
0;
|
||||
const complainedCount =
|
||||
countByDeliveryStatus.get(
|
||||
CAMPAIGN_MESSAGE_DELIVERY_STATUS.COMPLAINED,
|
||||
) ?? 0;
|
||||
|
||||
const campaignRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository(
|
||||
workspaceId,
|
||||
MessageCampaignWorkspaceEntity,
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
await campaignRepository.update(
|
||||
{ id: campaignId },
|
||||
{ sentCount, failedCount, bouncedCount, complainedCount },
|
||||
);
|
||||
}, buildSystemAuthContext(workspaceId));
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,9 @@ import { v4, v5 } from 'uuid';
|
||||
import {
|
||||
CAMPAIGN_MESSAGE_DELIVERY_STATUS,
|
||||
CAMPAIGN_MESSAGE_ID_NAMESPACE,
|
||||
CAMPAIGN_STATS_REFRESH_DEBOUNCE_MS,
|
||||
CAMPAIGN_STATS_REFRESH_DELAY_MS,
|
||||
CAMPAIGN_STATUS,
|
||||
MATERIALIZE_CAMPAIGN_JOB,
|
||||
MAX_CAMPAIGN_RECIPIENTS,
|
||||
REFRESH_CAMPAIGN_STATS_JOB,
|
||||
SEND_CAMPAIGN_EMAIL_JOB,
|
||||
} from 'src/engine/core-modules/emailing-domain/constants/campaign.constant';
|
||||
import {
|
||||
@@ -26,17 +23,12 @@ import { type CampaignRecipient } from 'src/engine/core-modules/emailing-domain/
|
||||
import { type CampaignSkippedBreakdown } from 'src/engine/core-modules/emailing-domain/types/campaign-skipped-breakdown.type';
|
||||
import { type MaterializeCampaignJobData } from 'src/engine/core-modules/emailing-domain/types/materialize-campaign-job-data.type';
|
||||
import { type RawCampaignRecipient } from 'src/engine/core-modules/emailing-domain/types/raw-campaign-recipient.type';
|
||||
import { type RefreshCampaignStatsJobData } from 'src/engine/core-modules/emailing-domain/types/refresh-campaign-stats-job-data.type';
|
||||
import { type SendCampaignEmailJobData } from 'src/engine/core-modules/emailing-domain/types/send-campaign-email-job-data.type';
|
||||
import { normalizeCampaignRecipients } from 'src/engine/core-modules/emailing-domain/utils/normalize-campaign-recipients.util';
|
||||
import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator';
|
||||
import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service';
|
||||
import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum';
|
||||
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
|
||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
|
||||
import { MessageChannelMetadataService } from 'src/engine/metadata-modules/message-channel/message-channel-metadata.service';
|
||||
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
|
||||
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
@@ -44,7 +36,6 @@ import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace
|
||||
import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository';
|
||||
import { EmailBillingService } from 'src/modules/emailing/services/email-billing.service';
|
||||
import { EmailingDomainSenderService } from 'src/modules/emailing/services/emailing-domain-sender.service';
|
||||
import { MessageCampaignStatisticsService } from 'src/modules/emailing/services/message-campaign-statistics.service';
|
||||
import { MessageSuppressionService } from 'src/modules/emailing/services/message-suppression.service';
|
||||
import { MessageCampaignWorkspaceEntity } from 'src/modules/emailing/standard-objects/message-campaign.workspace-entity';
|
||||
import { MessageListMemberWorkspaceEntity } from 'src/modules/emailing/standard-objects/message-list-member.workspace-entity';
|
||||
@@ -108,21 +99,14 @@ export class MessageCampaignService {
|
||||
private readonly messageQueueService: MessageQueueService,
|
||||
private readonly messageChannelMetadataService: MessageChannelMetadataService,
|
||||
private readonly messageSuppressionService: MessageSuppressionService,
|
||||
private readonly userRoleService: UserRoleService,
|
||||
private readonly messageCampaignStatisticsService: MessageCampaignStatisticsService,
|
||||
private readonly emailBillingService: EmailBillingService,
|
||||
@InjectCacheStorage(CacheStorageNamespace.ModuleEmailing)
|
||||
private readonly cacheStorageService: CacheStorageService,
|
||||
) {}
|
||||
|
||||
private getUserRepository<T extends ObjectLiteral>(
|
||||
workspaceId: string,
|
||||
entity: Type<T>,
|
||||
roleId: string,
|
||||
) {
|
||||
return this.globalWorkspaceOrmManager.getRepository(workspaceId, entity, {
|
||||
unionOf: [roleId],
|
||||
});
|
||||
return this.globalWorkspaceOrmManager.getRepository(workspaceId, entity);
|
||||
}
|
||||
|
||||
private getSystemRepository<T extends ObjectLiteral>(
|
||||
@@ -156,18 +140,12 @@ export class MessageCampaignService {
|
||||
);
|
||||
}
|
||||
|
||||
const roleId = await this.userRoleService.getRoleIdForUserWorkspace({
|
||||
workspaceId,
|
||||
userWorkspaceId,
|
||||
});
|
||||
|
||||
const { campaignId, recipients, skipped } =
|
||||
await this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
async () => {
|
||||
const rawRecipients = await this.resolveRecipientsFromList(
|
||||
workspaceId,
|
||||
listId,
|
||||
roleId,
|
||||
);
|
||||
|
||||
const normalized = normalizeCampaignRecipients(
|
||||
@@ -177,7 +155,6 @@ export class MessageCampaignService {
|
||||
|
||||
const newCampaignId = await this.createCampaign({
|
||||
workspaceId,
|
||||
roleId,
|
||||
subject,
|
||||
html,
|
||||
fromAddress,
|
||||
@@ -493,17 +470,11 @@ export class MessageCampaignService {
|
||||
}
|
||||
|
||||
await messageRepository.update(message.id, { deliveryStatus });
|
||||
|
||||
await this.scheduleCampaignStatsRefresh({
|
||||
workspaceId,
|
||||
campaignId: message.messageCampaignId,
|
||||
});
|
||||
}, buildSystemAuthContext(workspaceId));
|
||||
}
|
||||
|
||||
private async createCampaign({
|
||||
workspaceId,
|
||||
roleId,
|
||||
subject,
|
||||
html,
|
||||
fromAddress,
|
||||
@@ -511,7 +482,6 @@ export class MessageCampaignService {
|
||||
listId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
roleId: string;
|
||||
subject: string;
|
||||
html: string;
|
||||
fromAddress: string;
|
||||
@@ -521,7 +491,6 @@ export class MessageCampaignService {
|
||||
const campaignRepository = await this.getUserRepository(
|
||||
workspaceId,
|
||||
MessageCampaignWorkspaceEntity,
|
||||
roleId,
|
||||
);
|
||||
|
||||
const { identifiers } = await campaignRepository.insert({
|
||||
@@ -685,58 +654,22 @@ export class MessageCampaignService {
|
||||
sentAt: new Date(),
|
||||
},
|
||||
);
|
||||
|
||||
await this.scheduleCampaignStatsRefresh({
|
||||
workspaceId,
|
||||
campaignId,
|
||||
});
|
||||
}
|
||||
|
||||
private async scheduleCampaignStatsRefresh({
|
||||
workspaceId,
|
||||
campaignId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
campaignId: string;
|
||||
}): Promise<void> {
|
||||
const acquired = await this.cacheStorageService.acquireLock(
|
||||
`campaign-stats-refresh:${workspaceId}:${campaignId}`,
|
||||
CAMPAIGN_STATS_REFRESH_DEBOUNCE_MS,
|
||||
);
|
||||
|
||||
if (!acquired) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.messageQueueService.add<RefreshCampaignStatsJobData>(
|
||||
REFRESH_CAMPAIGN_STATS_JOB,
|
||||
{ workspaceId, campaignId },
|
||||
{ delay: CAMPAIGN_STATS_REFRESH_DELAY_MS },
|
||||
);
|
||||
}
|
||||
|
||||
async previewAudience({
|
||||
workspaceId,
|
||||
userWorkspaceId,
|
||||
listId,
|
||||
unsubscribeTopicId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
userWorkspaceId: string;
|
||||
listId: string;
|
||||
unsubscribeTopicId?: string;
|
||||
}): Promise<CampaignAudiencePreview> {
|
||||
const roleId = await this.userRoleService.getRoleIdForUserWorkspace({
|
||||
workspaceId,
|
||||
userWorkspaceId,
|
||||
});
|
||||
|
||||
return this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
async () => {
|
||||
const rawRecipients = await this.resolveRecipientsFromList(
|
||||
workspaceId,
|
||||
listId,
|
||||
roleId,
|
||||
);
|
||||
const totalMembers = rawRecipients.length;
|
||||
|
||||
@@ -791,12 +724,10 @@ export class MessageCampaignService {
|
||||
private async resolveRecipientsFromList(
|
||||
workspaceId: string,
|
||||
listId: string,
|
||||
roleId: string,
|
||||
): Promise<RawCampaignRecipient[]> {
|
||||
const listMemberRepository = await this.getUserRepository(
|
||||
workspaceId,
|
||||
MessageListMemberWorkspaceEntity,
|
||||
roleId,
|
||||
);
|
||||
|
||||
const members = await listMemberRepository.find({
|
||||
@@ -806,14 +737,12 @@ export class MessageCampaignService {
|
||||
return this.loadRecipientsByPersonIds(
|
||||
workspaceId,
|
||||
members.map((member) => member.personId),
|
||||
roleId,
|
||||
);
|
||||
}
|
||||
|
||||
private async loadRecipientsByPersonIds(
|
||||
workspaceId: string,
|
||||
personIds: string[],
|
||||
roleId: string,
|
||||
): Promise<RawCampaignRecipient[]> {
|
||||
if (personIds.length === 0) {
|
||||
return [];
|
||||
@@ -822,7 +751,6 @@ export class MessageCampaignService {
|
||||
const personRepository = await this.getUserRepository(
|
||||
workspaceId,
|
||||
PersonWorkspaceEntity,
|
||||
roleId,
|
||||
);
|
||||
|
||||
const people = await personRepository.find({
|
||||
|
||||
-4
@@ -12,10 +12,6 @@ export class MessageCampaignWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
fromAddress: EmailsMetadata | null;
|
||||
status: string;
|
||||
sentAt: Date | null;
|
||||
sentCount: number;
|
||||
failedCount: number;
|
||||
bouncedCount: number;
|
||||
complainedCount: number;
|
||||
unsubscribeTopicId: string | null;
|
||||
list: EntityRelation<MessageListWorkspaceEntity> | null;
|
||||
listId: string | null;
|
||||
|
||||
-71
@@ -1055,12 +1055,6 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"bodyTemplate": {
|
||||
"universalIdentifier": "b3a69d08-31ca-4a8d-8359-5ca462899342",
|
||||
},
|
||||
"bouncedCount": {
|
||||
"universalIdentifier": "20d884a9-34dd-4667-8ecb-ceec224258e2",
|
||||
},
|
||||
"complainedCount": {
|
||||
"universalIdentifier": "82842cfa-f12a-4bab-bbde-b2cf587d0406",
|
||||
},
|
||||
"createdAt": {
|
||||
"universalIdentifier": "4260eb89-0d55-5078-a6e5-5768781111ba",
|
||||
},
|
||||
@@ -1070,9 +1064,6 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"deletedAt": {
|
||||
"universalIdentifier": "da77cebd-4e72-5568-b808-027e21f748e8",
|
||||
},
|
||||
"failedCount": {
|
||||
"universalIdentifier": "d373fcd7-b1ce-4c77-8031-a5785c475028",
|
||||
},
|
||||
"fromAddress": {
|
||||
"universalIdentifier": "91e1a33c-c1ff-411a-b720-9085e13c05db",
|
||||
},
|
||||
@@ -1097,9 +1088,6 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"sentAt": {
|
||||
"universalIdentifier": "e2315b4f-9edf-4df2-96b9-961e76368671",
|
||||
},
|
||||
"sentCount": {
|
||||
"universalIdentifier": "2f333d2b-37b8-4ddc-ad0d-c07c6ce066ad",
|
||||
},
|
||||
"status": {
|
||||
"universalIdentifier": "c7117256-3de6-48e1-87df-c99c32bad610",
|
||||
},
|
||||
@@ -1131,46 +1119,6 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
},
|
||||
},
|
||||
"universalIdentifier": "238acb94-dd4c-4036-bc55-19b99d821efd",
|
||||
"views": {
|
||||
"allMessageCampaigns": {
|
||||
"universalIdentifier": "ffedb368-33f0-43a7-b84e-e622b4e97be9",
|
||||
"viewFields": {
|
||||
"bouncedCount": {
|
||||
"universalIdentifier": "135d3fb9-bc45-4426-980b-9836ed792e3a",
|
||||
},
|
||||
"complainedCount": {
|
||||
"universalIdentifier": "9957dc6d-05ae-4829-ae7d-7cdf9239cdd0",
|
||||
},
|
||||
"createdAt": {
|
||||
"universalIdentifier": "6dffa47d-3128-4d54-924a-4f67676116c2",
|
||||
},
|
||||
"failedCount": {
|
||||
"universalIdentifier": "ad346c8e-f462-499e-89c8-da01d5460dc6",
|
||||
},
|
||||
"fromAddress": {
|
||||
"universalIdentifier": "553a0ea6-1f55-4143-a2d0-8c1ad0cf3dd1",
|
||||
},
|
||||
"list": {
|
||||
"universalIdentifier": "c0bf6a48-8695-4520-81e6-7462d35033b5",
|
||||
},
|
||||
"recipients": {
|
||||
"universalIdentifier": "2f99f444-4af3-44fd-b08d-46955c4ac2a2",
|
||||
},
|
||||
"sentAt": {
|
||||
"universalIdentifier": "7f4a9d81-afac-4d27-98de-0a2da65114f7",
|
||||
},
|
||||
"sentCount": {
|
||||
"universalIdentifier": "0be62e57-3955-49bd-a9ef-8f82f7a6e9aa",
|
||||
},
|
||||
"status": {
|
||||
"universalIdentifier": "ef35df97-b1a5-4f16-8b85-5751e5019f63",
|
||||
},
|
||||
"subject": {
|
||||
"universalIdentifier": "b017c851-e38d-4a81-ab38-0fb10e9f239e",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"messageChannelMessageAssociation": {
|
||||
"fields": {
|
||||
@@ -1418,25 +1366,6 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
},
|
||||
},
|
||||
"universalIdentifier": "826561ea-4816-411c-baa0-eec5e6ca8866",
|
||||
"views": {
|
||||
"allMessageLists": {
|
||||
"universalIdentifier": "c72bae18-75e9-4cb0-baeb-379d3529b98f",
|
||||
"viewFields": {
|
||||
"campaigns": {
|
||||
"universalIdentifier": "037030a2-9dad-4bfd-957a-313b362172b4",
|
||||
},
|
||||
"createdAt": {
|
||||
"universalIdentifier": "29f3e7de-c40b-4597-8568-7318c146e4da",
|
||||
},
|
||||
"members": {
|
||||
"universalIdentifier": "6d314c4b-215a-4094-963a-ff9dd8221aea",
|
||||
},
|
||||
"name": {
|
||||
"universalIdentifier": "c9767580-34e6-420b-923d-b4abd8c13d96",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"messageListMember": {
|
||||
"fields": {
|
||||
|
||||
@@ -790,18 +790,6 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
status: { universalIdentifier: 'c7117256-3de6-48e1-87df-c99c32bad610' },
|
||||
sentAt: { universalIdentifier: 'e2315b4f-9edf-4df2-96b9-961e76368671' },
|
||||
sentCount: {
|
||||
universalIdentifier: '2f333d2b-37b8-4ddc-ad0d-c07c6ce066ad',
|
||||
},
|
||||
failedCount: {
|
||||
universalIdentifier: 'd373fcd7-b1ce-4c77-8031-a5785c475028',
|
||||
},
|
||||
bouncedCount: {
|
||||
universalIdentifier: '20d884a9-34dd-4667-8ecb-ceec224258e2',
|
||||
},
|
||||
complainedCount: {
|
||||
universalIdentifier: '82842cfa-f12a-4bab-bbde-b2cf587d0406',
|
||||
},
|
||||
unsubscribeTopicId: {
|
||||
universalIdentifier: '0648e7ad-1769-4ff6-a4d5-72da79ef169c',
|
||||
},
|
||||
@@ -825,46 +813,6 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '975823ad-9b97-4f39-b2c7-fbd7d77f4bd1',
|
||||
},
|
||||
},
|
||||
views: {
|
||||
allMessageCampaigns: {
|
||||
universalIdentifier: 'ffedb368-33f0-43a7-b84e-e622b4e97be9',
|
||||
viewFields: {
|
||||
subject: {
|
||||
universalIdentifier: 'b017c851-e38d-4a81-ab38-0fb10e9f239e',
|
||||
},
|
||||
status: {
|
||||
universalIdentifier: 'ef35df97-b1a5-4f16-8b85-5751e5019f63',
|
||||
},
|
||||
list: {
|
||||
universalIdentifier: 'c0bf6a48-8695-4520-81e6-7462d35033b5',
|
||||
},
|
||||
fromAddress: {
|
||||
universalIdentifier: '553a0ea6-1f55-4143-a2d0-8c1ad0cf3dd1',
|
||||
},
|
||||
sentAt: {
|
||||
universalIdentifier: '7f4a9d81-afac-4d27-98de-0a2da65114f7',
|
||||
},
|
||||
sentCount: {
|
||||
universalIdentifier: '0be62e57-3955-49bd-a9ef-8f82f7a6e9aa',
|
||||
},
|
||||
failedCount: {
|
||||
universalIdentifier: 'ad346c8e-f462-499e-89c8-da01d5460dc6',
|
||||
},
|
||||
bouncedCount: {
|
||||
universalIdentifier: '135d3fb9-bc45-4426-980b-9836ed792e3a',
|
||||
},
|
||||
complainedCount: {
|
||||
universalIdentifier: '9957dc6d-05ae-4829-ae7d-7cdf9239cdd0',
|
||||
},
|
||||
recipients: {
|
||||
universalIdentifier: '2f99f444-4af3-44fd-b08d-46955c4ac2a2',
|
||||
},
|
||||
createdAt: {
|
||||
universalIdentifier: '6dffa47d-3128-4d54-924a-4f67676116c2',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
messageList: {
|
||||
universalIdentifier: '826561ea-4816-411c-baa0-eec5e6ca8866',
|
||||
@@ -888,25 +836,6 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '8e205171-ed74-4620-b7d2-674aab85033a',
|
||||
},
|
||||
},
|
||||
views: {
|
||||
allMessageLists: {
|
||||
universalIdentifier: 'c72bae18-75e9-4cb0-baeb-379d3529b98f',
|
||||
viewFields: {
|
||||
name: {
|
||||
universalIdentifier: 'c9767580-34e6-420b-923d-b4abd8c13d96',
|
||||
},
|
||||
members: {
|
||||
universalIdentifier: '6d314c4b-215a-4094-963a-ff9dd8221aea',
|
||||
},
|
||||
campaigns: {
|
||||
universalIdentifier: '037030a2-9dad-4bfd-957a-313b362172b4',
|
||||
},
|
||||
createdAt: {
|
||||
universalIdentifier: '29f3e7de-c40b-4597-8568-7318c146e4da',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
messageListMember: {
|
||||
universalIdentifier: '27773d24-8ce3-40f8-aa6c-1f590f2c08d2',
|
||||
|
||||
Reference in New Issue
Block a user