Files
twenty/packages/twenty-server/src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant.ts
T
Félix Malfait d602f35cbd feat(data-model): custom-indexes management UI and mutations (#20846)
## Summary

Brings indexes management into the per-object Settings tab as a section
under Search (no feature flag, advanced mode only). Admins can create /
delete non-unique indexes with the UI; apps can declare indexes in code
with `defineIndex`. Composite-typed fields are now indexable by picking
a specific sub-column (e.g. `Address > City`).

A few related polish items also land here (invite-user dropdown lands on
the Invite tab; standard warning callout above the new-index form).

## What ships

### UI — custom indexes on per-object Settings
- New section directly under Search, wrapped in
`AdvancedSettingsWrapper`.
- Filter dropdown on the search bar toggles system-index visibility
(shown by default since advanced mode).
- **+ Add Index** button (disabled with tooltip once the per-object cap
is reached) navigates to a dedicated `SettingsObjectNewIndex` page
(matches the field-creation pattern, not a modal):
- Field picker mirrors the webhook event-form layout (rows of dropdowns,
implicit trailing empty row).
- Composite fields surface their sub-properties (`Address > City`,
`Currency > Amount`, …).
  - BTREE / GIN type selector.
- Standard warning Callout: "Use indexes sparingly — each one speeds
reads but slows writes."
- Trash icon on `isCustom: true` rows → confirmation modal →
`deleteOneIndex`.

### Server — `createOneIndex` / `deleteOneIndex` mutations
- Gated by `SettingsPermissionGuard(DATA_MODEL)`.
- `IndexMetadataService` wraps the existing migration runner via
`WorkspaceMigrationValidateBuildAndRunService` so the metadata row and
the SQL index land atomically.
- Validation: rejects empty fields, duplicate `(fieldMetadataId,
subFieldName)` pairs, fields not on the object, requires `subFieldName`
for composite parents, forbids `subFieldName` on scalar/relation,
enforces `MAX_CUSTOM_INDEXES_PER_OBJECT = 10`.
- Delete refuses on `isCustom: false` rows so system indexes can't be
removed via this API.
- Dedicated GraphQL exception handler maps each typed error to the right
transport error class.

### Composite sub-field indexing
- Adds `subFieldName: string | null` column to
`IndexFieldMetadataEntity` (fast instance command).
- The flat-entity flow (`UniversalFlatIndexFieldMetadata`,
`FlatIndexFieldMetadata`, `from-universal-flat-index-to-flat-index`,
runner column resolution) all carry `subFieldName` through.
- For composite parents, the runner uses
`computeCompositeColumnName({...}, property)` for the picked sub-column;
for non-composite parents, behavior is unchanged.
- The `'::'` separator encodes `(fieldMetadataId, subFieldName)` for
dedup on the wire; the frontend uses the same separator inside the
Select component's string value.

### Apps can declare indexes in code (`defineIndex`)
- New `IndexManifest` + `IndexFieldManifest` types in
`twenty-shared/application` wired into the `Manifest` type.
- `defineIndex` SDK helper + `IndexConfig`. CLI manifest builder +
extractor recognize `defineIndex` / `ManifestEntityKey.Indexes`.
- Server: `from-index-manifest-to-universal-flat-index` converter
resolves field IDs, validates composite/scalar `subFieldName` rules, and
delegates to `generateFlatIndexMetadataWithNameOrThrow` for the
deterministic name.
- Orchestrator wires the loop after the field-resolution pass;
per-object cap enforced inline against the manifest.
- Cascade on uninstall is automatic — when an app disappears its indexes
drop with it (universal-flat-entity diff handles it).
- Rich-app fixture ships a real `defineIndex` on `PostCard.status`,
exercising the full manifest → install path in CI.

### Closed for now (open later if needed)
- Apps cannot declare `isUnique` indexes — unique constraints stay with
the field-creation flow.
- Apps cannot use a partial-`indexWhereClause` — the UI surface keeps
the framework's hardcoded allowlist.
- UI cannot create unique or partial indexes either; same reasons.

### Cleanups along the way
- Reused the existing `getCompositeSubFieldLabel` +
`COMPOSITE_FIELD_SUB_FIELD_LABELS` (deleted the duplicates I'd created
early in the PR).
- Moved `MAX_CUSTOM_INDEXES_PER_OBJECT` to `twenty-shared/constants`
(single source for FE + BE).
- Replaced inline `isDefined(x) && x !== ''` with `isNonEmptyString`
(from `@sniptt/guards`).
- Hoisted the per-object fields Map + inlined the cap counter into the
indexes orchestrator loop (drops the install scan from O(indexes ×
totalFields) to O(totalFields + indexes)).
- Per design-feedback: page-based create flow (not a modal), filter
dropdown on the SearchInput (not a separate toggle), webhook-style
picker, field icons.

### Unrelated polish that lands here
- "Invite user" link in the multi-workspace dropdown now lands on the
Invite tab directly (`#invite`) instead of the first tab of the members
page.

## Test plan
- [ ] `npx nx typecheck twenty-server / twenty-front / twenty-sdk /
twenty-shared` — passes
- [ ] `npx nx lint:diff-with-main twenty-server / twenty-front` — clean
- [ ] `npx jest index-metadata.service.spec` — green
- [ ] `npx jest from-index-manifest-to-universal-flat-index` — green
(new converter spec, 8 cases)
- [ ] `npx vitest run
src/sdk/define/indexes/__tests__/define-index.spec.ts` (twenty-sdk) —
green (6 cases)
- [ ] `npx vitest run --config vitest.integration.config.ts -t
"rich-app"` — green (rich-app app-dev integration exercises the new
manifest path with the PostCard.status index)
- [ ] Advanced mode → Settings → any object → Settings tab → Indexes
section is visible under Search
- [ ] Create a single-field BTREE index, confirm SQL index exists
(verify via `pg_indexes`)
- [ ] Create a composite-field index (`Address > City`) and confirm the
column is `addressAddressCity`
- [ ] Create an index spanning two columns; column order matches the
picker order
- [ ] Attempt to create an 11th custom index → button is disabled with
tooltip
- [ ] Delete a custom index → confirmation modal → row disappears, PG
index dropped
- [ ] System indexes have no trash icon and are hidden by default
2026-05-25 17:47:09 +02:00

1683 lines
41 KiB
TypeScript

import { type AllMetadataName } from 'twenty-shared/metadata';
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
import { type MetadataManyToOneJoinColumn } from 'src/engine/metadata-modules/flat-entity/types/metadata-many-to-one-join-column.type';
import { type ScalarFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/scalar-flat-entity.type';
import { type AllJsonbPropertiesWithSerializedPropertiesForMetadataName } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/constants/all-jsonb-properties-with-serialized-relation-by-metadata-name.constant';
import { type ExtractJsonbProperties } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/extract-jsonb-properties.type';
import { type ToUniversalForeignKey } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/to-universal-foreign-key.type';
type HasObjectInUnion<T> = T extends unknown
? T extends object
? true
: false
: never;
type MetadataEntityPropertyConfiguration<
TMetadataName extends AllMetadataName,
> = {
[K in keyof Omit<
ScalarFlatEntity<MetadataEntity<TMetadataName>>,
'id' | 'workspaceId' | 'applicationId' | 'universalIdentifier'
>]: {
universalProperty: K extends AllJsonbPropertiesWithSerializedPropertiesForMetadataName<TMetadataName> &
string
? `universal${Capitalize<K>}`
: K extends MetadataManyToOneJoinColumn<TMetadataName> & string
? ToUniversalForeignKey<K>
: undefined;
toStringify: K extends ExtractJsonbProperties<MetadataEntity<TMetadataName>>
? true
: K extends keyof MetadataEntity<TMetadataName>
? NonNullable<MetadataEntity<TMetadataName>[K]> extends Date
? false
: HasObjectInUnion<MetadataEntity<TMetadataName>[K]>
: boolean;
toCompare: boolean;
isOverridable?: boolean;
};
};
export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
fieldMetadata: {
defaultValue: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
description: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
icon: { toCompare: true, toStringify: false, universalProperty: undefined },
isActive: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
isLabelSyncedWithName: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
// isUnique is derived from IndexMetadata at cache build time and is
// not a column on the fieldMetadata table. It stays in
// propertiesToCompare so per-type validators see the proposed
// change (e.g. rejecting unique on FILES), but the field-metadata
// runner drops it before issuing the SQL UPDATE — the actual state
// change rides on the side-effect index create/delete.
isUnique: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
label: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
name: { toCompare: true, toStringify: false, universalProperty: undefined },
options: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
standardOverrides: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
settings: {
toCompare: true,
toStringify: true,
universalProperty: 'universalSettings',
},
objectMetadataId: {
toCompare: false,
toStringify: false,
universalProperty: 'objectMetadataUniversalIdentifier',
},
type: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
isCustom: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
isSystem: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
isUIReadOnly: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
isNullable: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
relationTargetFieldMetadataId: {
toCompare: false,
toStringify: false,
universalProperty: 'relationTargetFieldMetadataUniversalIdentifier',
},
relationTargetObjectMetadataId: {
toCompare: false,
toStringify: false,
universalProperty: 'relationTargetObjectMetadataUniversalIdentifier',
},
morphId: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
objectMetadata: {
dataSourceId: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
color: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
description: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
icon: { toCompare: true, toStringify: false, universalProperty: undefined },
isActive: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
isLabelSyncedWithName: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
labelPlural: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
labelSingular: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
namePlural: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
nameSingular: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
labelIdentifierFieldMetadataId: {
toCompare: true,
toStringify: false,
// @ts-expect-error remove once https://github.com/twentyhq/core-team-issues/issues/2172 has been resolved
universalProperty: 'labelIdentifierFieldMetadataUniversalIdentifier',
},
standardOverrides: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
isCustom: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
isRemote: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
isSystem: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
isUIReadOnly: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
isAuditLogged: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
isSearchable: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
duplicateCriteria: {
toCompare: false,
toStringify: true,
universalProperty: undefined,
},
shortcut: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
imageIdentifierFieldMetadataId: {
toCompare: true,
toStringify: false,
// @ts-expect-error remove once https://github.com/twentyhq/core-team-issues/issues/2172 has been resolved
universalProperty: 'imageIdentifierFieldMetadataUniversalIdentifier',
},
targetTableName: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
view: {
key: { toCompare: true, toStringify: false, universalProperty: undefined },
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdByUserWorkspaceId: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
name: { toCompare: true, toStringify: false, universalProperty: undefined },
type: { toCompare: true, toStringify: false, universalProperty: undefined },
icon: { toCompare: true, toStringify: false, universalProperty: undefined },
position: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
isCompact: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
openRecordIn: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
kanbanAggregateOperation: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
kanbanAggregateOperationFieldMetadataId: {
toCompare: true,
toStringify: false,
universalProperty:
'kanbanAggregateOperationFieldMetadataUniversalIdentifier',
},
anyFieldFilterValue: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
calendarLayout: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
calendarFieldMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'calendarFieldMetadataUniversalIdentifier',
},
visibility: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
mainGroupByFieldMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'mainGroupByFieldMetadataUniversalIdentifier',
},
shouldHideEmptyGroups: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
objectMetadataId: {
toCompare: false,
toStringify: false,
universalProperty: 'objectMetadataUniversalIdentifier',
},
isCustom: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
viewFieldGroup: {
name: {
toStringify: false,
universalProperty: undefined,
toCompare: true,
isOverridable: true,
},
position: {
toStringify: false,
universalProperty: undefined,
toCompare: true,
isOverridable: true,
},
isVisible: {
toStringify: false,
universalProperty: undefined,
toCompare: true,
isOverridable: true,
},
isActive: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: false,
},
deletedAt: {
toStringify: false,
universalProperty: undefined,
toCompare: true,
},
createdAt: {
toCompare: false,
universalProperty: undefined,
toStringify: false,
},
updatedAt: {
toCompare: false,
universalProperty: undefined,
toStringify: false,
},
viewId: {
toCompare: false,
universalProperty: 'viewUniversalIdentifier',
toStringify: false,
},
overrides: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
},
viewField: {
isVisible: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: true,
},
size: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: true,
},
position: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: true,
},
aggregateOperation: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: true,
},
viewFieldGroupId: {
toStringify: false,
universalProperty: 'viewFieldGroupUniversalIdentifier',
toCompare: true,
isOverridable: true,
},
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
fieldMetadataId: {
toCompare: false,
toStringify: false,
universalProperty: 'fieldMetadataUniversalIdentifier',
},
viewId: {
toCompare: false,
toStringify: false,
universalProperty: 'viewUniversalIdentifier',
},
isActive: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: false,
},
overrides: {
toCompare: true,
toStringify: true,
universalProperty: 'universalOverrides',
},
},
viewGroup: {
isVisible: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
fieldValue: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
position: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
viewId: {
toCompare: false,
toStringify: false,
universalProperty: 'viewUniversalIdentifier',
},
},
index: {
indexType: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
indexWhereClause: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
isUnique: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
name: { toCompare: true, toStringify: false, universalProperty: undefined },
objectMetadataId: {
toCompare: false,
toStringify: false,
universalProperty: 'objectMetadataUniversalIdentifier',
},
isCustom: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
logicFunction: {
name: { toCompare: true, toStringify: false, universalProperty: undefined },
description: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
timeoutSeconds: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
checksum: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
sourceHandlerPath: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
handlerName: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
isBuildUpToDate: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
cronTriggerSettings: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
databaseEventTriggerSettings: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
httpRouteTriggerSettings: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
toolTriggerSettings: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
workflowActionTriggerSettings: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
builtHandlerPath: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
runtime: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
viewFilter: {
viewId: {
toCompare: true,
toStringify: false,
universalProperty: 'viewUniversalIdentifier',
},
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
fieldMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'fieldMetadataUniversalIdentifier',
},
operand: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
value: { toCompare: true, toStringify: true, universalProperty: undefined },
viewFilterGroupId: {
toCompare: true,
toStringify: false,
universalProperty: 'viewFilterGroupUniversalIdentifier',
},
positionInViewFilterGroup: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
subFieldName: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
relationTargetFieldMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'relationTargetFieldMetadataUniversalIdentifier',
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
role: {
label: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
description: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
icon: { toCompare: true, toStringify: false, universalProperty: undefined },
canUpdateAllSettings: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canAccessAllTools: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canReadAllObjectRecords: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canUpdateAllObjectRecords: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canSoftDeleteAllObjectRecords: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canDestroyAllObjectRecords: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canBeAssignedToUsers: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canBeAssignedToAgents: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canBeAssignedToApiKeys: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
isEditable: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
roleTarget: {
roleId: {
toCompare: true,
toStringify: false,
universalProperty: 'roleUniversalIdentifier',
},
userWorkspaceId: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
apiKeyId: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
agentId: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
agent: {
name: { toCompare: true, toStringify: false, universalProperty: undefined },
label: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
icon: { toCompare: true, toStringify: false, universalProperty: undefined },
description: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
prompt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
modelId: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
responseFormat: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
modelConfiguration: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
evaluationInputs: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
isCustom: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
deletedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
pageLayout: {
name: { toCompare: true, toStringify: false, universalProperty: undefined },
type: { toCompare: true, toStringify: false, universalProperty: undefined },
objectMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'objectMetadataUniversalIdentifier',
},
defaultTabToFocusOnMobileAndSidePanelId: {
toCompare: true,
toStringify: false,
universalProperty:
'defaultTabToFocusOnMobileAndSidePanelUniversalIdentifier',
},
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
pageLayoutWidget: {
title: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: true,
},
type: { toCompare: true, toStringify: false, universalProperty: undefined },
objectMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'objectMetadataUniversalIdentifier',
},
gridPosition: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
position: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
isOverridable: true,
},
configuration: {
toCompare: true,
toStringify: true,
universalProperty: 'universalConfiguration',
},
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
pageLayoutTabId: {
toCompare: false,
toStringify: false,
universalProperty: 'pageLayoutTabUniversalIdentifier',
isOverridable: true,
},
conditionalDisplay: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
isOverridable: true,
},
conditionalAvailabilityExpression: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: true,
},
isActive: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: false,
},
overrides: {
toCompare: true,
toStringify: true,
universalProperty: 'universalOverrides',
},
},
pageLayoutTab: {
title: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: true,
},
position: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: true,
},
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
icon: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: true,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
pageLayoutId: {
toCompare: false,
toStringify: false,
universalProperty: 'pageLayoutUniversalIdentifier',
},
layoutMode: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
isActive: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
isOverridable: false,
},
overrides: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
},
skill: {
name: { toCompare: true, toStringify: false, universalProperty: undefined },
label: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
icon: { toCompare: true, toStringify: false, universalProperty: undefined },
description: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
content: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
isActive: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
isCustom: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
commandMenuItem: {
label: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
icon: { toCompare: true, toStringify: false, universalProperty: undefined },
shortLabel: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
position: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
isPinned: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
availabilityType: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
conditionalAvailabilityExpression: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
availabilityObjectMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'availabilityObjectMetadataUniversalIdentifier',
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
frontComponentId: {
toCompare: false,
toStringify: false,
universalProperty: 'frontComponentUniversalIdentifier',
},
engineComponentKey: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
payload: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
hotKeys: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
workflowVersionId: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
pageLayoutId: {
toCompare: false,
toStringify: false,
universalProperty: 'pageLayoutUniversalIdentifier',
},
},
navigationMenuItem: {
type: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
position: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
folderId: {
toCompare: true,
toStringify: false,
universalProperty: 'folderUniversalIdentifier',
},
name: { toCompare: true, toStringify: false, universalProperty: undefined },
link: { toCompare: true, toStringify: false, universalProperty: undefined },
icon: { toCompare: true, toStringify: false, universalProperty: undefined },
color: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
viewId: {
toCompare: false,
toStringify: false,
universalProperty: 'viewUniversalIdentifier',
},
userWorkspaceId: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
targetRecordId: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
targetObjectMetadataId: {
toCompare: false,
toStringify: false,
universalProperty: 'targetObjectMetadataUniversalIdentifier',
},
pageLayoutId: {
toCompare: false,
toStringify: false,
universalProperty: 'pageLayoutUniversalIdentifier',
},
},
rolePermissionFlag: {
permissionFlagId: {
toCompare: true,
toStringify: false,
universalProperty: 'permissionFlagUniversalIdentifier',
},
roleId: {
toCompare: true,
toStringify: false,
universalProperty: 'roleUniversalIdentifier',
},
flag: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
permissionFlag: {
key: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
label: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
description: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
icon: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
permissionType: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
fieldPermission: {
roleId: {
toCompare: true,
toStringify: false,
universalProperty: 'roleUniversalIdentifier',
},
objectMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'objectMetadataUniversalIdentifier',
},
fieldMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'fieldMetadataUniversalIdentifier',
},
canReadFieldValue: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canUpdateFieldValue: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
objectPermission: {
roleId: {
toCompare: true,
toStringify: false,
universalProperty: 'roleUniversalIdentifier',
},
objectMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'objectMetadataUniversalIdentifier',
},
canReadObjectRecords: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canUpdateObjectRecords: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canSoftDeleteObjectRecords: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
canDestroyObjectRecords: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
rowLevelPermissionPredicate: {
fieldMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'fieldMetadataUniversalIdentifier',
},
operand: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
value: { toCompare: true, toStringify: true, universalProperty: undefined },
rowLevelPermissionPredicateGroupId: {
toCompare: true,
toStringify: false,
universalProperty: 'rowLevelPermissionPredicateGroupUniversalIdentifier',
},
positionInRowLevelPermissionPredicateGroup: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
subFieldName: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
workspaceMemberFieldMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'workspaceMemberFieldMetadataUniversalIdentifier',
},
workspaceMemberSubFieldName: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
objectMetadataId: {
toCompare: false,
toStringify: false,
universalProperty: 'objectMetadataUniversalIdentifier',
},
roleId: {
toCompare: false,
toStringify: false,
universalProperty: 'roleUniversalIdentifier',
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
rowLevelPermissionPredicateGroup: {
logicalOperator: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
positionInRowLevelPermissionPredicateGroup: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
parentRowLevelPermissionPredicateGroupId: {
toCompare: true,
toStringify: false,
universalProperty:
'parentRowLevelPermissionPredicateGroupUniversalIdentifier',
},
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
objectMetadataId: {
toCompare: false,
toStringify: false,
universalProperty: 'objectMetadataUniversalIdentifier',
},
roleId: {
toCompare: false,
toStringify: false,
universalProperty: 'roleUniversalIdentifier',
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
viewSort: {
direction: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
subFieldName: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
fieldMetadataId: {
toCompare: true,
toStringify: false,
universalProperty: 'fieldMetadataUniversalIdentifier',
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
viewId: {
toCompare: true,
toStringify: false,
universalProperty: 'viewUniversalIdentifier',
},
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
},
viewFilterGroup: {
viewId: {
toCompare: true,
toStringify: false,
universalProperty: 'viewUniversalIdentifier',
},
deletedAt: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
parentViewFilterGroupId: {
toCompare: true,
toStringify: false,
universalProperty: 'parentViewFilterGroupUniversalIdentifier',
},
logicalOperator: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
positionInViewFilterGroup: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
frontComponent: {
name: { toCompare: true, toStringify: false, universalProperty: undefined },
description: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
builtComponentChecksum: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
sourceComponentPath: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
builtComponentPath: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
componentName: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
isHeadless: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
usesSdkClient: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
webhook: {
targetUrl: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
operations: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
description: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
secret: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
deletedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
applicationVariable: {
key: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
value: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
description: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
isSecret: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
connectionProvider: {
name: { toCompare: true, toStringify: false, universalProperty: undefined },
displayName: {
toCompare: true,
toStringify: false,
universalProperty: undefined,
},
type: { toCompare: true, toStringify: false, universalProperty: undefined },
oauthConfig: {
toCompare: true,
toStringify: true,
universalProperty: undefined,
},
createdAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
updatedAt: {
toCompare: false,
toStringify: false,
universalProperty: undefined,
},
},
} as const satisfies {
[P in AllMetadataName]: MetadataEntityPropertyConfiguration<P>;
};
export type MetadataEntityPropertyName<T extends AllMetadataName> =
keyof (typeof ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME)[T];
type FilterComparableKeys<TConfig> = {
[P in keyof TConfig]: TConfig[P] extends { toCompare: true } ? P : never;
}[keyof TConfig];
export type MetadataEntityComparablePropertyName<T extends AllMetadataName> =
FilterComparableKeys<
(typeof ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME)[T]
>;
type FilterOverridableKeys<TConfig> = {
[P in keyof TConfig]: TConfig[P] extends { isOverridable: true } ? P : never;
}[keyof TConfig];
export type MetadataEntityOverridablePropertyName<T extends AllMetadataName> =
FilterOverridableKeys<
(typeof ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME)[T]
>;