diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781277453604-rename-is-ui-read-only-to-is-ui-editable.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781277453604-rename-is-ui-read-only-to-is-ui-editable.ts index d9dcf4a89f..98c99f563c 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781277453604-rename-is-ui-read-only-to-is-ui-editable.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781277453604-rename-is-ui-read-only-to-is-ui-editable.ts @@ -3,9 +3,19 @@ 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'; -// Replaces the negative isUIReadOnly flag with the positive isUIEditable flag -// (inverted polarity) on both objectMetadata and fieldMetadata, and adds the +// Adds the positive isUIEditable flag (inverted polarity of the legacy +// isUIReadOnly flag) on both objectMetadata and fieldMetadata, and adds the // object-level isUICreatable flag. +// +// The legacy isUIReadOnly column is intentionally NOT dropped here. The +// migration runs in an ArgoCD PreSync hook before the new pods roll out, so the +// previous release's pods keep serving while the schema changes — and they +// still SELECT isUIReadOnly on every fieldMetadata read. Dropping it in the +// same release that stops using it makes those pods throw "column isUIReadOnly +// does not exist" until the rollout completes. isUIReadOnly stays a plain +// column on both entities (no longer @WasRemovedInUpgrade, so it isn't +// dropped); its removal — decorator + physical drop — is deferred to a later +// release once no running code references it (core-team-issues#2542). @RegisteredInstanceCommand('2.13.0', 1781277453604) export class RenameIsUiReadOnlyToIsUiEditableFastInstanceCommand implements FastInstanceCommand @@ -17,9 +27,6 @@ export class RenameIsUiReadOnlyToIsUiEditableFastInstanceCommand await queryRunner.query( `UPDATE "core"."objectMetadata" SET "isUIEditable" = false WHERE "isUIReadOnly" = true`, ); - await queryRunner.query( - 'ALTER TABLE "core"."objectMetadata" DROP COLUMN IF EXISTS "isUIReadOnly"', - ); await queryRunner.query( 'ALTER TABLE "core"."objectMetadata" ADD COLUMN IF NOT EXISTS "isUICreatable" boolean NOT NULL DEFAULT true', @@ -31,18 +38,9 @@ export class RenameIsUiReadOnlyToIsUiEditableFastInstanceCommand await queryRunner.query( `UPDATE "core"."fieldMetadata" SET "isUIEditable" = false WHERE "isUIReadOnly" = true`, ); - await queryRunner.query( - 'ALTER TABLE "core"."fieldMetadata" DROP COLUMN IF EXISTS "isUIReadOnly"', - ); } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'ALTER TABLE "core"."fieldMetadata" ADD COLUMN IF NOT EXISTS "isUIReadOnly" boolean NOT NULL DEFAULT false', - ); - await queryRunner.query( - `UPDATE "core"."fieldMetadata" SET "isUIReadOnly" = true WHERE "isUIEditable" = false`, - ); await queryRunner.query( 'ALTER TABLE "core"."fieldMetadata" DROP COLUMN IF EXISTS "isUIEditable"', ); @@ -50,13 +48,6 @@ export class RenameIsUiReadOnlyToIsUiEditableFastInstanceCommand await queryRunner.query( 'ALTER TABLE "core"."objectMetadata" DROP COLUMN IF EXISTS "isUICreatable"', ); - - await queryRunner.query( - 'ALTER TABLE "core"."objectMetadata" ADD COLUMN IF NOT EXISTS "isUIReadOnly" boolean NOT NULL DEFAULT false', - ); - await queryRunner.query( - `UPDATE "core"."objectMetadata" SET "isUIReadOnly" = true WHERE "isUIEditable" = false`, - ); await queryRunner.query( 'ALTER TABLE "core"."objectMetadata" DROP COLUMN IF EXISTS "isUIEditable"', ); diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts index 969862ae7e..00b59f461f 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts @@ -129,10 +129,10 @@ export class FieldMetadataEntity< @Column({ default: true }) isUIEditable: boolean; - @WasRemovedInUpgrade({ - upgradeCommandName: - RENAME_IS_UI_READ_ONLY_TO_IS_UI_EDITABLE_UPGRADE_COMMAND_NAME, - }) + // Superseded by isUIEditable. Intentionally NOT @WasRemovedInUpgrade: dropping + // it in 2.13 would break the previous release's pods mid rolling-deploy, since + // they still SELECT it. The WasRemovedInUpgrade type is kept so callers may + // omit it; the decorator + physical drop are deferred (core-team-issues#2542). @Column({ type: 'boolean', default: false }) isUIReadOnly: WasRemovedInUpgrade; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-relation-properties-to-compare.constant.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-relation-properties-to-compare.constant.ts index e68ca9d714..153c1541e7 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-relation-properties-to-compare.constant.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-relation-properties-to-compare.constant.ts @@ -8,4 +8,5 @@ export const FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE = [ 'icon', 'name', 'universalSettings', + 'isUIEditable', ] as const satisfies (typeof ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY.fieldMetadata.propertiesToCompare)[number][]; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts index 077471d39d..9721c55a4e 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts @@ -95,10 +95,10 @@ export class ObjectMetadataEntity @Column({ default: true }) isUIEditable: boolean; - @WasRemovedInUpgrade({ - upgradeCommandName: - RENAME_IS_UI_READ_ONLY_TO_IS_UI_EDITABLE_UPGRADE_COMMAND_NAME, - }) + // Superseded by isUIEditable. Intentionally NOT @WasRemovedInUpgrade: dropping + // it in 2.13 would break the previous release's pods mid rolling-deploy, since + // they still SELECT it. The WasRemovedInUpgrade type is kept so callers may + // omit it; the decorator + physical drop are deferred (core-team-issues#2542). @Column({ type: 'boolean', default: false }) isUIReadOnly: WasRemovedInUpgrade;