feat(server): add isSystemSideEffect & merge createOneObject/createOneField side-effect migrations (#21673)
## Context When an object is created via the metadata API, `createOneObject` creates its side-effect entities (INDEX view + viewFields, indexes, navigation menu item, "go to" command menu item, record-page fields view, page layout/tabs/widgets) across **three separate `validateBuildAndRunWorkspaceMigration` calls**, purely because the protection behavior (mutations → overrides, delete → deactivate, reset → reactivate) was keyed on *"owned by the standard app"*, forcing the side effects into batches with different application owners. This misrepresents ownership and breaks atomicity. This PR separates two orthogonal concepts: - **Ownership** (`applicationId`), the true owner: the caller's application (the workspace custom app today, 3rd-party apps later). - **Protection** (`isSystemSideEffect`), the row was generated by the system, so user mutations route to overrides, deletion becomes deactivation, and reset restores defaults. Once side effects are re-owned to the caller, the old `applicationId === standardApp` check can no longer tell an original side-effect row from a user-added one so a dedicated `isSystemSideEffect` flag carries the protection instead. This is **PR 1 of 2** (forward-only). It makes newly created objects and fields correct; existing workspaces are handled by a follow-up backfill (see *Out of scope*). ## What this PR does - **`isSystemSideEffect` column** on the 8 affected entities (`view`, `viewField`, `indexMetadata`, `commandMenuItem`, `pageLayout`, `pageLayoutTab`, `pageLayoutWidget`, `fieldMetadata`), with `@WasIntroducedInUpgrade` + an entry in the flat-entity property configuration (`toCompare: true`, read-only). - **Single atomic migration in `createOneObject`**: the three `validateBuildAndRunWorkspaceMigration` calls are merged into one, owned by the caller (`resolvedOwnerFlatApplication`) and the record-page view/fields, page layout, and navigation command item are re-owned to the caller and flagged `isSystemSideEffect: true`. `buildNavigationFlatCommandMenuItem` is parameterized with `applicationUniversalIdentifier` (no longer hardcoded to the standard app). - **Field-creation side effects** (`createManyFields`/`createOneField` already run as a single caller-owned migration, so no re-ownership/merge was needed): the auto-created viewField is flagged `isSystemSideEffect: true`, and a new field now also propagates to the object's **INDEX/table view** (added there as a **hidden** column, `isVisible: false`) in addition to the record-page FIELDS widget. The INDEX view is targeted directly by `key = INDEX` (it is not a page-layout widget), de-duplicated per `(viewId, fieldMetadataUniversalIdentifier)` to respect the per-view unique index. The unique-field index is likewise flagged the inverse relation field stays unflagged (`isSystem: false`). - **Protection predicate** extended: `isCallerOverridingEntity` and the removal/reset split strategies now treat `isSystemSideEffect` rows as protected even when caller-owned (route to overrides / deactivate / reset) and the page-layout-reset guards allow resetting flagged entities. - **Standard compute maps** set the flag consistently so a re-sync produces no diff (standard-object side effects stay `false`; per-object nav command items and custom-object base fields are `true`). - **Read-only GraphQL exposure** of `isSystemSideEffect` on the view / view-field / page-layout / tab / widget / command-menu-item DTOs (not exposed on create/update inputs). => Todo: needs to take this new flag into account. This is fine for now because isSystem remains on object/field. - **Fast instance command** (`2-14`) adding the 8 columns (`NOT NULL DEFAULT false`). ## Scope decisions - **`pageLayout` is not an `OverridableEntity`**, its own row has nothing user-overridable (all customization lives on tabs/widgets). It's dual-purpose (`RECORD_PAGE` side-effect vs. user `DASHBOARD`), so it gets `isSystemSideEffect` for protection only, no `overrides` jsonb. - **`navigationMenuItem` is out of scope.**: Those are side effects only for the metadata API and not marked as "system" (they can be deleted/updated etc...) - **`viewFieldGroup` is not a side effect**, it's only created via the explicit view-field-group API, never by object/field creation, so it gets no flag. ## Out of scope (follow-ups) **PR 2** — slow per-workspace backfill (re-own + flag existing side effects, recreate missing ones) and deterministic v5 identifiers for base fields / pageLayout / tab. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21673?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:
+3
@@ -197,6 +197,8 @@ export class RefactorNavigationCommandsCommand extends ActiveOrSuspendedWorkspac
|
||||
objectMetadata,
|
||||
commandMenuItemId: v4(),
|
||||
applicationId: twentyStandardFlatApplication.id,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
workspaceId,
|
||||
position: nextPosition++,
|
||||
now,
|
||||
@@ -222,6 +224,7 @@ export class RefactorNavigationCommandsCommand extends ActiveOrSuspendedWorkspac
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION.universalIdentifier,
|
||||
workspaceId,
|
||||
isSystemSideEffect: false,
|
||||
label: commandMenuItem.label,
|
||||
shortLabel: commandMenuItem.shortLabel,
|
||||
icon: commandMenuItem.icon,
|
||||
|
||||
+1
@@ -122,6 +122,7 @@ const buildLegacyCalendarEventRecordingPreferenceFieldMetadata = ({
|
||||
icon: 'IconSettingsAutomation',
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isSystemSideEffect: false,
|
||||
isNullable: false,
|
||||
isUnique: false,
|
||||
isUIEditable: true,
|
||||
|
||||
+3
@@ -1,3 +1,4 @@
|
||||
import { TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER } from 'twenty-shared/application';
|
||||
import { v5 } from 'uuid';
|
||||
|
||||
import { buildNavigationCommandMenuItemOperationsOrThrow } from 'src/database/commands/upgrade-version-command/2-10/utils/build-navigation-command-menu-item-operations-or-throw.util';
|
||||
@@ -51,6 +52,8 @@ const buildExistingNavigationItem = ({
|
||||
},
|
||||
commandMenuItemId: `command-menu-item-${objectUniversalIdentifier}`,
|
||||
applicationId: APPLICATION_ID,
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
workspaceId: WORKSPACE_ID,
|
||||
position,
|
||||
now: NOW,
|
||||
|
||||
+3
@@ -1,3 +1,4 @@
|
||||
import { TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER } from 'twenty-shared/application';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4, v5 } from 'uuid';
|
||||
|
||||
@@ -63,6 +64,8 @@ export const buildNavigationCommandMenuItemOperationsOrThrow = ({
|
||||
objectMetadata,
|
||||
commandMenuItemId: v4(),
|
||||
applicationId,
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
workspaceId,
|
||||
position: nextPosition++,
|
||||
now,
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import { QueryRunner } from 'typeorm';
|
||||
|
||||
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
|
||||
import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface';
|
||||
|
||||
const TABLES_WITH_IS_SYSTEM_SIDE_EFFECT = [
|
||||
'view',
|
||||
'viewField',
|
||||
'indexMetadata',
|
||||
'commandMenuItem',
|
||||
'pageLayout',
|
||||
'pageLayoutTab',
|
||||
'pageLayoutWidget',
|
||||
'fieldMetadata',
|
||||
] as const;
|
||||
|
||||
@RegisteredInstanceCommand('2.15.0', 1781600000000)
|
||||
export class AddIsSystemSideEffectFastInstanceCommand
|
||||
implements FastInstanceCommand
|
||||
{
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
for (const table of TABLES_WITH_IS_SYSTEM_SIDE_EFFECT) {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."${table}" ADD COLUMN IF NOT EXISTS "isSystemSideEffect" boolean NOT NULL DEFAULT false`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
for (const table of TABLES_WITH_IS_SYSTEM_SIDE_EFFECT) {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."${table}" DROP COLUMN IF EXISTS "isSystemSideEffect"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export const ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME =
|
||||
'2.15.0_AddIsSystemSideEffectFastInstanceCommand_1781600000000';
|
||||
+14
-12
@@ -18,6 +18,19 @@ import { DropWorkspaceVersionColumnFastInstanceCommand } from 'src/database/comm
|
||||
import { AddIsPreInstalledToApplicationRegistrationFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-1/2-1-instance-command-fast-1776886452831-add-is-pre-installed-to-application-registration';
|
||||
import { AddProviderExecutedToAgentMessagePartFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-1/2-1-instance-command-fast-1777012800000-add-provider-executed-to-agent-message-part';
|
||||
import { BackfillPageLayoutWidgetPositionSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-1/2-1-instance-command-slow-1795000002000-backfill-page-layout-widget-position';
|
||||
import { DropEmailingDomainDriverColumnFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-11/2-11-instance-command-fast-1780926908000-drop-emailing-domain-driver-column';
|
||||
import { DropIsCustomFromObjectAndFieldMetadataFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-12/2-12-instance-command-fast-1780579070012-drop-is-custom-from-object-and-field-metadata';
|
||||
import { ViewOverridableEntityFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-12/2-12-instance-command-fast-1781114009075-view-overridable-entity';
|
||||
import { AddEmailingDomainUnsubscribeHostFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1780088214774-add-emailing-domain-unsubscribe-host';
|
||||
import { AddArchivedAtToConnectedAccountFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781171103000-add-archived-at-to-connected-account';
|
||||
import { CreateMessageSuppressionCoreTableFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781250000000-create-message-suppression-core-table';
|
||||
import { CommandMenuItemOverridableEntityFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781253016028-command-menu-item-overridable-entity';
|
||||
import { CreateUnsubscribeTopicCoreTableFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781260000000-create-unsubscribe-topic-core-table';
|
||||
import { RenameIsUiReadOnlyToIsUiEditableFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781277453604-rename-is-ui-read-only-to-is-ui-editable';
|
||||
import { BackfillNonUiCreatableStandardSystemObjectsSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-slow-1781277480000-backfill-non-ui-creatable-standard-system-objects';
|
||||
import { SetTableWidgetViewsVisibilityToWorkspaceSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-14/2-14-instance-command-slow-1781515653781-set-table-widget-views-visibility-to-workspace';
|
||||
import { AddIsSystemSideEffectFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-15/2-15-instance-command-fast-1781600000000-add-is-system-side-effect';
|
||||
import { BackfillConnectionSecuritySlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-15/2-15-instance-command-slow-1781461753981-backfill-connection-security';
|
||||
import { AddCacheTokensToAgentChatThreadFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-2/2-2-instance-command-fast-1777455269302-add-cache-tokens-to-agent-chat-thread';
|
||||
import { AddLogoToApplicationFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-2/2-2-instance-command-fast-1777539664664-add-logo-to-application';
|
||||
import { AddSubFieldNameToViewSortEarlyFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1747234200000-add-sub-field-name-to-view-sort';
|
||||
@@ -59,18 +72,6 @@ import { EmailingDomainTenantStatusAndGlobalUniquenessFastInstanceCommand } from
|
||||
import { AddLogicFunctionExecutionModeFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-9/2-9-instance-command-fast-1799000030000-add-logic-function-execution-mode';
|
||||
import { EncryptNonSecretApplicationVariableSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-9/2-9-instance-command-slow-1798400000000-encrypt-non-secret-application-variable';
|
||||
import { MigrateAiModelPreferencesSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-9/2-9-instance-command-slow-1799000010000-migrate-ai-model-preferences';
|
||||
import { DropIsCustomFromObjectAndFieldMetadataFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-12/2-12-instance-command-fast-1780579070012-drop-is-custom-from-object-and-field-metadata';
|
||||
import { AddArchivedAtToConnectedAccountFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781171103000-add-archived-at-to-connected-account';
|
||||
import { DropEmailingDomainDriverColumnFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-11/2-11-instance-command-fast-1780926908000-drop-emailing-domain-driver-column';
|
||||
import { AddEmailingDomainUnsubscribeHostFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1780088214774-add-emailing-domain-unsubscribe-host';
|
||||
import { CreateMessageSuppressionCoreTableFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781250000000-create-message-suppression-core-table';
|
||||
import { CreateUnsubscribeTopicCoreTableFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781260000000-create-unsubscribe-topic-core-table';
|
||||
import { ViewOverridableEntityFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-12/2-12-instance-command-fast-1781114009075-view-overridable-entity';
|
||||
import { RenameIsUiReadOnlyToIsUiEditableFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781277453604-rename-is-ui-read-only-to-is-ui-editable';
|
||||
import { BackfillNonUiCreatableStandardSystemObjectsSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-slow-1781277480000-backfill-non-ui-creatable-standard-system-objects';
|
||||
import { CommandMenuItemOverridableEntityFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781253016028-command-menu-item-overridable-entity';
|
||||
import { SetTableWidgetViewsVisibilityToWorkspaceSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-14/2-14-instance-command-slow-1781515653781-set-table-widget-views-visibility-to-workspace';
|
||||
import { BackfillConnectionSecuritySlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-15/2-15-instance-command-slow-1781461753981-backfill-connection-security';
|
||||
|
||||
export const INSTANCE_COMMANDS = [
|
||||
AddViewFieldGroupIdIndexOnViewFieldFastInstanceCommand,
|
||||
@@ -143,5 +144,6 @@ export const INSTANCE_COMMANDS = [
|
||||
BackfillNonUiCreatableStandardSystemObjectsSlowInstanceCommand,
|
||||
CommandMenuItemOverridableEntityFastInstanceCommand,
|
||||
SetTableWidgetViewsVisibilityToWorkspaceSlowInstanceCommand,
|
||||
AddIsSystemSideEffectFastInstanceCommand,
|
||||
BackfillConnectionSecuritySlowInstanceCommand,
|
||||
];
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ export const fromCommandMenuItemManifestToUniversalFlatCommandMenuItem = ({
|
||||
workflowVersionId: null,
|
||||
pageLayoutUniversalIdentifier: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
universalOverrides: null,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
|
||||
+2
@@ -94,6 +94,8 @@ export const fromFieldManifestToUniversalFlatFieldMetadata = ({
|
||||
universalSettings: fieldManifest.universalSettings ?? null,
|
||||
isActive: true,
|
||||
isSystem: fieldManifest.name in PARTIAL_SYSTEM_FLAT_FIELD_METADATAS,
|
||||
isSystemSideEffect:
|
||||
fieldManifest.name in PARTIAL_SYSTEM_FLAT_FIELD_METADATAS,
|
||||
isUIEditable: fieldManifest.isUIEditable ?? true,
|
||||
isNullable: fieldManifest.isNullable ?? true,
|
||||
isUnique: fieldManifest.isUnique ?? false,
|
||||
|
||||
+1
@@ -129,6 +129,7 @@ export const fromIndexManifestToUniversalFlatIndex = ({
|
||||
indexWhereClause: null,
|
||||
isCustom: false,
|
||||
isUnique: indexManifest.isUnique ?? false,
|
||||
isSystemSideEffect: false,
|
||||
universalFlatIndexFieldMetadatas,
|
||||
},
|
||||
});
|
||||
|
||||
+1
@@ -24,6 +24,7 @@ export const fromPageLayoutManifestToUniversalFlatPageLayout = ({
|
||||
pageLayoutManifest.defaultTabToFocusOnMobileAndSidePanelUniversalIdentifier ??
|
||||
null,
|
||||
tabUniversalIdentifiers: [],
|
||||
isSystemSideEffect: false,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
|
||||
+1
@@ -24,6 +24,7 @@ export const fromPageLayoutTabManifestToUniversalFlatPageLayoutTab = ({
|
||||
layoutMode:
|
||||
pageLayoutTabManifest.layoutMode ?? PageLayoutTabLayoutMode.GRID,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
widgetUniversalIdentifiers: [],
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
|
||||
+1
@@ -21,6 +21,7 @@ export const fromPageLayoutWidgetManifestToUniversalFlatPageLayoutWidget = ({
|
||||
pageLayoutTabUniversalIdentifier,
|
||||
title: pageLayoutWidgetManifest.title,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
type: pageLayoutWidgetManifest.type as WidgetType,
|
||||
objectMetadataUniversalIdentifier:
|
||||
pageLayoutWidgetManifest.objectUniversalIdentifier ?? null,
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ export const fromViewFieldManifestToUniversalFlatViewField = ({
|
||||
viewFieldManifest.viewFieldGroupUniversalIdentifier ?? null,
|
||||
isVisible: viewFieldManifest.isVisible ?? true,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
size: viewFieldManifest.size ?? 0,
|
||||
position: viewFieldManifest.position,
|
||||
aggregateOperation: viewFieldManifest.aggregateOperation ?? null,
|
||||
|
||||
+1
@@ -42,6 +42,7 @@ export const fromViewManifestToUniversalFlatView = ({
|
||||
anyFieldFilterValue: null,
|
||||
createdByUserWorkspaceId: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
universalOverrides: null,
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
|
||||
+1
@@ -356,6 +356,7 @@ export class CommandMenuItemService {
|
||||
flatCommandMenuItemToDelete.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
isSystemSideEffect: flatCommandMenuItemToDelete.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const deactivatedFlatCommandMenuItem = {
|
||||
|
||||
+7
@@ -14,6 +14,7 @@ import { type SerializedRelation } from 'twenty-shared/types';
|
||||
|
||||
import { WasIntroducedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-introduced-in-upgrade.decorator';
|
||||
import { type CommandMenuItemPayload } from 'src/engine/metadata-modules/command-menu-item/dtos/command-menu-item-payload.union';
|
||||
import { ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-15/is-system-side-effect-upgrade-command-name.constant';
|
||||
import { CommandMenuItemAvailabilityType } from 'src/engine/metadata-modules/command-menu-item/enums/command-menu-item-availability-type.enum';
|
||||
import { EngineComponentKey } from 'src/engine/metadata-modules/command-menu-item/enums/engine-component-key.enum';
|
||||
import { FrontComponentEntity } from 'src/engine/metadata-modules/front-component/entities/front-component.entity';
|
||||
@@ -129,6 +130,12 @@ export class CommandMenuItemEntity
|
||||
@JoinColumn({ name: 'pageLayoutId' })
|
||||
pageLayout: Relation<PageLayoutEntity> | null;
|
||||
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName: ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME,
|
||||
})
|
||||
@Column({ nullable: false, default: false, type: 'boolean' })
|
||||
isSystemSideEffect: boolean;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ const baseCommandMenuItem = {
|
||||
payload: { objectMetadataItemId: 'obj-id-1' },
|
||||
workspaceId: 'ws-id-1',
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
+7
@@ -22,6 +22,7 @@ import {
|
||||
|
||||
import { WasIntroducedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-introduced-in-upgrade.decorator';
|
||||
import { WasRemovedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-removed-in-upgrade.decorator';
|
||||
import { ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-15/is-system-side-effect-upgrade-command-name.constant';
|
||||
import { RENAME_IS_UI_READ_ONLY_TO_IS_UI_EDITABLE_UPGRADE_COMMAND_NAME } from 'src/engine/metadata-modules/object-metadata/constants/rename-is-ui-read-only-to-is-ui-editable-upgrade-command-name.constant';
|
||||
import { type FieldStandardOverridesDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-standard-overrides.dto';
|
||||
import { AssignIfIsGivenFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/assign-if-is-given-field-metadata-type.type';
|
||||
@@ -122,6 +123,12 @@ export class FieldMetadataEntity<
|
||||
@Column({ default: false })
|
||||
isSystem: boolean;
|
||||
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName: ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME,
|
||||
})
|
||||
@Column({ nullable: false, default: false, type: 'boolean' })
|
||||
isSystemSideEffect: boolean;
|
||||
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName:
|
||||
RENAME_IS_UI_READ_ONLY_TO_IS_UI_EDITABLE_UPGRADE_COMMAND_NAME,
|
||||
|
||||
+3
-5
@@ -10,7 +10,6 @@ import {
|
||||
NAVIGATION_INTERPOLATED_LABEL,
|
||||
NAVIGATION_INTERPOLATED_SHORT_LABEL,
|
||||
} from 'src/engine/metadata-modules/flat-command-menu-item/utils/build-navigation-flat-command-menu-item.util';
|
||||
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
|
||||
|
||||
const NAVIGATION_COMMAND_UUID_NAMESPACE =
|
||||
'b31830da-2ae0-48eb-a915-12fa4ab96dd3';
|
||||
@@ -26,6 +25,7 @@ const baseArgs = {
|
||||
objectMetadata: baseObjectMetadata,
|
||||
commandMenuItemId: 'cmd-id-1',
|
||||
applicationId: 'app-id-1',
|
||||
applicationUniversalIdentifier: 'app-universal-1',
|
||||
workspaceId: 'ws-id-1',
|
||||
position: 5,
|
||||
now: '2026-01-01T00:00:00.000Z',
|
||||
@@ -86,12 +86,10 @@ describe('buildNavigationFlatCommandMenuItem', () => {
|
||||
expect(result.position).toBe(5);
|
||||
});
|
||||
|
||||
it('should set applicationUniversalIdentifier from TWENTY_STANDARD_APPLICATION', () => {
|
||||
it('should set applicationUniversalIdentifier from the provided argument', () => {
|
||||
const result = buildNavigationFlatCommandMenuItem(baseArgs);
|
||||
|
||||
expect(result.applicationUniversalIdentifier).toBe(
|
||||
TWENTY_STANDARD_APPLICATION.universalIdentifier,
|
||||
);
|
||||
expect(result.applicationUniversalIdentifier).toBe('app-universal-1');
|
||||
});
|
||||
|
||||
it('should set engineComponentKey to NAVIGATION', () => {
|
||||
|
||||
+4
-3
@@ -6,7 +6,6 @@ import { v5 } from 'uuid';
|
||||
import { CommandMenuItemAvailabilityType } from 'src/engine/metadata-modules/command-menu-item/enums/command-menu-item-availability-type.enum';
|
||||
import { EngineComponentKey } from 'src/engine/metadata-modules/command-menu-item/enums/engine-component-key.enum';
|
||||
import { type FlatCommandMenuItem } from 'src/engine/metadata-modules/flat-command-menu-item/types/flat-command-menu-item.type';
|
||||
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
|
||||
|
||||
export const NAVIGATION_COMMAND_UUID_NAMESPACE =
|
||||
'b31830da-2ae0-48eb-a915-12fa4ab96dd3';
|
||||
@@ -51,6 +50,7 @@ export const buildNavigationFlatCommandMenuItem = ({
|
||||
objectMetadata,
|
||||
commandMenuItemId,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
workspaceId,
|
||||
position,
|
||||
now,
|
||||
@@ -63,6 +63,7 @@ export const buildNavigationFlatCommandMenuItem = ({
|
||||
};
|
||||
commandMenuItemId: string;
|
||||
applicationId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
workspaceId: string;
|
||||
position: number;
|
||||
now: string;
|
||||
@@ -82,8 +83,7 @@ export const buildNavigationFlatCommandMenuItem = ({
|
||||
id: commandMenuItemId,
|
||||
universalIdentifier,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
workspaceId,
|
||||
label: NAVIGATION_INTERPOLATED_LABEL,
|
||||
shortLabel: NAVIGATION_INTERPOLATED_SHORT_LABEL,
|
||||
@@ -105,6 +105,7 @@ export const buildNavigationFlatCommandMenuItem = ({
|
||||
pageLayoutId: null,
|
||||
pageLayoutUniversalIdentifier: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: true,
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
createdAt: now,
|
||||
|
||||
+1
@@ -116,6 +116,7 @@ export const fromCommandMenuItemEntityToFlatCommandMenuItem = ({
|
||||
pageLayoutId: commandMenuItemEntity.pageLayoutId,
|
||||
pageLayoutUniversalIdentifier,
|
||||
isActive: commandMenuItemEntity.isActive,
|
||||
isSystemSideEffect: commandMenuItemEntity.isSystemSideEffect,
|
||||
overrides: commandMenuItemEntity.overrides,
|
||||
universalOverrides,
|
||||
};
|
||||
|
||||
+1
@@ -77,6 +77,7 @@ export const fromCreateCommandMenuItemInputToFlatCommandMenuItemToCreate = ({
|
||||
applicationId: flatApplication.id,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
createdAt: now,
|
||||
|
||||
+1
@@ -53,6 +53,7 @@ export const fromUpdateCommandMenuItemInputToFlatCommandMenuItemToUpdateOrThrow
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingFlatCommandMenuItem.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingFlatCommandMenuItem.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
|
||||
+40
@@ -40,6 +40,11 @@ type MetadataEntityPropertyConfiguration<
|
||||
|
||||
export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
fieldMetadata: {
|
||||
isSystemSideEffect: {
|
||||
toCompare: false,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
},
|
||||
defaultValue: {
|
||||
toCompare: true,
|
||||
toStringify: true,
|
||||
@@ -265,6 +270,11 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
},
|
||||
},
|
||||
view: {
|
||||
isSystemSideEffect: {
|
||||
toCompare: false,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
},
|
||||
key: { toCompare: true, toStringify: false, universalProperty: undefined },
|
||||
deletedAt: {
|
||||
toCompare: true,
|
||||
@@ -445,6 +455,11 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
},
|
||||
},
|
||||
viewField: {
|
||||
isSystemSideEffect: {
|
||||
toCompare: false,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
},
|
||||
isVisible: {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
@@ -550,6 +565,11 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
},
|
||||
},
|
||||
index: {
|
||||
isSystemSideEffect: {
|
||||
toCompare: false,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
},
|
||||
indexType: {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
@@ -893,6 +913,11 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
},
|
||||
},
|
||||
pageLayout: {
|
||||
isSystemSideEffect: {
|
||||
toCompare: false,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
},
|
||||
name: { toCompare: true, toStringify: false, universalProperty: undefined },
|
||||
type: { toCompare: true, toStringify: false, universalProperty: undefined },
|
||||
objectMetadataId: {
|
||||
@@ -923,6 +948,11 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
},
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
isSystemSideEffect: {
|
||||
toCompare: false,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
},
|
||||
title: {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
@@ -997,6 +1027,11 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
},
|
||||
},
|
||||
pageLayoutTab: {
|
||||
isSystemSideEffect: {
|
||||
toCompare: false,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
},
|
||||
title: {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
@@ -1092,6 +1127,11 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
},
|
||||
},
|
||||
commandMenuItem: {
|
||||
isSystemSideEffect: {
|
||||
toCompare: false,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
},
|
||||
label: {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
|
||||
+3
-1
@@ -1,5 +1,6 @@
|
||||
type EntityWithApplicationIdentifier = {
|
||||
applicationUniversalIdentifier: string;
|
||||
isSystemSideEffect?: boolean;
|
||||
};
|
||||
|
||||
export const splitEntitiesByRemovalStrategy = <
|
||||
@@ -22,7 +23,8 @@ export const splitEntitiesByRemovalStrategy = <
|
||||
for (const entity of entitiesToRemove) {
|
||||
if (
|
||||
entity.applicationUniversalIdentifier ===
|
||||
workspaceCustomApplicationUniversalIdentifier
|
||||
workspaceCustomApplicationUniversalIdentifier &&
|
||||
!entity.isSystemSideEffect
|
||||
) {
|
||||
toHardDelete.push(entity);
|
||||
} else {
|
||||
|
||||
+3
-1
@@ -2,6 +2,7 @@ type EntityWithApplicationIdentifierAndOverrides = {
|
||||
applicationUniversalIdentifier: string;
|
||||
isActive: boolean;
|
||||
overrides: unknown;
|
||||
isSystemSideEffect?: boolean;
|
||||
};
|
||||
|
||||
export const splitEntitiesByResetStrategy = <
|
||||
@@ -28,7 +29,8 @@ export const splitEntitiesByResetStrategy = <
|
||||
for (const entity of entities) {
|
||||
if (
|
||||
entity.applicationUniversalIdentifier ===
|
||||
workspaceCustomApplicationUniversalIdentifier
|
||||
workspaceCustomApplicationUniversalIdentifier &&
|
||||
!entity.isSystemSideEffect
|
||||
) {
|
||||
toHardDelete.push(entity);
|
||||
} else {
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ export const getFlatFieldMetadataMock = <T extends FieldMetadataType>(
|
||||
icon: 'icon',
|
||||
id: faker.string.uuid(),
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
name: 'flatFieldMetadataName',
|
||||
label: 'flat field metadata label',
|
||||
isNullable: true,
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ export const getRelationTargetFlatFieldMetadataMock = ({
|
||||
const createdAt = '2024-01-01T00:00:00.000Z';
|
||||
|
||||
return {
|
||||
isSystemSideEffect: false,
|
||||
calendarViewIds: [],
|
||||
mainGroupByFieldMetadataViewIds: [],
|
||||
viewFilterIds: [],
|
||||
|
||||
+6
@@ -127,6 +127,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"kanbanAggregateOperationViewUniversalIdentifiers": [],
|
||||
@@ -161,6 +162,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"kanbanAggregateOperationViewUniversalIdentifiers": [],
|
||||
@@ -197,6 +199,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"kanbanAggregateOperationViewUniversalIdentifiers": [],
|
||||
@@ -231,6 +234,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"kanbanAggregateOperationViewUniversalIdentifiers": [],
|
||||
@@ -263,6 +267,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"indexType": "BTREE",
|
||||
"indexWhereClause": null,
|
||||
"isCustom": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUnique": false,
|
||||
"name": "IDX_f687e4e4252800dddd8e5518362",
|
||||
"objectMetadataUniversalIdentifier": Any<String>,
|
||||
@@ -285,6 +290,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"indexType": "BTREE",
|
||||
"indexWhereClause": null,
|
||||
"isCustom": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUnique": false,
|
||||
"name": "IDX_cb15d901e889e25d0a9acecb595",
|
||||
"objectMetadataUniversalIdentifier": Any<String>,
|
||||
|
||||
+1
@@ -38,6 +38,7 @@ export const generateIndexForFlatFieldMetadata = ({
|
||||
indexWhereClause: null,
|
||||
isCustom: true,
|
||||
isUnique: flatFieldMetadata.isUnique ?? false,
|
||||
isSystemSideEffect: true,
|
||||
objectMetadataUniversalIdentifier:
|
||||
flatObjectMetadata.universalIdentifier,
|
||||
universalIdentifier: indexMetadataUniversalIdentifier,
|
||||
|
||||
+1
@@ -41,6 +41,7 @@ export const getDefaultFlatFieldMetadata = ({
|
||||
createFieldInput.isRemoteCreation,
|
||||
),
|
||||
isSystem: createFieldInput.isSystem ?? false,
|
||||
isSystemSideEffect: false,
|
||||
isUnique: createFieldInput.isUnique ?? false,
|
||||
label: createFieldInput.label,
|
||||
name: createFieldInput.name,
|
||||
|
||||
+1
@@ -27,6 +27,7 @@ export const getFlatIndexMetadataMock = (
|
||||
indexWhereClause: null,
|
||||
isCustom: false,
|
||||
isUnique: false,
|
||||
isSystemSideEffect: false,
|
||||
name: 'defaultFlatIndexMetadataName',
|
||||
updatedAt: createdAt,
|
||||
workspaceId: faker.string.uuid(),
|
||||
|
||||
+8
-2
@@ -71,6 +71,7 @@ export const recomputeViewFieldIdentifierAfterFlatObjectIdentifierUpdate = ({
|
||||
position: lowestViewFieldPosition - 1,
|
||||
isVisible: true,
|
||||
isActive: true,
|
||||
isSystemSideEffect: flatView.isSystemSideEffect,
|
||||
size: DEFAULT_VIEW_FIELD_SIZE,
|
||||
viewId: flatView.id,
|
||||
viewUniversalIdentifier: flatView.universalIdentifier,
|
||||
@@ -92,11 +93,16 @@ export const recomputeViewFieldIdentifierAfterFlatObjectIdentifierUpdate = ({
|
||||
|
||||
accumulator.flatViewFieldsToCreate.push(flatViewFieldToCreate);
|
||||
} else if (
|
||||
labelMetadataIdentifierViewField.position > lowestViewFieldPosition
|
||||
labelMetadataIdentifierViewField.position > lowestViewFieldPosition ||
|
||||
labelMetadataIdentifierViewField.isVisible === false
|
||||
) {
|
||||
const updatedFlatViewField = {
|
||||
...labelMetadataIdentifierViewField,
|
||||
position: lowestViewFieldPosition - 1,
|
||||
position:
|
||||
labelMetadataIdentifierViewField.position > lowestViewFieldPosition
|
||||
? lowestViewFieldPosition - 1
|
||||
: labelMetadataIdentifierViewField.position,
|
||||
isVisible: true,
|
||||
};
|
||||
|
||||
accumulator.flatViewFieldsToUpdate.push(updatedFlatViewField);
|
||||
|
||||
+1
@@ -45,6 +45,7 @@ export const fromCreatePageLayoutTabInputToFlatPageLayoutTabToCreate = ({
|
||||
title: createPageLayoutTabInput.title,
|
||||
position: createPageLayoutTabInput.position ?? 0,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
pageLayoutId: createPageLayoutTabInput.pageLayoutId,
|
||||
pageLayoutUniversalIdentifier,
|
||||
workspaceId,
|
||||
|
||||
+1
@@ -60,6 +60,7 @@ export const fromUpdatePageLayoutTabInputToFlatPageLayoutTabToUpdateOrThrow = ({
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingFlatPageLayoutTabToUpdate.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingFlatPageLayoutTabToUpdate.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
|
||||
+1
@@ -42,6 +42,7 @@ export const transformPageLayoutTabEntityToFlatPageLayoutTab = ({
|
||||
title: pageLayoutTabEntity.title,
|
||||
position: pageLayoutTabEntity.position,
|
||||
isActive: pageLayoutTabEntity.isActive,
|
||||
isSystemSideEffect: pageLayoutTabEntity.isSystemSideEffect,
|
||||
pageLayoutId: pageLayoutTabEntity.pageLayoutId,
|
||||
workspaceId: pageLayoutTabEntity.workspaceId,
|
||||
universalIdentifier: pageLayoutTabEntity.universalIdentifier,
|
||||
|
||||
+1
@@ -65,6 +65,7 @@ export const fromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreate = ({
|
||||
id: pageLayoutWidgetId,
|
||||
...commonProperties,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
workspaceId,
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
|
||||
+2
@@ -89,6 +89,8 @@ export const fromUpdatePageLayoutWidgetInputToFlatPageLayoutWidgetToUpdateOrThro
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingFlatPageLayoutWidgetToUpdate.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
isSystemSideEffect:
|
||||
existingFlatPageLayoutWidgetToUpdate.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
|
||||
+1
@@ -44,6 +44,7 @@ export const fromCreatePageLayoutInputToFlatPageLayoutToCreate = ({
|
||||
type: createPageLayoutInput.type ?? PageLayoutType.RECORD_PAGE,
|
||||
objectMetadataId: createPageLayoutInput.objectMetadataId ?? null,
|
||||
objectMetadataUniversalIdentifier,
|
||||
isSystemSideEffect: false,
|
||||
workspaceId,
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
|
||||
+1
@@ -64,6 +64,7 @@ export const transformPageLayoutEntityToFlatPageLayout = ({
|
||||
name: pageLayoutEntity.name,
|
||||
type: pageLayoutEntity.type,
|
||||
objectMetadataId: pageLayoutEntity.objectMetadataId,
|
||||
isSystemSideEffect: pageLayoutEntity.isSystemSideEffect,
|
||||
workspaceId: pageLayoutEntity.workspaceId,
|
||||
universalIdentifier: pageLayoutEntity.universalIdentifier,
|
||||
applicationId: pageLayoutEntity.applicationId,
|
||||
|
||||
+1
@@ -59,6 +59,7 @@ export const fromUpdateViewFieldGroupInputToFlatViewFieldGroupToUpdateOrThrow =
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingFlatViewFieldGroupToUpdate.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
isSystemSideEffect: false,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
|
||||
+211
-2
@@ -1,3 +1,5 @@
|
||||
import { ViewKey } from 'twenty-shared/types';
|
||||
|
||||
import { type FlatPageLayoutWidgetMaps } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-maps.type';
|
||||
import { type FlatViewFieldGroupMaps } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group-maps.type';
|
||||
import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/metadata-modules/flat-view-field/constants/default-view-field-size.constant';
|
||||
@@ -21,13 +23,30 @@ const buildEmptyFlatEntityMaps = () => ({
|
||||
});
|
||||
|
||||
const buildFlatViewMaps = (
|
||||
entries: { id: string; universalIdentifier: string }[] = [],
|
||||
entries: {
|
||||
id: string;
|
||||
universalIdentifier: string;
|
||||
key?: ViewKey | null;
|
||||
isActive?: boolean;
|
||||
isSystemSideEffect?: boolean;
|
||||
objectMetadataUniversalIdentifier?: string | null;
|
||||
deletedAt?: string | null;
|
||||
}[] = [],
|
||||
): FlatViewMaps =>
|
||||
({
|
||||
byUniversalIdentifier: Object.fromEntries(
|
||||
entries.map((entry) => [
|
||||
entry.universalIdentifier,
|
||||
{ universalIdentifier: entry.universalIdentifier, id: entry.id },
|
||||
{
|
||||
universalIdentifier: entry.universalIdentifier,
|
||||
id: entry.id,
|
||||
key: entry.key ?? null,
|
||||
isActive: entry.isActive ?? true,
|
||||
isSystemSideEffect: entry.isSystemSideEffect ?? false,
|
||||
objectMetadataUniversalIdentifier:
|
||||
entry.objectMetadataUniversalIdentifier ?? null,
|
||||
deletedAt: entry.deletedAt ?? null,
|
||||
},
|
||||
]),
|
||||
),
|
||||
universalIdentifierById: Object.fromEntries(
|
||||
@@ -713,6 +732,196 @@ describe('computeFlatViewFieldsFromFieldsWidgets', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isSystemSideEffect inheritance from parent view', () => {
|
||||
it('should flag the created view field when the parent view is a system side effect', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget(),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{
|
||||
id: VIEW_ID,
|
||||
universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER,
|
||||
isSystemSideEffect: true,
|
||||
},
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].isSystemSideEffect).toBe(true);
|
||||
});
|
||||
|
||||
it('should not flag the created view field when the parent view is not a system side effect', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget(),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{
|
||||
id: VIEW_ID,
|
||||
universalIdentifier: VIEW_UNIVERSAL_IDENTIFIER,
|
||||
isSystemSideEffect: false,
|
||||
},
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].isSystemSideEffect).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('INDEX view propagation', () => {
|
||||
it('should add a hidden, flagged view field to the object INDEX view even without a fields widget', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps:
|
||||
buildEmptyFlatEntityMaps() as unknown as FlatPageLayoutWidgetMaps,
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{
|
||||
id: 'index-view-db-id',
|
||||
universalIdentifier: 'index-view-uid',
|
||||
key: ViewKey.INDEX,
|
||||
isSystemSideEffect: true,
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
},
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]).toMatchObject({
|
||||
viewUniversalIdentifier: 'index-view-uid',
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
isVisible: false,
|
||||
isSystemSideEffect: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should not target a standalone non-INDEX view without a widget', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps:
|
||||
buildEmptyFlatEntityMaps() as unknown as FlatPageLayoutWidgetMaps,
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{
|
||||
id: 'plain-view-db-id',
|
||||
universalIdentifier: 'plain-view-uid',
|
||||
key: null,
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
},
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should skip an inactive or soft-deleted INDEX view', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps:
|
||||
buildEmptyFlatEntityMaps() as unknown as FlatPageLayoutWidgetMaps,
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{
|
||||
id: 'inactive-index-view-db-id',
|
||||
universalIdentifier: 'inactive-index-view-uid',
|
||||
key: ViewKey.INDEX,
|
||||
isActive: false,
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
},
|
||||
{
|
||||
id: 'deleted-index-view-db-id',
|
||||
universalIdentifier: 'deleted-index-view-uid',
|
||||
key: ViewKey.INDEX,
|
||||
deletedAt: '2024-01-01T00:00:00.000Z',
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
},
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not duplicate a field when a fields widget and the INDEX view share the same view', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
fieldsToCreate: [
|
||||
{
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
fieldMetadataUniversalIdentifier: 'field-uid-1',
|
||||
},
|
||||
],
|
||||
flatPageLayoutWidgetMaps: buildFlatPageLayoutWidgetMaps([
|
||||
buildFieldsWidget({ viewId: 'index-view-db-id', isVisible: true }),
|
||||
]),
|
||||
flatViewFieldMaps: buildFlatViewFieldMaps(),
|
||||
flatViewMaps: buildFlatViewMaps([
|
||||
{
|
||||
id: 'index-view-db-id',
|
||||
universalIdentifier: 'index-view-uid',
|
||||
key: ViewKey.INDEX,
|
||||
objectMetadataUniversalIdentifier:
|
||||
OBJECT_METADATA_UNIVERSAL_IDENTIFIER,
|
||||
},
|
||||
]),
|
||||
flatViewFieldGroupMaps: buildFlatViewFieldGroupMaps(),
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].isVisible).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('unique universal identifiers', () => {
|
||||
it('should generate unique universalIdentifier for each created view field', () => {
|
||||
const result = computeFlatViewFieldsFromFieldsWidgets({
|
||||
|
||||
+77
-26
@@ -1,8 +1,8 @@
|
||||
import { ViewKey } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatPageLayoutWidgetMaps } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-maps.type';
|
||||
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
|
||||
import { type FlatViewFieldGroupMaps } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group-maps.type';
|
||||
import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/metadata-modules/flat-view-field/constants/default-view-field-size.constant';
|
||||
import { type FlatViewFieldMaps } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field-maps.type';
|
||||
@@ -19,6 +19,11 @@ type FieldToCreateInfo = {
|
||||
fieldMetadataUniversalIdentifier: string;
|
||||
};
|
||||
|
||||
type FieldViewTarget = {
|
||||
viewId: string;
|
||||
isVisible: boolean;
|
||||
};
|
||||
|
||||
const isFieldsWidgetConfiguration = (
|
||||
configuration: AllPageLayoutWidgetConfiguration,
|
||||
): configuration is FieldsConfigurationDTO => {
|
||||
@@ -28,25 +33,65 @@ const isFieldsWidgetConfiguration = (
|
||||
);
|
||||
};
|
||||
|
||||
const getMatchingFieldsWidgets = ({
|
||||
const getFieldViewTargets = ({
|
||||
objectMetadataUniversalIdentifier,
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatViewMaps,
|
||||
}: {
|
||||
objectMetadataUniversalIdentifier: string;
|
||||
flatPageLayoutWidgetMaps: FlatPageLayoutWidgetMaps;
|
||||
}): FlatPageLayoutWidget[] =>
|
||||
Object.values(flatPageLayoutWidgetMaps.byUniversalIdentifier)
|
||||
.filter(isDefined)
|
||||
.filter(
|
||||
(widget) =>
|
||||
widget.isActive &&
|
||||
widget.type === WidgetType.FIELDS &&
|
||||
widget.objectMetadataUniversalIdentifier ===
|
||||
objectMetadataUniversalIdentifier &&
|
||||
isFieldsWidgetConfiguration(widget.configuration) &&
|
||||
isDefined(widget.configuration.viewId) &&
|
||||
isDefined(widget.configuration.newFieldDefaultVisibility),
|
||||
);
|
||||
flatViewMaps: FlatViewMaps;
|
||||
}): FieldViewTarget[] => {
|
||||
const targets: FieldViewTarget[] = [];
|
||||
const seenViewIds = new Set<string>();
|
||||
|
||||
for (const widget of Object.values(
|
||||
flatPageLayoutWidgetMaps.byUniversalIdentifier,
|
||||
).filter(isDefined)) {
|
||||
if (
|
||||
!widget.isActive ||
|
||||
widget.type !== WidgetType.FIELDS ||
|
||||
widget.objectMetadataUniversalIdentifier !==
|
||||
objectMetadataUniversalIdentifier ||
|
||||
!isFieldsWidgetConfiguration(widget.configuration)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { viewId, newFieldDefaultVisibility } = widget.configuration;
|
||||
|
||||
if (
|
||||
!isDefined(viewId) ||
|
||||
!isDefined(newFieldDefaultVisibility) ||
|
||||
seenViewIds.has(viewId)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seenViewIds.add(viewId);
|
||||
targets.push({ viewId, isVisible: newFieldDefaultVisibility });
|
||||
}
|
||||
|
||||
for (const view of Object.values(flatViewMaps.byUniversalIdentifier).filter(
|
||||
isDefined,
|
||||
)) {
|
||||
if (
|
||||
view.key !== ViewKey.INDEX ||
|
||||
!view.isActive ||
|
||||
isDefined(view.deletedAt) ||
|
||||
view.objectMetadataUniversalIdentifier !==
|
||||
objectMetadataUniversalIdentifier ||
|
||||
seenViewIds.has(view.id)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seenViewIds.add(view.id);
|
||||
targets.push({ viewId: view.id, isVisible: false });
|
||||
}
|
||||
|
||||
return targets;
|
||||
};
|
||||
|
||||
const findLastViewFieldGroupId = ({
|
||||
viewId,
|
||||
@@ -130,11 +175,13 @@ export const computeFlatViewFieldsFromFieldsWidgets = ({
|
||||
];
|
||||
|
||||
const nextPositionByKey = new Map<string, number>();
|
||||
const queuedViewFieldKeys = new Set<string>();
|
||||
|
||||
for (const objectMetadataUniversalIdentifier of objectMetadataUniversalIdentifiers) {
|
||||
const matchingWidgets = getMatchingFieldsWidgets({
|
||||
const targets = getFieldViewTargets({
|
||||
objectMetadataUniversalIdentifier,
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatViewMaps,
|
||||
});
|
||||
|
||||
const fieldsForObject = fieldsToCreate.filter(
|
||||
@@ -143,16 +190,7 @@ export const computeFlatViewFieldsFromFieldsWidgets = ({
|
||||
objectMetadataUniversalIdentifier,
|
||||
);
|
||||
|
||||
for (const widget of matchingWidgets) {
|
||||
if (!isFieldsWidgetConfiguration(widget.configuration)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const configuration = widget.configuration;
|
||||
|
||||
const viewId = configuration.viewId!;
|
||||
const isVisible = configuration.newFieldDefaultVisibility!;
|
||||
|
||||
for (const { viewId, isVisible } of targets) {
|
||||
const viewUniversalIdentifier =
|
||||
flatViewMaps.universalIdentifierById[viewId] ?? null;
|
||||
|
||||
@@ -160,6 +198,10 @@ export const computeFlatViewFieldsFromFieldsWidgets = ({
|
||||
continue;
|
||||
}
|
||||
|
||||
const isSystemSideEffect =
|
||||
flatViewMaps.byUniversalIdentifier[viewUniversalIdentifier]
|
||||
?.isSystemSideEffect ?? false;
|
||||
|
||||
const viewFieldGroupId = findLastViewFieldGroupId({
|
||||
viewId,
|
||||
flatViewFieldGroupMaps,
|
||||
@@ -184,6 +226,14 @@ export const computeFlatViewFieldsFromFieldsWidgets = ({
|
||||
}
|
||||
|
||||
for (const field of fieldsForObject) {
|
||||
const dedupKey = `${viewId}:${field.fieldMetadataUniversalIdentifier}`;
|
||||
|
||||
if (queuedViewFieldKeys.has(dedupKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
queuedViewFieldKeys.add(dedupKey);
|
||||
|
||||
const position = nextPositionByKey.get(positionKey)!;
|
||||
|
||||
nextPositionByKey.set(positionKey, position + 1);
|
||||
@@ -200,6 +250,7 @@ export const computeFlatViewFieldsFromFieldsWidgets = ({
|
||||
position,
|
||||
aggregateOperation: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect,
|
||||
universalOverrides: null,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
|
||||
+1
@@ -67,6 +67,7 @@ export const fromCreateViewFieldInputToFlatViewFieldToCreate = ({
|
||||
position: createViewFieldInput.position ?? 0,
|
||||
aggregateOperation: createViewFieldInput.aggregateOperation ?? null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
universalOverrides: null,
|
||||
viewFieldGroupUniversalIdentifier,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
|
||||
+1
@@ -64,6 +64,7 @@ export const fromUpdateViewFieldInputToFlatViewFieldToUpdateOrThrow = ({
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingFlatViewFieldToUpdate.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingFlatViewFieldToUpdate.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
|
||||
+1
@@ -87,6 +87,7 @@ export const fromCreateViewInputToFlatViewToCreate = ({
|
||||
visibility: createViewInput.visibility ?? ViewVisibility.WORKSPACE,
|
||||
createdByUserWorkspaceId: createdByUserWorkspaceId ?? null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
universalOverrides: null,
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
|
||||
+1
@@ -49,6 +49,7 @@ export const fromDeleteViewInputToFlatViewOrThrow = ({
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingFlatViewToDelete.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingFlatViewToDelete.isSystemSideEffect,
|
||||
});
|
||||
|
||||
if (shouldDeactivate) {
|
||||
|
||||
+1
@@ -75,6 +75,7 @@ export const fromUpdateViewInputToFlatViewToUpdateOrThrow = ({
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingFlatViewToUpdate.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingFlatViewToUpdate.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
|
||||
+8
@@ -12,6 +12,8 @@ import {
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { WasIntroducedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-introduced-in-upgrade.decorator';
|
||||
import { ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-15/is-system-side-effect-upgrade-command-name.constant';
|
||||
import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity';
|
||||
import { IndexType } from 'src/engine/metadata-modules/index-metadata/types/indexType.types';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
@@ -78,4 +80,10 @@ export class IndexMetadataEntity
|
||||
nullable: false,
|
||||
})
|
||||
indexType: IndexType;
|
||||
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName: ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME,
|
||||
})
|
||||
@Column({ nullable: false, default: false, type: 'boolean' })
|
||||
isSystemSideEffect: boolean;
|
||||
}
|
||||
|
||||
+1
@@ -243,6 +243,7 @@ export class IndexMetadataService {
|
||||
indexWhereClause: null,
|
||||
isCustom: true,
|
||||
isUnique: false,
|
||||
isSystemSideEffect: false,
|
||||
objectMetadataUniversalIdentifier:
|
||||
flatObjectMetadata.universalIdentifier,
|
||||
universalIdentifier: indexMetadataUniversalIdentifier,
|
||||
|
||||
+1
@@ -65,6 +65,7 @@ describe('generateFlatIndexMetadataWithNameOrThrow', () => {
|
||||
indexWhereClause: overrides.indexWhereClause ?? null,
|
||||
isUnique: overrides.isUnique,
|
||||
isCustom: false,
|
||||
isSystemSideEffect: false,
|
||||
universalFlatIndexFieldMetadatas: overrides.fieldIds.map((id, order) => ({
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
|
||||
+8
@@ -23,6 +23,7 @@ const PARTIAL_ID_FIELD = {
|
||||
isUnique: true,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
isSystemSideEffect: true,
|
||||
isUIEditable: false,
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: 'uuid',
|
||||
@@ -51,6 +52,7 @@ const PARTIAL_CREATED_AT_FIELD = {
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
isSystemSideEffect: true,
|
||||
isUIEditable: false,
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: 'now',
|
||||
@@ -79,6 +81,7 @@ const PARTIAL_UPDATED_AT_FIELD = {
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
isSystemSideEffect: true,
|
||||
isUIEditable: false,
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: 'now',
|
||||
@@ -107,6 +110,7 @@ const PARTIAL_DELETED_AT_FIELD = {
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
isSystemSideEffect: true,
|
||||
isUIEditable: false,
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: null,
|
||||
@@ -135,6 +139,7 @@ const PARTIAL_CREATED_BY_FIELD = {
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
isSystemSideEffect: true,
|
||||
isUIEditable: false,
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: { name: "''", source: "'MANUAL'" },
|
||||
@@ -163,6 +168,7 @@ const PARTIAL_UPDATED_BY_FIELD = {
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
isSystemSideEffect: true,
|
||||
isUIEditable: false,
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: { name: "''", source: "'MANUAL'" },
|
||||
@@ -191,6 +197,7 @@ const PARTIAL_POSITION_FIELD = {
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
isSystemSideEffect: true,
|
||||
isUIEditable: false,
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: 0,
|
||||
@@ -219,6 +226,7 @@ const PARTIAL_SEARCH_VECTOR_FIELD = {
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
isSystemSideEffect: true,
|
||||
isUIEditable: false,
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: null,
|
||||
|
||||
+71
-100
@@ -145,7 +145,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
existingFlatObjectMetadata,
|
||||
flatCommandMenuItemMaps: existingFlatCommandMenuItemMaps,
|
||||
workspaceId,
|
||||
applicationId: twentyStandardFlatApplication.id,
|
||||
applicationId: resolvedOwnerFlatApplication.id,
|
||||
applicationUniversalIdentifier:
|
||||
resolvedOwnerFlatApplication.universalIdentifier,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
@@ -465,7 +467,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
workspaceId: string;
|
||||
ownerFlatApplication?: FlatApplication;
|
||||
}): Promise<FlatObjectMetadata> {
|
||||
const { workspaceCustomFlatApplication, twentyStandardFlatApplication } =
|
||||
const { workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{
|
||||
workspaceId,
|
||||
@@ -497,7 +499,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
});
|
||||
|
||||
const flatDefaultViewFieldsToCreate = computeFlatViewFieldsToCreate({
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
flatApplication: resolvedOwnerFlatApplication,
|
||||
objectFlatFieldMetadatas: flatFieldMetadataToCreateOnObject,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
flatObjectMetadataToCreate.labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
@@ -525,11 +527,38 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
{
|
||||
objectMetadata: flatObjectMetadataToCreate,
|
||||
workspaceId,
|
||||
applicationId: twentyStandardFlatApplication.id,
|
||||
applicationId: resolvedOwnerFlatApplication.id,
|
||||
applicationUniversalIdentifier:
|
||||
resolvedOwnerFlatApplication.universalIdentifier,
|
||||
flatCommandMenuItemMaps,
|
||||
},
|
||||
);
|
||||
|
||||
const flatRecordPageFieldsViewToCreate =
|
||||
this.computeFlatRecordPageFieldsViewToCreate({
|
||||
objectMetadata: flatObjectMetadataToCreate,
|
||||
flatApplication: resolvedOwnerFlatApplication,
|
||||
});
|
||||
|
||||
const flatRecordPageFieldsViewFieldsToCreate =
|
||||
computeFlatViewFieldsToCreate({
|
||||
flatApplication: resolvedOwnerFlatApplication,
|
||||
objectFlatFieldMetadatas: flatFieldMetadataToCreateOnObject,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
flatObjectMetadataToCreate.labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
viewUniversalIdentifier:
|
||||
flatRecordPageFieldsViewToCreate.universalIdentifier,
|
||||
excludeLabelIdentifier: true,
|
||||
});
|
||||
|
||||
const flatDefaultRecordPageLayoutsToCreate =
|
||||
this.computeFlatDefaultRecordPageLayoutToCreate({
|
||||
objectMetadata: flatObjectMetadataToCreate,
|
||||
flatApplication: resolvedOwnerFlatApplication,
|
||||
recordPageFieldsView: flatRecordPageFieldsViewToCreate,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
@@ -540,12 +569,18 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
view: {
|
||||
flatEntityToCreate: [flatDefaultViewToCreate],
|
||||
flatEntityToCreate: [
|
||||
flatDefaultViewToCreate,
|
||||
flatRecordPageFieldsViewToCreate,
|
||||
],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: flatDefaultViewFieldsToCreate,
|
||||
flatEntityToCreate: [
|
||||
...flatDefaultViewFieldsToCreate,
|
||||
...flatRecordPageFieldsViewFieldsToCreate,
|
||||
],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
@@ -562,6 +597,29 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
commandMenuItem: {
|
||||
flatEntityToCreate: [flatCommandMenuItemToCreate],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayout: {
|
||||
flatEntityToCreate:
|
||||
flatDefaultRecordPageLayoutsToCreate.pageLayouts,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutTab: {
|
||||
flatEntityToCreate:
|
||||
flatDefaultRecordPageLayoutsToCreate.pageLayoutTabs,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate:
|
||||
flatDefaultRecordPageLayoutsToCreate.pageLayoutWidgets,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
...(isDefined(flatNavigationMenuItemToCreate)
|
||||
? {
|
||||
navigationMenuItem: {
|
||||
@@ -586,100 +644,6 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
);
|
||||
}
|
||||
|
||||
const commandMenuItemMigrationResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
commandMenuItem: {
|
||||
flatEntityToCreate: [flatCommandMenuItemToCreate],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (commandMenuItemMigrationResult.status === 'fail') {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
commandMenuItemMigrationResult,
|
||||
'Multiple validation errors occurred while creating command menu item',
|
||||
);
|
||||
}
|
||||
|
||||
const flatRecordPageFieldsViewToCreate =
|
||||
this.computeFlatRecordPageFieldsViewToCreate({
|
||||
objectMetadata: flatObjectMetadataToCreate,
|
||||
flatApplication: twentyStandardFlatApplication,
|
||||
});
|
||||
|
||||
const flatRecordPageFieldsViewFieldsToCreate =
|
||||
computeFlatViewFieldsToCreate({
|
||||
flatApplication: twentyStandardFlatApplication,
|
||||
objectFlatFieldMetadatas: flatFieldMetadataToCreateOnObject,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
flatObjectMetadataToCreate.labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
viewUniversalIdentifier:
|
||||
flatRecordPageFieldsViewToCreate.universalIdentifier,
|
||||
excludeLabelIdentifier: true,
|
||||
});
|
||||
|
||||
const flatDefaultRecordPageLayoutsToCreate =
|
||||
this.computeFlatDefaultRecordPageLayoutToCreate({
|
||||
objectMetadata: flatObjectMetadataToCreate,
|
||||
flatApplication: twentyStandardFlatApplication,
|
||||
recordPageFieldsView: flatRecordPageFieldsViewToCreate,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const pageLayoutMigrationResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
view: {
|
||||
flatEntityToCreate: [flatRecordPageFieldsViewToCreate],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: flatRecordPageFieldsViewFieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayout: {
|
||||
flatEntityToCreate:
|
||||
flatDefaultRecordPageLayoutsToCreate.pageLayouts,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutTab: {
|
||||
flatEntityToCreate:
|
||||
flatDefaultRecordPageLayoutsToCreate.pageLayoutTabs,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate:
|
||||
flatDefaultRecordPageLayoutsToCreate.pageLayoutWidgets,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (pageLayoutMigrationResult.status === 'fail') {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
pageLayoutMigrationResult,
|
||||
'Multiple validation errors occurred while creating page layouts for object',
|
||||
);
|
||||
}
|
||||
|
||||
const { flatObjectMetadataMaps: recomputedFlatObjectMetadataMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
@@ -737,6 +701,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
visibility: ViewVisibility.WORKSPACE,
|
||||
createdByUserWorkspaceId: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: true,
|
||||
universalOverrides: null,
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
viewFieldGroupUniversalIdentifiers: [],
|
||||
@@ -847,6 +812,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
objectMetadata,
|
||||
workspaceId,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
flatCommandMenuItemMaps,
|
||||
}: {
|
||||
objectMetadata: {
|
||||
@@ -859,6 +825,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
};
|
||||
workspaceId: string;
|
||||
applicationId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
flatCommandMenuItemMaps: {
|
||||
byUniversalIdentifier: Record<string, FlatCommandMenuItem | undefined>;
|
||||
};
|
||||
@@ -876,6 +843,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
objectMetadata,
|
||||
commandMenuItemId: v4(),
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
workspaceId,
|
||||
position: nextPosition,
|
||||
now: new Date().toISOString(),
|
||||
@@ -909,6 +877,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
flatCommandMenuItemMaps,
|
||||
workspaceId,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
isBeingEnabled: boolean;
|
||||
isBeingDisabled: boolean;
|
||||
@@ -918,6 +887,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
};
|
||||
workspaceId: string;
|
||||
applicationId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
}): {
|
||||
commandMenuItemsToCreate: FlatCommandMenuItem[];
|
||||
commandMenuItemsToUpdate: FlatCommandMenuItem[];
|
||||
@@ -943,6 +913,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
objectMetadata: existingFlatObjectMetadata,
|
||||
workspaceId,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
flatCommandMenuItemMaps,
|
||||
}),
|
||||
],
|
||||
|
||||
+1
@@ -134,6 +134,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
isNullable: true,
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isSystemSideEffect: true,
|
||||
isUIEditable: true,
|
||||
defaultValue: null,
|
||||
createdAt: now,
|
||||
|
||||
+1
@@ -40,6 +40,7 @@ export const buildDefaultIndexesForCustomObject = ({
|
||||
indexWhereClause: null,
|
||||
isCustom: false,
|
||||
isUnique: false,
|
||||
isSystemSideEffect: true,
|
||||
objectMetadataUniversalIdentifier: flatObjectMetadata.universalIdentifier,
|
||||
universalIdentifier: tsFlatVectorIndexUniversalIdentifier,
|
||||
updatedAt: createdAt.toISOString(),
|
||||
|
||||
+3
@@ -64,6 +64,7 @@ export const computeFlatDefaultRecordPageLayoutToCreate = ({
|
||||
widgetIds: [widgetId],
|
||||
widgetUniversalIdentifiers: [widgetUniversalIdentifier],
|
||||
isActive: true,
|
||||
isSystemSideEffect: true,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
@@ -119,6 +120,7 @@ export const computeFlatDefaultRecordPageLayoutToCreate = ({
|
||||
objectMetadataId: objectMetadata.id,
|
||||
objectMetadataUniversalIdentifier: objectMetadata.universalIdentifier,
|
||||
isActive: true,
|
||||
isSystemSideEffect: true,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
@@ -141,6 +143,7 @@ export const computeFlatDefaultRecordPageLayoutToCreate = ({
|
||||
tabUniversalIdentifiers: pageLayoutTabs.map(
|
||||
(tab) => tab.universalIdentifier,
|
||||
),
|
||||
isSystemSideEffect: true,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
|
||||
+1
@@ -43,6 +43,7 @@ export const computeFlatRecordPageFieldsViewToCreate = ({
|
||||
visibility: ViewVisibility.WORKSPACE,
|
||||
createdByUserWorkspaceId: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: true,
|
||||
universalOverrides: null,
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
viewFieldGroupUniversalIdentifiers: [],
|
||||
|
||||
+1
@@ -65,6 +65,7 @@ export const computeFlatViewFieldsToCreate = ({
|
||||
position: index,
|
||||
aggregateOperation: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: true,
|
||||
universalOverrides: null,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
}));
|
||||
|
||||
+8
@@ -15,6 +15,8 @@ import {
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { WasIntroducedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-introduced-in-upgrade.decorator';
|
||||
import { ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-15/is-system-side-effect-upgrade-command-name.constant';
|
||||
import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity';
|
||||
import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity';
|
||||
import { OverridableEntity } from 'src/engine/workspace-manager/types/overridable-entity';
|
||||
@@ -70,6 +72,12 @@ export class PageLayoutTabEntity
|
||||
})
|
||||
layoutMode: PageLayoutTabLayoutMode;
|
||||
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName: ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME,
|
||||
})
|
||||
@Column({ nullable: false, default: false, type: 'boolean' })
|
||||
isSystemSideEffect: boolean;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
+8
@@ -19,6 +19,8 @@ import {
|
||||
type Relation,
|
||||
} from 'typeorm';
|
||||
|
||||
import { WasIntroducedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-introduced-in-upgrade.decorator';
|
||||
import { ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-15/is-system-side-effect-upgrade-command-name.constant';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity';
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
@@ -100,6 +102,12 @@ export class PageLayoutWidgetEntity<
|
||||
PageLayoutWidgetConfigurationTypeSettings<TWidgetConfigurationType>
|
||||
>;
|
||||
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName: ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME,
|
||||
})
|
||||
@Column({ nullable: false, default: false, type: 'boolean' })
|
||||
isSystemSideEffect: boolean;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
+8
@@ -14,6 +14,8 @@ import {
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { WasIntroducedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-introduced-in-upgrade.decorator';
|
||||
import { ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-15/is-system-side-effect-upgrade-command-name.constant';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity';
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
@@ -69,6 +71,12 @@ export class PageLayoutEntity
|
||||
@JoinColumn({ name: 'defaultTabToFocusOnMobileAndSidePanelId' })
|
||||
defaultTabToFocusOnMobileAndSidePanel: Relation<PageLayoutTabEntity> | null;
|
||||
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName: ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME,
|
||||
})
|
||||
@Column({ nullable: false, default: false, type: 'boolean' })
|
||||
isSystemSideEffect: boolean;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
+6
-3
@@ -112,7 +112,8 @@ export class PageLayoutResetService {
|
||||
|
||||
if (
|
||||
widget.applicationUniversalIdentifier ===
|
||||
workspaceCustomFlatApplication.universalIdentifier
|
||||
workspaceCustomFlatApplication.universalIdentifier &&
|
||||
!widget.isSystemSideEffect
|
||||
) {
|
||||
throw new PageLayoutWidgetException(
|
||||
`Custom widget "${id}" cannot be reset to default`,
|
||||
@@ -255,7 +256,8 @@ export class PageLayoutResetService {
|
||||
|
||||
if (
|
||||
tab.applicationUniversalIdentifier ===
|
||||
workspaceCustomFlatApplication.universalIdentifier
|
||||
workspaceCustomFlatApplication.universalIdentifier &&
|
||||
!tab.isSystemSideEffect
|
||||
) {
|
||||
throw new PageLayoutTabException(
|
||||
`Custom tab "${id}" cannot be reset to default`,
|
||||
@@ -404,7 +406,8 @@ export class PageLayoutResetService {
|
||||
|
||||
if (
|
||||
layout.applicationUniversalIdentifier ===
|
||||
workspaceCustomFlatApplication.universalIdentifier
|
||||
workspaceCustomFlatApplication.universalIdentifier &&
|
||||
!layout.isSystemSideEffect
|
||||
) {
|
||||
throw new PageLayoutException(
|
||||
`Custom page layout "${id}" cannot be reset to default`,
|
||||
|
||||
+5
@@ -328,6 +328,7 @@ export class PageLayoutUpdateService {
|
||||
layoutMode: tabInput.layoutMode ?? PageLayoutTabLayoutMode.GRID,
|
||||
overrides: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
};
|
||||
},
|
||||
);
|
||||
@@ -345,6 +346,7 @@ export class PageLayoutUpdateService {
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingTab.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingTab.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const editableProperties = {
|
||||
@@ -384,6 +386,7 @@ export class PageLayoutUpdateService {
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingTab.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingTab.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const editableProperties = {
|
||||
@@ -605,6 +608,7 @@ export class PageLayoutUpdateService {
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
universalConfiguration:
|
||||
fromPageLayoutWidgetConfigurationToUniversalConfiguration({
|
||||
configuration: widgetInput.configuration,
|
||||
@@ -721,6 +725,7 @@ export class PageLayoutUpdateService {
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingWidget.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingWidget.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const configuration = widgetInput.configuration ?? null;
|
||||
|
||||
+3
@@ -11,6 +11,7 @@ describe('isCallerOverridingEntity', () => {
|
||||
callerApplicationUniversalIdentifier: CUSTOM_APP_ID,
|
||||
entityApplicationUniversalIdentifier: STANDARD_APP_ID,
|
||||
workspaceCustomApplicationUniversalIdentifier: CUSTOM_APP_ID,
|
||||
isSystemSideEffect: false,
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
@@ -21,6 +22,7 @@ describe('isCallerOverridingEntity', () => {
|
||||
callerApplicationUniversalIdentifier: CUSTOM_APP_ID,
|
||||
entityApplicationUniversalIdentifier: CUSTOM_APP_ID,
|
||||
workspaceCustomApplicationUniversalIdentifier: CUSTOM_APP_ID,
|
||||
isSystemSideEffect: false,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
@@ -31,6 +33,7 @@ describe('isCallerOverridingEntity', () => {
|
||||
callerApplicationUniversalIdentifier: OTHER_APP_ID,
|
||||
entityApplicationUniversalIdentifier: STANDARD_APP_ID,
|
||||
workspaceCustomApplicationUniversalIdentifier: CUSTOM_APP_ID,
|
||||
isSystemSideEffect: false,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
+5
-2
@@ -2,15 +2,18 @@ export const isCallerOverridingEntity = ({
|
||||
callerApplicationUniversalIdentifier,
|
||||
entityApplicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
isSystemSideEffect,
|
||||
}: {
|
||||
callerApplicationUniversalIdentifier: string;
|
||||
entityApplicationUniversalIdentifier: string;
|
||||
workspaceCustomApplicationUniversalIdentifier: string;
|
||||
isSystemSideEffect: boolean;
|
||||
}): boolean => {
|
||||
return (
|
||||
callerApplicationUniversalIdentifier ===
|
||||
workspaceCustomApplicationUniversalIdentifier &&
|
||||
entityApplicationUniversalIdentifier !==
|
||||
workspaceCustomApplicationUniversalIdentifier
|
||||
(entityApplicationUniversalIdentifier !==
|
||||
workspaceCustomApplicationUniversalIdentifier ||
|
||||
isSystemSideEffect)
|
||||
);
|
||||
};
|
||||
|
||||
+7
@@ -250,6 +250,7 @@ export class FieldsWidgetUpsertService {
|
||||
existingGroup.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
applicationUniversalIdentifier,
|
||||
isSystemSideEffect: false,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties: sanitizedGroupProps } =
|
||||
@@ -349,6 +350,7 @@ export class FieldsWidgetUpsertService {
|
||||
existingField.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
applicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingField.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties: sanitizedFieldProps } =
|
||||
@@ -435,6 +437,7 @@ export class FieldsWidgetUpsertService {
|
||||
existingField.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
applicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingField.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties: sanitizedFieldProps } =
|
||||
@@ -530,6 +533,7 @@ export class FieldsWidgetUpsertService {
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
@@ -641,6 +645,7 @@ export class FieldsWidgetUpsertService {
|
||||
existingField.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
applicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingField.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties: sanitizedFieldProps } =
|
||||
@@ -700,6 +705,7 @@ export class FieldsWidgetUpsertService {
|
||||
existingField.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
applicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingField.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties: sanitizedFieldProps } =
|
||||
@@ -788,6 +794,7 @@ export class FieldsWidgetUpsertService {
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
|
||||
+8
@@ -15,7 +15,9 @@ import {
|
||||
type SerializedRelation,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
import { WasIntroducedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-introduced-in-upgrade.decorator';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-15/is-system-side-effect-upgrade-command-name.constant';
|
||||
import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { OverridableEntity } from 'src/engine/workspace-manager/types/overridable-entity';
|
||||
@@ -80,6 +82,12 @@ export class ViewFieldEntity
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
viewFieldGroupId: string | null;
|
||||
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName: ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME,
|
||||
})
|
||||
@Column({ nullable: false, default: false, type: 'boolean' })
|
||||
isSystemSideEffect: boolean;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
|
||||
import { WasIntroducedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-introduced-in-upgrade.decorator';
|
||||
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
import { ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-15/is-system-side-effect-upgrade-command-name.constant';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
@@ -204,6 +205,12 @@ export class ViewEntity
|
||||
})
|
||||
visibility: ViewVisibility;
|
||||
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName: ADD_IS_SYSTEM_SIDE_EFFECT_UPGRADE_COMMAND_NAME,
|
||||
})
|
||||
@Column({ nullable: false, default: false, type: 'boolean' })
|
||||
isSystemSideEffect: boolean;
|
||||
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
createdByUserWorkspaceId: string | null;
|
||||
|
||||
|
||||
+2
@@ -443,6 +443,7 @@ export class ViewWidgetUpsertService {
|
||||
existingField.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
applicationUniversalIdentifier,
|
||||
isSystemSideEffect: existingField.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const { overrides, updatedEditableProperties: sanitizedFieldProps } =
|
||||
@@ -523,6 +524,7 @@ export class ViewWidgetUpsertService {
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
|
||||
@@ -329,6 +329,7 @@ export class ViewService {
|
||||
existingFlatView.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
isSystemSideEffect: existingFlatView.isSystemSideEffect,
|
||||
});
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
+1
@@ -146,6 +146,7 @@ describe('WorkspaceEntityManager', () => {
|
||||
label: 'Field Name',
|
||||
objectMetadataId: 'test-entity-id',
|
||||
isNullable: true,
|
||||
isSystemSideEffect: false,
|
||||
isLabelSyncedWithName: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
|
||||
+1
@@ -70,6 +70,7 @@ describe('WorkspaceRepository', () => {
|
||||
type: FieldMetadataType.UUID,
|
||||
objectMetadataId: 'test-metadata-id',
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
isNullable: false,
|
||||
isUnique: true,
|
||||
isSystem: true,
|
||||
|
||||
+4
@@ -23,6 +23,7 @@ export const getPageLayoutFlatEntitySeeds = ({
|
||||
applicationId: flatApplication.id,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
workspaceId,
|
||||
isSystemSideEffect: false,
|
||||
name: 'Sales Dashboard Layout',
|
||||
type: PageLayoutType.DASHBOARD,
|
||||
objectMetadataId: null,
|
||||
@@ -44,6 +45,7 @@ export const getPageLayoutFlatEntitySeeds = ({
|
||||
applicationId: flatApplication.id,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
workspaceId,
|
||||
isSystemSideEffect: false,
|
||||
name: 'Customer Dashboard Layout',
|
||||
type: PageLayoutType.DASHBOARD,
|
||||
objectMetadataId: null,
|
||||
@@ -65,6 +67,7 @@ export const getPageLayoutFlatEntitySeeds = ({
|
||||
applicationId: flatApplication.id,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
workspaceId,
|
||||
isSystemSideEffect: false,
|
||||
name: 'Team Dashboard Layout',
|
||||
type: PageLayoutType.DASHBOARD,
|
||||
objectMetadataId: null,
|
||||
@@ -89,6 +92,7 @@ export const getPageLayoutFlatEntitySeeds = ({
|
||||
applicationId: flatApplication.id,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
workspaceId,
|
||||
isSystemSideEffect: false,
|
||||
name: 'Documentation',
|
||||
type: PageLayoutType.STANDALONE_PAGE,
|
||||
objectMetadataId: null,
|
||||
|
||||
+1
@@ -33,6 +33,7 @@ export const getPageLayoutTabFlatEntitySeeds = ({
|
||||
widgetIds: [],
|
||||
widgetUniversalIdentifiers: [],
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
icon: null,
|
||||
layoutMode: PageLayoutTabLayoutMode.GRID,
|
||||
overrides: null,
|
||||
|
||||
+1
@@ -92,6 +92,7 @@ export const prefillFrontComponentCommandMenuItems = async ({
|
||||
pageLayoutId: definition.pageLayoutId ?? null,
|
||||
pageLayoutUniversalIdentifier: definition.pageLayoutId ?? null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
createdAt: now,
|
||||
|
||||
+1
@@ -71,6 +71,7 @@ export const prefillWorkflowCommandMenuItems = async ({
|
||||
pageLayoutId: null,
|
||||
pageLayoutUniversalIdentifier: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
createdAt: now,
|
||||
|
||||
+3
@@ -1,3 +1,4 @@
|
||||
import { TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER } from 'twenty-shared/application';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
@@ -72,6 +73,8 @@ export const buildStandardFlatCommandMenuItemMaps = ({
|
||||
objectMetadata: flatObject,
|
||||
commandMenuItemId: v4(),
|
||||
applicationId: twentyStandardApplicationId,
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
workspaceId,
|
||||
position,
|
||||
now,
|
||||
|
||||
+1
@@ -77,6 +77,7 @@ export const createStandardCommandMenuItemFlatMetadata = ({
|
||||
pageLayoutId: null,
|
||||
pageLayoutUniversalIdentifier: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
createdAt: now,
|
||||
|
||||
+2
@@ -9,6 +9,7 @@ import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
import { TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER } from 'twenty-shared/application';
|
||||
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { PARTIAL_SYSTEM_FLAT_FIELD_METADATAS } from 'src/engine/metadata-modules/object-metadata/constants/partial-system-flat-field-metadatas.constant';
|
||||
import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type';
|
||||
import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type';
|
||||
import { type StandardBuilderArgs } from 'src/engine/workspace-manager/twenty-standard-application/types/metadata-standard-buillder-args.type';
|
||||
@@ -82,6 +83,7 @@ export const createStandardFieldFlatMetadata = <
|
||||
icon,
|
||||
isActive: true,
|
||||
isSystem,
|
||||
isSystemSideEffect: name in PARTIAL_SYSTEM_FLAT_FIELD_METADATAS,
|
||||
isNullable,
|
||||
isUnique,
|
||||
isUIEditable,
|
||||
|
||||
+1
@@ -101,6 +101,7 @@ export const createStandardRelationFieldFlatMetadata = <
|
||||
icon,
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isSystemSideEffect: false,
|
||||
isNullable,
|
||||
isUnique: false,
|
||||
isUIEditable,
|
||||
|
||||
+1
@@ -97,6 +97,7 @@ export const createStandardIndexFlatMetadata = <
|
||||
indexWhereClause,
|
||||
isCustom: false,
|
||||
isUnique,
|
||||
isSystemSideEffect: true,
|
||||
objectMetadataUniversalIdentifier: flatObjectMetadata.universalIdentifier,
|
||||
universalIdentifier: indexDefinition.universalIdentifier,
|
||||
updatedAt: now,
|
||||
|
||||
+3
@@ -2,6 +2,7 @@ import { type PageLayoutTabLayoutMode } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
import { STANDARD_PAGE_LAYOUTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout.constant';
|
||||
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
|
||||
import { type StandardPageLayoutMetadataRelatedEntityIds } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-page-layout-metadata-related-entity-ids.util';
|
||||
@@ -36,6 +37,7 @@ export const createStandardPageLayoutTabFlatMetadata = ({
|
||||
layoutName as keyof typeof STANDARD_PAGE_LAYOUTS
|
||||
] as {
|
||||
universalIdentifier: string;
|
||||
type: PageLayoutType;
|
||||
tabs: Record<
|
||||
string,
|
||||
StandardPageLayoutTabConfig & {
|
||||
@@ -69,6 +71,7 @@ export const createStandardPageLayoutTabFlatMetadata = ({
|
||||
widgetIds,
|
||||
widgetUniversalIdentifiers,
|
||||
isActive: true,
|
||||
isSystemSideEffect: layout.type === PageLayoutType.RECORD_PAGE,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
|
||||
+3
@@ -7,6 +7,7 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type MetadataUniversalFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-universal-flat-entity.type';
|
||||
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
import { type WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
|
||||
import { type AllPageLayoutWidgetConfiguration } from 'src/engine/metadata-modules/page-layout-widget/types/all-page-layout-widget-configuration.type';
|
||||
import { STANDARD_PAGE_LAYOUTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout.constant';
|
||||
@@ -69,6 +70,7 @@ export const createStandardPageLayoutWidgetFlatMetadata = ({
|
||||
const layout = STANDARD_PAGE_LAYOUTS[
|
||||
layoutName as keyof typeof STANDARD_PAGE_LAYOUTS
|
||||
] as {
|
||||
type: PageLayoutType;
|
||||
tabs: Record<
|
||||
string,
|
||||
StandardPageLayoutTabConfig & {
|
||||
@@ -107,6 +109,7 @@ export const createStandardPageLayoutWidgetFlatMetadata = ({
|
||||
objectMetadataId,
|
||||
objectMetadataUniversalIdentifier,
|
||||
isActive: true,
|
||||
isSystemSideEffect: layout.type === PageLayoutType.RECORD_PAGE,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
|
||||
+2
-1
@@ -3,7 +3,7 @@ import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
|
||||
import { type FlatPageLayout } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout.type';
|
||||
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
|
||||
import { type PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
import { STANDARD_PAGE_LAYOUTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout.constant';
|
||||
import { type StandardObjectMetadataRelatedEntityIds } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-object-metadata-related-entity-ids.util';
|
||||
import { type StandardPageLayoutMetadataRelatedEntityIds } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-page-layout-metadata-related-entity-ids.util';
|
||||
@@ -119,6 +119,7 @@ export const createStandardPageLayoutFlatMetadata = ({
|
||||
type,
|
||||
objectMetadataId,
|
||||
objectMetadataUniversalIdentifier: objectUniversalIdentifier,
|
||||
isSystemSideEffect: type === PageLayoutType.RECORD_PAGE,
|
||||
tabIds: [],
|
||||
tabUniversalIdentifiers: [],
|
||||
createdAt: now,
|
||||
|
||||
+11
-1
@@ -75,6 +75,8 @@ export type BuildStandardFlatViewFieldMetadataMapsArgs = Omit<
|
||||
export const buildStandardFlatViewFieldMetadataMaps = (
|
||||
args: BuildStandardFlatViewFieldMetadataMapsArgs,
|
||||
): FlatEntityMaps<FlatViewField> => {
|
||||
const { flatViewMaps } = args.dependencyFlatEntityMaps;
|
||||
|
||||
const allViewFieldMetadatas: FlatViewField[] = (
|
||||
Object.keys(
|
||||
STANDARD_FLAT_VIEW_FIELD_METADATA_BUILDERS_BY_OBJECT_NAME,
|
||||
@@ -94,8 +96,16 @@ export const buildStandardFlatViewFieldMetadataMaps = (
|
||||
let flatViewFieldMaps = createEmptyFlatEntityMaps();
|
||||
|
||||
for (const viewFieldMetadata of allViewFieldMetadatas) {
|
||||
const parentView =
|
||||
flatViewMaps.byUniversalIdentifier[
|
||||
viewFieldMetadata.viewUniversalIdentifier
|
||||
];
|
||||
|
||||
flatViewFieldMaps = addFlatEntityToFlatEntityMapsOrThrow({
|
||||
flatEntity: viewFieldMetadata,
|
||||
flatEntity: {
|
||||
...viewFieldMetadata,
|
||||
isSystemSideEffect: parentView?.isSystemSideEffect ?? false,
|
||||
},
|
||||
flatEntityMaps: flatViewFieldMaps,
|
||||
});
|
||||
}
|
||||
|
||||
+1
@@ -121,6 +121,7 @@ export const createStandardViewFieldFlatMetadata = <
|
||||
size,
|
||||
aggregateOperation,
|
||||
isActive: true,
|
||||
isSystemSideEffect: false,
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
createdAt: now,
|
||||
|
||||
+4
-2
@@ -2,8 +2,8 @@ import { isDefined } from 'class-validator';
|
||||
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
import {
|
||||
type AggregateOperations,
|
||||
type ViewType,
|
||||
type ViewKey,
|
||||
ViewType,
|
||||
ViewKey,
|
||||
ViewOpenRecordIn,
|
||||
ViewVisibility,
|
||||
} from 'twenty-shared/types';
|
||||
@@ -143,6 +143,8 @@ export const createStandardViewFlatMetadata = <
|
||||
visibility: ViewVisibility.WORKSPACE,
|
||||
createdByUserWorkspaceId: null,
|
||||
isActive: true,
|
||||
isSystemSideEffect:
|
||||
key === ViewKey.INDEX || type === ViewType.FIELDS_WIDGET,
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
viewFieldIds: [],
|
||||
|
||||
+4
@@ -20,6 +20,7 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a crea
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"kanbanAggregateOperationViewIds": [],
|
||||
@@ -84,6 +85,7 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a dele
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"kanbanAggregateOperationViewIds": [],
|
||||
@@ -162,6 +164,7 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"kanbanAggregateOperationViewIds": [],
|
||||
@@ -212,6 +215,7 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"kanbanAggregateOperationViewIds": [],
|
||||
|
||||
+1
@@ -82,6 +82,7 @@ export const fromUniversalFlatIndexToFlatIndex = ({
|
||||
name: universalFlatIndexMetadata.name,
|
||||
isCustom: universalFlatIndexMetadata.isCustom,
|
||||
isUnique: universalFlatIndexMetadata.isUnique,
|
||||
isSystemSideEffect: universalFlatIndexMetadata.isSystemSideEffect,
|
||||
indexWhereClause: universalFlatIndexMetadata.indexWhereClause,
|
||||
indexType: universalFlatIndexMetadata.indexType,
|
||||
createdAt: universalFlatIndexMetadata.createdAt,
|
||||
|
||||
+1
@@ -58,6 +58,7 @@ describe('flatEntityToScalarFlatEntity', () => {
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Test Label",
|
||||
|
||||
@@ -20,6 +20,7 @@ export const getMockFieldMetadataEntity = <
|
||||
overrides: GetMockFieldMetadataEntityOverride<T>,
|
||||
): FieldMetadataEntity => {
|
||||
return {
|
||||
isSystemSideEffect: false,
|
||||
workspace: {} as WorkspaceEntity,
|
||||
calendarViews: [],
|
||||
mainGroupByFieldMetadataViews: [],
|
||||
|
||||
+84
@@ -101,6 +101,90 @@ exports[`successful find view with all sub-relations (e2e) Company View Structur
|
||||
"viewFieldGroupId": null,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
{
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": null,
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"isVisible": false,
|
||||
"position": 7,
|
||||
"size": 180,
|
||||
"updatedAt": Any<String>,
|
||||
"viewFieldGroupId": null,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
{
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": null,
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"isVisible": false,
|
||||
"position": 8,
|
||||
"size": 180,
|
||||
"updatedAt": Any<String>,
|
||||
"viewFieldGroupId": null,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
{
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": null,
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"isVisible": false,
|
||||
"position": 9,
|
||||
"size": 180,
|
||||
"updatedAt": Any<String>,
|
||||
"viewFieldGroupId": null,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
{
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": null,
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"isVisible": false,
|
||||
"position": 10,
|
||||
"size": 180,
|
||||
"updatedAt": Any<String>,
|
||||
"viewFieldGroupId": null,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
{
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": null,
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"isVisible": false,
|
||||
"position": 11,
|
||||
"size": 180,
|
||||
"updatedAt": Any<String>,
|
||||
"viewFieldGroupId": null,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
{
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": null,
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"isVisible": false,
|
||||
"position": 12,
|
||||
"size": 180,
|
||||
"updatedAt": Any<String>,
|
||||
"viewFieldGroupId": null,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
{
|
||||
"createdAt": Any<String>,
|
||||
"deletedAt": null,
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"isVisible": false,
|
||||
"position": 13,
|
||||
"size": 180,
|
||||
"updatedAt": Any<String>,
|
||||
"viewFieldGroupId": null,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
],
|
||||
"viewFilterGroups": [],
|
||||
"viewFilters": [],
|
||||
|
||||
+9
-2
@@ -69,8 +69,15 @@ describe('successful find view with all sub-relations (e2e)', () => {
|
||||
|
||||
jestExpectToBeDefined(testView);
|
||||
|
||||
expect(testView).toMatchSnapshot(
|
||||
extractRecordIdsAndDatesAsExpectAny({ ...testView }),
|
||||
const stableTestView = {
|
||||
...testView,
|
||||
viewFields: [...testView.viewFields].sort(
|
||||
(a, b) => a.position - b.position,
|
||||
),
|
||||
};
|
||||
|
||||
expect(stableTestView).toMatchSnapshot(
|
||||
extractRecordIdsAndDatesAsExpectAny({ ...stableTestView }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+21
@@ -15,6 +15,7 @@ exports[`syncApplication should create a TEXT field on the standard Company obje
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Industry",
|
||||
@@ -108,6 +109,7 @@ exports[`syncApplication should delete old field and create equivalent one when
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Id",
|
||||
@@ -133,6 +135,7 @@ exports[`syncApplication should delete old field and create equivalent one when
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Creation date",
|
||||
@@ -158,6 +161,7 @@ exports[`syncApplication should delete old field and create equivalent one when
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Last update",
|
||||
@@ -183,6 +187,7 @@ exports[`syncApplication should delete old field and create equivalent one when
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Deleted at",
|
||||
@@ -213,6 +218,7 @@ exports[`syncApplication should delete old field and create equivalent one when
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Created by",
|
||||
@@ -243,6 +249,7 @@ exports[`syncApplication should delete old field and create equivalent one when
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Updated by",
|
||||
@@ -268,6 +275,7 @@ exports[`syncApplication should delete old field and create equivalent one when
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Position",
|
||||
@@ -293,6 +301,7 @@ exports[`syncApplication should delete old field and create equivalent one when
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Search vector",
|
||||
@@ -321,6 +330,7 @@ exports[`syncApplication should delete old field and create equivalent one when
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Description",
|
||||
@@ -388,6 +398,7 @@ exports[`syncApplication should delete old field and create equivalent one when
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUIReadOnly": false,
|
||||
"isUnique": false,
|
||||
@@ -434,6 +445,7 @@ exports[`syncApplication should delete old field and create equivalent one when
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Description",
|
||||
@@ -504,6 +516,7 @@ exports[`syncApplication should return workspace migration actions on initial sy
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Id",
|
||||
@@ -529,6 +542,7 @@ exports[`syncApplication should return workspace migration actions on initial sy
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Creation date",
|
||||
@@ -554,6 +568,7 @@ exports[`syncApplication should return workspace migration actions on initial sy
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Last update",
|
||||
@@ -579,6 +594,7 @@ exports[`syncApplication should return workspace migration actions on initial sy
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Deleted at",
|
||||
@@ -609,6 +625,7 @@ exports[`syncApplication should return workspace migration actions on initial sy
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Created by",
|
||||
@@ -639,6 +656,7 @@ exports[`syncApplication should return workspace migration actions on initial sy
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Updated by",
|
||||
@@ -664,6 +682,7 @@ exports[`syncApplication should return workspace migration actions on initial sy
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Position",
|
||||
@@ -689,6 +708,7 @@ exports[`syncApplication should return workspace migration actions on initial sy
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": true,
|
||||
"isSystemSideEffect": true,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Search vector",
|
||||
@@ -717,6 +737,7 @@ exports[`syncApplication should return workspace migration actions on initial sy
|
||||
"isLabelSyncedWithName": false,
|
||||
"isNullable": true,
|
||||
"isSystem": false,
|
||||
"isSystemSideEffect": false,
|
||||
"isUIEditable": true,
|
||||
"isUnique": false,
|
||||
"label": "Description",
|
||||
|
||||
+20
-3
@@ -43,13 +43,30 @@ exports[`createOne FieldMetadataService name/label sync should return an error w
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"totalErrors": 2,
|
||||
"viewField": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
|
||||
+40
-6
@@ -44,13 +44,30 @@ exports[`Failing create field metadata tests suite should fail to create NUMERIC
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"totalErrors": 2,
|
||||
"viewField": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
@@ -110,13 +127,30 @@ exports[`Failing create field metadata tests suite should fail to create POSITIO
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"totalErrors": 2,
|
||||
"viewField": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
|
||||
+80
-12
@@ -60,14 +60,31 @@ exports[`createOne FILES field metadata - failing should fail to create files fi
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField, 1 index",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields, 1 index",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"index": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 1,
|
||||
"totalErrors": 4,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
@@ -118,13 +135,30 @@ exports[`createOne FILES field metadata - failing should fail to create files fi
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"totalErrors": 2,
|
||||
"viewField": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
@@ -175,13 +209,30 @@ exports[`createOne FILES field metadata - failing should fail to create files fi
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"totalErrors": 2,
|
||||
"viewField": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
@@ -232,13 +283,30 @@ exports[`createOne FILES field metadata - failing should fail to create files fi
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"totalErrors": 2,
|
||||
"viewField": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
|
||||
+1400
-210
File diff suppressed because it is too large
Load Diff
+174
-21
@@ -112,14 +112,48 @@ exports[`failing createOne FieldMetadataService morph relation fields v2 Morph r
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 2 fieldMetadata, 2 viewFields, 2 indices",
|
||||
"message": "Validation failed for 2 fieldMetadata, 4 viewFields, 2 indices",
|
||||
"summary": {
|
||||
"fieldMetadata": 2,
|
||||
"index": 2,
|
||||
"totalErrors": 6,
|
||||
"viewField": 2,
|
||||
"totalErrors": 8,
|
||||
"viewField": 4,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
@@ -171,13 +205,30 @@ exports[`failing createOne FieldMetadataService morph relation fields v2 Morph r
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"totalErrors": 2,
|
||||
"viewField": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
@@ -280,14 +331,48 @@ exports[`failing createOne FieldMetadataService morph relation fields v2 it shou
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 2 fieldMetadata, 2 viewFields, 1 index",
|
||||
"message": "Validation failed for 2 fieldMetadata, 4 viewFields, 1 index",
|
||||
"summary": {
|
||||
"fieldMetadata": 2,
|
||||
"index": 1,
|
||||
"totalErrors": 5,
|
||||
"viewField": 2,
|
||||
"totalErrors": 7,
|
||||
"viewField": 4,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
@@ -397,14 +482,31 @@ exports[`failing createOne FieldMetadataService morph relation fields v2 it shou
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField, 1 index",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields, 1 index",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"index": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 1,
|
||||
"totalErrors": 4,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
@@ -474,14 +576,31 @@ exports[`failing createOne FieldMetadataService morph relation fields v2 it shou
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField, 1 index",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields, 1 index",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"index": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 1,
|
||||
"totalErrors": 4,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
@@ -551,14 +670,31 @@ exports[`failing createOne FieldMetadataService morph relation fields v2 it shou
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField, 1 index",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields, 1 index",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"index": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 1,
|
||||
"totalErrors": 4,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
@@ -634,14 +770,31 @@ exports[`failing createOne FieldMetadataService morph relation fields v2 it shou
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
"viewUniversalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "viewField",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata, 1 viewField, 1 index",
|
||||
"message": "Validation failed for 1 fieldMetadata, 2 viewFields, 1 index",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"index": 1,
|
||||
"totalErrors": 3,
|
||||
"viewField": 1,
|
||||
"totalErrors": 4,
|
||||
"viewField": 2,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user