refactor(server): unify the two metadata override mechanisms into one (#22417)
## Unify the two metadata override mechanisms into one Twenty had **two** override mechanisms: - **`standardOverrides`** — a bespoke JSONB column on `objectMetadata`/`fieldMetadata` with typed DTOs and a per-locale `translations` map, resolved by two i18n-aware resolvers. - **`OverridableEntity.overrides`** — a flat, registry-driven JSONB blob on view / view-field / view-field-group / command-menu-item / page-layout-tab / page-layout-widget, resolved by a plain spread. This PR collapses them into **one** concept: a single `overrides` blob, one registry-driven overridable set, one i18n-aware read path, and one write path (`computeMetadataOverridesBlob`, extracted in #22404). Object/field **stay on `SyncableEntity`** (not reparented to `OverridableEntity`) so their `isActive` default stays **FALSE** — this sidesteps the `isActive` default conflict entirely. ### GraphQL breaking change (accepted) The `standardOverrides` field is **removed** with no deprecation alias — `overrides` (a `JSON` scalar) is exposed instead on `Object` and `Field`. Product confirmed negligible external usage; the front-end has no hand-written consumer (only generated types), which are regenerated here. ### Commit structure (reviewable commit-by-commit) 1. **Unified resolver + parity harness** — `resolveEffectiveEntityProperty` is a strict superset of the three legacy resolvers; a corpus parity spec compares it against a *frozen reference* of the old logic across every locale, `isStandardApp` branch and override shape. 2. **Registry-driven** — object/field presentation props tagged `isOverridable` + `translatable`; the overridable/translatable sets are derived from the registry (a test asserts they equal the legacy hardcoded lists). 3. **Rename + swap + delete** — `standardOverrides` → `overrides` across entities, DTOs, flat/universal types, producers, the ~12 resolve/write/create/sync call sites, mocks and specs; the reconciler's two compare entries collapse to one; the three legacy resolvers, both DTOs and the hardcoded constants/types are deleted. 4. **Migration (zero-downtime, two-phase)** — split across two releases so a rolling deploy never drops a column a previous-release pod still `SELECT`s: - **2.19 fast** — add the `overrides` column (schema only). - **2.19 slow** — backfill `overrides` from `standardOverrides` in `runDataMigration` (kept out of the schema transaction so the bulk write doesn't hold the ACCESS EXCLUSIVE lock; skipped on fresh installs, which have no data to copy). - **2.20 fast** — drop the legacy `standardOverrides` column (gated by `TWENTY_NEXT_VERSIONS`, so it stays dormant until the instance reaches 2.20). 5. **Front/client-SDK regen** — regenerated metadata GraphQL types. 6. **Integration specs + i18n** — updated the standard object/field update integration specs + snapshots, and the reworded validator message catalog entry. ### Rolling-deploy safety `standardOverrides` is retained through 2.19 and only dropped in 2.20, mirroring the codebase's deferred-drop convention (`isUIReadOnly`/`isCustom`). During the 2.19 rollout both columns exist, so old and new pods coexist without "column does not exist" errors. The backfill lives in a slow `runDataMigration` (per the `no-data-mutation-in-fast-instance-command` rule) so it doesn't stall reads. ### `isActive` guard The migration never reads or writes `isActive`; the backfill asserts the active-row count is unchanged and aborts otherwise. Verified on a real DB: apply + revert preserves the blob **and** the nested `translations` map, with `isActive` counts identical before/after. ### Verification (local) - `nx typecheck twenty-server` + `nx typecheck twenty-front` — green - `nx lint:diff-with-main twenty-server` (oxlint `--type-aware` + oxfmt) — green - `nx test twenty-server` — green (unit + parity + registry + migration tests) - `nx run twenty-server:test:integration:with-db-reset` — green - `database:reset` applies the 2.19 phases and leaves **both** columns present (2.20 drop stays dormant); backfill + revert round-trip verified on a real DB - Metadata integration suites (standard object/field update, application sync) pass end-to-end against the two-column schema - Metadata GraphQL types regenerated against a booted server; zero `standardOverrides` references remain in application code (only the migration commands + the legacy schema baseline) --------- Co-authored-by: prastoin <paul@twenty.com>
This commit is contained in:
+1
-1
@@ -20,7 +20,7 @@ const mockObjectMetadata = {
|
||||
labelSingular: 'Person',
|
||||
description: 'A person',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: undefined,
|
||||
overrides: undefined,
|
||||
} as unknown as ObjectMetadataDTO;
|
||||
|
||||
const baseCommandMenuItem = {
|
||||
|
||||
+23
-25
@@ -1,15 +1,15 @@
|
||||
import { type I18n } from '@lingui/core';
|
||||
import { type APP_LOCALES } from 'twenty-shared/translations';
|
||||
|
||||
import { type ObjectStandardOverridesDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-standard-overrides.dto';
|
||||
import { resolveObjectMetadataStandardOverride } from 'src/engine/metadata-modules/object-metadata/utils/resolve-object-metadata-standard-override.util';
|
||||
import { type ObjectMetadataOverrides } from 'src/engine/metadata-modules/object-metadata/types/object-metadata-overrides.type';
|
||||
import { resolveEffectiveEntityProperty } from 'src/engine/metadata-modules/utils/resolve-effective-entity-property.util';
|
||||
|
||||
export type NavigationInterpolationObjectMetadata = {
|
||||
labelPlural: string;
|
||||
labelSingular: string;
|
||||
description?: string | null;
|
||||
icon?: string | null;
|
||||
standardOverrides?: ObjectStandardOverridesDTO | null;
|
||||
overrides?: ObjectMetadataOverrides | null;
|
||||
};
|
||||
|
||||
export const buildNavigationInterpolationContext = ({
|
||||
@@ -25,31 +25,29 @@ export const buildNavigationInterpolationContext = ({
|
||||
i18nInstance: I18n;
|
||||
applicationCatalog?: Record<string, string>;
|
||||
}): Record<string, unknown> => {
|
||||
const overrideInput = {
|
||||
labelPlural: objectMetadata.labelPlural,
|
||||
labelSingular: objectMetadata.labelSingular,
|
||||
description: objectMetadata.description ?? undefined,
|
||||
icon: objectMetadata.icon ?? undefined,
|
||||
standardOverrides: objectMetadata.standardOverrides ?? undefined,
|
||||
const overrides = objectMetadata.overrides ?? undefined;
|
||||
const i18nContext = {
|
||||
locale,
|
||||
i18nInstance,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
};
|
||||
|
||||
const resolvedLabelPlural = resolveObjectMetadataStandardOverride(
|
||||
overrideInput,
|
||||
'labelPlural',
|
||||
locale,
|
||||
i18nInstance,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
);
|
||||
const resolvedLabelPlural = resolveEffectiveEntityProperty({
|
||||
metadataName: 'objectMetadata',
|
||||
baseValue: objectMetadata.labelPlural,
|
||||
overrides,
|
||||
property: 'labelPlural',
|
||||
i18nContext,
|
||||
});
|
||||
|
||||
const resolvedIcon = resolveObjectMetadataStandardOverride(
|
||||
overrideInput,
|
||||
'icon',
|
||||
locale,
|
||||
i18nInstance,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
);
|
||||
const resolvedIcon = resolveEffectiveEntityProperty({
|
||||
metadataName: 'objectMetadata',
|
||||
baseValue: objectMetadata.icon,
|
||||
overrides,
|
||||
property: 'icon',
|
||||
i18nContext,
|
||||
});
|
||||
|
||||
return {
|
||||
navigateToObjectMetadataItem: {
|
||||
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import { type MetadataUniversalFlatEntityPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/metadata-universal-flat-entity-properties-to-compare.type';
|
||||
|
||||
export const FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES = [
|
||||
'label',
|
||||
'description',
|
||||
'icon',
|
||||
] as const satisfies MetadataUniversalFlatEntityPropertiesToCompare<'fieldMetadata'>[];
|
||||
+1
-1
@@ -15,7 +15,7 @@ export class CreateFieldInput extends OmitType(
|
||||
'id',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
'standardOverrides',
|
||||
'overrides',
|
||||
'applicationId',
|
||||
'morphId',
|
||||
'universalIdentifier',
|
||||
|
||||
+3
-4
@@ -32,7 +32,7 @@ import {
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { IsValidMetadataName } from 'src/engine/decorators/metadata/is-valid-metadata-name.decorator';
|
||||
import { FieldStandardOverridesDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-standard-overrides.dto';
|
||||
import { type FieldMetadataOverrides } from 'src/engine/metadata-modules/field-metadata/types/field-metadata-overrides.type';
|
||||
import { type FieldMetadataDefaultOption } from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
|
||||
import { ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto';
|
||||
import { transformEnumValue } from 'src/engine/utils/transform-enum-value';
|
||||
@@ -94,9 +94,8 @@ export class FieldMetadataDTO<T extends FieldMetadataType = FieldMetadataType> {
|
||||
@Field({ nullable: true })
|
||||
icon?: string;
|
||||
|
||||
@IsOptional()
|
||||
@Field(() => FieldStandardOverridesDTO, { nullable: true })
|
||||
standardOverrides?: FieldStandardOverridesDTO;
|
||||
@HideField()
|
||||
overrides?: FieldMetadataOverrides | null;
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { IsJSON, IsOptional, IsString } from 'class-validator';
|
||||
import { GraphQLJSON } from 'graphql-type-json';
|
||||
import { type APP_LOCALES } from 'twenty-shared/translations';
|
||||
|
||||
import { FieldMetadataStandardOverridesProperties } from 'src/engine/metadata-modules/field-metadata/types/field-metadata-standard-overrides-properties.type';
|
||||
|
||||
@ObjectType('StandardOverrides')
|
||||
export class FieldStandardOverridesDTO implements Partial<
|
||||
Record<FieldMetadataStandardOverridesProperties, unknown>
|
||||
> {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field(() => String, { nullable: true })
|
||||
label?: string | null;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field(() => String, { nullable: true })
|
||||
description?: string | null;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field(() => String, { nullable: true })
|
||||
icon?: string | null;
|
||||
|
||||
@IsJSON()
|
||||
@IsOptional()
|
||||
@Field(() => GraphQLJSON, {
|
||||
nullable: true,
|
||||
})
|
||||
translations?: Partial<
|
||||
Record<
|
||||
keyof typeof APP_LOCALES,
|
||||
{
|
||||
label?: string | null;
|
||||
description?: string | null;
|
||||
}
|
||||
>
|
||||
> | null;
|
||||
}
|
||||
+1
-1
@@ -27,7 +27,7 @@ export class UpdateFieldInput extends OmitType(
|
||||
'type',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
'standardOverrides',
|
||||
'overrides',
|
||||
'applicationId',
|
||||
'morphId',
|
||||
] as const,
|
||||
|
||||
+13
-2
@@ -23,8 +23,9 @@ 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 { ADD_METADATA_OVERRIDES_COLUMN_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-19/add-metadata-overrides-column-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 { type FieldMetadataOverrides } from 'src/engine/metadata-modules/field-metadata/types/field-metadata-overrides.type';
|
||||
import { AssignIfIsGivenFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/assign-if-is-given-field-metadata-type.type';
|
||||
import { AssignTypeIfIsMorphOrRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/assign-type-if-is-morph-or-relation-field-metadata-type.type';
|
||||
import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity';
|
||||
@@ -102,8 +103,18 @@ export class FieldMetadataEntity<
|
||||
@Column({ nullable: true, type: 'varchar' })
|
||||
icon: string | null;
|
||||
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName: ADD_METADATA_OVERRIDES_COLUMN_UPGRADE_COMMAND_NAME,
|
||||
})
|
||||
@Column({ type: 'jsonb', nullable: true })
|
||||
standardOverrides: JsonbProperty<FieldStandardOverridesDTO> | null;
|
||||
overrides: JsonbProperty<FieldMetadataOverrides> | null;
|
||||
|
||||
/**
|
||||
* @deprecated Superseded by `overrides`; kept readable for pods on the
|
||||
* previous release during a rolling deploy. Drop deferred to 2-20/README.md.
|
||||
*/
|
||||
@Column({ type: 'jsonb', nullable: true })
|
||||
standardOverrides: WasRemovedInUpgrade<JsonbProperty<FieldMetadataOverrides> | null>;
|
||||
|
||||
@Column('jsonb', { nullable: true })
|
||||
options: JsonbProperty<FieldMetadataOptions<TFieldMetadataType>>;
|
||||
|
||||
+17
-13
@@ -22,16 +22,16 @@ import { RelationDTO } from 'src/engine/metadata-modules/field-metadata/dtos/rel
|
||||
import { UpdateOneFieldMetadataInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
|
||||
import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service';
|
||||
import { fieldMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util';
|
||||
import { resolveFieldMetadataStandardOverride } from 'src/engine/metadata-modules/field-metadata/utils/resolve-field-metadata-standard-override.util';
|
||||
import { fromFlatFieldMetadataToFieldMetadataDto } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-flat-field-metadata-to-field-metadata-dto.util';
|
||||
import { resolveEffectiveEntityProperty } from 'src/engine/metadata-modules/utils/resolve-effective-entity-property.util';
|
||||
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
|
||||
|
||||
// Keep @Parent() structurally typed so ResolverValidationPipe does not validate
|
||||
// FieldMetadataDTO date decorators on already-loaded parent records.
|
||||
type FieldMetadataStandardOverrideParent = Parameters<
|
||||
typeof resolveFieldMetadataStandardOverride
|
||||
>[0] &
|
||||
Pick<FieldMetadataDTO, 'applicationId'>;
|
||||
type FieldMetadataStandardOverrideParent = Pick<
|
||||
FieldMetadataDTO,
|
||||
'label' | 'description' | 'icon' | 'overrides' | 'applicationId'
|
||||
>;
|
||||
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
@UsePipes(ResolverValidationPipe)
|
||||
@@ -76,14 +76,18 @@ export class FieldMetadataResolver {
|
||||
locale: context.req.locale,
|
||||
});
|
||||
|
||||
return resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
labelKey,
|
||||
context.req.locale,
|
||||
i18n,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
);
|
||||
return resolveEffectiveEntityProperty({
|
||||
metadataName: 'fieldMetadata',
|
||||
baseValue: fieldMetadata[labelKey],
|
||||
overrides: fieldMetadata.overrides,
|
||||
property: labelKey,
|
||||
i18nContext: {
|
||||
locale: context.req.locale,
|
||||
i18nInstance: i18n,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ResolveField(() => String, { nullable: true })
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import { type APP_LOCALES } from 'twenty-shared/translations';
|
||||
|
||||
export type FieldMetadataOverrides = {
|
||||
label?: string | null;
|
||||
description?: string | null;
|
||||
icon?: string | null;
|
||||
translations?: Partial<
|
||||
Record<
|
||||
keyof typeof APP_LOCALES,
|
||||
{
|
||||
label?: string | null;
|
||||
description?: string | null;
|
||||
}
|
||||
>
|
||||
> | null;
|
||||
};
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
import { type FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/field-metadata/constants/field-metadata-standard-overrides-properties.constant';
|
||||
|
||||
export type FieldMetadataStandardOverridesProperties =
|
||||
(typeof FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES)[number];
|
||||
-511
@@ -1,511 +0,0 @@
|
||||
import { type I18n } from '@lingui/core';
|
||||
import { SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
|
||||
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
|
||||
import { resolveFieldMetadataStandardOverride } from 'src/engine/metadata-modules/field-metadata/utils/resolve-field-metadata-standard-override.util';
|
||||
|
||||
jest.mock('src/engine/core-modules/i18n/utils/generateMessageId');
|
||||
|
||||
const mockGenerateMessageId = generateMessageId as jest.MockedFunction<
|
||||
typeof generateMessageId
|
||||
>;
|
||||
|
||||
describe('resolveFieldMetadataStandardOverride', () => {
|
||||
let mockI18n: jest.Mocked<I18n>;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockI18n = {
|
||||
_: jest.fn(),
|
||||
} as unknown as jest.Mocked<I18n>;
|
||||
});
|
||||
|
||||
describe('Custom fields', () => {
|
||||
it('should return the field value for custom label field', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Custom Label',
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Custom Label');
|
||||
});
|
||||
|
||||
it('should never translate a custom label even when it matches a standard catalog entry', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Status',
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('status.message.id');
|
||||
mockI18n._.mockReturnValue('Statut');
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Status');
|
||||
expect(mockGenerateMessageId).not.toHaveBeenCalled();
|
||||
expect(mockI18n._).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return the field value for custom description field', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Custom Label',
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'description',
|
||||
undefined,
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Custom Description');
|
||||
});
|
||||
|
||||
it('should return the field value for custom icon field', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Custom Label',
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'icon',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('custom-icon');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Standard fields - Icon overrides', () => {
|
||||
it('should return override icon when available for standard field', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
icon: 'override-icon',
|
||||
},
|
||||
};
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'icon',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('override-icon');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Standard fields - Translation overrides', () => {
|
||||
it('should return translation override when available for non-icon fields', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
label: 'Libellé traduit',
|
||||
description: 'Description traduite',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(
|
||||
resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
),
|
||||
).toBe('Libellé traduit');
|
||||
expect(
|
||||
resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'description',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
),
|
||||
).toBe('Description traduite');
|
||||
});
|
||||
|
||||
it('should fallback when translation override is not available for the locale', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'es-ES': {
|
||||
label: 'Etiqueta en español',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('generated-message-id');
|
||||
mockI18n._.mockReturnValue('generated-message-id');
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Standard Label');
|
||||
});
|
||||
|
||||
it('should fallback when translation override is not available for the labelKey', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
label: 'Libellé traduit',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('generated-message-id');
|
||||
mockI18n._.mockReturnValue('generated-message-id');
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'description',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Standard Description');
|
||||
});
|
||||
|
||||
it('should not use translation overrides when locale is undefined', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
label: 'Libellé traduit',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('generated-message-id');
|
||||
mockI18n._.mockReturnValue('generated-message-id');
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
undefined,
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Standard Label');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Standard fields - SOURCE_LOCALE overrides', () => {
|
||||
it('should return direct override for SOURCE_LOCALE when available', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
label: 'Overridden Label',
|
||||
description: 'Overridden Description',
|
||||
icon: 'overridden-icon',
|
||||
},
|
||||
};
|
||||
|
||||
expect(
|
||||
resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
),
|
||||
).toBe('Overridden Label');
|
||||
expect(
|
||||
resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'description',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
),
|
||||
).toBe('Overridden Description');
|
||||
expect(
|
||||
resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'icon',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
),
|
||||
).toBe('overridden-icon');
|
||||
});
|
||||
|
||||
it('should use direct override for non-SOURCE_LOCALE when translation override is missing', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
label: 'Overridden Label',
|
||||
},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('generated-message-id');
|
||||
mockI18n._.mockReturnValue('generated-message-id');
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Overridden Label');
|
||||
expect(mockGenerateMessageId).not.toHaveBeenCalled();
|
||||
expect(mockI18n._).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not use empty string override for SOURCE_LOCALE', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
label: '',
|
||||
},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('generated-message-id');
|
||||
mockI18n._.mockReturnValue('generated-message-id');
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Standard Label');
|
||||
});
|
||||
|
||||
it('should not use undefined override for SOURCE_LOCALE', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
label: undefined,
|
||||
},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('generated-message-id');
|
||||
mockI18n._.mockReturnValue('generated-message-id');
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Standard Label');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Standard fields - Auto translation fallback', () => {
|
||||
it('should return translated message when translation is available', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('standard.label.message.id');
|
||||
mockI18n._.mockReturnValue('Libellé traduit automatiquement');
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(mockGenerateMessageId).toHaveBeenCalledWith('Standard Label');
|
||||
expect(mockI18n._).toHaveBeenCalledWith('standard.label.message.id');
|
||||
expect(result).toBe('Libellé traduit automatiquement');
|
||||
});
|
||||
|
||||
it('should return original field value when no translation is found', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const messageId = 'standard.label.message.id';
|
||||
|
||||
mockGenerateMessageId.mockReturnValue(messageId);
|
||||
mockI18n._.mockReturnValue(messageId);
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Standard Label');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Priority order - Standard fields', () => {
|
||||
it('should prioritize translation override over SOURCE_LOCALE override for non-SOURCE_LOCALE', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
label: 'Source Override',
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
label: 'Translation Override',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Translation Override');
|
||||
expect(mockGenerateMessageId).not.toHaveBeenCalled();
|
||||
expect(mockI18n._).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should prioritize SOURCE_LOCALE override over auto translation for SOURCE_LOCALE', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
label: 'Source Override',
|
||||
},
|
||||
};
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Source Override');
|
||||
expect(mockGenerateMessageId).not.toHaveBeenCalled();
|
||||
expect(mockI18n._).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use auto translation when no overrides are available', () => {
|
||||
const fieldMetadata = {
|
||||
label: 'Standard Label',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('auto.translation.id');
|
||||
mockI18n._.mockReturnValue('Auto Translated Label');
|
||||
|
||||
const result = resolveFieldMetadataStandardOverride(
|
||||
fieldMetadata,
|
||||
'label',
|
||||
'de-DE',
|
||||
mockI18n,
|
||||
!fieldMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Auto Translated Label');
|
||||
expect(mockGenerateMessageId).toHaveBeenCalledWith('Standard Label');
|
||||
expect(mockI18n._).toHaveBeenCalledWith('auto.translation.id');
|
||||
});
|
||||
});
|
||||
});
|
||||
+1
-1
@@ -17,7 +17,7 @@ export const fromFieldMetadataEntityToFieldMetadataDto = (
|
||||
label: entity.label,
|
||||
description: entity.description ?? undefined,
|
||||
icon: entity.icon ?? undefined,
|
||||
standardOverrides: entity.standardOverrides ?? undefined,
|
||||
overrides: entity.overrides ?? undefined,
|
||||
isActive: entity.isActive,
|
||||
isSystem: entity.isSystem,
|
||||
isUIEditable: entity.isUIEditable,
|
||||
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
import { type I18n } from '@lingui/core';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { type APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { translateStandardLabel } from 'src/engine/core-modules/i18n/utils/translate-standard-label.util';
|
||||
import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
|
||||
|
||||
export const resolveFieldMetadataStandardOverride = (
|
||||
fieldMetadata: Pick<
|
||||
FieldMetadataDTO,
|
||||
'label' | 'description' | 'icon' | 'standardOverrides'
|
||||
>,
|
||||
labelKey: 'label' | 'description' | 'icon',
|
||||
locale: keyof typeof APP_LOCALES | undefined,
|
||||
i18nInstance: I18n,
|
||||
isStandardApp: boolean,
|
||||
applicationCatalog?: Record<string, string>,
|
||||
): string => {
|
||||
const safeLocale = locale ?? SOURCE_LOCALE;
|
||||
|
||||
if (!isStandardApp && !isDefined(applicationCatalog)) {
|
||||
return fieldMetadata[labelKey] ?? '';
|
||||
}
|
||||
|
||||
if (labelKey === 'icon' && isDefined(fieldMetadata.standardOverrides?.icon)) {
|
||||
return fieldMetadata.standardOverrides.icon;
|
||||
}
|
||||
|
||||
if (
|
||||
isDefined(fieldMetadata.standardOverrides?.translations) &&
|
||||
labelKey !== 'icon'
|
||||
) {
|
||||
const translationValue =
|
||||
fieldMetadata.standardOverrides.translations[safeLocale]?.[labelKey];
|
||||
|
||||
if (isDefined(translationValue)) {
|
||||
return translationValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNonEmptyString(fieldMetadata.standardOverrides?.[labelKey])) {
|
||||
return fieldMetadata.standardOverrides[labelKey] ?? '';
|
||||
}
|
||||
|
||||
return translateStandardLabel({
|
||||
sourceValue: fieldMetadata[labelKey] ?? '',
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
i18nInstance,
|
||||
});
|
||||
};
|
||||
+4
-4
@@ -72,7 +72,7 @@ exports[`ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY should ma
|
||||
"label",
|
||||
"name",
|
||||
"options",
|
||||
"standardOverrides",
|
||||
"overrides",
|
||||
"universalSettings",
|
||||
"isUIEditable",
|
||||
"isNullable",
|
||||
@@ -80,7 +80,7 @@ exports[`ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY should ma
|
||||
"propertiesToStringify": [
|
||||
"defaultValue",
|
||||
"options",
|
||||
"standardOverrides",
|
||||
"overrides",
|
||||
"universalSettings",
|
||||
],
|
||||
},
|
||||
@@ -171,14 +171,14 @@ exports[`ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY should ma
|
||||
"namePlural",
|
||||
"nameSingular",
|
||||
"labelIdentifierFieldMetadataUniversalIdentifier",
|
||||
"standardOverrides",
|
||||
"overrides",
|
||||
"isUIEditable",
|
||||
"isUICreatable",
|
||||
"isSearchable",
|
||||
"imageIdentifierFieldMetadataUniversalIdentifier",
|
||||
],
|
||||
"propertiesToStringify": [
|
||||
"standardOverrides",
|
||||
"overrides",
|
||||
],
|
||||
},
|
||||
"objectPermission": {
|
||||
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`registry-derived override property maps derives the overridable properties for every metadata entity 1`] = `
|
||||
{
|
||||
"agent": [],
|
||||
"applicationVariable": [],
|
||||
"commandMenuItem": [
|
||||
"label",
|
||||
"icon",
|
||||
"shortLabel",
|
||||
"position",
|
||||
"isPinned",
|
||||
"availabilityType",
|
||||
"availabilityObjectMetadataId",
|
||||
"engineComponentKey",
|
||||
"hotKeys",
|
||||
"pageLayoutId",
|
||||
],
|
||||
"connectionProvider": [],
|
||||
"fieldMetadata": [
|
||||
"description",
|
||||
"icon",
|
||||
"label",
|
||||
],
|
||||
"fieldPermission": [],
|
||||
"frontComponent": [],
|
||||
"index": [],
|
||||
"logicFunction": [],
|
||||
"navigationMenuItem": [],
|
||||
"objectMetadata": [
|
||||
"color",
|
||||
"description",
|
||||
"icon",
|
||||
"labelPlural",
|
||||
"labelSingular",
|
||||
],
|
||||
"objectPermission": [],
|
||||
"pageLayout": [],
|
||||
"pageLayoutTab": [
|
||||
"title",
|
||||
"position",
|
||||
"icon",
|
||||
],
|
||||
"pageLayoutWidget": [
|
||||
"title",
|
||||
"position",
|
||||
"pageLayoutTabId",
|
||||
"conditionalDisplay",
|
||||
"conditionalAvailabilityExpression",
|
||||
],
|
||||
"permissionFlag": [],
|
||||
"role": [],
|
||||
"rolePermissionFlag": [],
|
||||
"roleTarget": [],
|
||||
"rowLevelPermissionPredicate": [],
|
||||
"rowLevelPermissionPredicateGroup": [],
|
||||
"searchFieldMetadata": [],
|
||||
"skill": [],
|
||||
"view": [
|
||||
"name",
|
||||
"type",
|
||||
"icon",
|
||||
"position",
|
||||
"isCompact",
|
||||
"openRecordIn",
|
||||
"kanbanAggregateOperation",
|
||||
"kanbanAggregateOperationFieldMetadataId",
|
||||
"anyFieldFilterValue",
|
||||
"calendarLayout",
|
||||
"calendarFieldMetadataId",
|
||||
"visibility",
|
||||
"mainGroupByFieldMetadataId",
|
||||
"shouldHideEmptyGroups",
|
||||
"kanbanColumnWidth",
|
||||
],
|
||||
"viewField": [
|
||||
"isVisible",
|
||||
"size",
|
||||
"position",
|
||||
"aggregateOperation",
|
||||
"viewFieldGroupId",
|
||||
],
|
||||
"viewFieldGroup": [
|
||||
"name",
|
||||
"position",
|
||||
"isVisible",
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewFilterGroup": [],
|
||||
"viewGroup": [],
|
||||
"viewSort": [],
|
||||
"webhook": [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`registry-derived override property maps derives the translatable properties for every metadata entity 1`] = `
|
||||
{
|
||||
"agent": [],
|
||||
"applicationVariable": [],
|
||||
"commandMenuItem": [],
|
||||
"connectionProvider": [],
|
||||
"fieldMetadata": [
|
||||
"description",
|
||||
"label",
|
||||
],
|
||||
"fieldPermission": [],
|
||||
"frontComponent": [],
|
||||
"index": [],
|
||||
"logicFunction": [],
|
||||
"navigationMenuItem": [],
|
||||
"objectMetadata": [
|
||||
"description",
|
||||
"labelPlural",
|
||||
"labelSingular",
|
||||
],
|
||||
"objectPermission": [],
|
||||
"pageLayout": [],
|
||||
"pageLayoutTab": [],
|
||||
"pageLayoutWidget": [],
|
||||
"permissionFlag": [],
|
||||
"role": [],
|
||||
"rolePermissionFlag": [],
|
||||
"roleTarget": [],
|
||||
"rowLevelPermissionPredicate": [],
|
||||
"rowLevelPermissionPredicateGroup": [],
|
||||
"searchFieldMetadata": [],
|
||||
"skill": [],
|
||||
"view": [],
|
||||
"viewField": [],
|
||||
"viewFieldGroup": [],
|
||||
"viewFilter": [],
|
||||
"viewFilterGroup": [],
|
||||
"viewGroup": [],
|
||||
"viewSort": [],
|
||||
"webhook": [],
|
||||
}
|
||||
`;
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { ALL_OVERRIDABLE_PROPERTIES_BY_METADATA_NAME } from 'src/engine/metadata-modules/flat-entity/constant/all-overridable-properties-by-metadata-name.constant';
|
||||
import { ALL_TRANSLATABLE_PROPERTIES_BY_METADATA_NAME } from 'src/engine/metadata-modules/flat-entity/constant/all-translatable-properties-by-metadata-name.constant';
|
||||
|
||||
describe('registry-derived override property maps', () => {
|
||||
it('derives the overridable properties for every metadata entity', () => {
|
||||
expect(ALL_OVERRIDABLE_PROPERTIES_BY_METADATA_NAME).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('derives the translatable properties for every metadata entity', () => {
|
||||
expect(ALL_TRANSLATABLE_PROPERTIES_BY_METADATA_NAME).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
+35
-4
@@ -40,6 +40,7 @@ type MetadataEntityPropertyConfiguration<
|
||||
: boolean;
|
||||
toCompare: boolean;
|
||||
isOverridable?: boolean;
|
||||
translatable?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -59,8 +60,15 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
isOverridable: true,
|
||||
translatable: true,
|
||||
},
|
||||
icon: {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
isOverridable: true,
|
||||
},
|
||||
icon: { toCompare: true, toStringify: false, universalProperty: undefined },
|
||||
isActive: {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
@@ -86,6 +94,8 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
isOverridable: true,
|
||||
translatable: true,
|
||||
},
|
||||
name: { toCompare: true, toStringify: false, universalProperty: undefined },
|
||||
options: {
|
||||
@@ -93,7 +103,7 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
toStringify: true,
|
||||
universalProperty: undefined,
|
||||
},
|
||||
standardOverrides: {
|
||||
overrides: {
|
||||
toCompare: true,
|
||||
toStringify: true,
|
||||
universalProperty: undefined,
|
||||
@@ -164,13 +174,21 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
isOverridable: true,
|
||||
},
|
||||
description: {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
isOverridable: true,
|
||||
translatable: true,
|
||||
},
|
||||
icon: {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
isOverridable: true,
|
||||
},
|
||||
icon: { toCompare: true, toStringify: false, universalProperty: undefined },
|
||||
isActive: {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
@@ -185,11 +203,15 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
isOverridable: true,
|
||||
translatable: true,
|
||||
},
|
||||
labelSingular: {
|
||||
toCompare: true,
|
||||
toStringify: false,
|
||||
universalProperty: undefined,
|
||||
isOverridable: true,
|
||||
translatable: true,
|
||||
},
|
||||
namePlural: {
|
||||
toCompare: true,
|
||||
@@ -207,7 +229,7 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
// @ts-expect-error remove once https://github.com/twentyhq/core-team-issues/issues/2172 has been resolved
|
||||
universalProperty: 'labelIdentifierFieldMetadataUniversalIdentifier',
|
||||
},
|
||||
standardOverrides: {
|
||||
overrides: {
|
||||
toCompare: true,
|
||||
toStringify: true,
|
||||
universalProperty: undefined,
|
||||
@@ -1830,3 +1852,12 @@ export type MetadataEntityOverridablePropertyName<T extends AllMetadataName> =
|
||||
FilterOverridableKeys<
|
||||
(typeof ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME)[T]
|
||||
>;
|
||||
|
||||
type FilterTranslatableKeys<TConfig> = {
|
||||
[P in keyof TConfig]: TConfig[P] extends { translatable: true } ? P : never;
|
||||
}[keyof TConfig];
|
||||
|
||||
export type MetadataEntityTranslatablePropertyName<T extends AllMetadataName> =
|
||||
FilterTranslatableKeys<
|
||||
(typeof ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME)[T]
|
||||
>;
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
ALL_METADATA_NAME,
|
||||
type AllMetadataName,
|
||||
} from 'twenty-shared/metadata';
|
||||
|
||||
import {
|
||||
ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME,
|
||||
type MetadataEntityTranslatablePropertyName,
|
||||
} from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
|
||||
|
||||
const computeTranslatableProperties = <T extends AllMetadataName>(
|
||||
metadataName: T,
|
||||
): MetadataEntityTranslatablePropertyName<T>[] => {
|
||||
const config =
|
||||
ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME[metadataName];
|
||||
|
||||
return (Object.entries(config) as [string, { translatable?: boolean }][])
|
||||
.filter(([_, conf]) => conf.translatable === true)
|
||||
.map(([property]) => property as MetadataEntityTranslatablePropertyName<T>);
|
||||
};
|
||||
|
||||
export const ALL_TRANSLATABLE_PROPERTIES_BY_METADATA_NAME = Object.values(
|
||||
ALL_METADATA_NAME,
|
||||
).reduce(
|
||||
(acc, metadataName) => ({
|
||||
...acc,
|
||||
[metadataName]: computeTranslatableProperties(metadataName),
|
||||
}),
|
||||
{} as {
|
||||
[P in AllMetadataName]: MetadataEntityTranslatablePropertyName<P>[];
|
||||
},
|
||||
);
|
||||
+2
-2
@@ -17,7 +17,7 @@ type Assertions = [
|
||||
| 'description'
|
||||
| 'isActive'
|
||||
| 'defaultValue'
|
||||
| 'standardOverrides'
|
||||
| 'overrides'
|
||||
| 'options'
|
||||
| 'settings'
|
||||
| 'isUnique'
|
||||
@@ -43,7 +43,7 @@ type Assertions = [
|
||||
| 'color'
|
||||
| 'description'
|
||||
| 'isActive'
|
||||
| 'standardOverrides'
|
||||
| 'overrides'
|
||||
| 'isLabelSyncedWithName'
|
||||
| 'nameSingular'
|
||||
| 'namePlural'
|
||||
|
||||
+16
-16
@@ -19,7 +19,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: 'Attachment name',
|
||||
icon: 'IconFileUpload',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -41,7 +41,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: 'Attachment full path',
|
||||
icon: 'IconLink',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -63,7 +63,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: 'Attachment type',
|
||||
icon: 'IconList',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -85,7 +85,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'uuid',
|
||||
description: 'Id',
|
||||
icon: 'Icon123',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -107,7 +107,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -129,7 +129,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Last time the record was changed',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -151,7 +151,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Date when the record was deleted',
|
||||
icon: 'IconCalendarMinus',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -173,7 +173,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachment author',
|
||||
icon: 'IconCircleUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -199,7 +199,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachment task',
|
||||
icon: 'IconNotes',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -225,7 +225,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachment note',
|
||||
icon: 'IconNotes',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -251,7 +251,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachment person',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -277,7 +277,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachment company',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -303,7 +303,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachment opportunity',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -329,7 +329,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachments Rocket',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -355,7 +355,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachments Pet',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -381,7 +381,7 @@ export const ATTACHMENT_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachments Survey result',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
|
||||
+23
-23
@@ -19,7 +19,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: 'The company name',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -46,7 +46,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
description:
|
||||
'The company website URL. We use this url to fetch the company icon',
|
||||
icon: 'IconLink',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -72,7 +72,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: 'The company Linkedin account',
|
||||
icon: 'IconBrandLinkedin',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -94,7 +94,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: { amountMicros: null, currencyCode: "''" },
|
||||
description: "The company's total annual revenue",
|
||||
icon: 'IconMoneybag',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -125,7 +125,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: 'Address of the company',
|
||||
icon: 'IconMap',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -147,7 +147,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 0,
|
||||
description: 'Company record position',
|
||||
icon: 'IconHierarchy2',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -173,7 +173,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: 'The creator of the record',
|
||||
icon: 'IconCreativeCommonsSa',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -195,7 +195,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Field used for full-text search',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -217,7 +217,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'uuid',
|
||||
description: 'Id',
|
||||
icon: 'Icon123',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -239,7 +239,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -261,7 +261,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Last time the record was changed',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -283,7 +283,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Date when the record was deleted',
|
||||
icon: 'IconCalendarMinus',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -305,7 +305,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'People linked to the company.',
|
||||
icon: 'IconUsers',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -328,7 +328,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
description:
|
||||
'Your team member responsible for managing the company account',
|
||||
icon: 'IconUserCircle',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -354,7 +354,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Tasks tied to the company',
|
||||
icon: 'IconCheckbox',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -376,7 +376,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Notes tied to the company',
|
||||
icon: 'IconNotes',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -398,7 +398,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Opportunities linked to the company.',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -420,7 +420,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachments linked to the company',
|
||||
icon: 'IconFileImport',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -442,7 +442,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Timeline Activities linked to the company',
|
||||
icon: 'IconTimelineEvent',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -464,7 +464,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: null,
|
||||
icon: 'IconAdCircle',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -490,7 +490,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: null,
|
||||
icon: 'IconVideo',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -512,7 +512,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: 'IconHome',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: [
|
||||
{
|
||||
id: '325240d6-8c67-4fb2-bb02-51e9de4cd6be',
|
||||
@@ -556,7 +556,7 @@ export const COMPANY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: false,
|
||||
description: null,
|
||||
icon: 'IconBrandVisa',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ export const getFlatFieldMetadataMock = <T extends FieldMetadataType>(
|
||||
isUIEditable: true,
|
||||
isLabelSyncedWithName: false,
|
||||
isSystem: false,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
workspaceId: faker.string.uuid(),
|
||||
applicationId: faker.string.uuid(),
|
||||
relationTargetFieldMetadataId: null,
|
||||
@@ -68,7 +68,7 @@ export const getStandardFlatFieldMetadataMock = (
|
||||
overrides: Omit<FlatFieldMetadataOverrides, 'isCustom' | 'isSystem'>,
|
||||
) => {
|
||||
return getFlatFieldMetadataMock({
|
||||
standardOverrides: {},
|
||||
overrides: {},
|
||||
isSystem: true,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ export const getRelationTargetFlatFieldMetadataMock = ({
|
||||
isUIEditable: true,
|
||||
isLabelSyncedWithName: false,
|
||||
isSystem: false,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
workspaceId: faker.string.uuid(),
|
||||
objectMetadataId,
|
||||
type,
|
||||
|
||||
+12
-12
@@ -15,7 +15,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 0,
|
||||
description: 'Note record position',
|
||||
icon: 'IconHierarchy2',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -37,7 +37,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: 'Note title',
|
||||
icon: 'IconNotes',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -59,7 +59,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Note body',
|
||||
icon: 'IconFilePencil',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -85,7 +85,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: 'The creator of the record',
|
||||
icon: 'IconCreativeCommonsSa',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -107,7 +107,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Field used for full-text search',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -129,7 +129,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'uuid',
|
||||
description: 'Id',
|
||||
icon: 'Icon123',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -151,7 +151,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -173,7 +173,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Last time the record was changed',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -195,7 +195,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Date when the record was deleted',
|
||||
icon: 'IconCalendarMinus',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -217,7 +217,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Note targets',
|
||||
icon: 'IconArrowUpRight',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -239,7 +239,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Note attachments',
|
||||
icon: 'IconFileImport',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -261,7 +261,7 @@ export const NOTE_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Timeline Activities linked to the note.',
|
||||
icon: 'IconTimelineEvent',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
|
||||
+11
-11
@@ -19,7 +19,7 @@ export const NOTETARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'uuid',
|
||||
description: 'Id',
|
||||
icon: 'Icon123',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -41,7 +41,7 @@ export const NOTETARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -63,7 +63,7 @@ export const NOTETARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Last time the record was changed',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -85,7 +85,7 @@ export const NOTETARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Date when the record was deleted',
|
||||
icon: 'IconCalendarMinus',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -107,7 +107,7 @@ export const NOTETARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'NoteTarget note',
|
||||
icon: 'IconNotes',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -133,7 +133,7 @@ export const NOTETARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'NoteTarget person',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -159,7 +159,7 @@ export const NOTETARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'NoteTarget company',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -185,7 +185,7 @@ export const NOTETARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'NoteTarget opportunity',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -211,7 +211,7 @@ export const NOTETARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'NoteTargets Rocket',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -237,7 +237,7 @@ export const NOTETARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'NoteTargets Pet',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -263,7 +263,7 @@ export const NOTETARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'NoteTargets Survey result',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
|
||||
+17
-17
@@ -19,7 +19,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: 'The opportunity name',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -41,7 +41,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: { amountMicros: null, currencyCode: "''" },
|
||||
description: 'Opportunity amount',
|
||||
icon: 'IconCurrencyDollar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -63,7 +63,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Opportunity close date',
|
||||
icon: 'IconCalendarEvent',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -85,7 +85,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "'NEW'",
|
||||
description: 'Opportunity stage',
|
||||
icon: 'IconProgressCheck',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: [
|
||||
{
|
||||
id: 'fdf5cede-2b0e-44d0-adbe-3bc7e613efc9',
|
||||
@@ -143,7 +143,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 0,
|
||||
description: 'Opportunity record position',
|
||||
icon: 'IconHierarchy2',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -169,7 +169,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: 'The creator of the record',
|
||||
icon: 'IconCreativeCommonsSa',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -191,7 +191,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Field used for full-text search',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -213,7 +213,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'uuid',
|
||||
description: 'Id',
|
||||
icon: 'Icon123',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -235,7 +235,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -257,7 +257,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Last time the record was changed',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -279,7 +279,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Date when the record was deleted',
|
||||
icon: 'IconCalendarMinus',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -301,7 +301,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Opportunity point of contact',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -327,7 +327,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Opportunity company',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -353,7 +353,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Tasks tied to the opportunity',
|
||||
icon: 'IconCheckbox',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -375,7 +375,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Notes tied to the opportunity',
|
||||
icon: 'IconNotes',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -397,7 +397,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachments linked to the opportunity',
|
||||
icon: 'IconFileImport',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -419,7 +419,7 @@ export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Timeline Activities linked to the opportunity.',
|
||||
icon: 'IconTimelineEvent',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
|
||||
+25
-25
@@ -19,7 +19,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: { lastName: "''", firstName: "''" },
|
||||
description: 'Contact’s name',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -41,7 +41,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: { primaryEmail: "''", additionalEmails: null },
|
||||
description: 'Contact’s Emails',
|
||||
icon: 'IconMail',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -67,7 +67,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: 'Contact’s Linkedin account',
|
||||
icon: 'IconBrandLinkedin',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -89,7 +89,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: 'Contact’s job title',
|
||||
icon: 'IconBriefcase',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -116,7 +116,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: 'Contact’s phone numbers',
|
||||
icon: 'IconPhone',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -138,7 +138,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: 'Contact’s avatar',
|
||||
icon: 'IconFileUpload',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -160,7 +160,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 0,
|
||||
description: 'Person record Position',
|
||||
icon: 'IconHierarchy2',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -186,7 +186,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: 'The creator of the record',
|
||||
icon: 'IconCreativeCommonsSa',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -208,7 +208,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Field used for full-text search',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -230,7 +230,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'uuid',
|
||||
description: 'Id',
|
||||
icon: 'Icon123',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -252,7 +252,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -274,7 +274,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Last time the record was changed',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -296,7 +296,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Date when the record was deleted',
|
||||
icon: 'IconCalendarMinus',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -318,7 +318,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Contact’s company',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -345,7 +345,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
description:
|
||||
'List of opportunities for which that person is the point of contact',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -367,7 +367,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Tasks tied to the contact',
|
||||
icon: 'IconCheckbox',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -389,7 +389,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Notes tied to the contact',
|
||||
icon: 'IconNotes',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -411,7 +411,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachments linked to the contact.',
|
||||
icon: 'IconFileImport',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -433,7 +433,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Message Participants',
|
||||
icon: 'IconUserCircle',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -455,7 +455,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Calendar Event Participants',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -477,7 +477,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Events linked to the person',
|
||||
icon: 'IconTimelineEvent',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -499,7 +499,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: null,
|
||||
icon: 'IconNote',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -526,7 +526,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: null,
|
||||
icon: 'IconBrandWhatsapp',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -548,7 +548,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: 'IconHome',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: [
|
||||
{
|
||||
id: 'c33d02fd-0bd9-4769-bd32-036d9ff645a5',
|
||||
@@ -592,7 +592,7 @@ export const PERSON_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: 'IconStars',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: [
|
||||
{
|
||||
id: 'e6b4b1bb-c707-41cb-8f30-418a81ae3299',
|
||||
|
||||
+28
-28
@@ -15,7 +15,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'NoteTargets tied to the Pet',
|
||||
icon: 'IconCheckbox',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -37,7 +37,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'uuid',
|
||||
description: 'Id',
|
||||
icon: 'Icon123',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -59,7 +59,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "'Untitled'",
|
||||
description: 'Name',
|
||||
icon: 'IconAbc',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -81,7 +81,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -103,7 +103,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Last time the record was changed',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -125,7 +125,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Deletion date',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -147,7 +147,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: { name: "''", source: "'MANUAL'" },
|
||||
description: 'The creator of the record',
|
||||
icon: 'IconCreativeCommonsSa',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -169,7 +169,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 0,
|
||||
description: 'Position',
|
||||
icon: 'IconHierarchy2',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -191,7 +191,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TimelineActivities tied to the Pet',
|
||||
icon: 'IconTimelineEvent',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -213,7 +213,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachments tied to the Pet',
|
||||
icon: 'IconFileImport',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -235,7 +235,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TaskTargets tied to the Pet',
|
||||
icon: 'IconCheckbox',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -257,7 +257,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Field used for full-text search',
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: false,
|
||||
@@ -279,7 +279,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: [
|
||||
{
|
||||
id: '23a75463-ca50-4b33-bfd8-701e2944c76c',
|
||||
@@ -344,7 +344,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: [
|
||||
{
|
||||
id: '5bb37088-b364-44c5-a984-54b01aa241ce',
|
||||
@@ -409,7 +409,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -431,7 +431,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -462,7 +462,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -489,7 +489,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -511,7 +511,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: { primaryEmail: "''", additionalEmails: null },
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -533,7 +533,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -555,7 +555,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -581,7 +581,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -603,7 +603,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: { amountMicros: null, currencyCode: "''" },
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -625,7 +625,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: { lastName: "''", firstName: "''" },
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -647,7 +647,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: [
|
||||
{
|
||||
id: '4a3ed94d-30db-4231-8c2e-5893d55df860',
|
||||
@@ -700,7 +700,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -722,7 +722,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -744,7 +744,7 @@ export const PET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
|
||||
+12
-12
@@ -15,7 +15,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'uuid',
|
||||
description: 'Id',
|
||||
icon: 'Icon123',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -37,7 +37,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "'Untitled'",
|
||||
description: 'Name',
|
||||
icon: 'IconAbc',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -59,7 +59,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -81,7 +81,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Last time the record was changed',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -103,7 +103,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Deletion date',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -125,7 +125,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: { name: "''", source: "'MANUAL'" },
|
||||
description: 'The creator of the record',
|
||||
icon: 'IconCreativeCommonsSa',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -147,7 +147,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 0,
|
||||
description: 'Position',
|
||||
icon: 'IconHierarchy2',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -169,7 +169,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TimelineActivities tied to the Rocket',
|
||||
icon: 'IconTimelineEvent',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -191,7 +191,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Attachments tied to the Rocket',
|
||||
icon: 'IconFileImport',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -213,7 +213,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'NoteTargets tied to the Rocket',
|
||||
icon: 'IconCheckbox',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -235,7 +235,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TaskTargets tied to the Rocket',
|
||||
icon: 'IconCheckbox',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -257,7 +257,7 @@ export const ROCKET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Field used for full-text search',
|
||||
icon: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: false,
|
||||
|
||||
+15
-15
@@ -19,7 +19,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 0,
|
||||
description: 'Task record position',
|
||||
icon: 'IconHierarchy2',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -41,7 +41,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: 'Task title',
|
||||
icon: 'IconNotes',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -63,7 +63,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Task body',
|
||||
icon: 'IconFilePencil',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -85,7 +85,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Task due date',
|
||||
icon: 'IconCalendarEvent',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -107,7 +107,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "'TODO'",
|
||||
description: 'Task status',
|
||||
icon: 'IconCheck',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: [
|
||||
{
|
||||
id: '178a8a6f-6411-4731-a417-36e85e5526a3',
|
||||
@@ -155,7 +155,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
},
|
||||
description: 'The creator of the record',
|
||||
icon: 'IconCreativeCommonsSa',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -177,7 +177,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Field used for full-text search',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -199,7 +199,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'uuid',
|
||||
description: 'Id',
|
||||
icon: 'Icon123',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -221,7 +221,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -243,7 +243,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Last time the record was changed',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -265,7 +265,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Date when the record was deleted',
|
||||
icon: 'IconCalendarMinus',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -287,7 +287,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Task targets',
|
||||
icon: 'IconArrowUpRight',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -309,7 +309,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Task attachments',
|
||||
icon: 'IconFileImport',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
@@ -331,7 +331,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Task assignee',
|
||||
icon: 'IconUserCircle',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -357,7 +357,7 @@ export const TASK_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Timeline Activities linked to the task.',
|
||||
icon: 'IconTimelineEvent',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { relationType: RelationType.ONE_TO_MANY },
|
||||
isActive: true,
|
||||
|
||||
+11
-11
@@ -19,7 +19,7 @@ export const TASKTARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'uuid',
|
||||
description: 'Id',
|
||||
icon: 'Icon123',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -41,7 +41,7 @@ export const TASKTARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -63,7 +63,7 @@ export const TASKTARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Last time the record was changed',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -85,7 +85,7 @@ export const TASKTARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Date when the record was deleted',
|
||||
icon: 'IconCalendarMinus',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -107,7 +107,7 @@ export const TASKTARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TaskTarget task',
|
||||
icon: 'IconCheckbox',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -133,7 +133,7 @@ export const TASKTARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TaskTarget person',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -159,7 +159,7 @@ export const TASKTARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TaskTarget company',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -185,7 +185,7 @@ export const TASKTARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TaskTarget opportunity',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -211,7 +211,7 @@ export const TASKTARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TaskTargets Rocket',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -237,7 +237,7 @@ export const TASKTARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TaskTargets Pet',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -263,7 +263,7 @@ export const TASKTARGET_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TaskTargets Survey result',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
|
||||
+22
-22
@@ -19,7 +19,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -41,7 +41,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: 'Event name',
|
||||
icon: 'IconAbc',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -63,7 +63,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Json value for event details',
|
||||
icon: 'IconListDetails',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -85,7 +85,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: "''",
|
||||
description: 'Cached record name',
|
||||
icon: 'IconAbc',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -107,7 +107,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Linked Record id',
|
||||
icon: 'IconAbc',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -129,7 +129,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Linked Object Metadata Id',
|
||||
icon: 'IconAbc',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -151,7 +151,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'uuid',
|
||||
description: 'Id',
|
||||
icon: 'Icon123',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
isActive: true,
|
||||
@@ -173,7 +173,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Creation date',
|
||||
icon: 'IconCalendar',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -195,7 +195,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: 'now',
|
||||
description: 'Last time the record was changed',
|
||||
icon: 'IconCalendarClock',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -217,7 +217,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Date when the record was deleted',
|
||||
icon: 'IconCalendarMinus',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: { displayFormat: DateDisplayFormat.RELATIVE },
|
||||
isActive: true,
|
||||
@@ -239,7 +239,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Event workspace member',
|
||||
icon: 'IconCircleUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -265,7 +265,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Event person',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -291,7 +291,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Event company',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -317,7 +317,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Event opportunity',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -343,7 +343,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Event note',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -369,7 +369,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Event task',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
@@ -395,7 +395,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Event workflow',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -421,7 +421,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Event workflow version',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -447,7 +447,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'Event workflow run',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -473,7 +473,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TimelineActivities Rocket',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -499,7 +499,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TimelineActivities Pet',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
@@ -525,7 +525,7 @@ export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
|
||||
defaultValue: null,
|
||||
description: 'TimelineActivities Survey result',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
options: null,
|
||||
settings: {
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
|
||||
+4
-4
@@ -137,10 +137,10 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"name": "newFieldPets",
|
||||
"objectMetadataUniversalIdentifier": Any<String>,
|
||||
"options": null,
|
||||
"overrides": null,
|
||||
"relationTargetFieldMetadataUniversalIdentifier": Any<String>,
|
||||
"relationTargetObjectMetadataUniversalIdentifier": Any<String>,
|
||||
"searchFieldMetadataUniversalIdentifiers": [],
|
||||
"standardOverrides": null,
|
||||
"type": "MORPH_RELATION",
|
||||
"universalIdentifier": Any<String>,
|
||||
"universalSettings": {
|
||||
@@ -173,10 +173,10 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"name": "pet",
|
||||
"objectMetadataUniversalIdentifier": Any<String>,
|
||||
"options": null,
|
||||
"overrides": null,
|
||||
"relationTargetFieldMetadataUniversalIdentifier": Any<String>,
|
||||
"relationTargetObjectMetadataUniversalIdentifier": Any<String>,
|
||||
"searchFieldMetadataUniversalIdentifiers": [],
|
||||
"standardOverrides": null,
|
||||
"type": "RELATION",
|
||||
"universalIdentifier": Any<String>,
|
||||
"universalSettings": {
|
||||
@@ -211,10 +211,10 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"name": "newFieldCompanies",
|
||||
"objectMetadataUniversalIdentifier": Any<String>,
|
||||
"options": null,
|
||||
"overrides": null,
|
||||
"relationTargetFieldMetadataUniversalIdentifier": Any<String>,
|
||||
"relationTargetObjectMetadataUniversalIdentifier": Any<String>,
|
||||
"searchFieldMetadataUniversalIdentifiers": [],
|
||||
"standardOverrides": null,
|
||||
"type": "MORPH_RELATION",
|
||||
"universalIdentifier": Any<String>,
|
||||
"universalSettings": {
|
||||
@@ -247,10 +247,10 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"name": "company",
|
||||
"objectMetadataUniversalIdentifier": Any<String>,
|
||||
"options": null,
|
||||
"overrides": null,
|
||||
"relationTargetFieldMetadataUniversalIdentifier": Any<String>,
|
||||
"relationTargetObjectMetadataUniversalIdentifier": Any<String>,
|
||||
"searchFieldMetadataUniversalIdentifiers": [],
|
||||
"standardOverrides": null,
|
||||
"type": "RELATION",
|
||||
"universalIdentifier": Any<String>,
|
||||
"universalSettings": {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ export const FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE = [
|
||||
'label',
|
||||
'description',
|
||||
'isActive',
|
||||
'standardOverrides',
|
||||
'overrides',
|
||||
'icon',
|
||||
'name',
|
||||
'universalSettings',
|
||||
|
||||
+3
-3
@@ -44,7 +44,7 @@ export const computeFlatFieldToUpdateAndRelatedFlatFieldToUpdate = ({
|
||||
flatObjectMetadata,
|
||||
isSystemBuild,
|
||||
}: ComputeFlatFieldToUpdateAndRelatedFlatFieldToUpdateArgs): ComputeFlatFieldToUpdateAndRelatedFlatFieldToUpdateReturnType => {
|
||||
const { standardOverrides, updatedEditableFieldProperties } =
|
||||
const { overrides, updatedEditableFieldProperties } =
|
||||
sanitizeRawUpdateFieldInput({
|
||||
existingFlatFieldMetadata: fromFlatFieldMetadata,
|
||||
rawUpdateFieldInput,
|
||||
@@ -62,7 +62,7 @@ export const computeFlatFieldToUpdateAndRelatedFlatFieldToUpdate = ({
|
||||
],
|
||||
update: updatedEditableFieldProperties,
|
||||
}),
|
||||
standardOverrides,
|
||||
overrides,
|
||||
};
|
||||
|
||||
if (updatedEditableFieldProperties.settings !== undefined) {
|
||||
@@ -161,7 +161,7 @@ export const computeFlatFieldToUpdateAndRelatedFlatFieldToUpdate = ({
|
||||
properties: relatedMorphPropertiesToUpdateTo,
|
||||
update: updatedEditableFieldProperties,
|
||||
}),
|
||||
standardOverrides,
|
||||
overrides,
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ export const fromFlatFieldMetadataToFieldMetadataDto = (
|
||||
updatedAt,
|
||||
description,
|
||||
icon,
|
||||
standardOverrides,
|
||||
overrides,
|
||||
isNullable,
|
||||
isUnique,
|
||||
settings,
|
||||
@@ -49,7 +49,7 @@ export const fromFlatFieldMetadataToFieldMetadataDto = (
|
||||
updatedAt: new Date(updatedAt),
|
||||
description: description ?? undefined,
|
||||
icon: icon ?? undefined,
|
||||
standardOverrides: standardOverrides ?? undefined,
|
||||
overrides: overrides ?? undefined,
|
||||
isNullable: isNullable ?? false,
|
||||
isUnique: isUnique ?? false,
|
||||
settings: settings ?? undefined,
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ export const getDefaultFlatFieldMetadata = ({
|
||||
isUnique: createFieldInput.isUnique ?? false,
|
||||
label: createFieldInput.label,
|
||||
name: createFieldInput.name,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
type: createFieldInput.type,
|
||||
universalIdentifier: createFieldInput.universalIdentifier ?? v4(),
|
||||
options: createFieldInput.options ?? null,
|
||||
|
||||
+10
-10
@@ -4,12 +4,12 @@ import {
|
||||
} from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/field-metadata/constants/field-metadata-standard-overrides-properties.constant';
|
||||
import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
|
||||
import {
|
||||
FieldMetadataException,
|
||||
FieldMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { ALL_OVERRIDABLE_PROPERTIES_BY_METADATA_NAME } from 'src/engine/metadata-modules/flat-entity/constant/all-overridable-properties-by-metadata-name.constant';
|
||||
import { FLAT_FIELD_METADATA_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-editable-properties.constant';
|
||||
import { type FlatFieldMetadataEditableProperties } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-editable-properties.constant';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
@@ -62,7 +62,7 @@ export const sanitizeRawUpdateFieldInput = ({
|
||||
if (!isStandardField || isSystemBuild) {
|
||||
return {
|
||||
updatedEditableFieldProperties,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -82,16 +82,16 @@ export const sanitizeRawUpdateFieldInput = ({
|
||||
);
|
||||
}
|
||||
|
||||
const { overrides: standardOverrides, remainingProperties } =
|
||||
computeMetadataOverridesBlob({
|
||||
overridableProperties: FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES,
|
||||
updatedProperties: updatedEditableFieldProperties,
|
||||
existingEntity: existingFlatFieldMetadata,
|
||||
existingOverrides: existingFlatFieldMetadata.standardOverrides,
|
||||
});
|
||||
const { overrides, remainingProperties } = computeMetadataOverridesBlob({
|
||||
overridableProperties:
|
||||
ALL_OVERRIDABLE_PROPERTIES_BY_METADATA_NAME.fieldMetadata,
|
||||
updatedProperties: updatedEditableFieldProperties,
|
||||
existingEntity: existingFlatFieldMetadata,
|
||||
existingOverrides: existingFlatFieldMetadata.overrides,
|
||||
});
|
||||
|
||||
return {
|
||||
standardOverrides,
|
||||
overrides,
|
||||
updatedEditableFieldProperties: remainingProperties,
|
||||
};
|
||||
};
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ export const ATTACHMENT_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({
|
||||
labelPlural: 'Attachments',
|
||||
description: 'An attachment',
|
||||
icon: 'IconFileImport',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isRemote: false,
|
||||
isActive: true,
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ export const COMPANY_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({
|
||||
labelPlural: 'Companies',
|
||||
description: 'A company',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isRemote: false,
|
||||
isActive: true,
|
||||
|
||||
+2
-2
@@ -44,7 +44,7 @@ export const getFlatObjectMetadataMock = (
|
||||
nameSingular: 'defaultflatObjectMetadataNameSingular',
|
||||
shortcut: 'shortcut',
|
||||
applicationId,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: '',
|
||||
workspaceId: faker.string.uuid(),
|
||||
createdAt,
|
||||
@@ -69,7 +69,7 @@ export const getStandardFlatObjectMetadataMock = (
|
||||
overrides: Omit<FlatObjectMetadataOverrides, 'isCustom' | 'isSystem'>,
|
||||
) => {
|
||||
return getFlatObjectMetadataMock({
|
||||
standardOverrides: {},
|
||||
overrides: {},
|
||||
isSystem: true,
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ export const NOTE_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({
|
||||
labelPlural: 'Notes',
|
||||
description: 'A note',
|
||||
icon: 'IconNotes',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isRemote: false,
|
||||
isActive: true,
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ export const NOTE_TARGET_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({
|
||||
labelPlural: 'Note Targets',
|
||||
description: 'A note target',
|
||||
icon: 'IconCheckbox',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isRemote: false,
|
||||
isActive: true,
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ export const OPPORTUNITY_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({
|
||||
labelPlural: 'Opportunities',
|
||||
description: 'An opportunity',
|
||||
icon: 'IconTargetArrow',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isRemote: false,
|
||||
isActive: true,
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ export const PERSON_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({
|
||||
labelPlural: 'People',
|
||||
description: 'A person',
|
||||
icon: 'IconUser',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isRemote: false,
|
||||
isActive: true,
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ export const PET_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({
|
||||
labelPlural: 'Pets',
|
||||
description: null,
|
||||
icon: 'IconCat',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isRemote: false,
|
||||
isActive: true,
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ export const ROCKET_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({
|
||||
labelPlural: 'Rockets',
|
||||
description: 'A rocket',
|
||||
icon: 'IconRocket',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isRemote: false,
|
||||
isActive: true,
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ export const TASK_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({
|
||||
labelPlural: 'Tasks',
|
||||
description: 'A task',
|
||||
icon: 'IconCheckbox',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isRemote: false,
|
||||
isActive: true,
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ export const TASK_TARGET_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({
|
||||
labelPlural: 'Task Targets',
|
||||
description: 'A task target',
|
||||
icon: 'IconCheckbox',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isRemote: false,
|
||||
isActive: true,
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ export const TIMELINE_ACTIVITY_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({
|
||||
labelPlural: 'Timeline Activities',
|
||||
description: 'Aggregated / filtered event to be displayed on the timeline',
|
||||
icon: 'IconTimelineEvent',
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isRemote: false,
|
||||
isActive: true,
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
|
||||
namePlural: createObjectInput.namePlural,
|
||||
nameSingular: createObjectInput.nameSingular,
|
||||
shortcut: createObjectInput.shortcut ?? null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
targetTableName: 'DEPRECATED',
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
fieldUniversalIdentifiers: [],
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ export const fromFlatObjectMetadataToObjectMetadataDto = (
|
||||
color,
|
||||
description,
|
||||
icon,
|
||||
standardOverrides,
|
||||
overrides,
|
||||
shortcut,
|
||||
duplicateCriteria,
|
||||
id,
|
||||
@@ -55,7 +55,7 @@ export const fromFlatObjectMetadataToObjectMetadataDto = (
|
||||
color: color ?? undefined,
|
||||
description: description ?? undefined,
|
||||
icon: icon ?? undefined,
|
||||
standardOverrides: standardOverrides ?? undefined,
|
||||
overrides: overrides ?? undefined,
|
||||
shortcut: shortcut ?? undefined,
|
||||
duplicateCriteria: duplicateCriteria ?? undefined,
|
||||
applicationId,
|
||||
|
||||
+2
-2
@@ -66,7 +66,7 @@ export const fromUpdateObjectInputToFlatObjectMetadataAndRelatedFlatEntities =
|
||||
const isStandardObject = belongsToTwentyStandardApp(
|
||||
existingFlatObjectMetadata,
|
||||
);
|
||||
const { standardOverrides, updatedEditableObjectProperties } =
|
||||
const { overrides, updatedEditableObjectProperties } =
|
||||
sanitizeRawUpdateObjectInput({
|
||||
existingFlatObjectMetadata,
|
||||
rawUpdateObjectInput,
|
||||
@@ -81,7 +81,7 @@ export const fromUpdateObjectInputToFlatObjectMetadataAndRelatedFlatEntities =
|
||||
],
|
||||
update: updatedEditableObjectProperties,
|
||||
}),
|
||||
standardOverrides,
|
||||
overrides,
|
||||
};
|
||||
|
||||
if (
|
||||
|
||||
+11
-12
@@ -1,14 +1,13 @@
|
||||
import { extractAndSanitizeObjectStringFields } from 'twenty-shared/utils';
|
||||
|
||||
import { ALL_OVERRIDABLE_PROPERTIES_BY_METADATA_NAME } from 'src/engine/metadata-modules/flat-entity/constant/all-overridable-properties-by-metadata-name.constant';
|
||||
import { FLAT_OBJECT_METADATA_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-object-metadata/constants/flat-object-metadata-editable-properties.constant';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/object-metadata/constants/object-metadata-standard-overrides-properties.constant';
|
||||
import { type UpdateOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input';
|
||||
import {
|
||||
ObjectMetadataException,
|
||||
ObjectMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
|
||||
import { type ObjectMetadataStandardOverridesProperties } from 'src/engine/metadata-modules/object-metadata/types/object-metadata-standard-overrides-properties.types';
|
||||
import { belongsToTwentyStandardApp } from 'src/engine/metadata-modules/utils/belongs-to-twenty-standard-app.util';
|
||||
import { computeMetadataOverridesBlob } from 'src/engine/metadata-modules/utils/compute-metadata-overrides-blob.util';
|
||||
|
||||
@@ -37,7 +36,7 @@ export const sanitizeRawUpdateObjectInput = ({
|
||||
if (!isStandardObject) {
|
||||
return {
|
||||
updatedEditableObjectProperties,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,7 +45,7 @@ export const sanitizeRawUpdateObjectInput = ({
|
||||
).filter(
|
||||
(property) =>
|
||||
!FLAT_OBJECT_METADATA_EDITABLE_PROPERTIES.standard.includes(
|
||||
property as ObjectMetadataStandardOverridesProperties,
|
||||
property as (typeof FLAT_OBJECT_METADATA_EDITABLE_PROPERTIES.standard)[number],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -57,16 +56,16 @@ export const sanitizeRawUpdateObjectInput = ({
|
||||
);
|
||||
}
|
||||
|
||||
const { overrides: standardOverrides, remainingProperties } =
|
||||
computeMetadataOverridesBlob({
|
||||
overridableProperties: OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES,
|
||||
updatedProperties: updatedEditableObjectProperties,
|
||||
existingEntity: existingFlatObjectMetadata,
|
||||
existingOverrides: existingFlatObjectMetadata.standardOverrides,
|
||||
});
|
||||
const { overrides, remainingProperties } = computeMetadataOverridesBlob({
|
||||
overridableProperties:
|
||||
ALL_OVERRIDABLE_PROPERTIES_BY_METADATA_NAME.objectMetadata,
|
||||
updatedProperties: updatedEditableObjectProperties,
|
||||
existingEntity: existingFlatObjectMetadata,
|
||||
existingOverrides: existingFlatObjectMetadata.overrides,
|
||||
});
|
||||
|
||||
return {
|
||||
standardOverrides,
|
||||
overrides,
|
||||
updatedEditableObjectProperties: remainingProperties,
|
||||
};
|
||||
};
|
||||
|
||||
+20
-22
@@ -15,8 +15,8 @@ import { type CollectionHashDTO } from 'src/engine/metadata-modules/minimal-meta
|
||||
import { MinimalMetadataDTO } from 'src/engine/metadata-modules/minimal-metadata/dtos/minimal-metadata.dto';
|
||||
import { MinimalObjectMetadataDTO } from 'src/engine/metadata-modules/minimal-metadata/dtos/minimal-object-metadata.dto';
|
||||
import { MinimalViewDTO } from 'src/engine/metadata-modules/minimal-metadata/dtos/minimal-view.dto';
|
||||
import { resolveObjectMetadataStandardOverride } from 'src/engine/metadata-modules/object-metadata/utils/resolve-object-metadata-standard-override.util';
|
||||
import { belongsToTwentyStandardApp } from 'src/engine/metadata-modules/utils/belongs-to-twenty-standard-app.util';
|
||||
import { resolveEffectiveEntityProperty } from 'src/engine/metadata-modules/utils/resolve-effective-entity-property.util';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { type WorkspaceCacheKeyName } from 'src/engine/workspace-cache/types/workspace-cache-key.type';
|
||||
|
||||
@@ -80,33 +80,31 @@ export class MinimalMetadataService {
|
||||
.map((flatObjectMetadata) => {
|
||||
const isStandardApp = belongsToTwentyStandardApp(flatObjectMetadata);
|
||||
|
||||
const objectMetadataForOverride = {
|
||||
labelPlural: flatObjectMetadata.labelPlural,
|
||||
labelSingular: flatObjectMetadata.labelSingular,
|
||||
description: flatObjectMetadata.description ?? undefined,
|
||||
icon: flatObjectMetadata.icon ?? undefined,
|
||||
color: flatObjectMetadata.color ?? undefined,
|
||||
standardOverrides: flatObjectMetadata.standardOverrides ?? undefined,
|
||||
const overrides = flatObjectMetadata.overrides ?? undefined;
|
||||
const i18nContext = {
|
||||
locale: safeLocale,
|
||||
i18nInstance,
|
||||
isStandardApp,
|
||||
};
|
||||
|
||||
return {
|
||||
id: flatObjectMetadata.id,
|
||||
nameSingular: flatObjectMetadata.nameSingular,
|
||||
namePlural: flatObjectMetadata.namePlural,
|
||||
labelSingular: resolveObjectMetadataStandardOverride(
|
||||
objectMetadataForOverride,
|
||||
'labelSingular',
|
||||
safeLocale,
|
||||
i18nInstance,
|
||||
isStandardApp,
|
||||
),
|
||||
labelPlural: resolveObjectMetadataStandardOverride(
|
||||
objectMetadataForOverride,
|
||||
'labelPlural',
|
||||
safeLocale,
|
||||
i18nInstance,
|
||||
isStandardApp,
|
||||
),
|
||||
labelSingular: resolveEffectiveEntityProperty({
|
||||
metadataName: 'objectMetadata',
|
||||
baseValue: flatObjectMetadata.labelSingular,
|
||||
overrides,
|
||||
property: 'labelSingular',
|
||||
i18nContext,
|
||||
}),
|
||||
labelPlural: resolveEffectiveEntityProperty({
|
||||
metadataName: 'objectMetadata',
|
||||
baseValue: flatObjectMetadata.labelPlural,
|
||||
overrides,
|
||||
property: 'labelPlural',
|
||||
i18nContext,
|
||||
}),
|
||||
icon: flatObjectMetadata.icon ?? undefined,
|
||||
isActive: flatObjectMetadata.isActive,
|
||||
isSystem: flatObjectMetadata.isSystem,
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
import { type MetadataUniversalFlatEntityPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/metadata-universal-flat-entity-properties-to-compare.type';
|
||||
|
||||
export const OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES = [
|
||||
'color',
|
||||
'labelSingular',
|
||||
'labelPlural',
|
||||
'description',
|
||||
'icon',
|
||||
] as const satisfies MetadataUniversalFlatEntityPropertiesToCompare<'objectMetadata'>[];
|
||||
+8
-8
@@ -28,7 +28,7 @@ const PARTIAL_ID_FIELD = {
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: 'uuid',
|
||||
options: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
morphId: null,
|
||||
universalSettings: null,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
@@ -58,7 +58,7 @@ const PARTIAL_CREATED_AT_FIELD = {
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: 'now',
|
||||
options: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
morphId: null,
|
||||
universalSettings: null,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
@@ -88,7 +88,7 @@ const PARTIAL_UPDATED_AT_FIELD = {
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: 'now',
|
||||
options: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
morphId: null,
|
||||
universalSettings: null,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
@@ -118,7 +118,7 @@ const PARTIAL_DELETED_AT_FIELD = {
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: null,
|
||||
options: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
morphId: null,
|
||||
universalSettings: null,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
@@ -148,7 +148,7 @@ const PARTIAL_CREATED_BY_FIELD = {
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: { name: "''", source: "'MANUAL'" },
|
||||
options: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
morphId: null,
|
||||
universalSettings: null,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
@@ -178,7 +178,7 @@ const PARTIAL_UPDATED_BY_FIELD = {
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: { name: "''", source: "'MANUAL'" },
|
||||
options: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
morphId: null,
|
||||
universalSettings: null,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
@@ -208,7 +208,7 @@ const PARTIAL_POSITION_FIELD = {
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: 0,
|
||||
options: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
morphId: null,
|
||||
universalSettings: null,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
@@ -238,7 +238,7 @@ const PARTIAL_SEARCH_VECTOR_FIELD = {
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: null,
|
||||
options: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
morphId: null,
|
||||
// universalSettings for searchVector is computed at runtime
|
||||
// based on the name field (getTsVectorColumnExpressionFromFields)
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@ import { type WorkspaceEntityDuplicateCriteria } from 'src/engine/api/graphql/wo
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
|
||||
import { IndexMetadataDTO } from 'src/engine/metadata-modules/index-metadata/dtos/index-metadata.dto';
|
||||
import { ObjectStandardOverridesDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-standard-overrides.dto';
|
||||
import { type ObjectMetadataOverrides } from 'src/engine/metadata-modules/object-metadata/types/object-metadata-overrides.type';
|
||||
|
||||
@ObjectType('Object')
|
||||
@Authorize({
|
||||
@@ -53,8 +53,8 @@ export class ObjectMetadataDTO {
|
||||
@Field({ nullable: true })
|
||||
icon?: string;
|
||||
|
||||
@Field(() => ObjectStandardOverridesDTO, { nullable: true })
|
||||
standardOverrides?: ObjectStandardOverridesDTO;
|
||||
@HideField()
|
||||
overrides?: ObjectMetadataOverrides | null;
|
||||
|
||||
@Field({ nullable: true })
|
||||
shortcut?: string;
|
||||
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { IsJSON, IsOptional, IsString } from 'class-validator';
|
||||
import { GraphQLJSON } from 'graphql-type-json';
|
||||
import { type APP_LOCALES } from 'twenty-shared/translations';
|
||||
|
||||
@ObjectType('ObjectStandardOverrides')
|
||||
export class ObjectStandardOverridesDTO {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field(() => String, { nullable: true })
|
||||
labelSingular?: string | null;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field(() => String, { nullable: true })
|
||||
labelPlural?: string | null;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field(() => String, { nullable: true })
|
||||
description?: string | null;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field(() => String, { nullable: true })
|
||||
icon?: string | null;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field(() => String, { nullable: true })
|
||||
color?: string | null;
|
||||
|
||||
@IsJSON()
|
||||
@IsOptional()
|
||||
@Field(() => GraphQLJSON, {
|
||||
nullable: true,
|
||||
})
|
||||
translations?: Partial<
|
||||
Record<
|
||||
keyof typeof APP_LOCALES,
|
||||
{
|
||||
labelSingular?: string | null;
|
||||
labelPlural?: string | null;
|
||||
description?: string | null;
|
||||
}
|
||||
>
|
||||
> | null;
|
||||
}
|
||||
+13
-2
@@ -13,12 +13,13 @@ import { type WorkspaceEntityDuplicateCriteria } from 'src/engine/api/graphql/wo
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import { SearchFieldMetadataEntity } from 'src/engine/metadata-modules/search-field-metadata/search-field-metadata.entity';
|
||||
import { type ObjectStandardOverridesDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-standard-overrides.dto';
|
||||
import { type ObjectMetadataOverrides } from 'src/engine/metadata-modules/object-metadata/types/object-metadata-overrides.type';
|
||||
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 { 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_METADATA_OVERRIDES_COLUMN_UPGRADE_COMMAND_NAME } from 'src/database/commands/upgrade-version-command/2-19/add-metadata-overrides-column-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 { 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';
|
||||
@@ -64,8 +65,18 @@ export class ObjectMetadataEntity
|
||||
@Column({ nullable: true, type: 'text' })
|
||||
color: string | null;
|
||||
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName: ADD_METADATA_OVERRIDES_COLUMN_UPGRADE_COMMAND_NAME,
|
||||
})
|
||||
@Column({ type: 'jsonb', nullable: true })
|
||||
standardOverrides: JsonbProperty<ObjectStandardOverridesDTO> | null;
|
||||
overrides: JsonbProperty<ObjectMetadataOverrides> | null;
|
||||
|
||||
/**
|
||||
* @deprecated Superseded by `overrides`; kept readable for pods on the
|
||||
* previous release during a rolling deploy. Drop deferred to 2-20/README.md.
|
||||
*/
|
||||
@Column({ type: 'jsonb', nullable: true })
|
||||
standardOverrides: WasRemovedInUpgrade<JsonbProperty<ObjectMetadataOverrides> | null>;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
|
||||
+13
-9
@@ -32,7 +32,7 @@ import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metada
|
||||
import { ObjectRecordCountService } from 'src/engine/metadata-modules/object-metadata/object-record-count.service';
|
||||
import { SearchFieldMetadataDTO } from 'src/engine/metadata-modules/search-field-metadata/dtos/search-field-metadata.dto';
|
||||
import { objectMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util';
|
||||
import { resolveObjectMetadataStandardOverride } from 'src/engine/metadata-modules/object-metadata/utils/resolve-object-metadata-standard-override.util';
|
||||
import { resolveEffectiveEntityProperty } from 'src/engine/metadata-modules/utils/resolve-effective-entity-property.util';
|
||||
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
|
||||
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
@@ -92,14 +92,18 @@ export class ObjectMetadataResolver {
|
||||
locale: context.req.locale,
|
||||
});
|
||||
|
||||
return resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
labelKey,
|
||||
context.req.locale,
|
||||
i18n,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
);
|
||||
return resolveEffectiveEntityProperty({
|
||||
metadataName: 'objectMetadata',
|
||||
baseValue: objectMetadata[labelKey],
|
||||
overrides: objectMetadata.overrides,
|
||||
property: labelKey,
|
||||
i18nContext: {
|
||||
locale: context.req.locale,
|
||||
i18nInstance: i18n,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ResolveField(() => String, { nullable: true })
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metada
|
||||
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
|
||||
|
||||
const OBJECT_STRIP_WHEN_NULLISH = [
|
||||
'standardOverrides',
|
||||
'overrides',
|
||||
'color',
|
||||
'duplicateCriteria',
|
||||
'shortcut',
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { type APP_LOCALES } from 'twenty-shared/translations';
|
||||
|
||||
export type ObjectMetadataOverrides = {
|
||||
labelSingular?: string | null;
|
||||
labelPlural?: string | null;
|
||||
description?: string | null;
|
||||
icon?: string | null;
|
||||
color?: string | null;
|
||||
translations?: Partial<
|
||||
Record<
|
||||
keyof typeof APP_LOCALES,
|
||||
{
|
||||
labelSingular?: string | null;
|
||||
labelPlural?: string | null;
|
||||
description?: string | null;
|
||||
}
|
||||
>
|
||||
> | null;
|
||||
};
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
import { type OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/object-metadata/constants/object-metadata-standard-overrides-properties.constant';
|
||||
|
||||
export type ObjectMetadataStandardOverridesProperties =
|
||||
(typeof OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES)[number];
|
||||
+1
-1
@@ -31,7 +31,7 @@ const makeFieldMetadata = (
|
||||
icon: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
updatedAt: '2026-01-01T00:00:00.000Z',
|
||||
|
||||
-737
@@ -1,737 +0,0 @@
|
||||
import { type I18n } from '@lingui/core';
|
||||
import { SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
|
||||
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
|
||||
import { resolveObjectMetadataStandardOverride } from 'src/engine/metadata-modules/object-metadata/utils/resolve-object-metadata-standard-override.util';
|
||||
|
||||
jest.mock('src/engine/core-modules/i18n/utils/generateMessageId');
|
||||
|
||||
const mockGenerateMessageId = generateMessageId as jest.MockedFunction<
|
||||
typeof generateMessageId
|
||||
>;
|
||||
|
||||
describe('resolveObjectMetadataStandardOverride', () => {
|
||||
let mockI18n: jest.Mocked<I18n>;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockI18n = {
|
||||
_: jest.fn(),
|
||||
} as unknown as jest.Mocked<I18n>;
|
||||
});
|
||||
|
||||
describe('Custom objects', () => {
|
||||
it('should return the object value for custom labelSingular object', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'My Custom',
|
||||
labelPlural: 'My Customs',
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
color: 'blue',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('My Custom');
|
||||
});
|
||||
|
||||
it('should never translate a custom label even when it matches a standard catalog entry', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Company',
|
||||
labelPlural: 'Companies',
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
color: 'blue',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('company.message.id');
|
||||
mockI18n._.mockReturnValue('Entreprise');
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Company');
|
||||
expect(mockGenerateMessageId).not.toHaveBeenCalled();
|
||||
expect(mockI18n._).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return the object value for custom description object', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'My Custom',
|
||||
labelPlural: 'My Customs',
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
color: 'blue',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'description',
|
||||
undefined,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Custom Description');
|
||||
});
|
||||
|
||||
it('should return the object value for custom icon object', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'My Custom',
|
||||
labelPlural: 'My Customs',
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
color: 'blue',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'icon',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('custom-icon');
|
||||
});
|
||||
|
||||
it('should return the object value for custom color object', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'My Custom',
|
||||
labelPlural: 'My Customs',
|
||||
description: 'Custom Description',
|
||||
icon: 'custom-icon',
|
||||
color: 'green',
|
||||
isCustom: true,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'color',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('green');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Standard objects - Icon overrides', () => {
|
||||
it('should return override icon when available for standard object', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'My Custom',
|
||||
labelPlural: 'My Customs',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
icon: 'override-icon',
|
||||
},
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'icon',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('override-icon');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Standard objects - Color overrides', () => {
|
||||
it('should return override color when available for standard object', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Company',
|
||||
labelPlural: 'Companies',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
color: 'blue',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
color: 'red',
|
||||
},
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'color',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('red');
|
||||
});
|
||||
|
||||
it('should return base color when no override exists for standard object', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Company',
|
||||
labelPlural: 'Companies',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
color: 'blue',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('generated-message-id');
|
||||
mockI18n._.mockReturnValue('generated-message-id');
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'color',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('blue');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Standard objects - Translation overrides', () => {
|
||||
it('should return translation override when available for non-icon objects', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
labelSingular: 'Libellé traduit',
|
||||
labelPlural: 'Libellés traduits',
|
||||
description: 'Description traduite',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(
|
||||
resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
),
|
||||
).toBe('Libellé traduit');
|
||||
expect(
|
||||
resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelPlural',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
),
|
||||
).toBe('Libellés traduits');
|
||||
expect(
|
||||
resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'description',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
),
|
||||
).toBe('Description traduite');
|
||||
});
|
||||
|
||||
it('should fallback when translation override is not available for the locale', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'es-ES': {
|
||||
labelSingular: 'Etiqueta en español',
|
||||
labelPlural: 'Etiquetas en español',
|
||||
description: 'Descripción en español',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('generated-message-id');
|
||||
mockI18n._.mockReturnValue('generated-message-id');
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Standard Label');
|
||||
});
|
||||
|
||||
it('should fallback when translation override is not available for the labelKey', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
labelPlural: 'Libellés traduits',
|
||||
labelSingular: 'Libellé traduit',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('generated-message-id');
|
||||
mockI18n._.mockReturnValue('generated-message-id');
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'description',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Standard Description');
|
||||
});
|
||||
|
||||
it('should not use translation overrides when locale is undefined', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
labelSingular: 'Libellé traduit',
|
||||
labelPlural: 'Libellés traduits',
|
||||
description: 'Description traduite',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('generated-message-id');
|
||||
mockI18n._.mockReturnValue('generated-message-id');
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
undefined,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Standard Label');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Standard objects - SOURCE_LOCALE overrides', () => {
|
||||
it('should return direct override for SOURCE_LOCALE when available', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: 'Overridden Label',
|
||||
labelPlural: 'Overridden Labels',
|
||||
description: 'Overridden Description',
|
||||
icon: 'overridden-icon',
|
||||
},
|
||||
};
|
||||
|
||||
expect(
|
||||
resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
),
|
||||
).toBe('Overridden Label');
|
||||
expect(
|
||||
resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelPlural',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
),
|
||||
).toBe('Overridden Labels');
|
||||
expect(
|
||||
resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'description',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
),
|
||||
).toBe('Overridden Description');
|
||||
expect(
|
||||
resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'icon',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
),
|
||||
).toBe('overridden-icon');
|
||||
});
|
||||
|
||||
it('should use direct override for non-SOURCE_LOCALE', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: 'Overridden Label',
|
||||
labelPlural: 'Overridden Labels',
|
||||
},
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Overridden Label');
|
||||
});
|
||||
|
||||
it('should not use undefined override for SOURCE_LOCALE', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: undefined,
|
||||
},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('generated-message-id');
|
||||
mockI18n._.mockReturnValue('generated-message-id');
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Standard Label');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Standard objects - Auto translation fallback', () => {
|
||||
it('should return translated message when translation is available', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('standard.label.message.id');
|
||||
mockI18n._.mockReturnValue('Libellé traduit automatiquement');
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(mockGenerateMessageId).toHaveBeenCalledWith('Standard Label');
|
||||
expect(mockI18n._).toHaveBeenCalledWith('standard.label.message.id');
|
||||
expect(result).toBe('Libellé traduit automatiquement');
|
||||
});
|
||||
|
||||
it('should return original object value when no translation is found', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const messageId = 'standard.label.message.id';
|
||||
|
||||
mockGenerateMessageId.mockReturnValue(messageId);
|
||||
mockI18n._.mockReturnValue(messageId);
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Standard Label');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Priority order - Standard objects', () => {
|
||||
it('should prioritize translation override over SOURCE_LOCALE override for non-SOURCE_LOCALE', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: 'Source Override',
|
||||
labelPlural: 'Source Overrides',
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
labelSingular: 'Translation Override',
|
||||
labelPlural: 'Translation Overrides',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Translation Override');
|
||||
expect(mockGenerateMessageId).not.toHaveBeenCalled();
|
||||
expect(mockI18n._).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should prioritize SOURCE_LOCALE override over auto translation for SOURCE_LOCALE', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: 'Source Override',
|
||||
labelPlural: 'Source Overrides',
|
||||
},
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
SOURCE_LOCALE,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Source Override');
|
||||
expect(mockGenerateMessageId).not.toHaveBeenCalled();
|
||||
expect(mockI18n._).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use auto translation when no overrides are available', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {},
|
||||
};
|
||||
|
||||
mockGenerateMessageId.mockReturnValue('auto.translation.id');
|
||||
mockI18n._.mockReturnValue('Auto Translated Label');
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'de-DE',
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Auto Translated Label');
|
||||
expect(mockGenerateMessageId).toHaveBeenCalledWith('Standard Label');
|
||||
expect(mockI18n._).toHaveBeenCalledWith('auto.translation.id');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Undefined locale handling', () => {
|
||||
it('should use SOURCE_LOCALE fallback when locale is undefined for standard object', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
labelSingular: 'Source Override',
|
||||
},
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
undefined,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Source Override');
|
||||
expect(mockGenerateMessageId).not.toHaveBeenCalled();
|
||||
expect(mockI18n._).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fall back to auto translation when locale is undefined and no SOURCE_LOCALE override exists', () => {
|
||||
mockI18n._.mockReturnValue('Auto Translated Label');
|
||||
mockGenerateMessageId.mockReturnValue('auto.translation.id');
|
||||
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Standard Label',
|
||||
labelPlural: 'Standard Labels',
|
||||
description: 'Standard Description',
|
||||
icon: 'default-icon',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
undefined,
|
||||
mockI18n,
|
||||
!objectMetadata.isCustom,
|
||||
);
|
||||
|
||||
expect(result).toBe('Auto Translated Label');
|
||||
expect(mockGenerateMessageId).toHaveBeenCalledWith('Standard Label');
|
||||
expect(mockI18n._).toHaveBeenCalledWith('auto.translation.id');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Application objects - catalog translations', () => {
|
||||
it('should translate an application object label from its catalog', () => {
|
||||
mockGenerateMessageId.mockReturnValue('app.label.id');
|
||||
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Property',
|
||||
labelPlural: 'Properties',
|
||||
description: 'A property',
|
||||
icon: 'IconBuilding',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
false,
|
||||
{ 'app.label.id': 'Bien' },
|
||||
);
|
||||
|
||||
expect(result).toBe('Bien');
|
||||
expect(mockI18n._).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fall back to the source value when the catalog has no entry', () => {
|
||||
mockGenerateMessageId.mockReturnValue('missing.id');
|
||||
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Property',
|
||||
labelPlural: 'Properties',
|
||||
description: 'A property',
|
||||
icon: 'IconBuilding',
|
||||
isCustom: false,
|
||||
standardOverrides: undefined,
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
false,
|
||||
{},
|
||||
);
|
||||
|
||||
expect(result).toBe('Property');
|
||||
});
|
||||
|
||||
it('should prioritize a workspace translation override over the catalog', () => {
|
||||
const objectMetadata = {
|
||||
labelSingular: 'Property',
|
||||
labelPlural: 'Properties',
|
||||
description: 'A property',
|
||||
icon: 'IconBuilding',
|
||||
isCustom: false,
|
||||
standardOverrides: {
|
||||
translations: {
|
||||
'fr-FR': {
|
||||
labelSingular: 'Bien immobilier',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = resolveObjectMetadataStandardOverride(
|
||||
objectMetadata,
|
||||
'labelSingular',
|
||||
'fr-FR',
|
||||
mockI18n,
|
||||
false,
|
||||
{ 'app.label.id': 'Bien' },
|
||||
);
|
||||
|
||||
expect(result).toBe('Bien immobilier');
|
||||
expect(mockGenerateMessageId).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
+1
-1
@@ -139,7 +139,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
options: null,
|
||||
standardOverrides: null,
|
||||
overrides: null,
|
||||
morphId: null,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ export const fromObjectMetadataEntityToObjectMetadataDto = (
|
||||
icon: entity.icon ?? undefined,
|
||||
color: entity.color ?? undefined,
|
||||
shortcut: entity.shortcut ?? undefined,
|
||||
standardOverrides: entity.standardOverrides ?? undefined,
|
||||
overrides: entity.overrides ?? undefined,
|
||||
isRemote: entity.isRemote,
|
||||
isActive: entity.isActive,
|
||||
isSystem: entity.isSystem,
|
||||
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
import { type I18n } from '@lingui/core';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { type APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { translateStandardLabel } from 'src/engine/core-modules/i18n/utils/translate-standard-label.util';
|
||||
import { type ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto';
|
||||
|
||||
export const resolveObjectMetadataStandardOverride = (
|
||||
objectMetadata: Pick<
|
||||
ObjectMetadataDTO,
|
||||
| 'color'
|
||||
| 'labelPlural'
|
||||
| 'labelSingular'
|
||||
| 'description'
|
||||
| 'icon'
|
||||
| 'standardOverrides'
|
||||
>,
|
||||
labelKey: 'color' | 'labelPlural' | 'labelSingular' | 'description' | 'icon',
|
||||
locale: keyof typeof APP_LOCALES | undefined,
|
||||
i18nInstance: I18n,
|
||||
isStandardApp: boolean,
|
||||
applicationCatalog?: Record<string, string>,
|
||||
): string => {
|
||||
const safeLocale = locale ?? SOURCE_LOCALE;
|
||||
|
||||
if (!isStandardApp && !isDefined(applicationCatalog)) {
|
||||
return objectMetadata[labelKey] ?? '';
|
||||
}
|
||||
|
||||
if (
|
||||
(labelKey === 'icon' || labelKey === 'color') &&
|
||||
isDefined(objectMetadata.standardOverrides?.[labelKey])
|
||||
) {
|
||||
return objectMetadata.standardOverrides[labelKey];
|
||||
}
|
||||
|
||||
if (
|
||||
isDefined(objectMetadata.standardOverrides?.translations) &&
|
||||
labelKey !== 'icon' &&
|
||||
labelKey !== 'color'
|
||||
) {
|
||||
const translationValue =
|
||||
objectMetadata.standardOverrides.translations[safeLocale]?.[labelKey];
|
||||
|
||||
if (isDefined(translationValue)) {
|
||||
return translationValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNonEmptyString(objectMetadata.standardOverrides?.[labelKey])) {
|
||||
return objectMetadata.standardOverrides[labelKey] ?? '';
|
||||
}
|
||||
|
||||
return translateStandardLabel({
|
||||
sourceValue: objectMetadata[labelKey] ?? '',
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
i18nInstance,
|
||||
});
|
||||
};
|
||||
+3
-7
@@ -36,7 +36,7 @@ import {
|
||||
} from 'src/engine/metadata-modules/page-layout/exceptions/page-layout.exception';
|
||||
import { fromFlatPageLayoutWithTabsAndWidgetsToPageLayoutDto } from 'src/engine/metadata-modules/page-layout/utils/from-flat-page-layout-with-tabs-and-widgets-to-page-layout-dto.util';
|
||||
import { isCallerOverridingEntity } from 'src/engine/metadata-modules/utils/is-caller-overriding-entity.util';
|
||||
import { resolveFlatEntityOverridableProperties } from 'src/engine/metadata-modules/utils/resolve-flat-entity-overridable-properties.util';
|
||||
import { resolveEffectiveEntity } from 'src/engine/metadata-modules/utils/resolve-effective-entity.util';
|
||||
import { sanitizeOverridableEntityInput } from 'src/engine/metadata-modules/utils/sanitize-overridable-entity-input.util';
|
||||
import { ViewService } from 'src/engine/metadata-modules/view/services/view.service';
|
||||
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
|
||||
@@ -283,9 +283,7 @@ export class PageLayoutUpdateService {
|
||||
.filter(isDefined)
|
||||
.filter((tab) => tab.pageLayoutId === existingPageLayout.id);
|
||||
|
||||
const resolvedExistingTabs = existingTabs.map(
|
||||
resolveFlatEntityOverridableProperties,
|
||||
);
|
||||
const resolvedExistingTabs = existingTabs.map(resolveEffectiveEntity);
|
||||
|
||||
const {
|
||||
toCreate: entitiesToCreate,
|
||||
@@ -561,9 +559,7 @@ export class PageLayoutUpdateService {
|
||||
flatPageLayoutWidgetMaps,
|
||||
});
|
||||
|
||||
const resolvedExistingWidgets = existingWidgets.map(
|
||||
resolveFlatEntityOverridableProperties,
|
||||
);
|
||||
const resolvedExistingWidgets = existingWidgets.map(resolveEffectiveEntity);
|
||||
|
||||
const {
|
||||
toCreate: entitiesToCreate,
|
||||
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
import { type I18n } from '@lingui/core';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { type APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { translateStandardLabel } from 'src/engine/core-modules/i18n/utils/translate-standard-label.util';
|
||||
import { resolveEffectiveEntityProperty } from 'src/engine/metadata-modules/utils/resolve-effective-entity-property.util';
|
||||
import { resolveEffectiveEntity } from 'src/engine/metadata-modules/utils/resolve-effective-entity.util';
|
||||
|
||||
// Frozen reference implementations of the three resolvers that existed before
|
||||
// unification (resolve-object-metadata-standard-override,
|
||||
// resolve-field-metadata-standard-override,
|
||||
// resolve-flat-entity-overridable-properties), with standardOverrides renamed
|
||||
// to overrides. The unified resolver must reproduce these byte-for-byte across
|
||||
// the corpus below — this is the safety net for the whole override unification.
|
||||
|
||||
type Locale = keyof typeof APP_LOCALES | undefined;
|
||||
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
type AnyOverrides = any;
|
||||
|
||||
const frozenResolveObjectOverride = (
|
||||
objectMetadata: AnyOverrides,
|
||||
labelKey: 'color' | 'labelPlural' | 'labelSingular' | 'description' | 'icon',
|
||||
locale: Locale,
|
||||
i18nInstance: I18n,
|
||||
isStandardApp: boolean,
|
||||
applicationCatalog?: Record<string, string>,
|
||||
): string => {
|
||||
const safeLocale = locale ?? SOURCE_LOCALE;
|
||||
|
||||
if (!isStandardApp && !isDefined(applicationCatalog)) {
|
||||
return objectMetadata[labelKey] ?? '';
|
||||
}
|
||||
|
||||
if (
|
||||
(labelKey === 'icon' || labelKey === 'color') &&
|
||||
isDefined(objectMetadata.overrides?.[labelKey])
|
||||
) {
|
||||
return objectMetadata.overrides[labelKey];
|
||||
}
|
||||
|
||||
if (
|
||||
isDefined(objectMetadata.overrides?.translations) &&
|
||||
labelKey !== 'icon' &&
|
||||
labelKey !== 'color'
|
||||
) {
|
||||
const translationValue =
|
||||
objectMetadata.overrides.translations[safeLocale]?.[labelKey];
|
||||
|
||||
if (isDefined(translationValue)) {
|
||||
return translationValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNonEmptyString(objectMetadata.overrides?.[labelKey])) {
|
||||
return objectMetadata.overrides[labelKey] ?? '';
|
||||
}
|
||||
|
||||
return translateStandardLabel({
|
||||
sourceValue: objectMetadata[labelKey] ?? '',
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
i18nInstance,
|
||||
});
|
||||
};
|
||||
|
||||
const frozenResolveFieldOverride = (
|
||||
fieldMetadata: AnyOverrides,
|
||||
labelKey: 'label' | 'description' | 'icon',
|
||||
locale: Locale,
|
||||
i18nInstance: I18n,
|
||||
isStandardApp: boolean,
|
||||
applicationCatalog?: Record<string, string>,
|
||||
): string => {
|
||||
const safeLocale = locale ?? SOURCE_LOCALE;
|
||||
|
||||
if (!isStandardApp && !isDefined(applicationCatalog)) {
|
||||
return fieldMetadata[labelKey] ?? '';
|
||||
}
|
||||
|
||||
if (labelKey === 'icon' && isDefined(fieldMetadata.overrides?.icon)) {
|
||||
return fieldMetadata.overrides.icon;
|
||||
}
|
||||
|
||||
if (isDefined(fieldMetadata.overrides?.translations) && labelKey !== 'icon') {
|
||||
const translationValue =
|
||||
fieldMetadata.overrides.translations[safeLocale]?.[labelKey];
|
||||
|
||||
if (isDefined(translationValue)) {
|
||||
return translationValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNonEmptyString(fieldMetadata.overrides?.[labelKey])) {
|
||||
return fieldMetadata.overrides[labelKey] ?? '';
|
||||
}
|
||||
|
||||
return translateStandardLabel({
|
||||
sourceValue: fieldMetadata[labelKey] ?? '',
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
i18nInstance,
|
||||
});
|
||||
};
|
||||
|
||||
const frozenResolveFlat = (flatEntity: AnyOverrides): AnyOverrides => {
|
||||
if (!isDefined(flatEntity.overrides)) {
|
||||
return flatEntity;
|
||||
}
|
||||
|
||||
return {
|
||||
...flatEntity,
|
||||
...flatEntity.overrides,
|
||||
};
|
||||
};
|
||||
|
||||
const mockI18n = {
|
||||
_: (id: string) => `translated:${id}`,
|
||||
} as unknown as I18n;
|
||||
|
||||
const LOCALES: Locale[] = [undefined, SOURCE_LOCALE, 'fr-FR'];
|
||||
const BOOLS = [true, false];
|
||||
|
||||
const OBJECT_KEYS = [
|
||||
'labelSingular',
|
||||
'labelPlural',
|
||||
'description',
|
||||
'icon',
|
||||
'color',
|
||||
] as const;
|
||||
|
||||
const FIELD_KEYS = ['label', 'description', 'icon'] as const;
|
||||
|
||||
const buildObjectBase = () => ({
|
||||
labelSingular: 'Company',
|
||||
labelPlural: 'Companies',
|
||||
description: 'A company',
|
||||
icon: 'IconBuilding',
|
||||
color: 'blue',
|
||||
});
|
||||
|
||||
const buildFieldBase = () => ({
|
||||
label: 'Name',
|
||||
description: 'The name',
|
||||
icon: 'IconAbc',
|
||||
});
|
||||
|
||||
const OBJECT_OVERRIDES_CORPUS: AnyOverrides[] = [
|
||||
undefined,
|
||||
null,
|
||||
{},
|
||||
{ labelSingular: 'Org' },
|
||||
{ labelSingular: '' },
|
||||
{ labelPlural: 'Orgs', description: 'custom' },
|
||||
{ icon: 'IconStar' },
|
||||
{ color: 'red' },
|
||||
{ icon: 'IconStar', color: 'red', labelSingular: 'Org' },
|
||||
{ translations: { 'fr-FR': { labelSingular: 'Société' } } },
|
||||
{ translations: { en: { labelPlural: 'Companies EN' } } },
|
||||
{
|
||||
labelSingular: 'Org',
|
||||
translations: {
|
||||
'fr-FR': { labelSingular: 'Société', description: 'desc fr' },
|
||||
},
|
||||
},
|
||||
{ translations: {} },
|
||||
{ translations: { 'fr-FR': {} } },
|
||||
];
|
||||
|
||||
const FIELD_OVERRIDES_CORPUS: AnyOverrides[] = [
|
||||
undefined,
|
||||
null,
|
||||
{},
|
||||
{ label: 'Full name' },
|
||||
{ label: '' },
|
||||
{ description: 'custom desc' },
|
||||
{ icon: 'IconStar' },
|
||||
{ icon: 'IconStar', label: 'Full name' },
|
||||
{ translations: { 'fr-FR': { label: 'Nom' } } },
|
||||
{
|
||||
label: 'Full name',
|
||||
translations: { 'fr-FR': { label: 'Nom', description: 'desc fr' } },
|
||||
},
|
||||
{ translations: {} },
|
||||
];
|
||||
|
||||
const CATALOGS: (Record<string, string> | undefined)[] = [
|
||||
undefined,
|
||||
{ 'some.id': 'From catalog' },
|
||||
];
|
||||
|
||||
describe('resolveEffectiveEntityProperty (parity with legacy resolvers)', () => {
|
||||
it('matches the frozen object resolver across the corpus', () => {
|
||||
for (const overrides of OBJECT_OVERRIDES_CORPUS) {
|
||||
for (const key of OBJECT_KEYS) {
|
||||
for (const locale of LOCALES) {
|
||||
for (const isStandardApp of BOOLS) {
|
||||
for (const applicationCatalog of CATALOGS) {
|
||||
const entity = { ...buildObjectBase(), overrides };
|
||||
|
||||
const expected = frozenResolveObjectOverride(
|
||||
entity,
|
||||
key,
|
||||
locale,
|
||||
mockI18n,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
);
|
||||
|
||||
const actual = resolveEffectiveEntityProperty({
|
||||
metadataName: 'objectMetadata',
|
||||
baseValue: entity[key as keyof typeof entity] as string,
|
||||
overrides: entity.overrides,
|
||||
property: key,
|
||||
i18nContext: {
|
||||
locale,
|
||||
i18nInstance: mockI18n,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
},
|
||||
});
|
||||
|
||||
expect(actual).toBe(expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('matches the frozen field resolver across the corpus', () => {
|
||||
for (const overrides of FIELD_OVERRIDES_CORPUS) {
|
||||
for (const key of FIELD_KEYS) {
|
||||
for (const locale of LOCALES) {
|
||||
for (const isStandardApp of BOOLS) {
|
||||
for (const applicationCatalog of CATALOGS) {
|
||||
const entity = { ...buildFieldBase(), overrides };
|
||||
|
||||
const expected = frozenResolveFieldOverride(
|
||||
entity,
|
||||
key,
|
||||
locale,
|
||||
mockI18n,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
);
|
||||
|
||||
const actual = resolveEffectiveEntityProperty({
|
||||
metadataName: 'fieldMetadata',
|
||||
baseValue: entity[key as keyof typeof entity] as string,
|
||||
overrides: entity.overrides,
|
||||
property: key,
|
||||
i18nContext: {
|
||||
locale,
|
||||
i18nInstance: mockI18n,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
},
|
||||
});
|
||||
|
||||
expect(actual).toBe(expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveEffectiveEntity (parity with legacy flat spread)', () => {
|
||||
it('matches the frozen flat spread across the corpus', () => {
|
||||
const flatCorpus: AnyOverrides[] = [
|
||||
{ name: 'View', position: 1, overrides: undefined },
|
||||
{ name: 'View', position: 1, overrides: null },
|
||||
{ name: 'View', position: 1, overrides: {} },
|
||||
{ name: 'View', position: 1, overrides: { name: 'Overridden' } },
|
||||
{
|
||||
name: 'View',
|
||||
position: 1,
|
||||
icon: 'IconList',
|
||||
overrides: { name: 'Overridden', position: 2 },
|
||||
},
|
||||
];
|
||||
|
||||
for (const flatEntity of flatCorpus) {
|
||||
expect(resolveEffectiveEntity(flatEntity)).toEqual(
|
||||
frozenResolveFlat(flatEntity),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { type I18n } from '@lingui/core';
|
||||
import { type APP_LOCALES } from 'twenty-shared/translations';
|
||||
|
||||
export type EffectiveEntityI18nContext = {
|
||||
locale: keyof typeof APP_LOCALES | undefined;
|
||||
i18nInstance: I18n;
|
||||
isStandardApp: boolean;
|
||||
applicationCatalog?: Record<string, string>;
|
||||
};
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { type AllMetadataName } from 'twenty-shared/metadata';
|
||||
import { type APP_LOCALES } from 'twenty-shared/translations';
|
||||
|
||||
import {
|
||||
type MetadataEntityOverridablePropertyName,
|
||||
type MetadataEntityTranslatablePropertyName,
|
||||
} from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
|
||||
|
||||
type OverridesTranslationEntry<T extends AllMetadataName> = {
|
||||
[P in MetadataEntityTranslatablePropertyName<T>]?: string | null;
|
||||
};
|
||||
|
||||
export type MetadataPresentationOverrides<T extends AllMetadataName> = {
|
||||
[P in MetadataEntityOverridablePropertyName<T>]?: string | null;
|
||||
} & {
|
||||
translations?: Partial<
|
||||
Record<keyof typeof APP_LOCALES, OverridesTranslationEntry<T>>
|
||||
> | null;
|
||||
};
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { type AllMetadataName } from 'twenty-shared/metadata';
|
||||
import { SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { translateStandardLabel } from 'src/engine/core-modules/i18n/utils/translate-standard-label.util';
|
||||
import { type MetadataEntityOverridablePropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
|
||||
import { ALL_TRANSLATABLE_PROPERTIES_BY_METADATA_NAME } from 'src/engine/metadata-modules/flat-entity/constant/all-translatable-properties-by-metadata-name.constant';
|
||||
import { type EffectiveEntityI18nContext } from 'src/engine/metadata-modules/utils/effective-entity-i18n-context.type';
|
||||
import { type MetadataPresentationOverrides } from 'src/engine/metadata-modules/utils/metadata-presentation-overrides.type';
|
||||
|
||||
export const resolveEffectiveEntityProperty = <T extends AllMetadataName>({
|
||||
metadataName,
|
||||
baseValue,
|
||||
overrides,
|
||||
property,
|
||||
i18nContext,
|
||||
}: {
|
||||
metadataName: T;
|
||||
baseValue: string | null | undefined;
|
||||
overrides: MetadataPresentationOverrides<T> | null | undefined;
|
||||
property: MetadataEntityOverridablePropertyName<T> & string;
|
||||
i18nContext: EffectiveEntityI18nContext;
|
||||
}): string => {
|
||||
const isTranslatable = (
|
||||
ALL_TRANSLATABLE_PROPERTIES_BY_METADATA_NAME[metadataName] as string[]
|
||||
).includes(property);
|
||||
|
||||
const overrideValue = (
|
||||
overrides as Record<string, unknown> | null | undefined
|
||||
)?.[property];
|
||||
|
||||
const { locale, i18nInstance, isStandardApp, applicationCatalog } =
|
||||
i18nContext;
|
||||
const safeLocale = locale ?? SOURCE_LOCALE;
|
||||
const safeBaseValue = baseValue ?? '';
|
||||
|
||||
// Custom (non-standard) entities without a catalog have no standard label to
|
||||
// resolve or translate, and never carry overrides.
|
||||
if (!isStandardApp && !isDefined(applicationCatalog)) {
|
||||
return safeBaseValue;
|
||||
}
|
||||
|
||||
if (!isTranslatable && isDefined(overrideValue)) {
|
||||
return overrideValue as string;
|
||||
}
|
||||
|
||||
if (isTranslatable && isDefined(overrides?.translations)) {
|
||||
const translationValue = (
|
||||
overrides.translations[safeLocale] as
|
||||
| Record<string, string | null | undefined>
|
||||
| undefined
|
||||
)?.[property];
|
||||
|
||||
if (isDefined(translationValue)) {
|
||||
return translationValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNonEmptyString(overrideValue)) {
|
||||
return overrideValue;
|
||||
}
|
||||
|
||||
return translateStandardLabel({
|
||||
sourceValue: safeBaseValue,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
i18nInstance,
|
||||
});
|
||||
};
|
||||
+1
-3
@@ -5,9 +5,7 @@ type FlatEntityWithOverrides = {
|
||||
overrides: Record<string, unknown> | null;
|
||||
};
|
||||
|
||||
export const resolveFlatEntityOverridableProperties = <
|
||||
T extends FlatEntityWithOverrides,
|
||||
>(
|
||||
export const resolveEffectiveEntity = <T extends FlatEntityWithOverrides>(
|
||||
flatEntity: T,
|
||||
): T => {
|
||||
if (!isDefined(flatEntity.overrides)) {
|
||||
+11
-13
@@ -24,7 +24,7 @@ import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { resolveObjectMetadataStandardOverride } from 'src/engine/metadata-modules/object-metadata/utils/resolve-object-metadata-standard-override.util';
|
||||
import { resolveEffectiveEntityProperty } from 'src/engine/metadata-modules/utils/resolve-effective-entity-property.util';
|
||||
import { belongsToTwentyStandardApp } from 'src/engine/metadata-modules/utils/belongs-to-twenty-standard-app.util';
|
||||
import { CreateViewPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/create-view-permission.guard';
|
||||
import { DeleteViewPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/delete-view-permission.guard';
|
||||
@@ -211,19 +211,17 @@ export class ViewController {
|
||||
|
||||
if (objectMetadata) {
|
||||
const i18n = this.i18nService.getI18nInstance(locale ?? 'en');
|
||||
const translatedObjectLabel = resolveObjectMetadataStandardOverride(
|
||||
{
|
||||
labelPlural: objectMetadata.labelPlural,
|
||||
labelSingular: objectMetadata.labelSingular,
|
||||
description: objectMetadata.description ?? undefined,
|
||||
icon: objectMetadata.icon ?? undefined,
|
||||
standardOverrides: objectMetadata.standardOverrides ?? undefined,
|
||||
const translatedObjectLabel = resolveEffectiveEntityProperty({
|
||||
metadataName: 'objectMetadata',
|
||||
baseValue: objectMetadata.labelPlural,
|
||||
overrides: objectMetadata.overrides ?? undefined,
|
||||
property: 'labelPlural',
|
||||
i18nContext: {
|
||||
locale,
|
||||
i18nInstance: i18n,
|
||||
isStandardApp: belongsToTwentyStandardApp(objectMetadata),
|
||||
},
|
||||
'labelPlural',
|
||||
locale,
|
||||
i18n,
|
||||
belongsToTwentyStandardApp(objectMetadata),
|
||||
);
|
||||
});
|
||||
|
||||
processedName = this.viewService.processViewNameWithTemplate(
|
||||
view.name,
|
||||
|
||||
+12
-14
@@ -24,7 +24,7 @@ import { CustomPermissionGuard } from 'src/engine/guards/custom-permission.guard
|
||||
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
|
||||
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { resolveObjectMetadataStandardOverride } from 'src/engine/metadata-modules/object-metadata/utils/resolve-object-metadata-standard-override.util';
|
||||
import { resolveEffectiveEntityProperty } from 'src/engine/metadata-modules/utils/resolve-effective-entity-property.util';
|
||||
import { ViewFieldGroupDTO } from 'src/engine/metadata-modules/view-field-group/dtos/view-field-group.dto';
|
||||
import { ViewFieldDTO } from 'src/engine/metadata-modules/view-field/dtos/view-field.dto';
|
||||
import { ViewFilterGroupDTO } from 'src/engine/metadata-modules/view-filter-group/dtos/view-filter-group.dto';
|
||||
@@ -80,20 +80,18 @@ export class ViewResolver {
|
||||
workspaceId: workspace.id,
|
||||
locale: context.req.locale,
|
||||
});
|
||||
const translatedObjectLabel = resolveObjectMetadataStandardOverride(
|
||||
{
|
||||
labelPlural: objectMetadata.labelPlural,
|
||||
labelSingular: objectMetadata.labelSingular,
|
||||
description: objectMetadata.description ?? undefined,
|
||||
icon: objectMetadata.icon ?? undefined,
|
||||
standardOverrides: objectMetadata.standardOverrides ?? undefined,
|
||||
const translatedObjectLabel = resolveEffectiveEntityProperty({
|
||||
metadataName: 'objectMetadata',
|
||||
baseValue: objectMetadata.labelPlural,
|
||||
overrides: objectMetadata.overrides ?? undefined,
|
||||
property: 'labelPlural',
|
||||
i18nContext: {
|
||||
locale: context.req.locale,
|
||||
i18nInstance: i18n,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
},
|
||||
'labelPlural',
|
||||
context.req.locale,
|
||||
i18n,
|
||||
isStandardApp,
|
||||
applicationCatalog,
|
||||
);
|
||||
});
|
||||
|
||||
return this.viewService.processViewNameWithTemplate(
|
||||
view.name,
|
||||
|
||||
Reference in New Issue
Block a user