isCustom deprecation for Objects and Fields (#21228)
## Context
`isCustom` was a legacy denormalized boolean on `ObjectMetadataEntity`
and `FieldMetadataEntity`.
Now that every metadata row carries `applicationId` (via
`SyncableEntity`), "is this custom" is fully derivable, and the stored
boolean was a redundant second source of truth that could drift.
The real meaning of `isCustom` is **"the owning application is not the
twenty-standard application"** — i.e. `!belongsToTwentyStandardApp`.
Note this is *not* "belongs to the workspace custom app" as I initially
thought: third-party-application
objects/fields are custom too.
The standard application has a globally stable `universalIdentifier`, so
the value derives with no per-workspace lookup.
## Changed
## `isCustom` checks — before → after
`isCustom` is no longer a stored column. The table below lists every
site that branched on it and how it resolves now. The unifying rule:
`isCustom ≡
!isTwentyStandardApplicationUniversalIdentifier(applicationUniversalIdentifier)`.
### Server — behavioural checks
| Location | Purpose | Before | Now |
|---|---|---|---|
| `utils/compute-object-target-table.util.ts` | Physical table name `_`
prefix | `computeTableName(nameSingular, objectMetadata.isCustom)` |
derives from `applicationUniversalIdentifier` (single source for all
table-name callers) |
| `twenty-orm/factories/entity-schema.factory.ts` +
`…/entity-schema-metadata.type.ts` | ORM table name (hot path) |
`object.isCustom` | `object.applicationId !== standardApplicationId`
(computed in `buildEntitySchemaMetadataMaps`) |
|
`twenty-orm/repository/workspace-{delete,soft-delete,update}-query-builder.ts`
| Table name for mutations | `computeTableName(nameSingular,
objectMetadata.isCustom)` | `computeObjectTargetTable(objectMetadata)` |
| `index-metadata/utils/generate-deterministic-index-name-v2.ts` | Index
name hash (must stay bit-identical) | `flatObjectMetadata.isCustom` |
derives from `applicationUniversalIdentifier` |
| `object-metadata/object-record-count.service.ts` | Table name for
record count | `computeTableName(nameSingular, isCustom)` |
`computeObjectTargetTable(flatObjectMetadata)` |
|
`workspace-manager/dev-seeder/data/services/dev-seeder-data.service.ts`
| Match seed config by table name | `computeTableName(item.nameSingular,
item.isCustom)` | `computeObjectTargetTable(item)` |
| `commands/workspace-export/workspace-export.service.ts` +
`…/utils/generate-workspace-schema-ddl.util.ts` | Export table name (raw
entity) | `objectMetadata.isCustom` |
`!isTwentyStandard…(objectMetadata.application?.universalIdentifier)` |
|
`flat-field-metadata/services/flat-field-metadata-type-validator.service.ts`
| Block users creating reserved field types |
`args.flatEntityToValidate.isCustom` |
`!args.flatEntityToValidate.isSystem` |
| `api/common/.../common-create-many-query-runner.service.ts` | Don't
let client overwrite system `createdBy` |
`createdByFieldMetadata.isCustom === false` |
`createdByFieldMetadata.isSystem === true` |
|
`field-metadata/utils/resolve-field-metadata-standard-override.util.ts`
| Skip i18n/overrides for custom fields | `if (fieldMetadata.isCustom)
return raw` | **removed** — falls through on
`isDefined(standardOverrides)` |
|
`object-metadata/utils/resolve-object-metadata-standard-override.util.ts`
| Skip i18n/overrides for custom objects | `if (objectMetadata.isCustom)
return raw` | **removed** — same fall-through |
|
`command-menu-item/utils/build-navigation-interpolation-context.util.ts`
| Override context for nav labels | passed `isCustom` into resolver |
dropped (resolver no longer needs it) |
| `api/common/.../data-arg-processor.service.ts` | `isCustom` for
record-position table name | `flatObjectMetadata.isCustom` | derives
from `applicationUniversalIdentifier` |
| `metadata-modules/minimal-metadata/minimal-metadata.service.ts` |
Minimal DTO + override context | `flatObjectMetadata.isCustom` | derives
from `applicationUniversalIdentifier` |
|
`commands/upgrade-version-command/1-23/…backfill-record-page-layouts.command.ts`
| Filter to custom objects | `objectMetadata.isCustom` |
`!isTwentyStandard…(applicationUniversalIdentifier)` |
### Server — DTO / API population
| Location | Before | Now |
|---|---|---|
|
`flat-object-metadata/utils/from-flat-object-metadata-to-object-metadata-dto.util.ts`
| passthrough `isCustom` | derives from `applicationUniversalIdentifier`
|
|
`flat-field-metadata/utils/from-flat-field-metadata-to-field-metadata-dto.util.ts`
| passthrough `isCustom` | derives from `applicationUniversalIdentifier`
|
|
`object-metadata/utils/from-object-metadata-entity-to-object-metadata-dto.util.ts`
(REST) | `entity.isCustom` | `entity.applicationId !==
standardApplicationId` |
|
`field-metadata/utils/from-field-metadata-entity-to-field-metadata-dto.util.ts`
(REST) | `entity.isCustom` | `entity.applicationId !==
standardApplicationId` |
| `dataloaders/dataloader.service.ts` | passed
`flatFieldMetadata.isCustom` into override resolver | dropped (resolver
no longer needs it) |
> REST controllers (`object-metadata.controller.ts`,
`field-metadata.controller.ts`) resolve `standardApplicationId` once per
request from the cached `flatApplicationMaps`.
### Frontend
| Location | Purpose | Before | Now |
|---|---|---|---|
| `settings/.../SettingsObjectFieldDisabledActionDropdown.tsx` | Whether
an inactive field is deletable | `isDeletable = isCustomField` |
`isDeletable = isCustomField && !isSystemField` |
### Unchanged (out of scope)
`isCustom` on `IndexMetadata` / `View` / `Skill` / `Agent` and their
guards still read the persisted column.
Breaking change is on the isCustom filter on field and object APIs, this
is never used in the FE and unlikely used by external consumers
This commit is contained in:
-8
@@ -22,7 +22,6 @@ const PARTIAL_ID_FIELD = {
|
||||
isNullable: false,
|
||||
isUnique: true,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
isLabelSyncedWithName: false,
|
||||
@@ -51,7 +50,6 @@ const PARTIAL_CREATED_AT_FIELD = {
|
||||
isNullable: false,
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
isLabelSyncedWithName: false,
|
||||
@@ -80,7 +78,6 @@ const PARTIAL_UPDATED_AT_FIELD = {
|
||||
isNullable: false,
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
isLabelSyncedWithName: false,
|
||||
@@ -109,7 +106,6 @@ const PARTIAL_DELETED_AT_FIELD = {
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
isLabelSyncedWithName: false,
|
||||
@@ -138,7 +134,6 @@ const PARTIAL_CREATED_BY_FIELD = {
|
||||
isNullable: false,
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
isLabelSyncedWithName: false,
|
||||
@@ -167,7 +162,6 @@ const PARTIAL_UPDATED_BY_FIELD = {
|
||||
isNullable: false,
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
isLabelSyncedWithName: false,
|
||||
@@ -196,7 +190,6 @@ const PARTIAL_POSITION_FIELD = {
|
||||
isNullable: false,
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
isLabelSyncedWithName: false,
|
||||
@@ -225,7 +218,6 @@ const PARTIAL_SEARCH_VECTOR_FIELD = {
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isUIReadOnly: true,
|
||||
isLabelSyncedWithName: false,
|
||||
|
||||
+59
-28
@@ -16,9 +16,9 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { In, Repository } from 'typeorm';
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
import { FeatureFlagKey } from 'twenty-shared/types';
|
||||
import { In, Repository } from 'typeorm';
|
||||
|
||||
import { parseEndingBeforeRestRequest } from 'src/engine/api/rest/input-request-parsers/ending-before-parser-utils/parse-ending-before-rest-request.util';
|
||||
import { parseLimitRestRequest } from 'src/engine/api/rest/input-request-parsers/limit-parser-utils/parse-limit-rest-request.util';
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
type RestCursorPageInfo,
|
||||
} from 'src/engine/api/rest/metadata/utils/paginate-by-id-cursor.util';
|
||||
import { type AuthenticatedRequest } from 'src/engine/api/rest/types/authenticated-request';
|
||||
import { ApplicationRestApiExceptionFilter } from 'src/engine/core-modules/application/application-rest-api-exception.filter';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
@@ -37,8 +38,8 @@ import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { fromFieldMetadataEntityToFieldMetadataDto } from 'src/engine/metadata-modules/field-metadata/utils/from-field-metadata-entity-to-field-metadata-dto.util';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { computeUniqueFieldMetadataIdsFromFlatIndexMaps } from 'src/engine/metadata-modules/index-metadata/utils/compute-unique-field-metadata-ids-from-flat-index-maps.util';
|
||||
import { fromFlatObjectMetadataToObjectMetadataDto } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-to-object-metadata-dto.util';
|
||||
import { computeUniqueFieldMetadataIdsFromFlatIndexMaps } from 'src/engine/metadata-modules/index-metadata/utils/compute-unique-field-metadata-ids-from-flat-index-maps.util';
|
||||
import { CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/create-object.input';
|
||||
import { type ObjectMetadataWithFieldsDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata-with-fields.dto';
|
||||
import { UpdateObjectPayload } from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input';
|
||||
@@ -58,6 +59,7 @@ import {
|
||||
toLegacyObjectMetadataUpdateResponse,
|
||||
} from 'src/engine/metadata-modules/object-metadata/utils/to-legacy-object-metadata-response.util';
|
||||
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
|
||||
import { getTwentyStandardApplicationIdOrThrow } from 'src/engine/metadata-modules/utils/get-twenty-standard-application-id-or-throw.util';
|
||||
|
||||
@Controller('rest/metadata/objects')
|
||||
@UseGuards(
|
||||
@@ -68,6 +70,7 @@ import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/p
|
||||
@UseFilters(
|
||||
PermissionsRestApiExceptionFilter,
|
||||
ObjectMetadataRestApiExceptionFilter,
|
||||
ApplicationRestApiExceptionFilter,
|
||||
)
|
||||
@UsePipes(new ValidationPipe())
|
||||
export class ObjectMetadataController {
|
||||
@@ -92,6 +95,17 @@ export class ObjectMetadataController {
|
||||
return computeUniqueFieldMetadataIdsFromFlatIndexMaps(flatIndexMaps);
|
||||
}
|
||||
|
||||
private async loadStandardApplicationId(
|
||||
workspaceId: string,
|
||||
): Promise<string> {
|
||||
const { flatApplicationMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{ workspaceId, flatMapsKeys: ['flatApplicationMaps'] },
|
||||
);
|
||||
|
||||
return getTwentyStandardApplicationIdOrThrow(flatApplicationMaps);
|
||||
}
|
||||
|
||||
@Get()
|
||||
async findMany(
|
||||
@Req() request: AuthenticatedRequest,
|
||||
@@ -105,19 +119,22 @@ export class ObjectMetadataController {
|
||||
endingBefore: parseEndingBeforeRestRequest(request),
|
||||
});
|
||||
|
||||
const [fields, uniqueFieldMetadataIds] = await Promise.all([
|
||||
this.findFieldsForObjectIds(
|
||||
workspaceId,
|
||||
items.map((object) => object.id),
|
||||
),
|
||||
this.loadUniqueFieldMetadataIds(workspaceId),
|
||||
]);
|
||||
const [fields, uniqueFieldMetadataIds, standardApplicationId] =
|
||||
await Promise.all([
|
||||
this.findFieldsForObjectIds(
|
||||
workspaceId,
|
||||
items.map((object) => object.id),
|
||||
),
|
||||
this.loadUniqueFieldMetadataIds(workspaceId),
|
||||
this.loadStandardApplicationId(workspaceId),
|
||||
]);
|
||||
|
||||
const data = items.map((object) =>
|
||||
this.toObjectWithFieldsDto(
|
||||
object,
|
||||
fields.get(object.id) ?? [],
|
||||
uniqueFieldMetadataIds,
|
||||
standardApplicationId,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -148,17 +165,20 @@ export class ObjectMetadataController {
|
||||
);
|
||||
}
|
||||
|
||||
const [fields, uniqueFieldMetadataIds] = await Promise.all([
|
||||
this.fieldMetadataRepository.find({
|
||||
where: { objectMetadataId: object.id, workspaceId },
|
||||
}),
|
||||
this.loadUniqueFieldMetadataIds(workspaceId),
|
||||
]);
|
||||
const [fields, uniqueFieldMetadataIds, standardApplicationId] =
|
||||
await Promise.all([
|
||||
this.fieldMetadataRepository.find({
|
||||
where: { objectMetadataId: object.id, workspaceId },
|
||||
}),
|
||||
this.loadUniqueFieldMetadataIds(workspaceId),
|
||||
this.loadStandardApplicationId(workspaceId),
|
||||
]);
|
||||
|
||||
const result = this.toObjectWithFieldsDto(
|
||||
object,
|
||||
fields,
|
||||
uniqueFieldMetadataIds,
|
||||
standardApplicationId,
|
||||
);
|
||||
|
||||
return (await this.isNewMetadataFormat(workspaceId))
|
||||
@@ -176,18 +196,21 @@ export class ObjectMetadataController {
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const [fields, uniqueFieldMetadataIds] = await Promise.all([
|
||||
this.fieldMetadataRepository.find({
|
||||
where: { objectMetadataId: flatObject.id, workspaceId },
|
||||
}),
|
||||
this.loadUniqueFieldMetadataIds(workspaceId),
|
||||
]);
|
||||
const [fields, uniqueFieldMetadataIds, standardApplicationId] =
|
||||
await Promise.all([
|
||||
this.fieldMetadataRepository.find({
|
||||
where: { objectMetadataId: flatObject.id, workspaceId },
|
||||
}),
|
||||
this.loadUniqueFieldMetadataIds(workspaceId),
|
||||
this.loadStandardApplicationId(workspaceId),
|
||||
]);
|
||||
|
||||
const result: ObjectMetadataWithFieldsDTO = {
|
||||
...fromFlatObjectMetadataToObjectMetadataDto(flatObject),
|
||||
fields: fields.map((field) =>
|
||||
fromFieldMetadataEntityToFieldMetadataDto(
|
||||
field,
|
||||
standardApplicationId,
|
||||
uniqueFieldMetadataIds,
|
||||
),
|
||||
),
|
||||
@@ -247,18 +270,21 @@ export class ObjectMetadataController {
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const [fields, uniqueFieldMetadataIds] = await Promise.all([
|
||||
this.fieldMetadataRepository.find({
|
||||
where: { objectMetadataId: flatObject.id, workspaceId },
|
||||
}),
|
||||
this.loadUniqueFieldMetadataIds(workspaceId),
|
||||
]);
|
||||
const [fields, uniqueFieldMetadataIds, standardApplicationId] =
|
||||
await Promise.all([
|
||||
this.fieldMetadataRepository.find({
|
||||
where: { objectMetadataId: flatObject.id, workspaceId },
|
||||
}),
|
||||
this.loadUniqueFieldMetadataIds(workspaceId),
|
||||
this.loadStandardApplicationId(workspaceId),
|
||||
]);
|
||||
|
||||
const result: ObjectMetadataWithFieldsDTO = {
|
||||
...fromFlatObjectMetadataToObjectMetadataDto(flatObject),
|
||||
fields: fields.map((field) =>
|
||||
fromFieldMetadataEntityToFieldMetadataDto(
|
||||
field,
|
||||
standardApplicationId,
|
||||
uniqueFieldMetadataIds,
|
||||
),
|
||||
),
|
||||
@@ -307,12 +333,17 @@ export class ObjectMetadataController {
|
||||
object: ObjectMetadataEntity,
|
||||
fields: FieldMetadataEntity[],
|
||||
uniqueFieldMetadataIds: ReadonlySet<string>,
|
||||
standardApplicationId: string,
|
||||
): ObjectMetadataWithFieldsDTO {
|
||||
return {
|
||||
...fromObjectMetadataEntityToObjectMetadataDto(object),
|
||||
...fromObjectMetadataEntityToObjectMetadataDto(
|
||||
object,
|
||||
standardApplicationId,
|
||||
),
|
||||
fields: fields.map((field) =>
|
||||
fromFieldMetadataEntityToFieldMetadataDto(
|
||||
field,
|
||||
standardApplicationId,
|
||||
uniqueFieldMetadataIds,
|
||||
),
|
||||
),
|
||||
|
||||
+4
-1
@@ -62,7 +62,10 @@ export class ObjectMetadataDTO {
|
||||
@Field({ nullable: true })
|
||||
color?: string;
|
||||
|
||||
@FilterableField()
|
||||
@Field({
|
||||
deprecationReason:
|
||||
'isCustom is derived from the owning application and will be removed; an object is custom when it does not belong to the twenty-standard application.',
|
||||
})
|
||||
isCustom: boolean;
|
||||
|
||||
@FilterableField()
|
||||
|
||||
+7
-2
@@ -16,6 +16,7 @@ import { type ObjectStandardOverridesDTO } from 'src/engine/metadata-modules/obj
|
||||
import { FieldPermissionEntity } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.entity';
|
||||
import { ObjectPermissionEntity } from 'src/engine/metadata-modules/object-permission/object-permission.entity';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { WasRemovedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-removed-in-upgrade.decorator';
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';
|
||||
import { type JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
|
||||
@@ -69,8 +70,12 @@ export class ObjectMetadataEntity
|
||||
@Column({ nullable: false })
|
||||
targetTableName: string;
|
||||
|
||||
@Column({ default: false })
|
||||
isCustom: boolean;
|
||||
@WasRemovedInUpgrade({
|
||||
upgradeCommandName:
|
||||
'2.12.0_DropIsCustomFromObjectAndFieldMetadataFastInstanceCommand_1780579070012',
|
||||
})
|
||||
@Column({ type: 'boolean', default: false })
|
||||
isCustom: WasRemovedInUpgrade<boolean>;
|
||||
|
||||
@Column({ default: false })
|
||||
isRemote: boolean;
|
||||
|
||||
+1
@@ -45,6 +45,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
|
||||
TokenModule,
|
||||
WorkspaceCacheStorageModule,
|
||||
FeatureFlagModule,
|
||||
ApplicationModule,
|
||||
NestjsQueryGraphQLModule.forFeature({
|
||||
imports: [
|
||||
TypeORMModule,
|
||||
|
||||
+15
@@ -48,6 +48,21 @@ export class ObjectMetadataResolver {
|
||||
private readonly i18nService: I18nService,
|
||||
) {}
|
||||
|
||||
@ResolveField(() => Boolean, {
|
||||
deprecationReason:
|
||||
'isCustom is derived from the owning application and will be removed; an object is custom when it does not belong to the twenty-standard application.',
|
||||
})
|
||||
async isCustom(
|
||||
@Parent() objectMetadata: ObjectMetadataDTO,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
@Context() context: { loaders: IDataloaders },
|
||||
): Promise<boolean> {
|
||||
return context.loaders.isCustomLoader.load({
|
||||
workspaceId,
|
||||
applicationId: objectMetadata.applicationId,
|
||||
});
|
||||
}
|
||||
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.DATA_MODEL))
|
||||
@Query(() => [ObjectRecordCountDTO])
|
||||
async objectRecordCounts(
|
||||
|
||||
+2
-7
@@ -5,7 +5,7 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { type ObjectRecordCountDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-record-count.dto';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { computeTableName } from 'src/engine/utils/compute-table-name.util';
|
||||
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
|
||||
import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util';
|
||||
|
||||
@Injectable()
|
||||
@@ -57,12 +57,7 @@ export class ObjectRecordCountService {
|
||||
return flatObjectMetadatas.map((flatObjectMetadata) => ({
|
||||
objectNamePlural: flatObjectMetadata.namePlural,
|
||||
totalCount:
|
||||
countByTableName.get(
|
||||
computeTableName(
|
||||
flatObjectMetadata.nameSingular,
|
||||
flatObjectMetadata.isCustom,
|
||||
),
|
||||
) ?? 0,
|
||||
countByTableName.get(computeObjectTargetTable(flatObjectMetadata)) ?? 0,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -20,7 +20,6 @@ const makeFieldMetadata = (
|
||||
name: overrides.name,
|
||||
label: overrides.label ?? overrides.name,
|
||||
type: overrides.type,
|
||||
isCustom: overrides.isCustom ?? false,
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
|
||||
-25
@@ -29,7 +29,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
color: 'blue',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
} satisfies Pick<
|
||||
ObjectMetadataDTO,
|
||||
@@ -38,7 +37,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
| 'labelSingular'
|
||||
| 'description'
|
||||
| 'icon'
|
||||
| 'isCustom'
|
||||
| 'standardOverrides'
|
||||
>;
|
||||
|
||||
@@ -59,7 +57,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
color: 'blue',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
} satisfies Pick<
|
||||
ObjectMetadataDTO,
|
||||
@@ -68,7 +65,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
| 'labelSingular'
|
||||
| 'description'
|
||||
| 'icon'
|
||||
| 'isCustom'
|
||||
| 'standardOverrides'
|
||||
>;
|
||||
|
||||
@@ -89,7 +85,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
color: 'blue',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
} satisfies Pick<
|
||||
ObjectMetadataDTO,
|
||||
@@ -98,7 +93,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
| 'labelSingular'
|
||||
| 'description'
|
||||
| 'icon'
|
||||
| 'isCustom'
|
||||
| 'standardOverrides'
|
||||
>;
|
||||
|
||||
@@ -119,7 +113,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
color: 'green',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
} satisfies Pick<
|
||||
ObjectMetadataDTO,
|
||||
@@ -128,7 +121,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
| 'labelSingular'
|
||||
| 'description'
|
||||
| 'icon'
|
||||
| 'isCustom'
|
||||
| 'standardOverrides'
|
||||
>;
|
||||
|
||||
@@ -150,7 +142,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'My Customs',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
icon: 'override-icon',
|
||||
},
|
||||
@@ -175,7 +166,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
color: 'blue',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
color: 'red',
|
||||
},
|
||||
@@ -198,7 +188,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
color: 'blue',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
@@ -223,7 +212,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
@@ -267,7 +255,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'es-ES': {
|
||||
@@ -298,7 +285,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
@@ -328,7 +314,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
@@ -361,7 +346,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: 'Overridden Label',
|
||||
labelPlural: 'Overridden Labels',
|
||||
@@ -410,7 +394,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: 'Overridden Label',
|
||||
labelPlural: 'Overridden Labels',
|
||||
@@ -433,7 +416,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: undefined,
|
||||
},
|
||||
@@ -460,7 +442,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
@@ -485,7 +466,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
@@ -512,7 +492,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: 'Source Override',
|
||||
labelPlural: 'Source Overrides',
|
||||
@@ -543,7 +522,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: 'Source Override',
|
||||
labelPlural: 'Source Overrides',
|
||||
@@ -568,7 +546,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {},
|
||||
};
|
||||
|
||||
@@ -595,7 +572,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: 'Source Override',
|
||||
},
|
||||
@@ -622,7 +598,6 @@ describe('resolveObjectMetadataStandardOverride', () => {
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
|
||||
-1
@@ -133,7 +133,6 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
description: 'Name',
|
||||
isNullable: true,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
defaultValue: null,
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@ import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-me
|
||||
|
||||
export const fromObjectMetadataEntityToObjectMetadataDto = (
|
||||
entity: ObjectMetadataEntity,
|
||||
standardApplicationId: string,
|
||||
): ObjectMetadataDTO => ({
|
||||
id: entity.id,
|
||||
universalIdentifier: entity.universalIdentifier,
|
||||
@@ -16,7 +17,7 @@ export const fromObjectMetadataEntityToObjectMetadataDto = (
|
||||
color: entity.color ?? undefined,
|
||||
shortcut: entity.shortcut ?? undefined,
|
||||
standardOverrides: entity.standardOverrides ?? undefined,
|
||||
isCustom: entity.isCustom,
|
||||
isCustom: entity.applicationId !== standardApplicationId,
|
||||
isRemote: entity.isRemote,
|
||||
isActive: entity.isActive,
|
||||
isSystem: entity.isSystem,
|
||||
|
||||
-5
@@ -14,7 +14,6 @@ export const resolveObjectMetadataStandardOverride = (
|
||||
| 'labelSingular'
|
||||
| 'description'
|
||||
| 'icon'
|
||||
| 'isCustom'
|
||||
| 'standardOverrides'
|
||||
>,
|
||||
labelKey: 'color' | 'labelPlural' | 'labelSingular' | 'description' | 'icon',
|
||||
@@ -23,10 +22,6 @@ export const resolveObjectMetadataStandardOverride = (
|
||||
): string => {
|
||||
const safeLocale = locale ?? SOURCE_LOCALE;
|
||||
|
||||
if (objectMetadata.isCustom) {
|
||||
return objectMetadata[labelKey] ?? '';
|
||||
}
|
||||
|
||||
if (
|
||||
(labelKey === 'icon' || labelKey === 'color') &&
|
||||
isDefined(objectMetadata.standardOverrides?.[labelKey])
|
||||
|
||||
Reference in New Issue
Block a user