System side effect relations (#22882)
Closes twentyhq/core-team-issues#2667 ## What Default relations to the standard relation objects (`timelineActivities`, `attachments`, `noteTargets`, `taskTargets`) are now fully owned by the **metadata side-effect engine**. Neither the API transpilers nor the SDK manifest builder provision them anymore: any object creation, rename or deletion — regardless of the caller — goes through the same engine handlers. ## Why - Provisioning was duplicated across the API path and the SDK manifest builder, with diverging behavior. - Universal identifiers of relation fields were derived from object **names**, so renaming an object mutated them and forced lossy delete+create cycles on manifest sync. ## How ### Engine-owned lifecycle (side-effect handlers) - `objectSystemRelationsOnCreate`: provisions the 8 forward/reverse relation fields (+ join column indexes) when an object is created. - `objectSystemRelationsOnUpdate`: renames the reverse morph fields (`target<ObjectName>`) when their host object is renamed — a lossless `fieldMetadata.update`. - `objectSystemSideEffectsOnDelete`: cascades deletion of engine-owned fields/indexes when the object is deleted. - The API transpilers and the SDK `buildManifest` no longer inject these fields; `isSystemSideEffect: true` marks engine-owned entities, guarded by a granular property allowlist (only `isActive` is user-editable) and excluded from manifest deletion inference. ### Name-free deterministic universal identifiers New `getSystemRelationFieldUniversalIdentifier({ applicationUniversalIdentifier, objectUniversalIdentifier, relationTargetObjectUniversalIdentifier })` in `twenty-shared`, exported from `twenty-sdk/define`. The identifier is keyed on the two **object** identifiers instead of field names (direction encoded by argument order), so object renames never mutate relation field identifiers. It cannot collide with the name-based `getFieldUniversalIdentifier` derivation (field names cannot contain `:`). ### twenty-standard re-owned All 48 forward/reverse system relation field declarations in `STANDARD_OBJECTS` now pin the derived name-free identifiers (computed inline via the shared util) and carry `isSystemSideEffect: true`, with labels/icons declared explicitly (translated via `msg`). `twenty-standard` is projected as if the engine had generated these fields itself. ### 2.23 upgrade commands - `reconcile-system-relation-field-universal-identifier`: structurally matches existing default relation fields per workspace and backfills the derived universal identifiers, `isSystemSideEffect` flags, and standard labels/icons. - `upgrade-people-data-labs-application`: upgrades installed PDL apps to `1.0.7` right after the backfill to close the desync window (its views reference the re-derived identifiers). ### Misc - `people-data-labs` `1.0.7`: views temporarily pin the new derived identifiers (TODO: import from the next released `twenty-sdk`). - `UpgradeStatusModule` split out of `UpgradeModule` so the application module cluster can consume upgrade status/migration services without importing the versioned command bundles (fixes a require cycle that crashed boot). - Docs: `system-fields.mdx` documents the system relation fields and their resolver; `sync-and-recovery.mdx` plan example no longer shows auto-injected relations. ## Known red CI `people-data-labs (dockerhub-latest)` fails by design until the 2.23 server image is published: the app pins the new identifiers which only exist on a 2.23 server. The `local` leg (server built from this branch) is green. ## System fields are no longer manifest-authorable (accepted regression) The manifest converter no longer derives `isSystem` / `isSystemSideEffect` from field names. Reserved-system-named manifest fields (`id`, `createdAt`, `updatedAt`, `deletedAt`, `createdBy`, `updatedBy`, `position`, `searchVector`) are now skipped at conversion time when they carry the exact derived universal identifier (keeps manifests built with older SDKs installable), and rejected with `INVALID_INPUT` when they pin any other identifier. System fields are therefore fully engine-canonical: nothing a manifest carries can produce a system-flagged entity anymore. **Accepted regression**: a manifest can no longer influence system field properties at all. Previously a (legacy) re-declaration could shape them at creation — which actually produced broken system fields, e.g. a nullable, non-unique `id` — and could still toggle the allowlisted `isActive` / `universalSettings` afterwards. We consider this acceptable for now: per-app granularity over system fields will be reintroduced later through the **override framework**, which will also settle update semantics by forbidding direct updates over `isSystemSideEffect: true` entities and expressing divergence as overrides. `isSystemSideEffect`-only entities (the default relation fields provisioned by this PR) still have no engine-level update guard (see Follow-up below); that part is unchanged and also lands with the overrides refactor. ## Follow-up `isSystemSideEffect` field update/delete guards intentionally live at the API layer (`sanitize-raw-update-field-input.ts`, `from-delete-field-input-...util.ts`) rather than in the engine-level `FlatFieldMetadataValidatorService`. Moving them into the validator requires threading operation-origin (direct field mutation vs engine cascade) through the migration matrix, otherwise legitimate object rename/delete cascades (which carry `isSystemBuild=false`) would be rejected. Tracked in twentyhq/core-team-issues#2671. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22882?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@twentyhq/people-data-labs",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.7",
|
||||
"description": "People Data Labs enrichment app for Twenty",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^24.5.0",
|
||||
"npm": "please-use-yarn",
|
||||
"yarn": ">=4.0.2",
|
||||
"twenty": ">=2.20.0"
|
||||
"twenty": ">=2.23.0"
|
||||
},
|
||||
"keywords": [
|
||||
"twenty-app"
|
||||
|
||||
@@ -52,10 +52,14 @@ export default defineView({
|
||||
{ universalIdentifier: '0c027ae2-7e63-4354-8962-6922923929c0', fieldMetadataUniversalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlAlternativeDomains, position: 32, isVisible: true },
|
||||
{ universalIdentifier: '0814427e-6699-44fd-9d57-7af6f2389f7d', fieldMetadataUniversalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlTags, position: 33, isVisible: true },
|
||||
{ universalIdentifier: '65ca68c9-589f-44dc-bf57-d0a2152cb09c', fieldMetadataUniversalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.company.pdlAffiliatedProfiles, position: 34, isVisible: true },
|
||||
{ universalIdentifier: '3f0e5a60-3f49-4872-8451-5344a3715374', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.noteTargets.universalIdentifier, position: 35, isVisible: true },
|
||||
{ universalIdentifier: '70ab74e1-d2ff-4f15-81ef-196e223a783e', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.taskTargets.universalIdentifier, position: 36, isVisible: true },
|
||||
{ universalIdentifier: '035b3904-59b9-4fce-a366-ee0139770346', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.attachments.universalIdentifier, position: 37, isVisible: true },
|
||||
{ universalIdentifier: '617b7343-1ae5-4813-b4f5-6e99d0a833bb', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.timelineActivities.universalIdentifier, position: 38, isVisible: true },
|
||||
// TODO: derive these with getSystemRelationFieldUniversalIdentifier once
|
||||
// the next twenty-sdk is released. The system relation field universal
|
||||
// identifiers were re-derived name-free in twenty v2.23 and the pinned
|
||||
// twenty-sdk still embeds the old values.
|
||||
{ universalIdentifier: '3f0e5a60-3f49-4872-8451-5344a3715374', fieldMetadataUniversalIdentifier: '0b28db77-8099-5ce3-a11f-86a5778d7740', position: 35, isVisible: true }, // company.noteTargets
|
||||
{ universalIdentifier: '70ab74e1-d2ff-4f15-81ef-196e223a783e', fieldMetadataUniversalIdentifier: '9d7b0087-7037-55dc-bb59-456064455694', position: 36, isVisible: true }, // company.taskTargets
|
||||
{ universalIdentifier: '035b3904-59b9-4fce-a366-ee0139770346', fieldMetadataUniversalIdentifier: 'a4399ae3-fe89-59fe-a282-aec77d4e63a8', position: 37, isVisible: true }, // company.attachments
|
||||
{ universalIdentifier: '617b7343-1ae5-4813-b4f5-6e99d0a833bb', fieldMetadataUniversalIdentifier: '28ec0f8f-ad23-5317-b2d9-1a487bcefee2', position: 38, isVisible: true }, // company.timelineActivities
|
||||
{ universalIdentifier: '24d0411e-23d2-4cf8-9781-6efc8443efdc', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.createdBy.universalIdentifier, position: 39, isVisible: true },
|
||||
{ universalIdentifier: '4036071d-e527-46c8-940c-401f33803aa9', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.updatedBy.universalIdentifier, position: 40, isVisible: true },
|
||||
{ universalIdentifier: 'ab123fcd-ec53-4d33-b43c-c7319db72be4', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.createdAt.universalIdentifier, position: 41, isVisible: true },
|
||||
|
||||
@@ -56,10 +56,14 @@ export default defineView({
|
||||
{ universalIdentifier: '730dfb73-0ff7-429a-a70b-fefc6080b537', fieldMetadataUniversalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlSex, position: 36, isVisible: true },
|
||||
{ universalIdentifier: '1620bf1d-0b12-4f69-ad0e-ba7dd1d8aa44', fieldMetadataUniversalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlBirthDate, position: 37, isVisible: true },
|
||||
{ universalIdentifier: '029770cb-9353-4b5f-8395-b217cc95402e', fieldMetadataUniversalIdentifier: PDL_FIELD_UNIVERSAL_IDENTIFIERS.person.pdlBirthYear, position: 38, isVisible: true },
|
||||
{ universalIdentifier: 'ef6e496c-de6c-47ed-bd44-886736f942ec', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.fields.noteTargets.universalIdentifier, position: 39, isVisible: true },
|
||||
{ universalIdentifier: '3758ed96-f76d-49a0-b37b-7c5c9aa4c1c1', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.fields.taskTargets.universalIdentifier, position: 40, isVisible: true },
|
||||
{ universalIdentifier: 'a5bf7046-8fc9-4704-91a5-ba6c1b0f4b58', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.fields.attachments.universalIdentifier, position: 41, isVisible: true },
|
||||
{ universalIdentifier: 'f6ed39c3-aff2-4ccf-b4e8-57de72b64cdd', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.fields.timelineActivities.universalIdentifier, position: 42, isVisible: true },
|
||||
// TODO: derive these with getSystemRelationFieldUniversalIdentifier once
|
||||
// the next twenty-sdk is released. The system relation field universal
|
||||
// identifiers were re-derived name-free in twenty v2.23 and the pinned
|
||||
// twenty-sdk still embeds the old values.
|
||||
{ universalIdentifier: 'ef6e496c-de6c-47ed-bd44-886736f942ec', fieldMetadataUniversalIdentifier: '1c0e0dfe-a01f-58d6-8948-08b93164d03c', position: 39, isVisible: true }, // person.noteTargets
|
||||
{ universalIdentifier: '3758ed96-f76d-49a0-b37b-7c5c9aa4c1c1', fieldMetadataUniversalIdentifier: 'ddea86e6-5766-5798-ac32-14fbab6089f6', position: 40, isVisible: true }, // person.taskTargets
|
||||
{ universalIdentifier: 'a5bf7046-8fc9-4704-91a5-ba6c1b0f4b58', fieldMetadataUniversalIdentifier: '54dd92e1-67bf-5381-86f3-c747976dcdaf', position: 41, isVisible: true }, // person.attachments
|
||||
{ universalIdentifier: 'f6ed39c3-aff2-4ccf-b4e8-57de72b64cdd', fieldMetadataUniversalIdentifier: '32d7483f-6227-528b-bc65-62d9cf858cd8', position: 42, isVisible: true }, // person.timelineActivities
|
||||
{ universalIdentifier: '45159f0c-bac0-439c-ad8d-c7e4fce4b457', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.fields.createdBy.universalIdentifier, position: 43, isVisible: true },
|
||||
{ universalIdentifier: '8a5f1742-317f-4b01-b0c1-5d0866f78fa9', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.fields.updatedBy.universalIdentifier, position: 44, isVisible: true },
|
||||
{ universalIdentifier: '1614c9fb-3566-481f-9dfb-bbba37b1c8aa', fieldMetadataUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.fields.createdAt.universalIdentifier, position: 45, isVisible: true },
|
||||
|
||||
@@ -1976,113 +1976,6 @@ type RotateClientSecret {
|
||||
clientSecret: String!
|
||||
}
|
||||
|
||||
type Relation {
|
||||
type: RelationType!
|
||||
sourceObjectMetadata: Object!
|
||||
targetObjectMetadata: Object!
|
||||
sourceFieldMetadata: Field!
|
||||
targetFieldMetadata: Field!
|
||||
}
|
||||
|
||||
"""Relation type"""
|
||||
enum RelationType {
|
||||
ONE_TO_MANY
|
||||
MANY_TO_ONE
|
||||
}
|
||||
|
||||
type IndexField {
|
||||
id: UUID!
|
||||
fieldMetadataId: UUID!
|
||||
order: Float!
|
||||
subFieldName: String
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
}
|
||||
|
||||
type ObjectRecordCount {
|
||||
objectNamePlural: String!
|
||||
totalCount: Int!
|
||||
}
|
||||
|
||||
type SearchField {
|
||||
id: UUID!
|
||||
fieldMetadataId: UUID!
|
||||
tsVectorFieldMetadataId: UUID!
|
||||
position: Float!
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
}
|
||||
|
||||
type ObjectEdge {
|
||||
"""The node containing the Object"""
|
||||
node: Object!
|
||||
|
||||
"""Cursor for this node."""
|
||||
cursor: ConnectionCursor!
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
"""true if paging forward and there are more records."""
|
||||
hasNextPage: Boolean
|
||||
|
||||
"""true if paging backwards and there are more records."""
|
||||
hasPreviousPage: Boolean
|
||||
|
||||
"""The cursor of the first returned record."""
|
||||
startCursor: ConnectionCursor
|
||||
|
||||
"""The cursor of the last returned record."""
|
||||
endCursor: ConnectionCursor
|
||||
}
|
||||
|
||||
type ObjectConnection {
|
||||
"""Paging information"""
|
||||
pageInfo: PageInfo!
|
||||
|
||||
"""Array of edges."""
|
||||
edges: [ObjectEdge!]!
|
||||
}
|
||||
|
||||
type IndexEdge {
|
||||
"""The node containing the Index"""
|
||||
node: Index!
|
||||
|
||||
"""Cursor for this node."""
|
||||
cursor: ConnectionCursor!
|
||||
}
|
||||
|
||||
type ObjectIndexMetadatasConnection {
|
||||
"""Paging information"""
|
||||
pageInfo: PageInfo!
|
||||
|
||||
"""Array of edges."""
|
||||
edges: [IndexEdge!]!
|
||||
}
|
||||
|
||||
type FieldEdge {
|
||||
"""The node containing the Field"""
|
||||
node: Field!
|
||||
|
||||
"""Cursor for this node."""
|
||||
cursor: ConnectionCursor!
|
||||
}
|
||||
|
||||
type ObjectFieldsConnection {
|
||||
"""Paging information"""
|
||||
pageInfo: PageInfo!
|
||||
|
||||
"""Array of edges."""
|
||||
edges: [FieldEdge!]!
|
||||
}
|
||||
|
||||
type FieldConnection {
|
||||
"""Paging information"""
|
||||
pageInfo: PageInfo!
|
||||
|
||||
"""Array of edges."""
|
||||
edges: [FieldEdge!]!
|
||||
}
|
||||
|
||||
type AppConnection {
|
||||
id: ID!
|
||||
providerName: String!
|
||||
@@ -2234,6 +2127,113 @@ type MarketplaceAppDetail {
|
||||
manifest: JSON @deprecated(reason: "Use the explicit MarketplaceAppDetail fields (description, author, roles, ...) instead")
|
||||
}
|
||||
|
||||
type Relation {
|
||||
type: RelationType!
|
||||
sourceObjectMetadata: Object!
|
||||
targetObjectMetadata: Object!
|
||||
sourceFieldMetadata: Field!
|
||||
targetFieldMetadata: Field!
|
||||
}
|
||||
|
||||
"""Relation type"""
|
||||
enum RelationType {
|
||||
ONE_TO_MANY
|
||||
MANY_TO_ONE
|
||||
}
|
||||
|
||||
type IndexField {
|
||||
id: UUID!
|
||||
fieldMetadataId: UUID!
|
||||
order: Float!
|
||||
subFieldName: String
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
}
|
||||
|
||||
type ObjectRecordCount {
|
||||
objectNamePlural: String!
|
||||
totalCount: Int!
|
||||
}
|
||||
|
||||
type SearchField {
|
||||
id: UUID!
|
||||
fieldMetadataId: UUID!
|
||||
tsVectorFieldMetadataId: UUID!
|
||||
position: Float!
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
}
|
||||
|
||||
type ObjectEdge {
|
||||
"""The node containing the Object"""
|
||||
node: Object!
|
||||
|
||||
"""Cursor for this node."""
|
||||
cursor: ConnectionCursor!
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
"""true if paging forward and there are more records."""
|
||||
hasNextPage: Boolean
|
||||
|
||||
"""true if paging backwards and there are more records."""
|
||||
hasPreviousPage: Boolean
|
||||
|
||||
"""The cursor of the first returned record."""
|
||||
startCursor: ConnectionCursor
|
||||
|
||||
"""The cursor of the last returned record."""
|
||||
endCursor: ConnectionCursor
|
||||
}
|
||||
|
||||
type ObjectConnection {
|
||||
"""Paging information"""
|
||||
pageInfo: PageInfo!
|
||||
|
||||
"""Array of edges."""
|
||||
edges: [ObjectEdge!]!
|
||||
}
|
||||
|
||||
type IndexEdge {
|
||||
"""The node containing the Index"""
|
||||
node: Index!
|
||||
|
||||
"""Cursor for this node."""
|
||||
cursor: ConnectionCursor!
|
||||
}
|
||||
|
||||
type ObjectIndexMetadatasConnection {
|
||||
"""Paging information"""
|
||||
pageInfo: PageInfo!
|
||||
|
||||
"""Array of edges."""
|
||||
edges: [IndexEdge!]!
|
||||
}
|
||||
|
||||
type FieldEdge {
|
||||
"""The node containing the Field"""
|
||||
node: Field!
|
||||
|
||||
"""Cursor for this node."""
|
||||
cursor: ConnectionCursor!
|
||||
}
|
||||
|
||||
type ObjectFieldsConnection {
|
||||
"""Paging information"""
|
||||
pageInfo: PageInfo!
|
||||
|
||||
"""Array of edges."""
|
||||
edges: [FieldEdge!]!
|
||||
}
|
||||
|
||||
type FieldConnection {
|
||||
"""Paging information"""
|
||||
pageInfo: PageInfo!
|
||||
|
||||
"""Array of edges."""
|
||||
edges: [FieldEdge!]!
|
||||
}
|
||||
|
||||
type BillingEntitlement {
|
||||
key: BillingEntitlementKey!
|
||||
value: Boolean!
|
||||
@@ -3102,6 +3102,21 @@ type Query {
|
||||
currentWorkspace: Workspace!
|
||||
getPublicWorkspaceDataByDomain(origin: String): PublicWorkspaceData!
|
||||
getPublicWorkspaceDataById(id: UUID!): PublicWorkspaceDataSummary!
|
||||
findApplicationRegistrationByClientId(clientId: String!): PublicApplicationRegistration
|
||||
findApplicationRegistrationByUniversalIdentifier(universalIdentifier: String!): ApplicationRegistration
|
||||
findManyApplicationRegistrations: [ApplicationRegistration!]!
|
||||
findOneApplicationRegistration(id: String!): ApplicationRegistration!
|
||||
findApplicationRegistrationStats(id: String!): ApplicationRegistrationStats!
|
||||
findApplicationRegistrationVariables(applicationRegistrationId: String!): [ApplicationRegistrationVariableDTO!]!
|
||||
applicationRegistrationTarballUrl(id: String!): String
|
||||
findClaimableApplicationRegistration(sourcePackage: String, universalIdentifier: String): ClaimableApplicationRegistration
|
||||
githubClaimAuthorizationUrl(applicationRegistrationId: String!): String!
|
||||
findManyApplications: [Application!]!
|
||||
findOneApplication(id: UUID, universalIdentifier: UUID): Application!
|
||||
findManyMarketplaceApps(universalIdentifiers: [String!]): [MarketplaceApp!]!
|
||||
findMarketplaceAppDetail(universalIdentifier: String!): MarketplaceAppDetail!
|
||||
publicMarketplaceApps(isVetted: Boolean! = true): [MarketplaceApp!]!
|
||||
publicMarketplaceAppDetail(universalIdentifier: String!): MarketplaceAppDetail!
|
||||
field(
|
||||
"""The id of the record to find."""
|
||||
id: UUID!
|
||||
@@ -3115,21 +3130,6 @@ type Query {
|
||||
): FieldConnection!
|
||||
getViewGroups(viewId: String): [ViewGroup!]!
|
||||
getViewGroup(id: String!): ViewGroup
|
||||
findManyApplications: [Application!]!
|
||||
findOneApplication(id: UUID, universalIdentifier: UUID): Application!
|
||||
findManyMarketplaceApps(universalIdentifiers: [String!]): [MarketplaceApp!]!
|
||||
findMarketplaceAppDetail(universalIdentifier: String!): MarketplaceAppDetail!
|
||||
publicMarketplaceApps(isVetted: Boolean! = true): [MarketplaceApp!]!
|
||||
publicMarketplaceAppDetail(universalIdentifier: String!): MarketplaceAppDetail!
|
||||
findApplicationRegistrationByClientId(clientId: String!): PublicApplicationRegistration
|
||||
findApplicationRegistrationByUniversalIdentifier(universalIdentifier: String!): ApplicationRegistration
|
||||
findManyApplicationRegistrations: [ApplicationRegistration!]!
|
||||
findOneApplicationRegistration(id: String!): ApplicationRegistration!
|
||||
findApplicationRegistrationStats(id: String!): ApplicationRegistrationStats!
|
||||
findApplicationRegistrationVariables(applicationRegistrationId: String!): [ApplicationRegistrationVariableDTO!]!
|
||||
applicationRegistrationTarballUrl(id: String!): String
|
||||
findClaimableApplicationRegistration(sourcePackage: String, universalIdentifier: String): ClaimableApplicationRegistration
|
||||
githubClaimAuthorizationUrl(applicationRegistrationId: String!): String!
|
||||
getRoles: [Role!]!
|
||||
previewMessageCampaignAudience(input: PreviewMessageCampaignAudienceInput!): CampaignAudiencePreviewDTO!
|
||||
unsubscribeTopics: [UnsubscribeTopic!]!
|
||||
@@ -3380,20 +3380,7 @@ type Mutation {
|
||||
updateWorkspace(data: UpdateWorkspaceInput!): Workspace!
|
||||
deleteCurrentWorkspace: Workspace!
|
||||
checkCustomDomainValidRecords: DomainValidRecords
|
||||
createOneField(input: CreateOneFieldMetadataInput!): Field!
|
||||
updateOneField(input: UpdateOneFieldMetadataInput!): Field!
|
||||
deleteOneField(input: DeleteOneFieldInput!): Field!
|
||||
createViewGroup(input: CreateViewGroupInput!): ViewGroup!
|
||||
createManyViewGroups(inputs: [CreateViewGroupInput!]!): [ViewGroup!]!
|
||||
updateViewGroup(input: UpdateViewGroupInput!): ViewGroup!
|
||||
updateManyViewGroups(inputs: [UpdateViewGroupInput!]!): [ViewGroup!]!
|
||||
deleteViewGroup(input: DeleteViewGroupInput!): ViewGroup!
|
||||
destroyViewGroup(input: DestroyViewGroupInput!): ViewGroup!
|
||||
installMarketplaceApp(universalIdentifier: String!, version: String): Boolean! @deprecated(reason: "Use installApplication instead")
|
||||
installApplication(universalIdentifier: String!, version: String): Application!
|
||||
updateApplication(id: UUID!, input: UpdateApplicationInput!): Application!
|
||||
uninstallApplication(universalIdentifier: String!): Boolean!
|
||||
syncMarketplaceCatalog: Boolean!
|
||||
upgradeApplication(appRegistrationId: String!, targetVersion: String!): Boolean!
|
||||
createApplicationRegistration(input: CreateApplicationRegistrationInput!): CreateApplicationRegistration!
|
||||
updateApplicationRegistration(input: UpdateApplicationRegistrationInput!): ApplicationRegistration!
|
||||
deleteApplicationRegistration(id: String!): Boolean!
|
||||
@@ -3404,6 +3391,20 @@ type Mutation {
|
||||
uploadAppTarball(file: Upload!, universalIdentifier: String): ApplicationRegistration!
|
||||
claimApplicationRegistrationOwnership(applicationRegistrationId: String!): ApplicationRegistration!
|
||||
transferApplicationRegistrationOwnership(applicationRegistrationId: String!, targetWorkspaceSubdomain: String!): ApplicationRegistration!
|
||||
installMarketplaceApp(universalIdentifier: String!, version: String): Boolean! @deprecated(reason: "Use installApplication instead")
|
||||
installApplication(universalIdentifier: String!, version: String): Application!
|
||||
updateApplication(id: UUID!, input: UpdateApplicationInput!): Application!
|
||||
uninstallApplication(universalIdentifier: String!): Boolean!
|
||||
syncMarketplaceCatalog: Boolean!
|
||||
createOneField(input: CreateOneFieldMetadataInput!): Field!
|
||||
updateOneField(input: UpdateOneFieldMetadataInput!): Field!
|
||||
deleteOneField(input: DeleteOneFieldInput!): Field!
|
||||
createViewGroup(input: CreateViewGroupInput!): ViewGroup!
|
||||
createManyViewGroups(inputs: [CreateViewGroupInput!]!): [ViewGroup!]!
|
||||
updateViewGroup(input: UpdateViewGroupInput!): ViewGroup!
|
||||
updateManyViewGroups(inputs: [UpdateViewGroupInput!]!): [ViewGroup!]!
|
||||
deleteViewGroup(input: DeleteViewGroupInput!): ViewGroup!
|
||||
destroyViewGroup(input: DestroyViewGroupInput!): ViewGroup!
|
||||
updateWorkspaceMemberRole(workspaceMemberId: UUID!, roleId: UUID!): WorkspaceMember!
|
||||
createOneRole(createRoleInput: CreateRoleInput!): Role!
|
||||
updateOneRole(updateRoleInput: UpdateRoleInput!): Role!
|
||||
@@ -3496,7 +3497,6 @@ type Mutation {
|
||||
createDevelopmentApplication(universalIdentifier: String!, name: String!): DevelopmentApplication!
|
||||
syncApplication(manifest: JSON!, dryRun: Boolean): WorkspaceMigration!
|
||||
uploadApplicationFile(file: Upload!, applicationUniversalIdentifier: String!, fileFolder: FileFolder!, filePath: String!): File!
|
||||
upgradeApplication(appRegistrationId: String!, targetVersion: String!): Boolean!
|
||||
generateApplicationToken(applicationId: UUID!): ApplicationTokenPair!
|
||||
renewApplicationToken(applicationRefreshToken: String!): ApplicationTokenPair!
|
||||
}
|
||||
@@ -4200,6 +4200,50 @@ input UpdateWorkspaceInput {
|
||||
isInternalMessagesImportEnabled: Boolean
|
||||
}
|
||||
|
||||
input CreateApplicationRegistrationInput {
|
||||
name: String!
|
||||
universalIdentifier: String
|
||||
oAuthRedirectUris: [String!]
|
||||
oAuthScopes: [String!]
|
||||
}
|
||||
|
||||
input UpdateApplicationRegistrationInput {
|
||||
id: String!
|
||||
update: UpdateApplicationRegistrationPayload!
|
||||
}
|
||||
|
||||
input UpdateApplicationRegistrationPayload {
|
||||
name: String
|
||||
oAuthRedirectUris: [String!]
|
||||
oAuthScopes: [String!]
|
||||
isListed: Boolean
|
||||
isPreInstalled: Boolean
|
||||
isVetted: Boolean
|
||||
}
|
||||
|
||||
input CreateApplicationRegistrationVariableInput {
|
||||
applicationRegistrationId: String!
|
||||
key: String!
|
||||
value: String!
|
||||
description: String
|
||||
isSecret: Boolean
|
||||
}
|
||||
|
||||
input UpdateApplicationRegistrationVariableInput {
|
||||
id: String!
|
||||
update: UpdateApplicationRegistrationVariablePayload!
|
||||
}
|
||||
|
||||
input UpdateApplicationRegistrationVariablePayload {
|
||||
value: String
|
||||
resetValue: Boolean
|
||||
description: String
|
||||
}
|
||||
|
||||
input UpdateApplicationInput {
|
||||
autoUpgrade: Boolean
|
||||
}
|
||||
|
||||
input CreateOneFieldMetadataInput {
|
||||
"""The record to create"""
|
||||
field: CreateFieldInput!
|
||||
@@ -4293,50 +4337,6 @@ input DestroyViewGroupInput {
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
input UpdateApplicationInput {
|
||||
autoUpgrade: Boolean
|
||||
}
|
||||
|
||||
input CreateApplicationRegistrationInput {
|
||||
name: String!
|
||||
universalIdentifier: String
|
||||
oAuthRedirectUris: [String!]
|
||||
oAuthScopes: [String!]
|
||||
}
|
||||
|
||||
input UpdateApplicationRegistrationInput {
|
||||
id: String!
|
||||
update: UpdateApplicationRegistrationPayload!
|
||||
}
|
||||
|
||||
input UpdateApplicationRegistrationPayload {
|
||||
name: String
|
||||
oAuthRedirectUris: [String!]
|
||||
oAuthScopes: [String!]
|
||||
isListed: Boolean
|
||||
isPreInstalled: Boolean
|
||||
isVetted: Boolean
|
||||
}
|
||||
|
||||
input CreateApplicationRegistrationVariableInput {
|
||||
applicationRegistrationId: String!
|
||||
key: String!
|
||||
value: String!
|
||||
description: String
|
||||
isSecret: Boolean
|
||||
}
|
||||
|
||||
input UpdateApplicationRegistrationVariableInput {
|
||||
id: String!
|
||||
update: UpdateApplicationRegistrationVariablePayload!
|
||||
}
|
||||
|
||||
input UpdateApplicationRegistrationVariablePayload {
|
||||
value: String
|
||||
resetValue: Boolean
|
||||
description: String
|
||||
}
|
||||
|
||||
input CreateRoleInput {
|
||||
id: String
|
||||
label: String!
|
||||
|
||||
@@ -1636,113 +1636,6 @@ export interface RotateClientSecret {
|
||||
__typename: 'RotateClientSecret'
|
||||
}
|
||||
|
||||
export interface Relation {
|
||||
type: RelationType
|
||||
sourceObjectMetadata: Object
|
||||
targetObjectMetadata: Object
|
||||
sourceFieldMetadata: Field
|
||||
targetFieldMetadata: Field
|
||||
__typename: 'Relation'
|
||||
}
|
||||
|
||||
|
||||
/** Relation type */
|
||||
export type RelationType = 'ONE_TO_MANY' | 'MANY_TO_ONE'
|
||||
|
||||
export interface IndexField {
|
||||
id: Scalars['UUID']
|
||||
fieldMetadataId: Scalars['UUID']
|
||||
order: Scalars['Float']
|
||||
subFieldName?: Scalars['String']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
__typename: 'IndexField'
|
||||
}
|
||||
|
||||
export interface ObjectRecordCount {
|
||||
objectNamePlural: Scalars['String']
|
||||
totalCount: Scalars['Int']
|
||||
__typename: 'ObjectRecordCount'
|
||||
}
|
||||
|
||||
export interface SearchField {
|
||||
id: Scalars['UUID']
|
||||
fieldMetadataId: Scalars['UUID']
|
||||
tsVectorFieldMetadataId: Scalars['UUID']
|
||||
position: Scalars['Float']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
__typename: 'SearchField'
|
||||
}
|
||||
|
||||
export interface ObjectEdge {
|
||||
/** The node containing the Object */
|
||||
node: Object
|
||||
/** Cursor for this node. */
|
||||
cursor: Scalars['ConnectionCursor']
|
||||
__typename: 'ObjectEdge'
|
||||
}
|
||||
|
||||
export interface PageInfo {
|
||||
/** true if paging forward and there are more records. */
|
||||
hasNextPage?: Scalars['Boolean']
|
||||
/** true if paging backwards and there are more records. */
|
||||
hasPreviousPage?: Scalars['Boolean']
|
||||
/** The cursor of the first returned record. */
|
||||
startCursor?: Scalars['ConnectionCursor']
|
||||
/** The cursor of the last returned record. */
|
||||
endCursor?: Scalars['ConnectionCursor']
|
||||
__typename: 'PageInfo'
|
||||
}
|
||||
|
||||
export interface ObjectConnection {
|
||||
/** Paging information */
|
||||
pageInfo: PageInfo
|
||||
/** Array of edges. */
|
||||
edges: ObjectEdge[]
|
||||
__typename: 'ObjectConnection'
|
||||
}
|
||||
|
||||
export interface IndexEdge {
|
||||
/** The node containing the Index */
|
||||
node: Index
|
||||
/** Cursor for this node. */
|
||||
cursor: Scalars['ConnectionCursor']
|
||||
__typename: 'IndexEdge'
|
||||
}
|
||||
|
||||
export interface ObjectIndexMetadatasConnection {
|
||||
/** Paging information */
|
||||
pageInfo: PageInfo
|
||||
/** Array of edges. */
|
||||
edges: IndexEdge[]
|
||||
__typename: 'ObjectIndexMetadatasConnection'
|
||||
}
|
||||
|
||||
export interface FieldEdge {
|
||||
/** The node containing the Field */
|
||||
node: Field
|
||||
/** Cursor for this node. */
|
||||
cursor: Scalars['ConnectionCursor']
|
||||
__typename: 'FieldEdge'
|
||||
}
|
||||
|
||||
export interface ObjectFieldsConnection {
|
||||
/** Paging information */
|
||||
pageInfo: PageInfo
|
||||
/** Array of edges. */
|
||||
edges: FieldEdge[]
|
||||
__typename: 'ObjectFieldsConnection'
|
||||
}
|
||||
|
||||
export interface FieldConnection {
|
||||
/** Paging information */
|
||||
pageInfo: PageInfo
|
||||
/** Array of edges. */
|
||||
edges: FieldEdge[]
|
||||
__typename: 'FieldConnection'
|
||||
}
|
||||
|
||||
export interface AppConnection {
|
||||
id: Scalars['ID']
|
||||
providerName: Scalars['String']
|
||||
@@ -1912,6 +1805,113 @@ export interface MarketplaceAppDetail {
|
||||
__typename: 'MarketplaceAppDetail'
|
||||
}
|
||||
|
||||
export interface Relation {
|
||||
type: RelationType
|
||||
sourceObjectMetadata: Object
|
||||
targetObjectMetadata: Object
|
||||
sourceFieldMetadata: Field
|
||||
targetFieldMetadata: Field
|
||||
__typename: 'Relation'
|
||||
}
|
||||
|
||||
|
||||
/** Relation type */
|
||||
export type RelationType = 'ONE_TO_MANY' | 'MANY_TO_ONE'
|
||||
|
||||
export interface IndexField {
|
||||
id: Scalars['UUID']
|
||||
fieldMetadataId: Scalars['UUID']
|
||||
order: Scalars['Float']
|
||||
subFieldName?: Scalars['String']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
__typename: 'IndexField'
|
||||
}
|
||||
|
||||
export interface ObjectRecordCount {
|
||||
objectNamePlural: Scalars['String']
|
||||
totalCount: Scalars['Int']
|
||||
__typename: 'ObjectRecordCount'
|
||||
}
|
||||
|
||||
export interface SearchField {
|
||||
id: Scalars['UUID']
|
||||
fieldMetadataId: Scalars['UUID']
|
||||
tsVectorFieldMetadataId: Scalars['UUID']
|
||||
position: Scalars['Float']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
__typename: 'SearchField'
|
||||
}
|
||||
|
||||
export interface ObjectEdge {
|
||||
/** The node containing the Object */
|
||||
node: Object
|
||||
/** Cursor for this node. */
|
||||
cursor: Scalars['ConnectionCursor']
|
||||
__typename: 'ObjectEdge'
|
||||
}
|
||||
|
||||
export interface PageInfo {
|
||||
/** true if paging forward and there are more records. */
|
||||
hasNextPage?: Scalars['Boolean']
|
||||
/** true if paging backwards and there are more records. */
|
||||
hasPreviousPage?: Scalars['Boolean']
|
||||
/** The cursor of the first returned record. */
|
||||
startCursor?: Scalars['ConnectionCursor']
|
||||
/** The cursor of the last returned record. */
|
||||
endCursor?: Scalars['ConnectionCursor']
|
||||
__typename: 'PageInfo'
|
||||
}
|
||||
|
||||
export interface ObjectConnection {
|
||||
/** Paging information */
|
||||
pageInfo: PageInfo
|
||||
/** Array of edges. */
|
||||
edges: ObjectEdge[]
|
||||
__typename: 'ObjectConnection'
|
||||
}
|
||||
|
||||
export interface IndexEdge {
|
||||
/** The node containing the Index */
|
||||
node: Index
|
||||
/** Cursor for this node. */
|
||||
cursor: Scalars['ConnectionCursor']
|
||||
__typename: 'IndexEdge'
|
||||
}
|
||||
|
||||
export interface ObjectIndexMetadatasConnection {
|
||||
/** Paging information */
|
||||
pageInfo: PageInfo
|
||||
/** Array of edges. */
|
||||
edges: IndexEdge[]
|
||||
__typename: 'ObjectIndexMetadatasConnection'
|
||||
}
|
||||
|
||||
export interface FieldEdge {
|
||||
/** The node containing the Field */
|
||||
node: Field
|
||||
/** Cursor for this node. */
|
||||
cursor: Scalars['ConnectionCursor']
|
||||
__typename: 'FieldEdge'
|
||||
}
|
||||
|
||||
export interface ObjectFieldsConnection {
|
||||
/** Paging information */
|
||||
pageInfo: PageInfo
|
||||
/** Array of edges. */
|
||||
edges: FieldEdge[]
|
||||
__typename: 'ObjectFieldsConnection'
|
||||
}
|
||||
|
||||
export interface FieldConnection {
|
||||
/** Paging information */
|
||||
pageInfo: PageInfo
|
||||
/** Array of edges. */
|
||||
edges: FieldEdge[]
|
||||
__typename: 'FieldConnection'
|
||||
}
|
||||
|
||||
export interface BillingEntitlement {
|
||||
key: BillingEntitlementKey
|
||||
value: Scalars['Boolean']
|
||||
@@ -2751,16 +2751,6 @@ export interface Query {
|
||||
currentWorkspace: Workspace
|
||||
getPublicWorkspaceDataByDomain: PublicWorkspaceData
|
||||
getPublicWorkspaceDataById: PublicWorkspaceDataSummary
|
||||
field: Field
|
||||
fields: FieldConnection
|
||||
getViewGroups: ViewGroup[]
|
||||
getViewGroup?: ViewGroup
|
||||
findManyApplications: Application[]
|
||||
findOneApplication: Application
|
||||
findManyMarketplaceApps: MarketplaceApp[]
|
||||
findMarketplaceAppDetail: MarketplaceAppDetail
|
||||
publicMarketplaceApps: MarketplaceApp[]
|
||||
publicMarketplaceAppDetail: MarketplaceAppDetail
|
||||
findApplicationRegistrationByClientId?: PublicApplicationRegistration
|
||||
findApplicationRegistrationByUniversalIdentifier?: ApplicationRegistration
|
||||
findManyApplicationRegistrations: ApplicationRegistration[]
|
||||
@@ -2770,6 +2760,16 @@ export interface Query {
|
||||
applicationRegistrationTarballUrl?: Scalars['String']
|
||||
findClaimableApplicationRegistration?: ClaimableApplicationRegistration
|
||||
githubClaimAuthorizationUrl: Scalars['String']
|
||||
findManyApplications: Application[]
|
||||
findOneApplication: Application
|
||||
findManyMarketplaceApps: MarketplaceApp[]
|
||||
findMarketplaceAppDetail: MarketplaceAppDetail
|
||||
publicMarketplaceApps: MarketplaceApp[]
|
||||
publicMarketplaceAppDetail: MarketplaceAppDetail
|
||||
field: Field
|
||||
fields: FieldConnection
|
||||
getViewGroups: ViewGroup[]
|
||||
getViewGroup?: ViewGroup
|
||||
getRoles: Role[]
|
||||
previewMessageCampaignAudience: CampaignAudiencePreviewDTO
|
||||
unsubscribeTopics: UnsubscribeTopic[]
|
||||
@@ -2927,21 +2927,7 @@ export interface Mutation {
|
||||
updateWorkspace: Workspace
|
||||
deleteCurrentWorkspace: Workspace
|
||||
checkCustomDomainValidRecords?: DomainValidRecords
|
||||
createOneField: Field
|
||||
updateOneField: Field
|
||||
deleteOneField: Field
|
||||
createViewGroup: ViewGroup
|
||||
createManyViewGroups: ViewGroup[]
|
||||
updateViewGroup: ViewGroup
|
||||
updateManyViewGroups: ViewGroup[]
|
||||
deleteViewGroup: ViewGroup
|
||||
destroyViewGroup: ViewGroup
|
||||
/** @deprecated Use installApplication instead */
|
||||
installMarketplaceApp: Scalars['Boolean']
|
||||
installApplication: Application
|
||||
updateApplication: Application
|
||||
uninstallApplication: Scalars['Boolean']
|
||||
syncMarketplaceCatalog: Scalars['Boolean']
|
||||
upgradeApplication: Scalars['Boolean']
|
||||
createApplicationRegistration: CreateApplicationRegistration
|
||||
updateApplicationRegistration: ApplicationRegistration
|
||||
deleteApplicationRegistration: Scalars['Boolean']
|
||||
@@ -2952,6 +2938,21 @@ export interface Mutation {
|
||||
uploadAppTarball: ApplicationRegistration
|
||||
claimApplicationRegistrationOwnership: ApplicationRegistration
|
||||
transferApplicationRegistrationOwnership: ApplicationRegistration
|
||||
/** @deprecated Use installApplication instead */
|
||||
installMarketplaceApp: Scalars['Boolean']
|
||||
installApplication: Application
|
||||
updateApplication: Application
|
||||
uninstallApplication: Scalars['Boolean']
|
||||
syncMarketplaceCatalog: Scalars['Boolean']
|
||||
createOneField: Field
|
||||
updateOneField: Field
|
||||
deleteOneField: Field
|
||||
createViewGroup: ViewGroup
|
||||
createManyViewGroups: ViewGroup[]
|
||||
updateViewGroup: ViewGroup
|
||||
updateManyViewGroups: ViewGroup[]
|
||||
deleteViewGroup: ViewGroup
|
||||
destroyViewGroup: ViewGroup
|
||||
updateWorkspaceMemberRole: WorkspaceMember
|
||||
createOneRole: Role
|
||||
updateOneRole: Role
|
||||
@@ -3044,7 +3045,6 @@ export interface Mutation {
|
||||
createDevelopmentApplication: DevelopmentApplication
|
||||
syncApplication: WorkspaceMigration
|
||||
uploadApplicationFile: File
|
||||
upgradeApplication: Scalars['Boolean']
|
||||
generateApplicationToken: ApplicationTokenPair
|
||||
renewApplicationToken: ApplicationTokenPair
|
||||
__typename: 'Mutation'
|
||||
@@ -4749,121 +4749,6 @@ export interface RotateClientSecretGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface RelationGenqlSelection{
|
||||
type?: boolean | number
|
||||
sourceObjectMetadata?: ObjectGenqlSelection
|
||||
targetObjectMetadata?: ObjectGenqlSelection
|
||||
sourceFieldMetadata?: FieldGenqlSelection
|
||||
targetFieldMetadata?: FieldGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface IndexFieldGenqlSelection{
|
||||
id?: boolean | number
|
||||
fieldMetadataId?: boolean | number
|
||||
order?: boolean | number
|
||||
subFieldName?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ObjectRecordCountGenqlSelection{
|
||||
objectNamePlural?: boolean | number
|
||||
totalCount?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface SearchFieldGenqlSelection{
|
||||
id?: boolean | number
|
||||
fieldMetadataId?: boolean | number
|
||||
tsVectorFieldMetadataId?: boolean | number
|
||||
position?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ObjectEdgeGenqlSelection{
|
||||
/** The node containing the Object */
|
||||
node?: ObjectGenqlSelection
|
||||
/** Cursor for this node. */
|
||||
cursor?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface PageInfoGenqlSelection{
|
||||
/** true if paging forward and there are more records. */
|
||||
hasNextPage?: boolean | number
|
||||
/** true if paging backwards and there are more records. */
|
||||
hasPreviousPage?: boolean | number
|
||||
/** The cursor of the first returned record. */
|
||||
startCursor?: boolean | number
|
||||
/** The cursor of the last returned record. */
|
||||
endCursor?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ObjectConnectionGenqlSelection{
|
||||
/** Paging information */
|
||||
pageInfo?: PageInfoGenqlSelection
|
||||
/** Array of edges. */
|
||||
edges?: ObjectEdgeGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface IndexEdgeGenqlSelection{
|
||||
/** The node containing the Index */
|
||||
node?: IndexGenqlSelection
|
||||
/** Cursor for this node. */
|
||||
cursor?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ObjectIndexMetadatasConnectionGenqlSelection{
|
||||
/** Paging information */
|
||||
pageInfo?: PageInfoGenqlSelection
|
||||
/** Array of edges. */
|
||||
edges?: IndexEdgeGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface FieldEdgeGenqlSelection{
|
||||
/** The node containing the Field */
|
||||
node?: FieldGenqlSelection
|
||||
/** Cursor for this node. */
|
||||
cursor?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ObjectFieldsConnectionGenqlSelection{
|
||||
/** Paging information */
|
||||
pageInfo?: PageInfoGenqlSelection
|
||||
/** Array of edges. */
|
||||
edges?: FieldEdgeGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface FieldConnectionGenqlSelection{
|
||||
/** Paging information */
|
||||
pageInfo?: PageInfoGenqlSelection
|
||||
/** Array of edges. */
|
||||
edges?: FieldEdgeGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface AppConnectionGenqlSelection{
|
||||
id?: boolean | number
|
||||
providerName?: boolean | number
|
||||
@@ -5049,6 +4934,121 @@ export interface MarketplaceAppDetailGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface RelationGenqlSelection{
|
||||
type?: boolean | number
|
||||
sourceObjectMetadata?: ObjectGenqlSelection
|
||||
targetObjectMetadata?: ObjectGenqlSelection
|
||||
sourceFieldMetadata?: FieldGenqlSelection
|
||||
targetFieldMetadata?: FieldGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface IndexFieldGenqlSelection{
|
||||
id?: boolean | number
|
||||
fieldMetadataId?: boolean | number
|
||||
order?: boolean | number
|
||||
subFieldName?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ObjectRecordCountGenqlSelection{
|
||||
objectNamePlural?: boolean | number
|
||||
totalCount?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface SearchFieldGenqlSelection{
|
||||
id?: boolean | number
|
||||
fieldMetadataId?: boolean | number
|
||||
tsVectorFieldMetadataId?: boolean | number
|
||||
position?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ObjectEdgeGenqlSelection{
|
||||
/** The node containing the Object */
|
||||
node?: ObjectGenqlSelection
|
||||
/** Cursor for this node. */
|
||||
cursor?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface PageInfoGenqlSelection{
|
||||
/** true if paging forward and there are more records. */
|
||||
hasNextPage?: boolean | number
|
||||
/** true if paging backwards and there are more records. */
|
||||
hasPreviousPage?: boolean | number
|
||||
/** The cursor of the first returned record. */
|
||||
startCursor?: boolean | number
|
||||
/** The cursor of the last returned record. */
|
||||
endCursor?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ObjectConnectionGenqlSelection{
|
||||
/** Paging information */
|
||||
pageInfo?: PageInfoGenqlSelection
|
||||
/** Array of edges. */
|
||||
edges?: ObjectEdgeGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface IndexEdgeGenqlSelection{
|
||||
/** The node containing the Index */
|
||||
node?: IndexGenqlSelection
|
||||
/** Cursor for this node. */
|
||||
cursor?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ObjectIndexMetadatasConnectionGenqlSelection{
|
||||
/** Paging information */
|
||||
pageInfo?: PageInfoGenqlSelection
|
||||
/** Array of edges. */
|
||||
edges?: IndexEdgeGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface FieldEdgeGenqlSelection{
|
||||
/** The node containing the Field */
|
||||
node?: FieldGenqlSelection
|
||||
/** Cursor for this node. */
|
||||
cursor?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ObjectFieldsConnectionGenqlSelection{
|
||||
/** Paging information */
|
||||
pageInfo?: PageInfoGenqlSelection
|
||||
/** Array of edges. */
|
||||
edges?: FieldEdgeGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface FieldConnectionGenqlSelection{
|
||||
/** Paging information */
|
||||
pageInfo?: PageInfoGenqlSelection
|
||||
/** Array of edges. */
|
||||
edges?: FieldEdgeGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface BillingEntitlementGenqlSelection{
|
||||
key?: boolean | number
|
||||
value?: boolean | number
|
||||
@@ -5950,6 +5950,21 @@ export interface QueryGenqlSelection{
|
||||
currentWorkspace?: WorkspaceGenqlSelection
|
||||
getPublicWorkspaceDataByDomain?: (PublicWorkspaceDataGenqlSelection & { __args?: {origin?: (Scalars['String'] | null)} })
|
||||
getPublicWorkspaceDataById?: (PublicWorkspaceDataSummaryGenqlSelection & { __args: {id: Scalars['UUID']} })
|
||||
findApplicationRegistrationByClientId?: (PublicApplicationRegistrationGenqlSelection & { __args: {clientId: Scalars['String']} })
|
||||
findApplicationRegistrationByUniversalIdentifier?: (ApplicationRegistrationGenqlSelection & { __args: {universalIdentifier: Scalars['String']} })
|
||||
findManyApplicationRegistrations?: ApplicationRegistrationGenqlSelection
|
||||
findOneApplicationRegistration?: (ApplicationRegistrationGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
findApplicationRegistrationStats?: (ApplicationRegistrationStatsGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
findApplicationRegistrationVariables?: (ApplicationRegistrationVariableDTOGenqlSelection & { __args: {applicationRegistrationId: Scalars['String']} })
|
||||
applicationRegistrationTarballUrl?: { __args: {id: Scalars['String']} }
|
||||
findClaimableApplicationRegistration?: (ClaimableApplicationRegistrationGenqlSelection & { __args?: {sourcePackage?: (Scalars['String'] | null), universalIdentifier?: (Scalars['String'] | null)} })
|
||||
githubClaimAuthorizationUrl?: { __args: {applicationRegistrationId: Scalars['String']} }
|
||||
findManyApplications?: ApplicationGenqlSelection
|
||||
findOneApplication?: (ApplicationGenqlSelection & { __args?: {id?: (Scalars['UUID'] | null), universalIdentifier?: (Scalars['UUID'] | null)} })
|
||||
findManyMarketplaceApps?: (MarketplaceAppGenqlSelection & { __args?: {universalIdentifiers?: (Scalars['String'][] | null)} })
|
||||
findMarketplaceAppDetail?: (MarketplaceAppDetailGenqlSelection & { __args: {universalIdentifier: Scalars['String']} })
|
||||
publicMarketplaceApps?: (MarketplaceAppGenqlSelection & { __args: {isVetted: Scalars['Boolean']} })
|
||||
publicMarketplaceAppDetail?: (MarketplaceAppDetailGenqlSelection & { __args: {universalIdentifier: Scalars['String']} })
|
||||
field?: (FieldGenqlSelection & { __args: {
|
||||
/** The id of the record to find. */
|
||||
id: Scalars['UUID']} })
|
||||
@@ -5960,21 +5975,6 @@ export interface QueryGenqlSelection{
|
||||
filter: FieldFilter} })
|
||||
getViewGroups?: (ViewGroupGenqlSelection & { __args?: {viewId?: (Scalars['String'] | null)} })
|
||||
getViewGroup?: (ViewGroupGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
findManyApplications?: ApplicationGenqlSelection
|
||||
findOneApplication?: (ApplicationGenqlSelection & { __args?: {id?: (Scalars['UUID'] | null), universalIdentifier?: (Scalars['UUID'] | null)} })
|
||||
findManyMarketplaceApps?: (MarketplaceAppGenqlSelection & { __args?: {universalIdentifiers?: (Scalars['String'][] | null)} })
|
||||
findMarketplaceAppDetail?: (MarketplaceAppDetailGenqlSelection & { __args: {universalIdentifier: Scalars['String']} })
|
||||
publicMarketplaceApps?: (MarketplaceAppGenqlSelection & { __args: {isVetted: Scalars['Boolean']} })
|
||||
publicMarketplaceAppDetail?: (MarketplaceAppDetailGenqlSelection & { __args: {universalIdentifier: Scalars['String']} })
|
||||
findApplicationRegistrationByClientId?: (PublicApplicationRegistrationGenqlSelection & { __args: {clientId: Scalars['String']} })
|
||||
findApplicationRegistrationByUniversalIdentifier?: (ApplicationRegistrationGenqlSelection & { __args: {universalIdentifier: Scalars['String']} })
|
||||
findManyApplicationRegistrations?: ApplicationRegistrationGenqlSelection
|
||||
findOneApplicationRegistration?: (ApplicationRegistrationGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
findApplicationRegistrationStats?: (ApplicationRegistrationStatsGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
findApplicationRegistrationVariables?: (ApplicationRegistrationVariableDTOGenqlSelection & { __args: {applicationRegistrationId: Scalars['String']} })
|
||||
applicationRegistrationTarballUrl?: { __args: {id: Scalars['String']} }
|
||||
findClaimableApplicationRegistration?: (ClaimableApplicationRegistrationGenqlSelection & { __args?: {sourcePackage?: (Scalars['String'] | null), universalIdentifier?: (Scalars['String'] | null)} })
|
||||
githubClaimAuthorizationUrl?: { __args: {applicationRegistrationId: Scalars['String']} }
|
||||
getRoles?: RoleGenqlSelection
|
||||
previewMessageCampaignAudience?: (CampaignAudiencePreviewDTOGenqlSelection & { __args: {input: PreviewMessageCampaignAudienceInput} })
|
||||
unsubscribeTopics?: UnsubscribeTopicGenqlSelection
|
||||
@@ -6159,21 +6159,7 @@ export interface MutationGenqlSelection{
|
||||
updateWorkspace?: (WorkspaceGenqlSelection & { __args: {data: UpdateWorkspaceInput} })
|
||||
deleteCurrentWorkspace?: WorkspaceGenqlSelection
|
||||
checkCustomDomainValidRecords?: DomainValidRecordsGenqlSelection
|
||||
createOneField?: (FieldGenqlSelection & { __args: {input: CreateOneFieldMetadataInput} })
|
||||
updateOneField?: (FieldGenqlSelection & { __args: {input: UpdateOneFieldMetadataInput} })
|
||||
deleteOneField?: (FieldGenqlSelection & { __args: {input: DeleteOneFieldInput} })
|
||||
createViewGroup?: (ViewGroupGenqlSelection & { __args: {input: CreateViewGroupInput} })
|
||||
createManyViewGroups?: (ViewGroupGenqlSelection & { __args: {inputs: CreateViewGroupInput[]} })
|
||||
updateViewGroup?: (ViewGroupGenqlSelection & { __args: {input: UpdateViewGroupInput} })
|
||||
updateManyViewGroups?: (ViewGroupGenqlSelection & { __args: {inputs: UpdateViewGroupInput[]} })
|
||||
deleteViewGroup?: (ViewGroupGenqlSelection & { __args: {input: DeleteViewGroupInput} })
|
||||
destroyViewGroup?: (ViewGroupGenqlSelection & { __args: {input: DestroyViewGroupInput} })
|
||||
/** @deprecated Use installApplication instead */
|
||||
installMarketplaceApp?: { __args: {universalIdentifier: Scalars['String'], version?: (Scalars['String'] | null)} }
|
||||
installApplication?: (ApplicationGenqlSelection & { __args: {universalIdentifier: Scalars['String'], version?: (Scalars['String'] | null)} })
|
||||
updateApplication?: (ApplicationGenqlSelection & { __args: {id: Scalars['UUID'], input: UpdateApplicationInput} })
|
||||
uninstallApplication?: { __args: {universalIdentifier: Scalars['String']} }
|
||||
syncMarketplaceCatalog?: boolean | number
|
||||
upgradeApplication?: { __args: {appRegistrationId: Scalars['String'], targetVersion: Scalars['String']} }
|
||||
createApplicationRegistration?: (CreateApplicationRegistrationGenqlSelection & { __args: {input: CreateApplicationRegistrationInput} })
|
||||
updateApplicationRegistration?: (ApplicationRegistrationGenqlSelection & { __args: {input: UpdateApplicationRegistrationInput} })
|
||||
deleteApplicationRegistration?: { __args: {id: Scalars['String']} }
|
||||
@@ -6184,6 +6170,21 @@ export interface MutationGenqlSelection{
|
||||
uploadAppTarball?: (ApplicationRegistrationGenqlSelection & { __args: {file: Scalars['Upload'], universalIdentifier?: (Scalars['String'] | null)} })
|
||||
claimApplicationRegistrationOwnership?: (ApplicationRegistrationGenqlSelection & { __args: {applicationRegistrationId: Scalars['String']} })
|
||||
transferApplicationRegistrationOwnership?: (ApplicationRegistrationGenqlSelection & { __args: {applicationRegistrationId: Scalars['String'], targetWorkspaceSubdomain: Scalars['String']} })
|
||||
/** @deprecated Use installApplication instead */
|
||||
installMarketplaceApp?: { __args: {universalIdentifier: Scalars['String'], version?: (Scalars['String'] | null)} }
|
||||
installApplication?: (ApplicationGenqlSelection & { __args: {universalIdentifier: Scalars['String'], version?: (Scalars['String'] | null)} })
|
||||
updateApplication?: (ApplicationGenqlSelection & { __args: {id: Scalars['UUID'], input: UpdateApplicationInput} })
|
||||
uninstallApplication?: { __args: {universalIdentifier: Scalars['String']} }
|
||||
syncMarketplaceCatalog?: boolean | number
|
||||
createOneField?: (FieldGenqlSelection & { __args: {input: CreateOneFieldMetadataInput} })
|
||||
updateOneField?: (FieldGenqlSelection & { __args: {input: UpdateOneFieldMetadataInput} })
|
||||
deleteOneField?: (FieldGenqlSelection & { __args: {input: DeleteOneFieldInput} })
|
||||
createViewGroup?: (ViewGroupGenqlSelection & { __args: {input: CreateViewGroupInput} })
|
||||
createManyViewGroups?: (ViewGroupGenqlSelection & { __args: {inputs: CreateViewGroupInput[]} })
|
||||
updateViewGroup?: (ViewGroupGenqlSelection & { __args: {input: UpdateViewGroupInput} })
|
||||
updateManyViewGroups?: (ViewGroupGenqlSelection & { __args: {inputs: UpdateViewGroupInput[]} })
|
||||
deleteViewGroup?: (ViewGroupGenqlSelection & { __args: {input: DeleteViewGroupInput} })
|
||||
destroyViewGroup?: (ViewGroupGenqlSelection & { __args: {input: DestroyViewGroupInput} })
|
||||
updateWorkspaceMemberRole?: (WorkspaceMemberGenqlSelection & { __args: {workspaceMemberId: Scalars['UUID'], roleId: Scalars['UUID']} })
|
||||
createOneRole?: (RoleGenqlSelection & { __args: {createRoleInput: CreateRoleInput} })
|
||||
updateOneRole?: (RoleGenqlSelection & { __args: {updateRoleInput: UpdateRoleInput} })
|
||||
@@ -6276,7 +6277,6 @@ export interface MutationGenqlSelection{
|
||||
createDevelopmentApplication?: (DevelopmentApplicationGenqlSelection & { __args: {universalIdentifier: Scalars['String'], name: Scalars['String']} })
|
||||
syncApplication?: (WorkspaceMigrationGenqlSelection & { __args: {manifest: Scalars['JSON'], dryRun?: (Scalars['Boolean'] | null)} })
|
||||
uploadApplicationFile?: (FileGenqlSelection & { __args: {file: Scalars['Upload'], applicationUniversalIdentifier: Scalars['String'], fileFolder: FileFolder, filePath: Scalars['String']} })
|
||||
upgradeApplication?: { __args: {appRegistrationId: Scalars['String'], targetVersion: Scalars['String']} }
|
||||
generateApplicationToken?: (ApplicationTokenPairGenqlSelection & { __args: {applicationId: Scalars['UUID']} })
|
||||
renewApplicationToken?: (ApplicationTokenPairGenqlSelection & { __args: {applicationRefreshToken: Scalars['String']} })
|
||||
__typename?: boolean | number
|
||||
@@ -6517,6 +6517,20 @@ displayName?: (Scalars['String'] | null)}
|
||||
|
||||
export interface UpdateWorkspaceInput {subdomain?: (Scalars['String'] | null),customDomain?: (Scalars['String'] | null),displayName?: (Scalars['String'] | null),logo?: (Scalars['String'] | null),inviteHash?: (Scalars['String'] | null),isPublicInviteLinkEnabled?: (Scalars['Boolean'] | null),workspaceDiscoverability?: (WorkspaceDiscoverability | null),allowImpersonation?: (Scalars['Boolean'] | null),isGoogleAuthEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthEnabled?: (Scalars['Boolean'] | null),isPasswordAuthEnabled?: (Scalars['Boolean'] | null),isGoogleAuthBypassEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthBypassEnabled?: (Scalars['Boolean'] | null),isPasswordAuthBypassEnabled?: (Scalars['Boolean'] | null),defaultRoleId?: (Scalars['UUID'] | null),isTwoFactorAuthenticationEnforced?: (Scalars['Boolean'] | null),trashRetentionDays?: (Scalars['Float'] | null),eventLogRetentionDays?: (Scalars['Float'] | null),fastModel?: (Scalars['String'] | null),smartModel?: (Scalars['String'] | null),aiAdditionalInstructions?: (Scalars['String'] | null),editableProfileFields?: (Scalars['String'][] | null),enabledAiModelIds?: (Scalars['String'][] | null),useRecommendedModels?: (Scalars['Boolean'] | null),isInternalMessagesImportEnabled?: (Scalars['Boolean'] | null)}
|
||||
|
||||
export interface CreateApplicationRegistrationInput {name: Scalars['String'],universalIdentifier?: (Scalars['String'] | null),oAuthRedirectUris?: (Scalars['String'][] | null),oAuthScopes?: (Scalars['String'][] | null)}
|
||||
|
||||
export interface UpdateApplicationRegistrationInput {id: Scalars['String'],update: UpdateApplicationRegistrationPayload}
|
||||
|
||||
export interface UpdateApplicationRegistrationPayload {name?: (Scalars['String'] | null),oAuthRedirectUris?: (Scalars['String'][] | null),oAuthScopes?: (Scalars['String'][] | null),isListed?: (Scalars['Boolean'] | null),isPreInstalled?: (Scalars['Boolean'] | null),isVetted?: (Scalars['Boolean'] | null)}
|
||||
|
||||
export interface CreateApplicationRegistrationVariableInput {applicationRegistrationId: Scalars['String'],key: Scalars['String'],value: Scalars['String'],description?: (Scalars['String'] | null),isSecret?: (Scalars['Boolean'] | null)}
|
||||
|
||||
export interface UpdateApplicationRegistrationVariableInput {id: Scalars['String'],update: UpdateApplicationRegistrationVariablePayload}
|
||||
|
||||
export interface UpdateApplicationRegistrationVariablePayload {value?: (Scalars['String'] | null),resetValue?: (Scalars['Boolean'] | null),description?: (Scalars['String'] | null)}
|
||||
|
||||
export interface UpdateApplicationInput {autoUpgrade?: (Scalars['Boolean'] | null)}
|
||||
|
||||
export interface CreateOneFieldMetadataInput {
|
||||
/** The record to create */
|
||||
field: CreateFieldInput}
|
||||
@@ -6553,20 +6567,6 @@ export interface DestroyViewGroupInput {
|
||||
/** The id of the view group to destroy. */
|
||||
id: Scalars['UUID']}
|
||||
|
||||
export interface UpdateApplicationInput {autoUpgrade?: (Scalars['Boolean'] | null)}
|
||||
|
||||
export interface CreateApplicationRegistrationInput {name: Scalars['String'],universalIdentifier?: (Scalars['String'] | null),oAuthRedirectUris?: (Scalars['String'][] | null),oAuthScopes?: (Scalars['String'][] | null)}
|
||||
|
||||
export interface UpdateApplicationRegistrationInput {id: Scalars['String'],update: UpdateApplicationRegistrationPayload}
|
||||
|
||||
export interface UpdateApplicationRegistrationPayload {name?: (Scalars['String'] | null),oAuthRedirectUris?: (Scalars['String'][] | null),oAuthScopes?: (Scalars['String'][] | null),isListed?: (Scalars['Boolean'] | null),isPreInstalled?: (Scalars['Boolean'] | null),isVetted?: (Scalars['Boolean'] | null)}
|
||||
|
||||
export interface CreateApplicationRegistrationVariableInput {applicationRegistrationId: Scalars['String'],key: Scalars['String'],value: Scalars['String'],description?: (Scalars['String'] | null),isSecret?: (Scalars['Boolean'] | null)}
|
||||
|
||||
export interface UpdateApplicationRegistrationVariableInput {id: Scalars['String'],update: UpdateApplicationRegistrationVariablePayload}
|
||||
|
||||
export interface UpdateApplicationRegistrationVariablePayload {value?: (Scalars['String'] | null),resetValue?: (Scalars['Boolean'] | null),description?: (Scalars['String'] | null)}
|
||||
|
||||
export interface CreateRoleInput {id?: (Scalars['String'] | null),label: Scalars['String'],description?: (Scalars['String'] | null),icon?: (Scalars['String'] | null),canUpdateAllSettings?: (Scalars['Boolean'] | null),canAccessAllTools?: (Scalars['Boolean'] | null),canReadAllObjectRecords?: (Scalars['Boolean'] | null),canUpdateAllObjectRecords?: (Scalars['Boolean'] | null),canSoftDeleteAllObjectRecords?: (Scalars['Boolean'] | null),canDestroyAllObjectRecords?: (Scalars['Boolean'] | null),canBeAssignedToUsers?: (Scalars['Boolean'] | null),canBeAssignedToAgents?: (Scalars['Boolean'] | null),canBeAssignedToApiKeys?: (Scalars['Boolean'] | null)}
|
||||
|
||||
export interface UpdateRoleInput {update: UpdateRolePayload,
|
||||
@@ -7763,102 +7763,6 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const Relation_possibleTypes: string[] = ['Relation']
|
||||
export const isRelation = (obj?: { __typename?: any } | null): obj is Relation => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isRelation"')
|
||||
return Relation_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const IndexField_possibleTypes: string[] = ['IndexField']
|
||||
export const isIndexField = (obj?: { __typename?: any } | null): obj is IndexField => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isIndexField"')
|
||||
return IndexField_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ObjectRecordCount_possibleTypes: string[] = ['ObjectRecordCount']
|
||||
export const isObjectRecordCount = (obj?: { __typename?: any } | null): obj is ObjectRecordCount => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isObjectRecordCount"')
|
||||
return ObjectRecordCount_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const SearchField_possibleTypes: string[] = ['SearchField']
|
||||
export const isSearchField = (obj?: { __typename?: any } | null): obj is SearchField => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isSearchField"')
|
||||
return SearchField_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ObjectEdge_possibleTypes: string[] = ['ObjectEdge']
|
||||
export const isObjectEdge = (obj?: { __typename?: any } | null): obj is ObjectEdge => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isObjectEdge"')
|
||||
return ObjectEdge_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const PageInfo_possibleTypes: string[] = ['PageInfo']
|
||||
export const isPageInfo = (obj?: { __typename?: any } | null): obj is PageInfo => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isPageInfo"')
|
||||
return PageInfo_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ObjectConnection_possibleTypes: string[] = ['ObjectConnection']
|
||||
export const isObjectConnection = (obj?: { __typename?: any } | null): obj is ObjectConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isObjectConnection"')
|
||||
return ObjectConnection_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const IndexEdge_possibleTypes: string[] = ['IndexEdge']
|
||||
export const isIndexEdge = (obj?: { __typename?: any } | null): obj is IndexEdge => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isIndexEdge"')
|
||||
return IndexEdge_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ObjectIndexMetadatasConnection_possibleTypes: string[] = ['ObjectIndexMetadatasConnection']
|
||||
export const isObjectIndexMetadatasConnection = (obj?: { __typename?: any } | null): obj is ObjectIndexMetadatasConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isObjectIndexMetadatasConnection"')
|
||||
return ObjectIndexMetadatasConnection_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const FieldEdge_possibleTypes: string[] = ['FieldEdge']
|
||||
export const isFieldEdge = (obj?: { __typename?: any } | null): obj is FieldEdge => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isFieldEdge"')
|
||||
return FieldEdge_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ObjectFieldsConnection_possibleTypes: string[] = ['ObjectFieldsConnection']
|
||||
export const isObjectFieldsConnection = (obj?: { __typename?: any } | null): obj is ObjectFieldsConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isObjectFieldsConnection"')
|
||||
return ObjectFieldsConnection_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const FieldConnection_possibleTypes: string[] = ['FieldConnection']
|
||||
export const isFieldConnection = (obj?: { __typename?: any } | null): obj is FieldConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isFieldConnection"')
|
||||
return FieldConnection_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const AppConnection_possibleTypes: string[] = ['AppConnection']
|
||||
export const isAppConnection = (obj?: { __typename?: any } | null): obj is AppConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isAppConnection"')
|
||||
@@ -7987,6 +7891,102 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const Relation_possibleTypes: string[] = ['Relation']
|
||||
export const isRelation = (obj?: { __typename?: any } | null): obj is Relation => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isRelation"')
|
||||
return Relation_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const IndexField_possibleTypes: string[] = ['IndexField']
|
||||
export const isIndexField = (obj?: { __typename?: any } | null): obj is IndexField => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isIndexField"')
|
||||
return IndexField_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ObjectRecordCount_possibleTypes: string[] = ['ObjectRecordCount']
|
||||
export const isObjectRecordCount = (obj?: { __typename?: any } | null): obj is ObjectRecordCount => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isObjectRecordCount"')
|
||||
return ObjectRecordCount_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const SearchField_possibleTypes: string[] = ['SearchField']
|
||||
export const isSearchField = (obj?: { __typename?: any } | null): obj is SearchField => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isSearchField"')
|
||||
return SearchField_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ObjectEdge_possibleTypes: string[] = ['ObjectEdge']
|
||||
export const isObjectEdge = (obj?: { __typename?: any } | null): obj is ObjectEdge => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isObjectEdge"')
|
||||
return ObjectEdge_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const PageInfo_possibleTypes: string[] = ['PageInfo']
|
||||
export const isPageInfo = (obj?: { __typename?: any } | null): obj is PageInfo => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isPageInfo"')
|
||||
return PageInfo_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ObjectConnection_possibleTypes: string[] = ['ObjectConnection']
|
||||
export const isObjectConnection = (obj?: { __typename?: any } | null): obj is ObjectConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isObjectConnection"')
|
||||
return ObjectConnection_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const IndexEdge_possibleTypes: string[] = ['IndexEdge']
|
||||
export const isIndexEdge = (obj?: { __typename?: any } | null): obj is IndexEdge => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isIndexEdge"')
|
||||
return IndexEdge_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ObjectIndexMetadatasConnection_possibleTypes: string[] = ['ObjectIndexMetadatasConnection']
|
||||
export const isObjectIndexMetadatasConnection = (obj?: { __typename?: any } | null): obj is ObjectIndexMetadatasConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isObjectIndexMetadatasConnection"')
|
||||
return ObjectIndexMetadatasConnection_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const FieldEdge_possibleTypes: string[] = ['FieldEdge']
|
||||
export const isFieldEdge = (obj?: { __typename?: any } | null): obj is FieldEdge => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isFieldEdge"')
|
||||
return FieldEdge_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ObjectFieldsConnection_possibleTypes: string[] = ['ObjectFieldsConnection']
|
||||
export const isObjectFieldsConnection = (obj?: { __typename?: any } | null): obj is ObjectFieldsConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isObjectFieldsConnection"')
|
||||
return ObjectFieldsConnection_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const FieldConnection_possibleTypes: string[] = ['FieldConnection']
|
||||
export const isFieldConnection = (obj?: { __typename?: any } | null): obj is FieldConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isFieldConnection"')
|
||||
return FieldConnection_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const BillingEntitlement_possibleTypes: string[] = ['BillingEntitlement']
|
||||
export const isBillingEntitlement = (obj?: { __typename?: any } | null): obj is BillingEntitlement => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isBillingEntitlement"')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -86,6 +86,52 @@ The same resolved id works anywhere a `fieldMetadataUniversalIdentifier` is expe
|
||||
inputs change, and avoids drift if the derivation ever evolves.
|
||||
</Note>
|
||||
|
||||
## System relation fields
|
||||
|
||||
<Note>
|
||||
`getSystemRelationFieldUniversalIdentifier` is available from `twenty-sdk`
|
||||
2.23 onward and requires a Twenty server on 2.23 or later.
|
||||
</Note>
|
||||
|
||||
Besides the scalar system fields above, the server also provisions four **system relation fields** on every object: `timelineActivities`, `attachments`, `noteTargets` and `taskTargets`, each pointing at the matching standard relation object.
|
||||
|
||||
These fields are not resolved with `getFieldUniversalIdentifier`: their identifier is derived **name-free**, from the object hosting the field and the object the field points to. That way renaming an object never changes the identifiers of its relation fields.
|
||||
|
||||
Use `getSystemRelationFieldUniversalIdentifier` to resolve them:
|
||||
|
||||
```ts
|
||||
import {
|
||||
getSystemRelationFieldUniversalIdentifier,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk/define';
|
||||
|
||||
// rocket.attachments — the relation field hosted on your custom object
|
||||
const rocketAttachmentsFieldId = getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment.universalIdentifier,
|
||||
});
|
||||
```
|
||||
|
||||
- `objectUniversalIdentifier` is the object **hosting** the field.
|
||||
- `relationTargetObjectUniversalIdentifier` is the object the field **points to**.
|
||||
|
||||
The direction is encoded by the argument order. To resolve the reverse side (e.g. `attachment.targetRocket`, the morph field the server creates on the standard relation object), swap the two:
|
||||
|
||||
```ts
|
||||
// attachment.targetRocket — the reverse morph field on Attachment
|
||||
const attachmentTargetRocketFieldId =
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment.universalIdentifier,
|
||||
relationTargetObjectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
```
|
||||
|
||||
As with scalar system fields, the resolved id works anywhere a `fieldMetadataUniversalIdentifier` is expected.
|
||||
|
||||
## Standard Twenty objects
|
||||
|
||||
For a **standard** Twenty object (Person, Company, Opportunity, …), you don't need to derive anything: the system field identifiers are pre-computed constants you can import directly.
|
||||
|
||||
@@ -73,7 +73,7 @@ yarn twenty plan
|
||||
Building manifest...
|
||||
Computing metadata plan (read-only, nothing will be applied)...
|
||||
|
||||
# fieldMetadata "timelineActivities" will be created
|
||||
# fieldMetadata "crewCapacity" will be created
|
||||
+ ...
|
||||
|
||||
Plan: 1 to add, 1 to change, 0 to destroy.
|
||||
|
||||
+23
-23
@@ -1388,7 +1388,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "44d1bf28-de4c-46c8-a7a5-7ba770db12f2",
|
||||
"universalIdentifier": "20202020-bf6f-4220-8c55-2764f1175870",
|
||||
"universalIdentifier": "6e0748cd-8876-53f9-b78d-8bdb3c71883e",
|
||||
"type": "RELATION",
|
||||
"name": "attachments",
|
||||
"label": "Attachments",
|
||||
@@ -1440,7 +1440,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "20acfd6a-3b43-4829-8844-2fb9539ed78b",
|
||||
"universalIdentifier": "99c330c0-5b7d-4276-a764-aed84499dfb5",
|
||||
"universalIdentifier": "82711ab6-00a2-57e7-9db8-9f77dde9944c",
|
||||
"type": "RELATION",
|
||||
"name": "timelineActivities",
|
||||
"label": "Timeline Activities",
|
||||
@@ -1899,7 +1899,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "24084abc-ee9c-49e2-aff3-410c35234d0e",
|
||||
"universalIdentifier": "20202020-87c7-4118-83d6-2f4031005209",
|
||||
"universalIdentifier": "37d15d4b-7441-5bbc-8a5f-228f2d62abf4",
|
||||
"type": "RELATION",
|
||||
"name": "attachments",
|
||||
"label": "Attachments",
|
||||
@@ -2005,7 +2005,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "8793e14d-8782-48c4-93f0-d665f48215bb",
|
||||
"universalIdentifier": "20202020-dd3f-42d5-a382-db58aabf43d3",
|
||||
"universalIdentifier": "ee980fc9-5f51-5986-9fbe-ccf5a103f595",
|
||||
"type": "RELATION",
|
||||
"name": "noteTargets",
|
||||
"label": "Notes",
|
||||
@@ -2111,7 +2111,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "5925f4d7-f2ea-4f84-9fe8-8cf337b938d0",
|
||||
"universalIdentifier": "20202020-59c0-4179-a208-4a255f04a5be",
|
||||
"universalIdentifier": "3e20f0e5-c0f5-5af4-8cac-02a65ecc4e86",
|
||||
"type": "RELATION",
|
||||
"name": "taskTargets",
|
||||
"label": "Tasks",
|
||||
@@ -2163,7 +2163,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "a8a81fec-6315-46b1-927b-064f3e52ab94",
|
||||
"universalIdentifier": "20202020-30e2-421f-96c7-19c69d1cf631",
|
||||
"universalIdentifier": "64f26c76-9427-55a1-82e6-332b495878ad",
|
||||
"type": "RELATION",
|
||||
"name": "timelineActivities",
|
||||
"label": "Timeline Activities",
|
||||
@@ -3185,7 +3185,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "0419db16-5fd4-4306-bd1d-ea0b1dde5349",
|
||||
"universalIdentifier": "20202020-7664-4a35-a3df-580d389fd527",
|
||||
"universalIdentifier": "1598c13c-d539-52c8-a56c-974a6b724393",
|
||||
"type": "MORPH_RELATION",
|
||||
"name": "target",
|
||||
"label": "Target",
|
||||
@@ -4136,7 +4136,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "077d02f7-6730-40dd-a9bb-5960a68fe033",
|
||||
"universalIdentifier": "20202020-4a8c-4e2d-9b1c-7e5f3a2b4c6d",
|
||||
"universalIdentifier": "78d27c16-be35-54d2-988a-451dc24f77ff",
|
||||
"type": "RELATION",
|
||||
"name": "attachments",
|
||||
"label": "Attachments",
|
||||
@@ -4188,7 +4188,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "5bfdccb5-ae15-428e-9cb8-acc2569220dc",
|
||||
"universalIdentifier": "20202020-906e-486a-a798-131a5f081faf",
|
||||
"universalIdentifier": "0ca041cd-598d-5c6b-881c-fe89ee97a0bc",
|
||||
"type": "RELATION",
|
||||
"name": "timelineActivities",
|
||||
"label": "Timeline Activities",
|
||||
@@ -10001,7 +10001,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "3eaf07bb-8dae-42d8-870f-8499499cb790",
|
||||
"universalIdentifier": "20202020-af4d-4eb0-babc-eb960a45b356",
|
||||
"universalIdentifier": "1e8e4e87-48c3-54d5-bd75-5cda9cf393b0",
|
||||
"type": "RELATION",
|
||||
"name": "timelineActivities",
|
||||
"label": "Timeline Activities",
|
||||
@@ -13956,7 +13956,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "13d4bb57-4d6e-43ec-a9ed-1e319af50cd8",
|
||||
"universalIdentifier": "20202020-794d-4783-a8ff-cecdb15be139",
|
||||
"universalIdentifier": "d88469f5-b558-5e11-ab85-66f9ffcaecc0",
|
||||
"type": "RELATION",
|
||||
"name": "attachments",
|
||||
"label": "Attachments",
|
||||
@@ -14114,7 +14114,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "4bd3102c-f570-4488-abb6-1cac4889a8a6",
|
||||
"universalIdentifier": "20202020-c778-4278-99ee-23a2837aee64",
|
||||
"universalIdentifier": "9058db0a-b156-5c9e-999f-c89387ef4a9b",
|
||||
"type": "RELATION",
|
||||
"name": "timelineActivities",
|
||||
"label": "Timeline Activities",
|
||||
@@ -14587,7 +14587,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "1a1ee54b-8af0-46f1-b02e-836dc676cd53",
|
||||
"universalIdentifier": "20202020-fcb0-4695-b17e-3b43a421c633",
|
||||
"universalIdentifier": "4be90325-f6ca-5931-a977-1194bb4b3d5c",
|
||||
"type": "RELATION",
|
||||
"name": "timelineActivities",
|
||||
"label": "Timeline Activities",
|
||||
@@ -15279,7 +15279,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "60cfa81c-51ae-41f2-96cc-ee75ae1d57c4",
|
||||
"universalIdentifier": "20202020-cd97-451f-87fa-bcb789bdbf3a",
|
||||
"universalIdentifier": "54dd92e1-67bf-5381-86f3-c747976dcdaf",
|
||||
"type": "RELATION",
|
||||
"name": "attachments",
|
||||
"label": "Attachments",
|
||||
@@ -15489,7 +15489,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "2a4ae297-c70c-4c18-978a-b1dfbf472e8f",
|
||||
"universalIdentifier": "20202020-c8fc-4258-8250-15905d3fcfec",
|
||||
"universalIdentifier": "1c0e0dfe-a01f-58d6-8948-08b93164d03c",
|
||||
"type": "RELATION",
|
||||
"name": "noteTargets",
|
||||
"label": "Notes",
|
||||
@@ -15593,7 +15593,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "d97cf1e1-e92c-4ec0-b349-7a8a2efc4d83",
|
||||
"universalIdentifier": "20202020-584b-4d3e-88b6-53ab1fa03c3a",
|
||||
"universalIdentifier": "ddea86e6-5766-5798-ac32-14fbab6089f6",
|
||||
"type": "RELATION",
|
||||
"name": "taskTargets",
|
||||
"label": "Tasks",
|
||||
@@ -15645,7 +15645,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "f2839b7a-3eae-4048-9b00-4a631f733e70",
|
||||
"universalIdentifier": "20202020-a43e-4873-9c23-e522de906ce5",
|
||||
"universalIdentifier": "32d7483f-6227-528b-bc65-62d9cf858cd8",
|
||||
"type": "RELATION",
|
||||
"name": "timelineActivities",
|
||||
"label": "Events",
|
||||
@@ -17109,7 +17109,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "7bea72b6-41ff-4012-83fe-df7fd52e5ffc",
|
||||
"universalIdentifier": "20202020-c1b5-4120-b0f0-987ca401ed53",
|
||||
"universalIdentifier": "a4399ae3-fe89-59fe-a282-aec77d4e63a8",
|
||||
"type": "RELATION",
|
||||
"name": "attachments",
|
||||
"label": "Attachments",
|
||||
@@ -17267,7 +17267,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "ef490149-f4f3-437e-a40a-7b1528b6b09a",
|
||||
"universalIdentifier": "20202020-cb17-4a61-8f8f-3be6730480de",
|
||||
"universalIdentifier": "9d7b0087-7037-55dc-bb59-456064455694",
|
||||
"type": "RELATION",
|
||||
"name": "taskTargets",
|
||||
"label": "Tasks",
|
||||
@@ -17319,7 +17319,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "e34f74fc-3019-4c01-a23d-a9312444a7aa",
|
||||
"universalIdentifier": "20202020-bae0-4556-a74a-a9c686f77a88",
|
||||
"universalIdentifier": "0b28db77-8099-5ce3-a11f-86a5778d7740",
|
||||
"type": "RELATION",
|
||||
"name": "noteTargets",
|
||||
"label": "Notes",
|
||||
@@ -17423,7 +17423,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "3b6d99ee-d1f8-4011-b05e-9da8f1d21fe8",
|
||||
"universalIdentifier": "20202020-0414-4daf-9c0d-64fe7b27f89f",
|
||||
"universalIdentifier": "28ec0f8f-ad23-5317-b2d9-1a487bcefee2",
|
||||
"type": "RELATION",
|
||||
"name": "timelineActivities",
|
||||
"label": "Timeline Activities",
|
||||
@@ -18066,7 +18066,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "471b32ff-a033-4085-95c3-ef240b47f00e",
|
||||
"universalIdentifier": "20202020-4986-4c92-bf19-39934b149b16",
|
||||
"universalIdentifier": "b5e03b44-f726-5eae-9ea9-141d074f2120",
|
||||
"type": "RELATION",
|
||||
"name": "attachments",
|
||||
"label": "Attachments",
|
||||
@@ -18170,7 +18170,7 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery =
|
||||
{
|
||||
"__typename": "Field",
|
||||
"id": "583a87e2-b8ea-4a7f-bbe0-deded7e5f3db",
|
||||
"universalIdentifier": "20202020-7030-42f8-929c-1a57b25d6bce",
|
||||
"universalIdentifier": "dd80c0fb-074a-5ca2-8596-dbb967f20155",
|
||||
"type": "RELATION",
|
||||
"name": "timelineActivities",
|
||||
"label": "Timeline Activities",
|
||||
|
||||
@@ -867,7 +867,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-cb17-4a61-8f8f-3be6730480de',
|
||||
standardId: '9d7b0087-7037-55dc-bb59-456064455694',
|
||||
description: 'Tasks tied to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -892,7 +892,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-bae0-4556-a74a-a9c686f77a88',
|
||||
standardId: '0b28db77-8099-5ce3-a11f-86a5778d7740',
|
||||
description: 'Notes tied to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -967,7 +967,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-c1b5-4120-b0f0-987ca401ed53',
|
||||
standardId: 'a4399ae3-fe89-59fe-a282-aec77d4e63a8',
|
||||
description: 'Attachments linked to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -992,7 +992,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-0414-4daf-9c0d-64fe7b27f89f',
|
||||
standardId: '28ec0f8f-ad23-5317-b2d9-1a487bcefee2',
|
||||
description:
|
||||
'Timeline Activities linked to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
@@ -2048,7 +2048,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-cb17-4a61-8f8f-3be6730480de',
|
||||
standardId: '9d7b0087-7037-55dc-bb59-456064455694',
|
||||
description: 'Tasks tied to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -2086,7 +2086,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-bae0-4556-a74a-a9c686f77a88',
|
||||
standardId: '0b28db77-8099-5ce3-a11f-86a5778d7740',
|
||||
description: 'Notes tied to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -2200,7 +2200,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-c1b5-4120-b0f0-987ca401ed53',
|
||||
standardId: 'a4399ae3-fe89-59fe-a282-aec77d4e63a8',
|
||||
description: 'Attachments linked to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -2238,7 +2238,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-0414-4daf-9c0d-64fe7b27f89f',
|
||||
standardId: '28ec0f8f-ad23-5317-b2d9-1a487bcefee2',
|
||||
description: 'Timeline Activities linked to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -2528,7 +2528,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-0414-4daf-9c0d-64fe7b27f89f',
|
||||
standardId: '28ec0f8f-ad23-5317-b2d9-1a487bcefee2',
|
||||
description: 'Timeline Activities linked to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -2566,7 +2566,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-c1b5-4120-b0f0-987ca401ed53',
|
||||
standardId: 'a4399ae3-fe89-59fe-a282-aec77d4e63a8',
|
||||
description: 'Attachments linked to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -3041,7 +3041,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-bae0-4556-a74a-a9c686f77a88',
|
||||
standardId: '0b28db77-8099-5ce3-a11f-86a5778d7740',
|
||||
description: 'Notes tied to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -3266,7 +3266,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-cb17-4a61-8f8f-3be6730480de',
|
||||
standardId: '9d7b0087-7037-55dc-bb59-456064455694',
|
||||
description: 'Tasks tied to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -3918,7 +3918,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-c1b5-4120-b0f0-987ca401ed53',
|
||||
standardId: 'a4399ae3-fe89-59fe-a282-aec77d4e63a8',
|
||||
description: 'Attachments linked to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -3956,7 +3956,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-bae0-4556-a74a-a9c686f77a88',
|
||||
standardId: '0b28db77-8099-5ce3-a11f-86a5778d7740',
|
||||
description: 'Notes tied to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -3994,7 +3994,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-cb17-4a61-8f8f-3be6730480de',
|
||||
standardId: '9d7b0087-7037-55dc-bb59-456064455694',
|
||||
description: 'Tasks tied to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -4218,7 +4218,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-0414-4daf-9c0d-64fe7b27f89f',
|
||||
standardId: '28ec0f8f-ad23-5317-b2d9-1a487bcefee2',
|
||||
description: 'Timeline Activities linked to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -5316,7 +5316,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-cb17-4a61-8f8f-3be6730480de',
|
||||
standardId: '9d7b0087-7037-55dc-bb59-456064455694',
|
||||
description: 'Tasks tied to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -5340,7 +5340,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-bae0-4556-a74a-a9c686f77a88',
|
||||
standardId: '0b28db77-8099-5ce3-a11f-86a5778d7740',
|
||||
description: 'Notes tied to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -5412,7 +5412,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-c1b5-4120-b0f0-987ca401ed53',
|
||||
standardId: 'a4399ae3-fe89-59fe-a282-aec77d4e63a8',
|
||||
description: 'Attachments linked to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
@@ -5436,7 +5436,7 @@ export const oneSucceededWorkflowRunQueryResult = {
|
||||
createdAt: '2025-03-05T15:41:09.390Z',
|
||||
updatedAt: '2025-03-05T15:41:09.390Z',
|
||||
isNullable: true,
|
||||
standardId: '20202020-0414-4daf-9c0d-64fe7b27f89f',
|
||||
standardId: '28ec0f8f-ad23-5317-b2d9-1a487bcefee2',
|
||||
description: 'Timeline Activities linked to the company',
|
||||
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
|
||||
defaultValue: null,
|
||||
|
||||
@@ -1150,7 +1150,7 @@ export const workflowQueryResult = {
|
||||
updatedAt: '2025-01-30T09:40:10.256Z',
|
||||
isNullable: true,
|
||||
standardId:
|
||||
'20202020-cb17-4a61-8f8f-3be6730480de',
|
||||
'9d7b0087-7037-55dc-bb59-456064455694',
|
||||
description: 'Tasks tied to the company',
|
||||
workspaceId:
|
||||
'3b8e6458-5fc1-4e63-8563-008ccddaa6db',
|
||||
@@ -1177,7 +1177,7 @@ export const workflowQueryResult = {
|
||||
updatedAt: '2025-01-30T09:40:10.256Z',
|
||||
isNullable: true,
|
||||
standardId:
|
||||
'20202020-bae0-4556-a74a-a9c686f77a88',
|
||||
'0b28db77-8099-5ce3-a11f-86a5778d7740',
|
||||
description: 'Notes tied to the company',
|
||||
workspaceId:
|
||||
'3b8e6458-5fc1-4e63-8563-008ccddaa6db',
|
||||
@@ -1260,7 +1260,7 @@ export const workflowQueryResult = {
|
||||
updatedAt: '2025-01-30T09:40:10.256Z',
|
||||
isNullable: true,
|
||||
standardId:
|
||||
'20202020-c1b5-4120-b0f0-987ca401ed53',
|
||||
'a4399ae3-fe89-59fe-a282-aec77d4e63a8',
|
||||
description:
|
||||
'Attachments linked to the company',
|
||||
workspaceId:
|
||||
@@ -1288,7 +1288,7 @@ export const workflowQueryResult = {
|
||||
updatedAt: '2025-01-30T09:40:10.256Z',
|
||||
isNullable: true,
|
||||
standardId:
|
||||
'20202020-0414-4daf-9c0d-64fe7b27f89f',
|
||||
'28ec0f8f-ad23-5317-b2d9-1a487bcefee2',
|
||||
description:
|
||||
'Timeline Activities linked to the company',
|
||||
workspaceId:
|
||||
|
||||
+2
-151
@@ -1,10 +1,6 @@
|
||||
import { FieldType } from '@/sdk/define';
|
||||
import type { Manifest } from 'twenty-shared/application';
|
||||
import {
|
||||
FieldMetadataType,
|
||||
RelationOnDeleteAction,
|
||||
RelationType,
|
||||
} from 'twenty-shared/types';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
export const EXPECTED_MANIFEST: Manifest = {
|
||||
commandMenuItems: [],
|
||||
@@ -23,88 +19,7 @@ export const EXPECTED_MANIFEST: Manifest = {
|
||||
agents: [],
|
||||
publicAssets: [],
|
||||
indexes: [],
|
||||
fields: [
|
||||
{
|
||||
name: 'targetMyNote',
|
||||
label: 'MyNote',
|
||||
description: 'MyNote My note',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
universalSettings: {
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
joinColumnName: 'targetMyNoteId',
|
||||
},
|
||||
universalIdentifier: '55153e55-1bdc-590d-8fb1-40eafec88ef0',
|
||||
objectUniversalIdentifier: '20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'559713af-d9c0-5894-a972-9a3951661a2b',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'e1e2e3e4-e5e6-4000-8000-000000000030',
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
|
||||
},
|
||||
{
|
||||
name: 'targetMyNote',
|
||||
label: 'MyNote',
|
||||
description: 'MyNote My note',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
universalSettings: {
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
joinColumnName: 'targetMyNoteId',
|
||||
},
|
||||
universalIdentifier: '80596d88-f896-5108-8cff-302a2eb61668',
|
||||
objectUniversalIdentifier: '20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'8f8e42e3-77de-5b0a-b444-d96b6d3c7600',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'e1e2e3e4-e5e6-4000-8000-000000000030',
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: '20202020-f634-435d-ab8d-e1168b375c69',
|
||||
},
|
||||
{
|
||||
name: 'targetMyNote',
|
||||
label: 'MyNote',
|
||||
description: 'MyNote My note',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
universalSettings: {
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
joinColumnName: 'targetMyNoteId',
|
||||
},
|
||||
universalIdentifier: '67bf90bd-f3d0-58ce-a96e-648364249812',
|
||||
objectUniversalIdentifier: '20202020-fff0-4b44-be82-bda313884400',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'0cbc9a5c-34b2-5d39-97a2-878662cb13d5',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'e1e2e3e4-e5e6-4000-8000-000000000030',
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: '20202020-f635-435d-ab8d-e1168b375c70',
|
||||
},
|
||||
{
|
||||
name: 'targetMyNote',
|
||||
label: 'MyNote',
|
||||
description: 'MyNote My note',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
universalSettings: {
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
joinColumnName: 'targetMyNoteId',
|
||||
},
|
||||
universalIdentifier: '2689365b-e6ce-5b14-a2b5-6daafbfe91f8',
|
||||
objectUniversalIdentifier: '20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'affdd37c-4460-53fc-998b-ffb04bb3a470',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'e1e2e3e4-e5e6-4000-8000-000000000030',
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: '20202020-f636-435d-ab8d-e1168b375c71',
|
||||
},
|
||||
],
|
||||
fields: [],
|
||||
objects: [
|
||||
{
|
||||
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000030',
|
||||
@@ -133,70 +48,6 @@ export const EXPECTED_MANIFEST: Manifest = {
|
||||
type: FieldMetadataType.TEXT,
|
||||
universalIdentifier: '9a7f457a-6c15-581e-8f28-e2c680f75f97',
|
||||
},
|
||||
{
|
||||
name: 'timelineActivities',
|
||||
label: 'Timeline Activities',
|
||||
description: 'My notes tied to the MyNote',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
type: FieldType.RELATION,
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
universalIdentifier: '559713af-d9c0-5894-a972-9a3951661a2b',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'55153e55-1bdc-590d-8fb1-40eafec88ef0',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
},
|
||||
{
|
||||
name: 'attachments',
|
||||
label: 'Attachments',
|
||||
description: 'My notes tied to the MyNote',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
type: FieldType.RELATION,
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
universalIdentifier: '8f8e42e3-77de-5b0a-b444-d96b6d3c7600',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'80596d88-f896-5108-8cff-302a2eb61668',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
},
|
||||
{
|
||||
name: 'noteTargets',
|
||||
label: 'Note Targets',
|
||||
description: 'My notes tied to the MyNote',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
type: FieldType.RELATION,
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
universalIdentifier: '0cbc9a5c-34b2-5d39-97a2-878662cb13d5',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'67bf90bd-f3d0-58ce-a96e-648364249812',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-fff0-4b44-be82-bda313884400',
|
||||
},
|
||||
{
|
||||
name: 'taskTargets',
|
||||
label: 'Task Targets',
|
||||
description: 'My notes tied to the MyNote',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
type: FieldType.RELATION,
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
universalIdentifier: 'affdd37c-4460-53fc-998b-ffb04bb3a470',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'2689365b-e6ce-5b14-a2b5-6daafbfe91f8',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
-580
@@ -297,87 +297,6 @@ export const EXPECTED_MANIFEST: Manifest = {
|
||||
],
|
||||
|
||||
fields: [
|
||||
// Reverse relation fields for rootNote (5 fields)
|
||||
{
|
||||
description: 'RootNote Root note',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
label: 'RootNote',
|
||||
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
|
||||
name: 'targetRootNote',
|
||||
objectUniversalIdentifier: '20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'e1478d59-c947-5926-af8b-4b2f0f842c91',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'b0b1b2b3-b4b5-4000-8000-000000000001',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: '7f891268-9376-5d00-b8ec-bc32a023154d',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetRootNoteId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'RootNote Root note',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
label: 'RootNote',
|
||||
morphId: '20202020-f634-435d-ab8d-e1168b375c69',
|
||||
name: 'targetRootNote',
|
||||
objectUniversalIdentifier: '20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'34a6b8e9-0187-57e1-86c1-41bacf1b2479',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'b0b1b2b3-b4b5-4000-8000-000000000001',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: 'd72bb002-9952-5651-983e-649436949113',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetRootNoteId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'RootNote Root note',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
label: 'RootNote',
|
||||
morphId: '20202020-f635-435d-ab8d-e1168b375c70',
|
||||
name: 'targetRootNote',
|
||||
objectUniversalIdentifier: '20202020-fff0-4b44-be82-bda313884400',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'7a62bbd6-e697-54b0-8c1c-163ac47c0305',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'b0b1b2b3-b4b5-4000-8000-000000000001',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: '61252ad6-2311-5054-ae51-b318dfd5fbd8',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetRootNoteId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'RootNote Root note',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
label: 'RootNote',
|
||||
morphId: '20202020-f636-435d-ab8d-e1168b375c71',
|
||||
name: 'targetRootNote',
|
||||
objectUniversalIdentifier: '20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'10c1af7e-e541-56bc-b5b3-d0297df3e23d',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'b0b1b2b3-b4b5-4000-8000-000000000001',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: '2f4f3d69-b78e-5465-9e87-17059959fca8',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetRootNoteId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
// User-defined relation and field definitions
|
||||
{
|
||||
label: 'Post Card',
|
||||
@@ -485,249 +404,6 @@ export const EXPECTED_MANIFEST: Manifest = {
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
// Reverse relation fields for postCardRecipient (5 fields)
|
||||
{
|
||||
description: 'PostCardRecipient Post Card Recipient',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
label: 'PostCardRecipient',
|
||||
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
|
||||
name: 'targetPostCardRecipient',
|
||||
objectUniversalIdentifier: '20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'8f95b434-ee92-5c0f-95de-9d489af4d40c',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'e1a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5e',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: 'a865f403-3843-5850-9a60-04e832220954',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetPostCardRecipientId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'PostCardRecipient Post Card Recipient',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
label: 'PostCardRecipient',
|
||||
morphId: '20202020-f634-435d-ab8d-e1168b375c69',
|
||||
name: 'targetPostCardRecipient',
|
||||
objectUniversalIdentifier: '20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'0c20df83-8cef-5cd6-9752-b98fb7780904',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'e1a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5e',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: '501c46b7-7140-59a0-b703-9844bbcb34b9',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetPostCardRecipientId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'PostCardRecipient Post Card Recipient',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
label: 'PostCardRecipient',
|
||||
morphId: '20202020-f635-435d-ab8d-e1168b375c70',
|
||||
name: 'targetPostCardRecipient',
|
||||
objectUniversalIdentifier: '20202020-fff0-4b44-be82-bda313884400',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'b9642a90-2df5-555b-ab83-23cdce7a4142',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'e1a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5e',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: '721418ff-1b53-58ef-8dd7-b58927c085c6',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetPostCardRecipientId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'PostCardRecipient Post Card Recipient',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
label: 'PostCardRecipient',
|
||||
morphId: '20202020-f636-435d-ab8d-e1168b375c71',
|
||||
name: 'targetPostCardRecipient',
|
||||
objectUniversalIdentifier: '20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'd938a2d0-1279-5c48-b758-ac52f9460a76',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'e1a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5e',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: 'feeba797-7ebb-5a36-91cd-7279ff92a2b6',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetPostCardRecipientId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
// Reverse relation fields for postCard (5 fields)
|
||||
{
|
||||
description: 'PostCard Post card',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
label: 'PostCard',
|
||||
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
|
||||
name: 'targetPostCard',
|
||||
objectUniversalIdentifier: '20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'9e58820c-78d7-539d-807c-d84362e1eab6',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'54b589ca-eeed-4950-a176-358418b85c05',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: '47d21bb5-075f-5ed4-ba89-c0e7322a57cd',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetPostCardId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'PostCard Post card',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
label: 'PostCard',
|
||||
morphId: '20202020-f634-435d-ab8d-e1168b375c69',
|
||||
name: 'targetPostCard',
|
||||
objectUniversalIdentifier: '20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'3f0d38c8-a50f-51c7-bdcb-84a715f4b92d',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'54b589ca-eeed-4950-a176-358418b85c05',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: '4d3cf1bd-d87d-5325-8fbc-19f72c252050',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetPostCardId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'PostCard Post card',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
label: 'PostCard',
|
||||
morphId: '20202020-f635-435d-ab8d-e1168b375c70',
|
||||
name: 'targetPostCard',
|
||||
objectUniversalIdentifier: '20202020-fff0-4b44-be82-bda313884400',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'def1f10a-847b-574e-a0a2-177caf02129c',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'54b589ca-eeed-4950-a176-358418b85c05',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: 'bc1f9abe-e27b-574a-9290-a1c9c8255a6b',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetPostCardId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'PostCard Post card',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
label: 'PostCard',
|
||||
morphId: '20202020-f636-435d-ab8d-e1168b375c71',
|
||||
name: 'targetPostCard',
|
||||
objectUniversalIdentifier: '20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'b1238c2d-bc9c-53d6-8bee-eb045b9b9086',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'54b589ca-eeed-4950-a176-358418b85c05',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: 'fb610de1-db20-5e78-8e4a-7630e57148eb',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetPostCardId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
// Reverse relation fields for recipient (5 fields)
|
||||
{
|
||||
description: 'Recipient Recipient',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
label: 'Recipient',
|
||||
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
|
||||
name: 'targetRecipient',
|
||||
objectUniversalIdentifier: '20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'1118dd8a-9781-5254-b625-2d0f05eb46fe',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'd1a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5d',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: '1ce06ca1-6e9a-53ce-9888-9152b1b2b628',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetRecipientId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Recipient Recipient',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
label: 'Recipient',
|
||||
morphId: '20202020-f634-435d-ab8d-e1168b375c69',
|
||||
name: 'targetRecipient',
|
||||
objectUniversalIdentifier: '20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'15714c1a-d354-5407-8a15-25c117d605f8',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'd1a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5d',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: '2081700d-7ce6-5698-a7da-a013feda0eb6',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetRecipientId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Recipient Recipient',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
label: 'Recipient',
|
||||
morphId: '20202020-f635-435d-ab8d-e1168b375c70',
|
||||
name: 'targetRecipient',
|
||||
objectUniversalIdentifier: '20202020-fff0-4b44-be82-bda313884400',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'167f6de7-835e-51e1-b751-34055eef6aa5',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'd1a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5d',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: 'a93c479c-6206-5714-94ce-affa6e9886aa',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetRecipientId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Recipient Recipient',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
label: 'Recipient',
|
||||
morphId: '20202020-f636-435d-ab8d-e1168b375c71',
|
||||
name: 'targetRecipient',
|
||||
objectUniversalIdentifier: '20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'd0db1844-4fde-5a5a-b037-ebeabd4467af',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'd1a2b3c4-5e6f-4a7b-8c9d-0e1f2a3b4c5d',
|
||||
type: FieldType.MORPH_RELATION,
|
||||
universalIdentifier: '45752445-c4b6-5e80-8aa1-f5321a838b43',
|
||||
universalSettings: {
|
||||
joinColumnName: 'targetRecipientId',
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
},
|
||||
},
|
||||
// Field on standard company object
|
||||
{
|
||||
defaultValue: false,
|
||||
@@ -766,70 +442,6 @@ export const EXPECTED_MANIFEST: Manifest = {
|
||||
type: FieldMetadataType.TEXT,
|
||||
universalIdentifier: '10452ca3-30cb-56fa-9e58-73f7b1c9fd65',
|
||||
},
|
||||
{
|
||||
description: 'Root notes tied to the RootNote',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Timeline Activities',
|
||||
name: 'timelineActivities',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'7f891268-9376-5d00-b8ec-bc32a023154d',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: 'e1478d59-c947-5926-af8b-4b2f0f842c91',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Root notes tied to the RootNote',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Attachments',
|
||||
name: 'attachments',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'd72bb002-9952-5651-983e-649436949113',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: '34a6b8e9-0187-57e1-86c1-41bacf1b2479',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Root notes tied to the RootNote',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Note Targets',
|
||||
name: 'noteTargets',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'61252ad6-2311-5054-ae51-b318dfd5fbd8',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-fff0-4b44-be82-bda313884400',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: '7a62bbd6-e697-54b0-8c1c-163ac47c0305',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Root notes tied to the RootNote',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Task Targets',
|
||||
name: 'taskTargets',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'2f4f3d69-b78e-5465-9e87-17059959fca8',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: '10c1af7e-e541-56bc-b5b3-d0297df3e23d',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
],
|
||||
icon: 'IconNote',
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
@@ -862,70 +474,6 @@ export const EXPECTED_MANIFEST: Manifest = {
|
||||
type: FieldMetadataType.TEXT,
|
||||
universalIdentifier: 'f485cd3a-4c55-5b8f-b926-a83e5e6ba651',
|
||||
},
|
||||
{
|
||||
description: 'Post Card Recipients tied to the PostCardRecipient',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Timeline Activities',
|
||||
name: 'timelineActivities',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'a865f403-3843-5850-9a60-04e832220954',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: '8f95b434-ee92-5c0f-95de-9d489af4d40c',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Post Card Recipients tied to the PostCardRecipient',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Attachments',
|
||||
name: 'attachments',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'501c46b7-7140-59a0-b703-9844bbcb34b9',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: '0c20df83-8cef-5cd6-9752-b98fb7780904',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Post Card Recipients tied to the PostCardRecipient',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Note Targets',
|
||||
name: 'noteTargets',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'721418ff-1b53-58ef-8dd7-b58927c085c6',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-fff0-4b44-be82-bda313884400',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: 'b9642a90-2df5-555b-ab83-23cdce7a4142',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Post Card Recipients tied to the PostCardRecipient',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Task Targets',
|
||||
name: 'taskTargets',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'feeba797-7ebb-5a36-91cd-7279ff92a2b6',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: 'd938a2d0-1279-5c48-b758-ac52f9460a76',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
],
|
||||
icon: 'IconLink',
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
@@ -1025,70 +573,6 @@ export const EXPECTED_MANIFEST: Manifest = {
|
||||
type: FieldMetadataType.TEXT,
|
||||
universalIdentifier: '3e14e30f-8271-5a13-9c1f-ce5edb932325',
|
||||
},
|
||||
{
|
||||
description: 'Post cards tied to the PostCard',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Timeline Activities',
|
||||
name: 'timelineActivities',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'47d21bb5-075f-5ed4-ba89-c0e7322a57cd',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: '9e58820c-78d7-539d-807c-d84362e1eab6',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Post cards tied to the PostCard',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Attachments',
|
||||
name: 'attachments',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'4d3cf1bd-d87d-5325-8fbc-19f72c252050',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: '3f0d38c8-a50f-51c7-bdcb-84a715f4b92d',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Post cards tied to the PostCard',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Note Targets',
|
||||
name: 'noteTargets',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'bc1f9abe-e27b-574a-9290-a1c9c8255a6b',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-fff0-4b44-be82-bda313884400',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: 'def1f10a-847b-574e-a0a2-177caf02129c',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Post cards tied to the PostCard',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Task Targets',
|
||||
name: 'taskTargets',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'fb610de1-db20-5e78-8e4a-7630e57148eb',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: 'b1238c2d-bc9c-53d6-8bee-eb045b9b9086',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
],
|
||||
icon: 'IconMail',
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
@@ -1126,70 +610,6 @@ export const EXPECTED_MANIFEST: Manifest = {
|
||||
type: FieldMetadataType.TEXT,
|
||||
universalIdentifier: 'c400ccb8-cd91-5ae1-81e3-2df8b6f2cf53',
|
||||
},
|
||||
{
|
||||
description: 'Recipients tied to the Recipient',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Timeline Activities',
|
||||
name: 'timelineActivities',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'1ce06ca1-6e9a-53ce-9888-9152b1b2b628',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: '1118dd8a-9781-5254-b625-2d0f05eb46fe',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Recipients tied to the Recipient',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Attachments',
|
||||
name: 'attachments',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'2081700d-7ce6-5698-a7da-a013feda0eb6',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: '15714c1a-d354-5407-8a15-25c117d605f8',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Recipients tied to the Recipient',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Note Targets',
|
||||
name: 'noteTargets',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'a93c479c-6206-5714-94ce-affa6e9886aa',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-fff0-4b44-be82-bda313884400',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: '167f6de7-835e-51e1-b751-34055eef6aa5',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Recipients tied to the Recipient',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
label: 'Task Targets',
|
||||
name: 'taskTargets',
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
'45752445-c4b6-5e80-8aa1-f5321a838b43',
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
'20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
type: FieldType.RELATION,
|
||||
universalIdentifier: 'd0db1844-4fde-5a5a-b037-ebeabd4467af',
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
},
|
||||
},
|
||||
],
|
||||
icon: 'IconUser',
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ export const defineManifestTests = (appPath: string): void => {
|
||||
expect(manifest.logicFunctions).toHaveLength(7);
|
||||
expect(manifest.frontComponents).toHaveLength(4);
|
||||
expect(manifest.roles).toHaveLength(2);
|
||||
expect(manifest.fields).toHaveLength(23);
|
||||
expect(manifest.fields).toHaveLength(7);
|
||||
expect(manifest.views).toHaveLength(5);
|
||||
expect(manifest.navigationMenuItems).toHaveLength(3);
|
||||
expect(manifest.pageLayoutTabs).toHaveLength(1);
|
||||
|
||||
+1
@@ -38,6 +38,7 @@ exports[`stub-twenty-sdk-define plugin > matches the recorded export partition 1
|
||||
"favoriteRecordIds",
|
||||
"featureFlags",
|
||||
"getFieldUniversalIdentifier",
|
||||
"getSystemRelationFieldUniversalIdentifier",
|
||||
"hasAnySoftDeleteFilterOnView",
|
||||
"includes",
|
||||
"includesEvery",
|
||||
|
||||
@@ -502,13 +502,11 @@ export const buildManifest = async (
|
||||
|
||||
if (applicationConfig) {
|
||||
for (const objectConfig of objectConfigs) {
|
||||
const {
|
||||
objectFields: objectFieldsWithDefaults,
|
||||
fields: reverseRelationFields,
|
||||
} = getDefaultFieldsInObjectFields({
|
||||
objectConfig,
|
||||
applicationUniversalIdentifier: applicationConfig.universalIdentifier,
|
||||
});
|
||||
const { objectFields: objectFieldsWithDefaults } =
|
||||
getDefaultFieldsInObjectFields({
|
||||
objectConfig,
|
||||
applicationUniversalIdentifier: applicationConfig.universalIdentifier,
|
||||
});
|
||||
|
||||
const labelIdentifierFieldMetadataUniversalIdentifier =
|
||||
objectConfig.labelIdentifierFieldMetadataUniversalIdentifier ??
|
||||
@@ -529,7 +527,6 @@ export const buildManifest = async (
|
||||
};
|
||||
|
||||
objects.push(objectManifest);
|
||||
fields.push(...reverseRelationFields);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-16
@@ -1,7 +1,5 @@
|
||||
import { getDefaultRelationObjectFields } from '@/cli/utilities/build/manifest/utils/get-default-relation-object-fields';
|
||||
import type { ObjectConfig } from '@/sdk/define/objects/object-config';
|
||||
import {
|
||||
type FieldManifest,
|
||||
getFieldUniversalIdentifier,
|
||||
type ObjectFieldManifest,
|
||||
} from 'twenty-shared/application';
|
||||
@@ -34,13 +32,7 @@ export const getDefaultFieldsInObjectFields = ({
|
||||
}: {
|
||||
objectConfig: ObjectConfig;
|
||||
applicationUniversalIdentifier: string;
|
||||
}): { objectFields: ObjectFieldManifest[]; fields: FieldManifest[] } => {
|
||||
const { objectFields: defaultRelationObjectFields, fields: reverseFields } =
|
||||
getDefaultRelationObjectFields({
|
||||
objectConfig,
|
||||
applicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
}): { objectFields: ObjectFieldManifest[] } => {
|
||||
const objectConfigFieldNames = (objectConfig.fields ?? []).map(
|
||||
(field) => field.name,
|
||||
);
|
||||
@@ -56,11 +48,5 @@ export const getDefaultFieldsInObjectFields = ({
|
||||
objectFieldsWithDefaults.push(defaultNameObjectField);
|
||||
}
|
||||
|
||||
for (const defaultRelationField of defaultRelationObjectFields) {
|
||||
if (!objectConfigFieldNames.includes(defaultRelationField.name)) {
|
||||
objectFieldsWithDefaults.push(defaultRelationField);
|
||||
}
|
||||
}
|
||||
|
||||
return { objectFields: objectFieldsWithDefaults, fields: reverseFields };
|
||||
return { objectFields: objectFieldsWithDefaults };
|
||||
};
|
||||
|
||||
-174
@@ -1,174 +0,0 @@
|
||||
import { RelationType } from '@/sdk/define';
|
||||
import type { ObjectConfig } from '@/sdk/define/objects/object-config';
|
||||
import {
|
||||
type FieldManifest,
|
||||
getFieldUniversalIdentifier,
|
||||
type ObjectFieldManifest,
|
||||
} from 'twenty-shared/application';
|
||||
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
import { FieldMetadataType, RelationOnDeleteAction } from 'twenty-shared/types';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
type DefaultRelationConfig = {
|
||||
fieldName: string;
|
||||
label: string;
|
||||
targetFieldName: (objectConfig: ObjectConfig) => string;
|
||||
targetLabel: (objectConfig: ObjectConfig) => string;
|
||||
icon: string;
|
||||
targetIcon: string;
|
||||
standardObjectKey: keyof typeof STANDARD_OBJECTS;
|
||||
} & (
|
||||
| { targetFieldType: FieldMetadataType.RELATION }
|
||||
| { targetFieldType: FieldMetadataType.MORPH_RELATION; morphId: string }
|
||||
);
|
||||
|
||||
const DEFAULT_DEFAULT_RELATION = {
|
||||
targetFieldName: (objectConfig: ObjectConfig) =>
|
||||
`target${capitalize(objectConfig.nameSingular)}`,
|
||||
targetLabel: (objectConfig: ObjectConfig) =>
|
||||
capitalize(objectConfig.nameSingular),
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
};
|
||||
|
||||
const DEFAULT_RELATION_CONFIGS = [
|
||||
{
|
||||
...DEFAULT_DEFAULT_RELATION,
|
||||
fieldName: 'timelineActivities',
|
||||
label: 'Timeline Activities',
|
||||
targetIcon: 'IconTimelineEvent',
|
||||
targetFieldType: FieldMetadataType.MORPH_RELATION,
|
||||
standardObjectKey: 'timelineActivity',
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
},
|
||||
{
|
||||
...DEFAULT_DEFAULT_RELATION,
|
||||
fieldName: 'attachments',
|
||||
label: 'Attachments',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
targetIcon: 'IconFileImport',
|
||||
targetFieldType: FieldMetadataType.MORPH_RELATION,
|
||||
standardObjectKey: 'attachment',
|
||||
morphId: STANDARD_OBJECTS.attachment.morphIds.targetMorphId.morphId,
|
||||
},
|
||||
{
|
||||
...DEFAULT_DEFAULT_RELATION,
|
||||
fieldName: 'noteTargets',
|
||||
label: 'Note Targets',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
targetIcon: 'IconCheckbox',
|
||||
targetFieldType: FieldMetadataType.MORPH_RELATION,
|
||||
standardObjectKey: 'noteTarget',
|
||||
morphId: STANDARD_OBJECTS.noteTarget.morphIds.targetMorphId.morphId,
|
||||
},
|
||||
{
|
||||
...DEFAULT_DEFAULT_RELATION,
|
||||
fieldName: 'taskTargets',
|
||||
label: 'Task Targets',
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
targetIcon: 'IconCheckbox',
|
||||
targetFieldType: FieldMetadataType.MORPH_RELATION,
|
||||
standardObjectKey: 'taskTarget',
|
||||
morphId: STANDARD_OBJECTS.taskTarget.morphIds.targetMorphId.morphId,
|
||||
},
|
||||
] as const satisfies DefaultRelationConfig[];
|
||||
|
||||
const buildReverseField = ({
|
||||
config,
|
||||
forwardFieldUniversalIdentifier,
|
||||
objectConfig,
|
||||
universalIdentifier,
|
||||
}: {
|
||||
config: DefaultRelationConfig;
|
||||
objectConfig: ObjectConfig;
|
||||
universalIdentifier: string;
|
||||
forwardFieldUniversalIdentifier: string;
|
||||
}): FieldManifest<typeof config.targetFieldType> => {
|
||||
const standardObject = STANDARD_OBJECTS[config.standardObjectKey];
|
||||
|
||||
const commonFields = {
|
||||
name: config.targetFieldName(objectConfig),
|
||||
label: config.targetLabel(objectConfig),
|
||||
description: `${config.targetLabel(objectConfig)} ${objectConfig.labelSingular}`,
|
||||
icon: config.targetIcon,
|
||||
isNullable: true,
|
||||
universalSettings: {
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
joinColumnName: `target${capitalize(objectConfig.nameSingular)}Id`,
|
||||
},
|
||||
universalIdentifier,
|
||||
objectUniversalIdentifier: standardObject.universalIdentifier,
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
forwardFieldUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
objectConfig.universalIdentifier,
|
||||
};
|
||||
|
||||
if (config.targetFieldType === FieldMetadataType.MORPH_RELATION) {
|
||||
return {
|
||||
...commonFields,
|
||||
type: config.targetFieldType,
|
||||
morphId: config.morphId,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...commonFields,
|
||||
type: config.targetFieldType,
|
||||
};
|
||||
};
|
||||
|
||||
export const getDefaultRelationObjectFields = ({
|
||||
objectConfig,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
objectConfig: ObjectConfig;
|
||||
applicationUniversalIdentifier: string;
|
||||
}): { objectFields: ObjectFieldManifest[]; fields: FieldManifest[] } => {
|
||||
const objectFields: ObjectFieldManifest[] = [];
|
||||
const fields: FieldManifest[] = [];
|
||||
|
||||
for (const config of DEFAULT_RELATION_CONFIGS) {
|
||||
const standardObject = STANDARD_OBJECTS[config.standardObjectKey];
|
||||
|
||||
const forwardFieldUniversalIdentifier = getFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier: objectConfig.universalIdentifier,
|
||||
name: config.fieldName,
|
||||
});
|
||||
|
||||
const reverseFieldUniversalIdentifier = getFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier: standardObject.universalIdentifier,
|
||||
name: config.targetFieldName(objectConfig),
|
||||
});
|
||||
|
||||
const forwardField: ObjectFieldManifest = {
|
||||
name: config.fieldName,
|
||||
label: config.label,
|
||||
description: `${objectConfig.labelPlural} tied to the ${config.targetLabel(objectConfig)}`,
|
||||
icon: config.icon,
|
||||
isNullable: config.isNullable,
|
||||
type: FieldMetadataType.RELATION,
|
||||
universalSettings: { relationType: RelationType.ONE_TO_MANY },
|
||||
universalIdentifier: forwardFieldUniversalIdentifier,
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
reverseFieldUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
standardObject.universalIdentifier,
|
||||
};
|
||||
|
||||
const reverseField = buildReverseField({
|
||||
config,
|
||||
objectConfig,
|
||||
universalIdentifier: reverseFieldUniversalIdentifier,
|
||||
forwardFieldUniversalIdentifier,
|
||||
});
|
||||
|
||||
objectFields.push(forwardField);
|
||||
fields.push(reverseField);
|
||||
}
|
||||
|
||||
return { objectFields, fields };
|
||||
};
|
||||
@@ -23,7 +23,10 @@ export type {
|
||||
} from '@/sdk/define/fields/composite-fields';
|
||||
export { defineField } from '@/sdk/define/fields/define-field';
|
||||
export { FieldType } from '@/sdk/define/fields/field-type';
|
||||
export { getFieldUniversalIdentifier } from 'twenty-shared/application';
|
||||
export {
|
||||
getFieldUniversalIdentifier,
|
||||
getSystemRelationFieldUniversalIdentifier,
|
||||
} from 'twenty-shared/application';
|
||||
export { OnDeleteAction } from '@/sdk/define/fields/on-delete-action';
|
||||
export { RelationType } from '@/sdk/define/fields/relation-type';
|
||||
export { validateFields } from '@/sdk/define/fields/validate-fields';
|
||||
|
||||
+2
-1
@@ -221,7 +221,8 @@ export class BackfillMessageThreadSubjectCommand extends ProvisionedWorkspaceCom
|
||||
universalIdentifier:
|
||||
STANDARD_OBJECTS.messageThread.fields.subject.universalIdentifier,
|
||||
},
|
||||
flatApplication: twentyStandardFlatApplication,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
objectMetadataUniversalIdentifier:
|
||||
messageThreadObjectMetadata.universalIdentifier,
|
||||
}),
|
||||
|
||||
+12
@@ -1,22 +1,34 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { WorkspaceIteratorModule } from 'src/database/commands/command-runners/workspace-iterator.module';
|
||||
import { AddWorkflowCoreSoftRefFieldCommand } from 'src/database/commands/upgrade-version-command/2-23/2-23-workspace-command-1784286706000-add-workflow-core-soft-ref-field.command';
|
||||
import { BackfillWorkflowCoreLinksCommand } from 'src/database/commands/upgrade-version-command/2-23/2-23-workspace-command-1784286707000-backfill-workflow-core-links.command';
|
||||
import { ReconcileSystemRelationFieldUniversalIdentifierCommand } from 'src/database/commands/upgrade-version-command/2-23/2-23-workspace-command-1784565136000-reconcile-system-relation-field-universal-identifier.command';
|
||||
import { UpgradePeopleDataLabsApplicationCommand } from 'src/database/commands/upgrade-version-command/2-23/2-23-workspace-command-1784565137000-upgrade-people-data-labs-application.command';
|
||||
import { ApplicationUpgradeModule } from 'src/engine/core-modules/application/application-upgrade/application-upgrade.module';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/workspace-migration-runner.module';
|
||||
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([FieldMetadataEntity, ApplicationEntity]),
|
||||
ApplicationModule,
|
||||
WorkspaceCacheModule,
|
||||
WorkspaceMigrationModule,
|
||||
WorkspaceMigrationRunnerModule,
|
||||
WorkspaceIteratorModule,
|
||||
ApplicationUpgradeModule,
|
||||
],
|
||||
providers: [
|
||||
AddWorkflowCoreSoftRefFieldCommand,
|
||||
BackfillWorkflowCoreLinksCommand,
|
||||
ReconcileSystemRelationFieldUniversalIdentifierCommand,
|
||||
UpgradePeopleDataLabsApplicationCommand,
|
||||
],
|
||||
})
|
||||
export class V2_23_UpgradeVersionCommandModule {}
|
||||
|
||||
+276
@@ -0,0 +1,276 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Command } from 'nest-commander';
|
||||
import { getSystemRelationFieldUniversalIdentifier } from 'twenty-shared/application';
|
||||
import {
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS,
|
||||
STANDARD_OBJECTS,
|
||||
} from 'twenty-shared/metadata';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { ProvisionedWorkspaceCommandRunner } from 'src/database/commands/command-runners/provisioned-workspace.command-runner';
|
||||
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||
import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspace.command-runner';
|
||||
import { RegisteredWorkspaceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-workspace-command.decorator';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
|
||||
import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util';
|
||||
import { getMetadataSerializedRelationNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-serialized-relation-names.util';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-migration/constant/standard-object-icons';
|
||||
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/services/workspace-migration-runner.service';
|
||||
|
||||
const REVERSE_SYSTEM_RELATION_FIELD_NAME_PREFIX = 'target';
|
||||
|
||||
// Every provisioning path of the default relations (legacy SDK manifest, legacy
|
||||
// API transpiler, twenty-standard) stamps the reverse morph field with the
|
||||
// engine-defined targetMorphId of its host standard object, while user-created
|
||||
// morph relations carry freshly generated morphIds. Matching on this morphId
|
||||
// (in addition to the name prefix) makes the reconciliation an exact
|
||||
// fingerprint and cannot hijack a user-authored `target*` morph field hosted
|
||||
// on one of the four standard relation objects.
|
||||
const TARGET_MORPH_ID_BY_DEFAULT_RELATION_OBJECT_UNIVERSAL_IDENTIFIER: Record<
|
||||
string,
|
||||
string
|
||||
> = Object.fromEntries(
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS.map((standardObjectNameSingular) => [
|
||||
STANDARD_OBJECTS[standardObjectNameSingular].universalIdentifier,
|
||||
STANDARD_OBJECTS[standardObjectNameSingular].morphIds.targetMorphId.morphId,
|
||||
]),
|
||||
);
|
||||
|
||||
type SystemRelationFieldUpdate = {
|
||||
id: string;
|
||||
update: Partial<
|
||||
Pick<
|
||||
FieldMetadataEntity,
|
||||
'universalIdentifier' | 'isSystemSideEffect' | 'label' | 'icon'
|
||||
>
|
||||
>;
|
||||
};
|
||||
|
||||
@RegisteredWorkspaceCommand('2.23.0', 1784565136000)
|
||||
@Command({
|
||||
name: 'upgrade:2-23:reconcile-system-relation-field-universal-identifier',
|
||||
description:
|
||||
'Reconcile the default relations (timelineActivity/attachment/noteTarget/taskTarget) with the engine convention, for standard and custom source objects alike. Both sides get the name-free deterministic universal identifier (host and relation target object identifiers, direction encoded by swapping them) and isSystemSideEffect: true; reverse morph fields additionally get the name-derived label/icon. An object rename becomes a lossless update and standard fields match custom ones, as if twenty-standard objects had been provisioned by the side-effect engine.',
|
||||
})
|
||||
export class ReconcileSystemRelationFieldUniversalIdentifierCommand extends ProvisionedWorkspaceCommandRunner {
|
||||
constructor(
|
||||
protected readonly workspaceIteratorService: WorkspaceIteratorService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
|
||||
@InjectRepository(FieldMetadataEntity)
|
||||
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
||||
) {
|
||||
super(workspaceIteratorService);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
const isDryRun = options.dryRun ?? false;
|
||||
|
||||
const { flatFieldMetadataMaps, flatObjectMetadataMaps } =
|
||||
await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatFieldMetadataMaps',
|
||||
'flatObjectMetadataMaps',
|
||||
]);
|
||||
|
||||
const systemRelationFieldUpdates: SystemRelationFieldUpdate[] = [];
|
||||
|
||||
for (const flatFieldMetadata of Object.values(
|
||||
flatFieldMetadataMaps.byUniversalIdentifier,
|
||||
)) {
|
||||
if (
|
||||
!isDefined(flatFieldMetadata) ||
|
||||
flatFieldMetadata.type !== FieldMetadataType.MORPH_RELATION ||
|
||||
!flatFieldMetadata.name.startsWith(
|
||||
REVERSE_SYSTEM_RELATION_FIELD_NAME_PREFIX,
|
||||
) ||
|
||||
!isDefined(flatFieldMetadata.relationTargetObjectMetadataId)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const hostFlatObjectMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
flatEntityId: flatFieldMetadata.objectMetadataId,
|
||||
});
|
||||
|
||||
if (!isDefined(hostFlatObjectMetadata)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const expectedTargetMorphId =
|
||||
TARGET_MORPH_ID_BY_DEFAULT_RELATION_OBJECT_UNIVERSAL_IDENTIFIER[
|
||||
hostFlatObjectMetadata.universalIdentifier
|
||||
];
|
||||
|
||||
if (
|
||||
!isDefined(expectedTargetMorphId) ||
|
||||
flatFieldMetadata.morphId !== expectedTargetMorphId
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const sourceFlatObjectMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
flatEntityId: flatFieldMetadata.relationTargetObjectMetadataId,
|
||||
});
|
||||
|
||||
if (!isDefined(sourceFlatObjectMetadata)) {
|
||||
this.logger.warn(
|
||||
`Missing source object for reverse relation field ${flatFieldMetadata.name} (${flatFieldMetadata.id}) in workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const derivedUniversalIdentifier =
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
sourceFlatObjectMetadata.applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier: hostFlatObjectMetadata.universalIdentifier,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
sourceFlatObjectMetadata.universalIdentifier,
|
||||
});
|
||||
// Name-derived label + host-object icon, matching the engine provisioner
|
||||
// convention already used for custom objects.
|
||||
const derivedLabel = capitalize(sourceFlatObjectMetadata.nameSingular);
|
||||
const derivedIcon =
|
||||
STANDARD_OBJECT_ICONS[
|
||||
hostFlatObjectMetadata.nameSingular as keyof typeof STANDARD_OBJECT_ICONS
|
||||
] ?? 'IconBuildingSkyscraper';
|
||||
|
||||
const update: SystemRelationFieldUpdate['update'] = {};
|
||||
|
||||
if (
|
||||
flatFieldMetadata.universalIdentifier !== derivedUniversalIdentifier
|
||||
) {
|
||||
update.universalIdentifier = derivedUniversalIdentifier;
|
||||
}
|
||||
if (!flatFieldMetadata.isSystemSideEffect) {
|
||||
update.isSystemSideEffect = true;
|
||||
}
|
||||
if (flatFieldMetadata.label !== derivedLabel) {
|
||||
update.label = derivedLabel;
|
||||
}
|
||||
if (flatFieldMetadata.icon !== derivedIcon) {
|
||||
update.icon = derivedIcon;
|
||||
}
|
||||
|
||||
if (Object.keys(update).length > 0) {
|
||||
systemRelationFieldUpdates.push({ id: flatFieldMetadata.id, update });
|
||||
}
|
||||
|
||||
// Both sides of a default relation are engine-owned, for standard and
|
||||
// custom source objects alike: the forward field on the source object
|
||||
// was provisioned alongside the reverse field (by the side-effect engine
|
||||
// for custom objects, by twenty-standard for standard ones), so it must
|
||||
// carry isSystemSideEffect and the same name-free deterministic
|
||||
// universal identifier as the reverse side, with host and relation
|
||||
// target swapped — matching what the create side-effect handler emits
|
||||
// for objects created post-2.23.
|
||||
const forwardFlatFieldMetadata = isDefined(
|
||||
flatFieldMetadata.relationTargetFieldMetadataId,
|
||||
)
|
||||
? findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
flatEntityId: flatFieldMetadata.relationTargetFieldMetadataId,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
if (!isDefined(forwardFlatFieldMetadata)) {
|
||||
this.logger.warn(
|
||||
`Missing forward field for reverse relation field ${flatFieldMetadata.name} (${flatFieldMetadata.id}) in workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const derivedForwardUniversalIdentifier =
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
sourceFlatObjectMetadata.applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier:
|
||||
sourceFlatObjectMetadata.universalIdentifier,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
hostFlatObjectMetadata.universalIdentifier,
|
||||
});
|
||||
|
||||
const forwardUpdate: SystemRelationFieldUpdate['update'] = {};
|
||||
|
||||
if (
|
||||
forwardFlatFieldMetadata.universalIdentifier !==
|
||||
derivedForwardUniversalIdentifier
|
||||
) {
|
||||
forwardUpdate.universalIdentifier = derivedForwardUniversalIdentifier;
|
||||
}
|
||||
if (!forwardFlatFieldMetadata.isSystemSideEffect) {
|
||||
forwardUpdate.isSystemSideEffect = true;
|
||||
}
|
||||
|
||||
if (Object.keys(forwardUpdate).length > 0) {
|
||||
systemRelationFieldUpdates.push({
|
||||
id: forwardFlatFieldMetadata.id,
|
||||
update: forwardUpdate,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (systemRelationFieldUpdates.length === 0) {
|
||||
this.logger.log(
|
||||
`No default-relation field to reconcile for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Reconciling ${systemRelationFieldUpdates.length} default-relation field(s) for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
if (isDryRun) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Single transaction per workspace: a partial backfill would leave old and
|
||||
// new universal identifiers coexisting, breaking the reconcile invariant
|
||||
// for the follow-up people-data-labs upgrade command.
|
||||
await this.fieldMetadataRepository.manager.transaction(
|
||||
async (entityManager) => {
|
||||
const transactionalFieldMetadataRepository =
|
||||
entityManager.getRepository(FieldMetadataEntity);
|
||||
|
||||
for (const { id, update } of systemRelationFieldUpdates) {
|
||||
await transactionalFieldMetadataRepository.update(
|
||||
{ id, workspaceId },
|
||||
update,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const fieldMetadataRelatedNames = [
|
||||
'fieldMetadata',
|
||||
...getMetadataRelatedMetadataNames('fieldMetadata'),
|
||||
...getMetadataSerializedRelationNames('fieldMetadata'),
|
||||
'index',
|
||||
] as const;
|
||||
const allFlatEntityMapsKeys = [
|
||||
...new Set(fieldMetadataRelatedNames.map(getMetadataFlatEntityMapsKey)),
|
||||
];
|
||||
|
||||
await this.workspaceMigrationRunnerService.invalidateCache({
|
||||
allFlatEntityMapsKeys,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
this.logger.log(
|
||||
`Reconciled ${systemRelationFieldUpdates.length} default-relation field(s) for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Command } from 'nest-commander';
|
||||
import * as semver from 'semver';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { ProvisionedWorkspaceCommandRunner } from 'src/database/commands/command-runners/provisioned-workspace.command-runner';
|
||||
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||
import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspace.command-runner';
|
||||
import { ApplicationUpgradeService } from 'src/engine/core-modules/application/application-upgrade/application-upgrade.service';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { RegisteredWorkspaceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-workspace-command.decorator';
|
||||
|
||||
// packages/twenty-apps/public/people-data-labs APPLICATION_UNIVERSAL_IDENTIFIER
|
||||
const PEOPLE_DATA_LABS_APPLICATION_UNIVERSAL_IDENTIFIER =
|
||||
'4a1178c1-3535-4a47-b592-231d3216b36f';
|
||||
|
||||
// First version whose views pin the re-derived name-free system relation
|
||||
// field universal identifiers, published ahead of the 2.23 release.
|
||||
const PEOPLE_DATA_LABS_TARGET_VERSION = '1.0.7';
|
||||
|
||||
// The people-data-labs views reference the person/company forward system
|
||||
// relation fields (noteTargets/taskTargets/attachments/timelineActivities) by
|
||||
// universal identifier. The 2.23 reconcile command re-derives those
|
||||
// identifiers name-free, so installed versions <= 1.0.6 hold dangling
|
||||
// references and any re-sync of the stored manifest would fail. Upgrading the
|
||||
// app right after the backfill closes that desync window. The command pins
|
||||
// the target version rather than resolving latest, so the upgrade is
|
||||
// deterministic and idempotent; workspaces already at or above it are left
|
||||
// untouched.
|
||||
@RegisteredWorkspaceCommand('2.23.0', 1784565137000)
|
||||
@Command({
|
||||
name: 'upgrade:2-23:upgrade-people-data-labs-application',
|
||||
description:
|
||||
'Upgrade the people-data-labs application to 1.0.7 right after the system relation field universal identifier backfill, so its views reference the re-derived name-free identifiers instead of the stale pre-2.23 ones. Workspaces already at or above 1.0.7 are left untouched.',
|
||||
})
|
||||
export class UpgradePeopleDataLabsApplicationCommand extends ProvisionedWorkspaceCommandRunner {
|
||||
constructor(
|
||||
protected readonly workspaceIteratorService: WorkspaceIteratorService,
|
||||
private readonly applicationUpgradeService: ApplicationUpgradeService,
|
||||
@InjectRepository(ApplicationEntity)
|
||||
private readonly applicationRepository: Repository<ApplicationEntity>,
|
||||
) {
|
||||
super(workspaceIteratorService);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
const isDryRun = options.dryRun ?? false;
|
||||
|
||||
const application = await this.applicationRepository.findOne({
|
||||
where: {
|
||||
workspaceId,
|
||||
universalIdentifier: PEOPLE_DATA_LABS_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
},
|
||||
relations: ['applicationRegistration'],
|
||||
});
|
||||
|
||||
if (!isDefined(application)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const applicationRegistration = application.applicationRegistration;
|
||||
|
||||
if (!isDefined(applicationRegistration)) {
|
||||
this.logger.warn(
|
||||
`people-data-labs is installed but has no application registration, skipping upgrade for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const installedVersion = semver.valid(application.version);
|
||||
|
||||
if (
|
||||
isDefined(installedVersion) &&
|
||||
semver.gte(installedVersion, PEOPLE_DATA_LABS_TARGET_VERSION)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDryRun) {
|
||||
this.logger.log(
|
||||
`[DRY RUN] Would upgrade people-data-labs from ${application.version} to ${PEOPLE_DATA_LABS_TARGET_VERSION} for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.applicationUpgradeService.upgradeApplication({
|
||||
appRegistrationId: applicationRegistration.id,
|
||||
targetVersion: PEOPLE_DATA_LABS_TARGET_VERSION,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
this.logger.log(
|
||||
`Upgraded people-data-labs from ${application.version} to ${PEOPLE_DATA_LABS_TARGET_VERSION} for workspace ${workspaceId}`,
|
||||
);
|
||||
} catch (error) {
|
||||
// Non-fatal: the app stays functional at runtime (view fields reference
|
||||
// fields by database id); only a manifest re-sync of the stale version
|
||||
// would fail, and the upgrade can be retried from the UI.
|
||||
this.logger.error(
|
||||
`Failed to upgrade people-data-labs for workspace ${workspaceId}: ${error}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -106,6 +106,23 @@ describe('fromFieldManifestToUniversalFlatFieldMetadata', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('system flags', () => {
|
||||
it('never derives isSystem or isSystemSideEffect, even for reserved system field names', () => {
|
||||
const result = fromFieldManifestToUniversalFlatFieldMetadata({
|
||||
fieldManifest: buildFieldManifest({
|
||||
type: FieldMetadataType.DATE_TIME,
|
||||
name: 'createdAt',
|
||||
label: 'Creation date',
|
||||
}),
|
||||
applicationUniversalIdentifier: APP_UID,
|
||||
now: NOW,
|
||||
});
|
||||
|
||||
expect(result.isSystem).toBe(false);
|
||||
expect(result.isSystemSideEffect).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isUIEditable', () => {
|
||||
it('defaults to true when omitted from the manifest', () => {
|
||||
const result = fromFieldManifestToUniversalFlatFieldMetadata({
|
||||
|
||||
+2
-7
@@ -12,7 +12,6 @@ import { type CompositeFieldMetadataType } from 'src/engine/metadata-modules/fie
|
||||
import { generateDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/generate-default-value';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
import { nullifyEmptyCompositeDefaultValue } from 'src/engine/metadata-modules/flat-field-metadata/utils/nullify-empty-composite-default-value.util';
|
||||
import { PARTIAL_SYSTEM_FLAT_FIELD_METADATAS } from 'src/engine/metadata-modules/object-metadata/constants/partial-system-flat-field-metadatas.constant';
|
||||
import { isMorphOrRelationFieldMetadataType } from 'src/engine/utils/is-morph-or-relation-field-metadata-type.util';
|
||||
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
|
||||
|
||||
@@ -68,9 +67,6 @@ export const fromFieldManifestToUniversalFlatFieldMetadata = ({
|
||||
relationTargetObjectMetadataUniversalIdentifier,
|
||||
} = getRelationTargetUniversalIdentifiers(fieldManifest);
|
||||
|
||||
// TODO: generate system fields server-side from the object manifest
|
||||
// so the converter doesn't need to re-normalize composite defaults
|
||||
// that the SDK couldn't have known the canonical shape of.
|
||||
const rawDefaultValue =
|
||||
fieldManifest.defaultValue ?? generateDefaultValue(fieldManifest.type);
|
||||
const defaultValue = isCompositeFieldMetadataType(fieldManifest.type)
|
||||
@@ -93,9 +89,8 @@ export const fromFieldManifestToUniversalFlatFieldMetadata = ({
|
||||
defaultValue,
|
||||
universalSettings: fieldManifest.universalSettings ?? null,
|
||||
isActive: true,
|
||||
isSystem: fieldManifest.name in PARTIAL_SYSTEM_FLAT_FIELD_METADATAS,
|
||||
isSystemSideEffect:
|
||||
fieldManifest.name in PARTIAL_SYSTEM_FLAT_FIELD_METADATAS,
|
||||
isSystem: false,
|
||||
isSystemSideEffect: false,
|
||||
isUIEditable: fieldManifest.isUIEditable ?? true,
|
||||
isNullable: fieldManifest.isNullable ?? true,
|
||||
isUnique: fieldManifest.isUnique ?? false,
|
||||
|
||||
+2
-2
@@ -8,14 +8,14 @@ import { FileStorageModule } from 'src/engine/core-modules/file-storage/file-sto
|
||||
import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity';
|
||||
import { SecureHttpClientModule } from 'src/engine/core-modules/secure-http-client/secure-http-client.module';
|
||||
import { TwentyConfigModule } from 'src/engine/core-modules/twenty-config/twenty-config.module';
|
||||
import { UpgradeModule } from 'src/engine/core-modules/upgrade/upgrade.module';
|
||||
import { UpgradeStatusModule } from 'src/engine/core-modules/upgrade/upgrade-status.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
FileStorageModule,
|
||||
SecureHttpClientModule,
|
||||
TwentyConfigModule,
|
||||
UpgradeModule,
|
||||
UpgradeStatusModule,
|
||||
TypeOrmModule.forFeature([FileEntity, ApplicationEntity]),
|
||||
],
|
||||
providers: [
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { DiscoveryModule } from '@nestjs/core';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { CoreEntityCacheModule } from 'src/engine/core-entity-cache/core-entity-cache.module';
|
||||
import { UpgradeCommandRegistryService } from 'src/engine/core-modules/upgrade/services/upgrade-command-registry.service';
|
||||
import { UpgradeMigrationService } from 'src/engine/core-modules/upgrade/services/upgrade-migration.service';
|
||||
import { UpgradeSequenceReaderService } from 'src/engine/core-modules/upgrade/services/upgrade-sequence-reader.service';
|
||||
import { UpgradeStatusCacheService } from 'src/engine/core-modules/upgrade/services/upgrade-status-cache.service';
|
||||
import { UpgradeStatusService } from 'src/engine/core-modules/upgrade/services/upgrade-status.service';
|
||||
import { UpgradeMigrationEntity } from 'src/engine/core-modules/upgrade/upgrade-migration.entity';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
CoreEntityCacheModule,
|
||||
DiscoveryModule,
|
||||
TypeOrmModule.forFeature([UpgradeMigrationEntity, WorkspaceEntity]),
|
||||
],
|
||||
providers: [
|
||||
UpgradeCommandRegistryService,
|
||||
UpgradeMigrationService,
|
||||
UpgradeSequenceReaderService,
|
||||
UpgradeStatusCacheService,
|
||||
UpgradeStatusService,
|
||||
],
|
||||
exports: [
|
||||
UpgradeCommandRegistryService,
|
||||
UpgradeMigrationService,
|
||||
UpgradeSequenceReaderService,
|
||||
UpgradeStatusCacheService,
|
||||
UpgradeStatusService,
|
||||
],
|
||||
})
|
||||
export class UpgradeStatusModule {}
|
||||
@@ -1,59 +1,39 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { DiscoveryModule } from '@nestjs/core';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { WorkspaceIteratorModule } from 'src/database/commands/command-runners/workspace-iterator.module';
|
||||
import { InstanceCommandProviderModule } from 'src/database/commands/upgrade-version-command/instance-command-provider.module';
|
||||
import { WorkspaceCommandProviderModule } from 'src/database/commands/upgrade-version-command/workspace-command-provider.module';
|
||||
import { CoreEntityCacheModule } from 'src/engine/core-entity-cache/core-entity-cache.module';
|
||||
import { MetricsModule } from 'src/engine/core-modules/metrics/metrics.module';
|
||||
import { InstanceCommandRunnerService } from 'src/engine/core-modules/upgrade/services/instance-command-runner.service';
|
||||
import { UpgradeCommandRegistryService } from 'src/engine/core-modules/upgrade/services/upgrade-command-registry.service';
|
||||
import { UpgradeMigrationService } from 'src/engine/core-modules/upgrade/services/upgrade-migration.service';
|
||||
import { UpgradeSequenceReaderService } from 'src/engine/core-modules/upgrade/services/upgrade-sequence-reader.service';
|
||||
import { UpgradeSequenceRunnerService } from 'src/engine/core-modules/upgrade/services/upgrade-sequence-runner.service';
|
||||
import { UpgradeStatusCacheService } from 'src/engine/core-modules/upgrade/services/upgrade-status-cache.service';
|
||||
import { UpgradeStatusService } from 'src/engine/core-modules/upgrade/services/upgrade-status.service';
|
||||
import { WorkspaceCommandRunnerService } from 'src/engine/core-modules/upgrade/services/workspace-command-runner.service';
|
||||
import { UpgradeGaugeService } from 'src/engine/core-modules/upgrade/upgrade-gauge.service';
|
||||
import { UpgradeMigrationEntity } from 'src/engine/core-modules/upgrade/upgrade-migration.entity';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { UpgradeStatusModule } from 'src/engine/core-modules/upgrade/upgrade-status.module';
|
||||
import { UpgradeAwareEntityMetadataAdapter } from 'src/engine/twenty-orm/upgrade-aware/upgrade-aware-entity-metadata.adapter';
|
||||
import { WorkspaceVersionModule } from 'src/engine/workspace-manager/workspace-version/workspace-version.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
CoreEntityCacheModule,
|
||||
DiscoveryModule,
|
||||
InstanceCommandProviderModule,
|
||||
MetricsModule,
|
||||
UpgradeStatusModule,
|
||||
WorkspaceCommandProviderModule,
|
||||
WorkspaceIteratorModule,
|
||||
WorkspaceVersionModule,
|
||||
TypeOrmModule.forFeature([UpgradeMigrationEntity, WorkspaceEntity]),
|
||||
],
|
||||
providers: [
|
||||
UpgradeMigrationService,
|
||||
InstanceCommandRunnerService,
|
||||
WorkspaceCommandRunnerService,
|
||||
UpgradeCommandRegistryService,
|
||||
UpgradeAwareEntityMetadataAdapter,
|
||||
UpgradeSequenceReaderService,
|
||||
UpgradeSequenceRunnerService,
|
||||
UpgradeStatusService,
|
||||
UpgradeStatusCacheService,
|
||||
UpgradeGaugeService,
|
||||
],
|
||||
exports: [
|
||||
UpgradeMigrationService,
|
||||
UpgradeStatusModule,
|
||||
InstanceCommandRunnerService,
|
||||
WorkspaceCommandRunnerService,
|
||||
UpgradeCommandRegistryService,
|
||||
UpgradeAwareEntityMetadataAdapter,
|
||||
UpgradeSequenceReaderService,
|
||||
UpgradeSequenceRunnerService,
|
||||
UpgradeStatusService,
|
||||
UpgradeStatusCacheService,
|
||||
],
|
||||
})
|
||||
export class UpgradeModule {}
|
||||
|
||||
+4
@@ -27,3 +27,7 @@ export const FLAT_FIELD_METADATA_EDITABLE_PROPERTIES = {
|
||||
'standard' | 'custom',
|
||||
MetadataEntityPropertyName<'fieldMetadata'>[]
|
||||
>;
|
||||
|
||||
export const FLAT_FIELD_METADATA_SYSTEM_SIDE_EFFECT_EDITABLE_PROPERTIES = [
|
||||
'isActive',
|
||||
] as const satisfies MetadataEntityPropertyName<'fieldMetadata'>[];
|
||||
|
||||
+14
-7
@@ -70,7 +70,8 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'petId',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
applicationUniversalIdentifier:
|
||||
MOCK_FLAT_APPLICATION.universalIdentifier,
|
||||
createFieldInput: {
|
||||
name: 'pets',
|
||||
label: 'Pets',
|
||||
@@ -104,7 +105,8 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'petId',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
applicationUniversalIdentifier:
|
||||
MOCK_FLAT_APPLICATION.universalIdentifier,
|
||||
createFieldInput: {
|
||||
name: 'pets',
|
||||
label: 'Pets',
|
||||
@@ -138,7 +140,8 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'petId',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
applicationUniversalIdentifier:
|
||||
MOCK_FLAT_APPLICATION.universalIdentifier,
|
||||
createFieldInput: {
|
||||
name: 'pets',
|
||||
label: 'Pets',
|
||||
@@ -172,7 +175,8 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'targetPetId',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
applicationUniversalIdentifier:
|
||||
MOCK_FLAT_APPLICATION.universalIdentifier,
|
||||
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
|
||||
createFieldInput: {
|
||||
name: 'targetPet',
|
||||
@@ -207,7 +211,8 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'targetPetId',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
applicationUniversalIdentifier:
|
||||
MOCK_FLAT_APPLICATION.universalIdentifier,
|
||||
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
|
||||
createFieldInput: {
|
||||
name: 'targetPet',
|
||||
@@ -242,7 +247,8 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.MORPH_RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'targetPetId',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
applicationUniversalIdentifier:
|
||||
MOCK_FLAT_APPLICATION.universalIdentifier,
|
||||
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
|
||||
createFieldInput: {
|
||||
name: 'targetPet',
|
||||
@@ -353,7 +359,8 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'petId',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
applicationUniversalIdentifier:
|
||||
MOCK_FLAT_APPLICATION.universalIdentifier,
|
||||
createFieldInput: {
|
||||
name: 'pets',
|
||||
label: 'Pets',
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ export const computeFlatFieldToUpdateFromMorphRelationUpdatePayload = ({
|
||||
sourceFlatObjectMetadata: sourceObjectMetadata,
|
||||
targetFlatObjectMetadata: newTargetObjectMetadata,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
sourceFlatObjectMetadataJoinColumnName:
|
||||
computeMorphOrRelationFieldJoinColumnName({
|
||||
name: computedMorphName,
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
|
||||
const commonFlatFieldMetadata = getDefaultFlatFieldMetadata({
|
||||
createFieldInput,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
objectMetadataUniversalIdentifier:
|
||||
parentFlatObjectMetadata.universalIdentifier,
|
||||
});
|
||||
|
||||
+7
@@ -66,6 +66,13 @@ export const fromDeleteFieldInputToFlatFieldMetadatasToDelete = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (flatFieldMetadataToDelete.isSystemSideEffect === true) {
|
||||
throw new FieldMetadataException(
|
||||
`Cannot delete system-managed field "${flatFieldMetadataToDelete.name}"`,
|
||||
FieldMetadataExceptionCode.FIELD_MUTATION_NOT_ALLOWED,
|
||||
);
|
||||
}
|
||||
|
||||
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: flatFieldMetadataToDelete.objectMetadataId,
|
||||
flatEntityMaps: existingFlatObjectMetadataMaps,
|
||||
|
||||
+1
-1
@@ -110,7 +110,7 @@ export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
targetFlatObjectMetadata,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
morphId,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
junctionTargetFlatFieldMetadata,
|
||||
});
|
||||
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ export const fromRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
sourceFlatObjectMetadata,
|
||||
targetFlatObjectMetadata,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
junctionTargetFlatFieldMetadata,
|
||||
});
|
||||
|
||||
|
||||
+9
-6
@@ -7,10 +7,9 @@ import {
|
||||
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { type MorphOrRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/morph-or-relation-field-metadata-type.type';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { generateIndexForFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-index-for-flat-field-metadata.util';
|
||||
import { getDefaultFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util';
|
||||
@@ -59,11 +58,12 @@ type GenerateMorphOrRelationFlatFieldMetadataPairArgs = {
|
||||
Pick<CreateFieldInput, 'relationCreationPayload' | 'type' | 'name'>
|
||||
> & { type: MorphOrRelationFieldMetadataType };
|
||||
morphId?: string | null;
|
||||
flatApplication: FlatApplication;
|
||||
applicationUniversalIdentifier: string;
|
||||
targetFieldName?: string;
|
||||
junctionTargetFlatFieldMetadata?: FlatFieldMetadata;
|
||||
sourceFieldUniversalIdentifier?: string;
|
||||
targetFieldUniversalIdentifier?: string;
|
||||
isSystemSideEffect?: boolean;
|
||||
};
|
||||
|
||||
export type SourceTargetMorphOrRelationFlatFieldAndFlatIndex = {
|
||||
@@ -76,13 +76,14 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
|
||||
sourceFlatObjectMetadata,
|
||||
targetFlatObjectMetadata,
|
||||
targetFlatFieldMetadataType,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
sourceFlatObjectMetadataJoinColumnName,
|
||||
morphId = null,
|
||||
targetFieldName,
|
||||
junctionTargetFlatFieldMetadata,
|
||||
sourceFieldUniversalIdentifier: providedSourceFieldUniversalIdentifier,
|
||||
targetFieldUniversalIdentifier: providedTargetFieldUniversalIdentifier,
|
||||
isSystemSideEffect = false,
|
||||
}: GenerateMorphOrRelationFlatFieldMetadataPairArgs): SourceTargetMorphOrRelationFlatFieldAndFlatIndex => {
|
||||
const sourceFlatFieldMetadataType = createFieldInput.type;
|
||||
|
||||
@@ -119,9 +120,10 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
|
||||
createFieldInput.universalIdentifier ??
|
||||
sourceFieldUniversalIdentifier,
|
||||
},
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier:
|
||||
sourceFlatObjectMetadata.universalIdentifier,
|
||||
isSystemSideEffect,
|
||||
}),
|
||||
morphId:
|
||||
sourceFlatFieldMetadataType === FieldMetadataType.MORPH_RELATION
|
||||
@@ -175,9 +177,10 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
|
||||
...targetCreateFieldInput,
|
||||
universalIdentifier: targetFieldUniversalIdentifier,
|
||||
},
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier:
|
||||
targetFlatObjectMetadata.universalIdentifier,
|
||||
isSystemSideEffect,
|
||||
}),
|
||||
morphId:
|
||||
targetFlatFieldMetadataType === FieldMetadataType.MORPH_RELATION
|
||||
|
||||
+6
-5
@@ -4,7 +4,6 @@ import {
|
||||
} from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { generateDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/generate-default-value';
|
||||
import { generateNullable } from 'src/engine/metadata-modules/field-metadata/utils/generate-nullable';
|
||||
@@ -14,13 +13,15 @@ import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/wo
|
||||
|
||||
type GetDefaultFlatFieldMetadataArgs = {
|
||||
createFieldInput: Omit<CreateFieldInput, 'workspaceId' | 'objectMetadataId'>;
|
||||
flatApplication: FlatApplication;
|
||||
applicationUniversalIdentifier: string;
|
||||
objectMetadataUniversalIdentifier: string;
|
||||
isSystemSideEffect?: boolean;
|
||||
};
|
||||
export const getDefaultFlatFieldMetadata = ({
|
||||
createFieldInput,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
isSystemSideEffect = false,
|
||||
}: GetDefaultFlatFieldMetadataArgs) => {
|
||||
const { defaultValue, settings } = extractAndSanitizeObjectStringFields(
|
||||
createFieldInput,
|
||||
@@ -41,7 +42,7 @@ export const getDefaultFlatFieldMetadata = ({
|
||||
createFieldInput.isRemoteCreation,
|
||||
),
|
||||
isSystem: createFieldInput.isSystem ?? false,
|
||||
isSystemSideEffect: false,
|
||||
isSystemSideEffect,
|
||||
isUnique: createFieldInput.isUnique ?? false,
|
||||
label: createFieldInput.label,
|
||||
name: createFieldInput.name,
|
||||
@@ -65,7 +66,7 @@ export const getDefaultFlatFieldMetadata = ({
|
||||
? !createFieldInput.isUIReadOnly
|
||||
: true),
|
||||
morphId: null,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
|
||||
+26
-2
@@ -9,11 +9,14 @@ import {
|
||||
FieldMetadataException,
|
||||
FieldMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
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 {
|
||||
FLAT_FIELD_METADATA_EDITABLE_PROPERTIES,
|
||||
FLAT_FIELD_METADATA_SYSTEM_SIDE_EFFECT_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';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
import { nullifyEmptyCompositeDefaultValue } from 'src/engine/metadata-modules/flat-field-metadata/utils/nullify-empty-composite-default-value.util';
|
||||
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';
|
||||
@@ -39,6 +42,27 @@ export const sanitizeRawUpdateFieldInput = ({
|
||||
],
|
||||
);
|
||||
|
||||
if (existingFlatFieldMetadata.isSystemSideEffect === true && !isSystemBuild) {
|
||||
const forbiddenUpdatedProperties = [
|
||||
...Object.keys(updatedEditableFieldProperties),
|
||||
...(isDefined(rawUpdateFieldInput.morphRelationsUpdatePayload)
|
||||
? ['morphRelationsUpdatePayload']
|
||||
: []),
|
||||
].filter(
|
||||
(property) =>
|
||||
!FLAT_FIELD_METADATA_SYSTEM_SIDE_EFFECT_EDITABLE_PROPERTIES.includes(
|
||||
property as (typeof FLAT_FIELD_METADATA_SYSTEM_SIDE_EFFECT_EDITABLE_PROPERTIES)[number],
|
||||
),
|
||||
);
|
||||
|
||||
if (forbiddenUpdatedProperties.length > 0) {
|
||||
throw new FieldMetadataException(
|
||||
`Cannot edit system-managed field "${existingFlatFieldMetadata.name}" properties: ${forbiddenUpdatedProperties.join(', ')}`,
|
||||
FieldMetadataExceptionCode.FIELD_MUTATION_NOT_ALLOWED,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
updatedEditableFieldProperties.options = !isDefined(
|
||||
updatedEditableFieldProperties.options,
|
||||
)
|
||||
|
||||
+3
-23
@@ -7,30 +7,24 @@ import {
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { type CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/create-object.input';
|
||||
import { buildNameFlatFieldMetadataForCustomObject } from 'src/engine/metadata-modules/object-metadata/utils/build-name-flat-field-metadata-for-custom-object.util';
|
||||
import { buildDefaultRelationFlatFieldMetadatasForCustomObject } from 'src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util';
|
||||
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
|
||||
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
|
||||
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
|
||||
|
||||
type FromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreateArgs =
|
||||
{
|
||||
createObjectInput: CreateObjectInput;
|
||||
flatApplication: FlatApplication;
|
||||
} & Pick<AllFlatEntityMaps, 'flatObjectMetadataMaps'>;
|
||||
};
|
||||
|
||||
export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreate =
|
||||
({
|
||||
createObjectInput: rawCreateObjectInput,
|
||||
flatApplication,
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
}: FromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreateArgs): {
|
||||
flatObjectMetadataToCreate: UniversalFlatObjectMetadata & { id: string };
|
||||
flatFieldMetadataToCreateOnObject: UniversalFlatFieldMetadata[];
|
||||
relationTargetFlatFieldMetadataToCreate: UniversalFlatFieldMetadata[];
|
||||
flatIndexMetadataToCreate: UniversalFlatIndexMetadata[];
|
||||
} => {
|
||||
const createObjectInput =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
@@ -105,25 +99,11 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
standardSourceFlatFieldMetadatas,
|
||||
standardTargetFlatFieldMetadatas,
|
||||
standardTargetFlatIndexMetadatas,
|
||||
} = buildDefaultRelationFlatFieldMetadatasForCustomObject({
|
||||
existingFlatObjectMetadataMaps,
|
||||
sourceFlatObjectMetadata: universalFlatObjectMetadataToCreate,
|
||||
flatApplication,
|
||||
});
|
||||
|
||||
const flatFieldMetadataToCreateOnObject: UniversalFlatFieldMetadata[] = [
|
||||
...(isDefined(nameFlatFieldMetadata) ? [nameFlatFieldMetadata] : []),
|
||||
...standardSourceFlatFieldMetadatas,
|
||||
];
|
||||
const flatFieldMetadataToCreateOnObject: UniversalFlatFieldMetadata[] =
|
||||
isDefined(nameFlatFieldMetadata) ? [nameFlatFieldMetadata] : [];
|
||||
|
||||
return {
|
||||
flatObjectMetadataToCreate: universalFlatObjectMetadataToCreate,
|
||||
flatFieldMetadataToCreateOnObject,
|
||||
relationTargetFlatFieldMetadataToCreate: standardTargetFlatFieldMetadatas,
|
||||
flatIndexMetadataToCreate: standardTargetFlatIndexMetadatas,
|
||||
};
|
||||
};
|
||||
|
||||
+8
@@ -59,6 +59,10 @@ export const fromDeleteObjectInputToFlatFieldMetadatasToDelete = ({
|
||||
});
|
||||
const flatFieldMetadatasToDelete = objectFlatFieldMetadatas.flatMap(
|
||||
(flatFieldMetadata) => {
|
||||
if (flatFieldMetadata.isSystemSideEffect === true) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (
|
||||
isMorphOrRelationFlatFieldMetadata(flatFieldMetadata) &&
|
||||
flatFieldMetadata.relationTargetObjectMetadataId !==
|
||||
@@ -87,6 +91,10 @@ export const fromDeleteObjectInputToFlatFieldMetadatasToDelete = ({
|
||||
).filter(
|
||||
(flatIndex): flatIndex is FlatIndexMetadata =>
|
||||
isDefined(flatIndex) &&
|
||||
!(
|
||||
flatIndex.isSystemSideEffect === true &&
|
||||
flatIndex.objectMetadataId === flatObjectMetadataToDelete.id
|
||||
) &&
|
||||
(flatIndex.objectMetadataId === flatObjectMetadataToDelete.id ||
|
||||
flatIndex.flatIndexFieldMetadatas.some((flatIndexField) =>
|
||||
fieldIdsToDelete.has(flatIndexField.fieldMetadataId),
|
||||
|
||||
+1
@@ -53,6 +53,7 @@ export const handleFlatObjectMetadataUpdateSideEffect = ({
|
||||
toFlatObjectMetadata,
|
||||
flatObjectMetadataMaps,
|
||||
flatIndexMaps,
|
||||
systemSideEffectMorphFieldsOnly: false,
|
||||
})
|
||||
: {
|
||||
morphRelatedFlatIndexesToUpdate: [],
|
||||
|
||||
+16
-2
@@ -3,6 +3,7 @@ import {
|
||||
type FieldMetadataType,
|
||||
type FromTo,
|
||||
} from 'twenty-shared/types';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { computeMorphRelationFlatFieldName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-relation-flat-field-name.util';
|
||||
@@ -52,9 +53,15 @@ const updateMorphFlatFieldName = ({
|
||||
})
|
||||
: undefined;
|
||||
|
||||
const newLabel =
|
||||
fromMorphFlatFieldMetadata.isSystemSideEffect === true
|
||||
? capitalize(toRelationTargetFlatObjectMetadata.nameSingular)
|
||||
: fromMorphFlatFieldMetadata.label;
|
||||
|
||||
return {
|
||||
...fromMorphFlatFieldMetadata,
|
||||
name: newMorphFieldName,
|
||||
label: newLabel,
|
||||
universalSettings: {
|
||||
...fromMorphFlatFieldMetadata.universalSettings,
|
||||
joinColumnName: newJoinColumnName,
|
||||
@@ -69,7 +76,9 @@ type RenameRelatedMorphFieldOnObjectNamesUpdateArgs = FromTo<
|
||||
Pick<
|
||||
AllFlatEntityMaps,
|
||||
'flatFieldMetadataMaps' | 'flatObjectMetadataMaps' | 'flatIndexMaps'
|
||||
>;
|
||||
> & {
|
||||
systemSideEffectMorphFieldsOnly: boolean;
|
||||
};
|
||||
|
||||
type RenameRelatedMorphFieldOnObjectNamesUpdateReturnType = {
|
||||
morphFlatFieldMetadatasToUpdate: UniversalFlatFieldMetadata<FieldMetadataType.MORPH_RELATION>[];
|
||||
@@ -81,6 +90,7 @@ export const renameRelatedMorphFieldOnObjectNamesUpdate = ({
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatIndexMaps,
|
||||
systemSideEffectMorphFieldsOnly,
|
||||
}: RenameRelatedMorphFieldOnObjectNamesUpdateArgs): RenameRelatedMorphFieldOnObjectNamesUpdateReturnType => {
|
||||
const objectFlatFieldMetadatas =
|
||||
findManyFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
@@ -92,7 +102,11 @@ export const renameRelatedMorphFieldOnObjectNamesUpdate = ({
|
||||
getFlatObjectMetadataTargetMorphRelationFlatFieldMetadatasOrThrow({
|
||||
flatFieldMetadataMaps,
|
||||
objectFlatFieldMetadatas,
|
||||
});
|
||||
}).filter(
|
||||
(morphFlatFieldMetadata) =>
|
||||
(morphFlatFieldMetadata.isSystemSideEffect === true) ===
|
||||
systemSideEffectMorphFieldsOnly,
|
||||
);
|
||||
|
||||
const initialAccumulator: RenameRelatedMorphFieldOnObjectNamesUpdateReturnType =
|
||||
{
|
||||
|
||||
+4
@@ -7,6 +7,8 @@ import { FieldUniqueBackingIndexOnUpdateSideEffectHandlerService } from 'src/eng
|
||||
import { ObjectSearchVectorOnCreateSideEffectHandlerService } from 'src/engine/metadata-modules/metadata-side-effect/handlers/object-metadata/services/object-search-vector-on-create-side-effect-handler.service';
|
||||
import { ObjectSearchVectorOnUpdateSideEffectHandlerService } from 'src/engine/metadata-modules/metadata-side-effect/handlers/object-metadata/services/object-search-vector-on-update-side-effect-handler.service';
|
||||
import { ObjectSystemFieldsOnCreateSideEffectHandlerService } from 'src/engine/metadata-modules/metadata-side-effect/handlers/object-metadata/services/object-system-fields-on-create-side-effect-handler.service';
|
||||
import { ObjectSystemRelationsOnCreateSideEffectHandlerService } from 'src/engine/metadata-modules/metadata-side-effect/handlers/object-metadata/services/object-system-relations-on-create-side-effect-handler.service';
|
||||
import { ObjectSystemRelationsOnUpdateSideEffectHandlerService } from 'src/engine/metadata-modules/metadata-side-effect/handlers/object-metadata/services/object-system-relations-on-update-side-effect-handler.service';
|
||||
import { ObjectSystemSideEffectsOnDeleteSideEffectHandlerService } from 'src/engine/metadata-modules/metadata-side-effect/handlers/object-metadata/services/object-system-side-effects-on-delete-side-effect-handler.service';
|
||||
|
||||
@Module({
|
||||
@@ -16,6 +18,8 @@ import { ObjectSystemSideEffectsOnDeleteSideEffectHandlerService } from 'src/eng
|
||||
FieldUniqueBackingIndexOnDeleteSideEffectHandlerService,
|
||||
FieldSearchFieldMetadataOnDeleteSideEffectHandlerService,
|
||||
ObjectSystemFieldsOnCreateSideEffectHandlerService,
|
||||
ObjectSystemRelationsOnCreateSideEffectHandlerService,
|
||||
ObjectSystemRelationsOnUpdateSideEffectHandlerService,
|
||||
ObjectSearchVectorOnCreateSideEffectHandlerService,
|
||||
ObjectSearchVectorOnUpdateSideEffectHandlerService,
|
||||
ObjectSystemSideEffectsOnDeleteSideEffectHandlerService,
|
||||
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
import { getSystemRelationFieldUniversalIdentifier } from 'twenty-shared/application';
|
||||
import {
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS,
|
||||
STANDARD_OBJECTS,
|
||||
} from 'twenty-shared/metadata';
|
||||
|
||||
import { type AllFlatEntityOperationRecordByMetadataName } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-operation-record-by-metadata-name.type';
|
||||
import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock';
|
||||
import { type BuildSideEffectsArgs } from 'src/engine/metadata-modules/metadata-side-effect/interfaces/base-metadata-side-effect-handler.service';
|
||||
import { ObjectSystemRelationsOnCreateSideEffectHandlerService } from 'src/engine/metadata-modules/metadata-side-effect/handlers/object-metadata/services/object-system-relations-on-create-side-effect-handler.service';
|
||||
|
||||
const APPLICATION_UNIVERSAL_IDENTIFIER = 'a1a2a3a4-a5a6-4000-8000-000000000001';
|
||||
const SOURCE_OBJECT_UNIVERSAL_IDENTIFIER =
|
||||
'b1b2b3b4-b5b6-4000-8000-000000000001';
|
||||
|
||||
const NAME_PLURAL_BY_STANDARD_OBJECT_NAME_SINGULAR: Record<string, string> = {
|
||||
timelineActivity: 'timelineActivities',
|
||||
attachment: 'attachments',
|
||||
noteTarget: 'noteTargets',
|
||||
taskTarget: 'taskTargets',
|
||||
};
|
||||
|
||||
// The handler resolves the standard relation objects by their pinned standard
|
||||
// universal identifiers, so the mocks must carry them.
|
||||
const buildStandardTargetFlatObjectMetadatas = () =>
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS.map((nameSingular) =>
|
||||
getFlatObjectMetadataMock({
|
||||
universalIdentifier: STANDARD_OBJECTS[nameSingular].universalIdentifier,
|
||||
nameSingular,
|
||||
namePlural: NAME_PLURAL_BY_STANDARD_OBJECT_NAME_SINGULAR[nameSingular],
|
||||
labelSingular: nameSingular,
|
||||
labelPlural: NAME_PLURAL_BY_STANDARD_OBJECT_NAME_SINGULAR[nameSingular],
|
||||
}),
|
||||
);
|
||||
|
||||
const SOURCE_FLAT_OBJECT_METADATA = getFlatObjectMetadataMock({
|
||||
universalIdentifier: SOURCE_OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
nameSingular: 'rocket',
|
||||
namePlural: 'rockets',
|
||||
labelSingular: 'Rocket',
|
||||
labelPlural: 'Rockets',
|
||||
});
|
||||
|
||||
const buildArgs = ({
|
||||
standardTargetFlatObjectMetadatas = buildStandardTargetFlatObjectMetadatas(),
|
||||
callerFieldMetadataToCreateByUniversalIdentifier = {},
|
||||
existingFieldMetadataByUniversalIdentifier = {},
|
||||
}: {
|
||||
standardTargetFlatObjectMetadatas?: ReturnType<
|
||||
typeof buildStandardTargetFlatObjectMetadatas
|
||||
>;
|
||||
callerFieldMetadataToCreateByUniversalIdentifier?: Record<string, unknown>;
|
||||
existingFieldMetadataByUniversalIdentifier?: Record<string, unknown>;
|
||||
}): BuildSideEffectsArgs<'objectMetadata'> => {
|
||||
const objectByUniversalIdentifier: Record<string, unknown> = {};
|
||||
|
||||
for (const flatObjectMetadata of standardTargetFlatObjectMetadatas) {
|
||||
objectByUniversalIdentifier[flatObjectMetadata.universalIdentifier] =
|
||||
flatObjectMetadata;
|
||||
}
|
||||
|
||||
return {
|
||||
flatEntity: SOURCE_FLAT_OBJECT_METADATA,
|
||||
allFlatEntityOperationRecordByMetadataName: {
|
||||
fieldMetadata: {
|
||||
flatEntityToCreate: callerFieldMetadataToCreateByUniversalIdentifier,
|
||||
},
|
||||
} as unknown as AllFlatEntityOperationRecordByMetadataName,
|
||||
relatedFlatEntityMaps: {
|
||||
flatObjectMetadataMaps: {
|
||||
byUniversalIdentifier: objectByUniversalIdentifier,
|
||||
},
|
||||
flatFieldMetadataMaps: {
|
||||
byUniversalIdentifier: existingFieldMetadataByUniversalIdentifier,
|
||||
},
|
||||
},
|
||||
context: {},
|
||||
} as unknown as BuildSideEffectsArgs<'objectMetadata'>;
|
||||
};
|
||||
|
||||
describe('ObjectSystemRelationsOnCreateSideEffectHandlerService', () => {
|
||||
const handler =
|
||||
new (ObjectSystemRelationsOnCreateSideEffectHandlerService as unknown as new () => ObjectSystemRelationsOnCreateSideEffectHandlerService)();
|
||||
|
||||
const targets = buildStandardTargetFlatObjectMetadatas();
|
||||
|
||||
const forwardUniversalIdentifierFor = (
|
||||
standardObjectUniversalIdentifier: string,
|
||||
) =>
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier: SOURCE_OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
standardObjectUniversalIdentifier,
|
||||
});
|
||||
|
||||
const reverseUniversalIdentifierFor = (objectUniversalIdentifier: string) =>
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
SOURCE_OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
it('should provision a forward + reverse (both name-free, isSystemSideEffect) field pair and its index for all four standard relation objects', () => {
|
||||
const result = handler.buildSideEffects(buildArgs({}));
|
||||
|
||||
expect(result.status).toBe('success');
|
||||
|
||||
if (result.status !== 'success') {
|
||||
throw new Error('expected success');
|
||||
}
|
||||
|
||||
const fieldMetadataToCreate =
|
||||
result.operations.fieldMetadata?.flatEntityToCreate ?? {};
|
||||
const indexToCreate = result.operations.index?.flatEntityToCreate ?? {};
|
||||
|
||||
expect(Object.keys(fieldMetadataToCreate)).toHaveLength(
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS.length * 2,
|
||||
);
|
||||
expect(Object.keys(indexToCreate)).toHaveLength(
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS.length,
|
||||
);
|
||||
|
||||
for (const target of targets) {
|
||||
const forwardUniversalIdentifier = forwardUniversalIdentifierFor(
|
||||
target.universalIdentifier,
|
||||
);
|
||||
const reverseUniversalIdentifier = reverseUniversalIdentifierFor(
|
||||
target.universalIdentifier,
|
||||
);
|
||||
|
||||
const forwardField = fieldMetadataToCreate[forwardUniversalIdentifier];
|
||||
const reverseField = fieldMetadataToCreate[reverseUniversalIdentifier];
|
||||
|
||||
expect(forwardField).toBeDefined();
|
||||
expect(reverseField).toBeDefined();
|
||||
expect(forwardField?.isSystemSideEffect).toBe(true);
|
||||
expect(reverseField?.isSystemSideEffect).toBe(true);
|
||||
expect(
|
||||
reverseField?.relationTargetObjectMetadataUniversalIdentifier,
|
||||
).toBe(SOURCE_OBJECT_UNIVERSAL_IDENTIFIER);
|
||||
}
|
||||
});
|
||||
|
||||
// The handler always emits its bundles: a caller field colliding on
|
||||
// universal identifier is not skipped but hard-fails at the engine merge
|
||||
// (RESERVED_SYSTEM_UNIVERSAL_IDENTIFIER collision).
|
||||
it('should emit all bundles even when a caller field collides on universal identifier', () => {
|
||||
const collidingTarget = targets[0];
|
||||
const collidingForwardUniversalIdentifier = forwardUniversalIdentifierFor(
|
||||
collidingTarget.universalIdentifier,
|
||||
);
|
||||
|
||||
const result = handler.buildSideEffects(
|
||||
buildArgs({
|
||||
callerFieldMetadataToCreateByUniversalIdentifier: {
|
||||
[collidingForwardUniversalIdentifier]: {
|
||||
universalIdentifier: collidingForwardUniversalIdentifier,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(result.status).toBe('success');
|
||||
|
||||
if (result.status !== 'success') {
|
||||
throw new Error('expected success');
|
||||
}
|
||||
|
||||
const fieldMetadataToCreate =
|
||||
result.operations.fieldMetadata?.flatEntityToCreate ?? {};
|
||||
const indexToCreate = result.operations.index?.flatEntityToCreate ?? {};
|
||||
|
||||
expect(Object.keys(fieldMetadataToCreate)).toHaveLength(
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS.length * 2,
|
||||
);
|
||||
expect(Object.keys(indexToCreate)).toHaveLength(
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS.length,
|
||||
);
|
||||
expect(
|
||||
fieldMetadataToCreate[collidingForwardUniversalIdentifier],
|
||||
).toBeDefined();
|
||||
});
|
||||
|
||||
it('should fail with one error per missing standard relation object', () => {
|
||||
const [, , ...standardTargetFlatObjectMetadatasMissingFirstTwo] =
|
||||
buildStandardTargetFlatObjectMetadatas();
|
||||
|
||||
const result = handler.buildSideEffects(
|
||||
buildArgs({
|
||||
standardTargetFlatObjectMetadatas:
|
||||
standardTargetFlatObjectMetadatasMissingFirstTwo,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(result.status).toBe('fail');
|
||||
|
||||
if (result.status !== 'fail') {
|
||||
throw new Error('expected fail');
|
||||
}
|
||||
|
||||
expect(result.errors).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
import { type AllFlatEntityOperationRecordByMetadataName } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-operation-record-by-metadata-name.type';
|
||||
import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock';
|
||||
import { type BuildSideEffectsArgs } from 'src/engine/metadata-modules/metadata-side-effect/interfaces/base-metadata-side-effect-handler.service';
|
||||
import { ObjectSystemRelationsOnUpdateSideEffectHandlerService } from 'src/engine/metadata-modules/metadata-side-effect/handlers/object-metadata/services/object-system-relations-on-update-side-effect-handler.service';
|
||||
|
||||
const OBJECT_UNIVERSAL_IDENTIFIER = 'b1b2b3b4-b5b6-4000-8000-000000000001';
|
||||
|
||||
const buildArgs = ({
|
||||
updatedNameSingular,
|
||||
updatedNamePlural,
|
||||
existingNameSingular = 'rocket',
|
||||
existingNamePlural = 'rockets',
|
||||
includeExisting = true,
|
||||
}: {
|
||||
updatedNameSingular: string;
|
||||
updatedNamePlural: string;
|
||||
existingNameSingular?: string;
|
||||
existingNamePlural?: string;
|
||||
includeExisting?: boolean;
|
||||
}): BuildSideEffectsArgs<'objectMetadata'> => {
|
||||
const existingFlatObjectMetadata = getFlatObjectMetadataMock({
|
||||
universalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
nameSingular: existingNameSingular,
|
||||
namePlural: existingNamePlural,
|
||||
labelSingular: existingNameSingular,
|
||||
labelPlural: existingNamePlural,
|
||||
});
|
||||
|
||||
const updatedFlatObjectMetadata = getFlatObjectMetadataMock({
|
||||
universalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
nameSingular: updatedNameSingular,
|
||||
namePlural: updatedNamePlural,
|
||||
labelSingular: updatedNameSingular,
|
||||
labelPlural: updatedNamePlural,
|
||||
});
|
||||
|
||||
return {
|
||||
flatEntity: updatedFlatObjectMetadata,
|
||||
allFlatEntityOperationRecordByMetadataName:
|
||||
{} as unknown as AllFlatEntityOperationRecordByMetadataName,
|
||||
relatedFlatEntityMaps: {
|
||||
flatObjectMetadataMaps: {
|
||||
byUniversalIdentifier: includeExisting
|
||||
? { [OBJECT_UNIVERSAL_IDENTIFIER]: existingFlatObjectMetadata }
|
||||
: {},
|
||||
},
|
||||
flatFieldMetadataMaps: { byUniversalIdentifier: {} },
|
||||
flatIndexMaps: { byUniversalIdentifier: {} },
|
||||
},
|
||||
context: {},
|
||||
} as unknown as BuildSideEffectsArgs<'objectMetadata'>;
|
||||
};
|
||||
|
||||
describe('ObjectSystemRelationsOnUpdateSideEffectHandlerService', () => {
|
||||
const handler =
|
||||
new (ObjectSystemRelationsOnUpdateSideEffectHandlerService as unknown as new () => ObjectSystemRelationsOnUpdateSideEffectHandlerService)();
|
||||
|
||||
it('should noop when the object name is unchanged', () => {
|
||||
const result = handler.buildSideEffects(
|
||||
buildArgs({
|
||||
existingNameSingular: 'rocket',
|
||||
existingNamePlural: 'rockets',
|
||||
updatedNameSingular: 'rocket',
|
||||
updatedNamePlural: 'rockets',
|
||||
}),
|
||||
);
|
||||
|
||||
expect(result.status).toBe('noop');
|
||||
});
|
||||
|
||||
it('should fail when the existing object cannot be resolved from the maps', () => {
|
||||
const result = handler.buildSideEffects(
|
||||
buildArgs({
|
||||
includeExisting: false,
|
||||
updatedNameSingular: 'house',
|
||||
updatedNamePlural: 'houses',
|
||||
}),
|
||||
);
|
||||
|
||||
expect(result.status).toBe('fail');
|
||||
});
|
||||
|
||||
it('should noop when a renamed object has no system side-effect morph relations to rename', () => {
|
||||
const result = handler.buildSideEffects(
|
||||
buildArgs({
|
||||
updatedNameSingular: 'house',
|
||||
updatedNamePlural: 'houses',
|
||||
}),
|
||||
);
|
||||
|
||||
expect(result.status).toBe('noop');
|
||||
});
|
||||
});
|
||||
+68
@@ -99,6 +99,74 @@ describe('ObjectSystemSideEffectsOnDeleteSideEffectHandlerService', () => {
|
||||
).toEqual([SEARCH_FIELD_METADATA_UNIVERSAL_IDENTIFIER]);
|
||||
});
|
||||
|
||||
it('should cascade-delete the default-relation reverse morph field on a standard object and its join-column index', () => {
|
||||
const FORWARD_FIELD_UNIVERSAL_IDENTIFIER =
|
||||
'd1d2d3d4-d5d6-4000-8000-000000000003';
|
||||
const REVERSE_FIELD_UNIVERSAL_IDENTIFIER =
|
||||
'd1d2d3d4-d5d6-4000-8000-000000000004';
|
||||
const REVERSE_INDEX_UNIVERSAL_IDENTIFIER =
|
||||
'e1e2e3e4-e5e6-4000-8000-000000000002';
|
||||
|
||||
const result = handler.buildSideEffects(
|
||||
buildArgs({
|
||||
relatedFlatEntityMaps: {
|
||||
flatFieldMetadataMaps: {
|
||||
byUniversalIdentifier: {
|
||||
[FORWARD_FIELD_UNIVERSAL_IDENTIFIER]: {
|
||||
universalIdentifier: FORWARD_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
isSystemSideEffect: true,
|
||||
objectMetadataUniversalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
OTHER_OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
},
|
||||
[REVERSE_FIELD_UNIVERSAL_IDENTIFIER]: {
|
||||
universalIdentifier: REVERSE_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
isSystemSideEffect: true,
|
||||
objectMetadataUniversalIdentifier:
|
||||
OTHER_OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
},
|
||||
},
|
||||
},
|
||||
flatIndexMaps: {
|
||||
byUniversalIdentifier: {
|
||||
[REVERSE_INDEX_UNIVERSAL_IDENTIFIER]: {
|
||||
universalIdentifier: REVERSE_INDEX_UNIVERSAL_IDENTIFIER,
|
||||
isSystemSideEffect: true,
|
||||
objectMetadataUniversalIdentifier:
|
||||
OTHER_OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
universalFlatIndexFieldMetadatas: [
|
||||
{
|
||||
fieldMetadataUniversalIdentifier:
|
||||
REVERSE_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
flatSearchFieldMetadataMaps: { byUniversalIdentifier: {} },
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(result.status).toBe('success');
|
||||
|
||||
if (result.status !== 'success') {
|
||||
throw new Error('expected success');
|
||||
}
|
||||
|
||||
expect(
|
||||
Object.keys(result.operations.fieldMetadata?.flatEntityToDelete ?? {}),
|
||||
).toEqual([
|
||||
FORWARD_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
REVERSE_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
]);
|
||||
expect(
|
||||
Object.keys(result.operations.index?.flatEntityToDelete ?? {}),
|
||||
).toEqual([REVERSE_INDEX_UNIVERSAL_IDENTIFIER]);
|
||||
});
|
||||
|
||||
it('should not delete entities belonging to a different object', () => {
|
||||
const result = handler.buildSideEffects(
|
||||
buildArgs({
|
||||
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
import { msg, t } from '@lingui/core/macro';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { isNonEmptyArray } from '@sniptt/guards';
|
||||
|
||||
import {
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS,
|
||||
STANDARD_OBJECTS,
|
||||
} from 'twenty-shared/metadata';
|
||||
import { fromArrayToUniqueKeyRecord, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
|
||||
import { MetadataSideEffectExceptionCode } from 'src/engine/metadata-modules/metadata-side-effect/exceptions/metadata-side-effect-exception-code';
|
||||
import {
|
||||
type BuildSideEffectsArgs,
|
||||
MetadataSideEffectHandler,
|
||||
} from 'src/engine/metadata-modules/metadata-side-effect/interfaces/base-metadata-side-effect-handler.service';
|
||||
import {
|
||||
type MetadataSideEffectFailure,
|
||||
type MetadataSideEffectResult,
|
||||
} from 'src/engine/metadata-modules/metadata-side-effect/types/metadata-side-effect-result.type';
|
||||
import { buildSystemRelationFlatFieldMetadatasForObject } from 'src/engine/metadata-modules/object-metadata/utils/build-system-relation-flat-field-metadatas-for-object.util';
|
||||
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
|
||||
|
||||
type DefaultRelationStandardObjectNameSingular =
|
||||
(typeof DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS)[number];
|
||||
|
||||
@Injectable()
|
||||
export class ObjectSystemRelationsOnCreateSideEffectHandlerService extends MetadataSideEffectHandler(
|
||||
{
|
||||
operation: 'create',
|
||||
metadataName: 'objectMetadata',
|
||||
name: 'objectSystemRelationsOnCreate',
|
||||
description:
|
||||
'When an object is created, provision its default relations to the four standard relation objects (timelineActivity, attachment, noteTarget, taskTarget): the forward RELATION field on the new object, the reverse MORPH_RELATION field on the standard object (name-free deterministic identifier so an object rename is a lossless update), and the reverse join-column index. All emitted entities are isSystemSideEffect, so the engine owns their lifecycle. twenty-standard authors these fields itself and never reaches this handler (it syncs via the FromTo path). The handler always emits its bundles: a caller-provided field colliding on universal identifier hard-fails at merge time (RESERVED_SYSTEM_UNIVERSAL_IDENTIFIER), and a caller field colliding on name hard-fails in the field validator (NOT_AVAILABLE).',
|
||||
},
|
||||
) {
|
||||
buildSideEffects({
|
||||
flatEntity: flatObjectMetadata,
|
||||
relatedFlatEntityMaps,
|
||||
}: BuildSideEffectsArgs<'objectMetadata'>): MetadataSideEffectResult {
|
||||
const sourceFlatObjectMetadata =
|
||||
flatObjectMetadata as UniversalFlatObjectMetadata;
|
||||
|
||||
const standardTargetFlatObjectMetadataByNameSingular = {} as Record<
|
||||
DefaultRelationStandardObjectNameSingular,
|
||||
UniversalFlatObjectMetadata
|
||||
>;
|
||||
|
||||
const missingStandardObjectErrors: MetadataSideEffectFailure['errors'] = [];
|
||||
|
||||
for (const standardObjectNameSingular of DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS) {
|
||||
const standardTargetFlatObjectMetadata =
|
||||
relatedFlatEntityMaps.flatObjectMetadataMaps.byUniversalIdentifier[
|
||||
STANDARD_OBJECTS[standardObjectNameSingular].universalIdentifier
|
||||
];
|
||||
|
||||
if (!isDefined(standardTargetFlatObjectMetadata)) {
|
||||
missingStandardObjectErrors.push({
|
||||
code: MetadataSideEffectExceptionCode.SIDE_EFFECT_PARENT_METADATA_NOT_FOUND,
|
||||
message: t`Could not resolve standard relation object "${standardObjectNameSingular}" to provision default relations`,
|
||||
userFriendlyMessage: msg`A standard object required to provision default relations could not be found`,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
standardTargetFlatObjectMetadataByNameSingular[
|
||||
standardObjectNameSingular
|
||||
] = standardTargetFlatObjectMetadata;
|
||||
}
|
||||
|
||||
if (isNonEmptyArray(missingStandardObjectErrors)) {
|
||||
return {
|
||||
status: 'fail',
|
||||
type: 'create',
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityMinimalInformation: {
|
||||
universalIdentifier: sourceFlatObjectMetadata.universalIdentifier,
|
||||
nameSingular: sourceFlatObjectMetadata.nameSingular,
|
||||
} as Partial<MetadataFlatEntity<'objectMetadata'>>,
|
||||
errors: missingStandardObjectErrors,
|
||||
};
|
||||
}
|
||||
|
||||
const systemRelationBundles =
|
||||
buildSystemRelationFlatFieldMetadatasForObject({
|
||||
sourceFlatObjectMetadata,
|
||||
standardTargetFlatObjectMetadataByNameSingular,
|
||||
applicationUniversalIdentifier:
|
||||
sourceFlatObjectMetadata.applicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
return {
|
||||
status: 'success',
|
||||
operations: {
|
||||
fieldMetadata: {
|
||||
flatEntityToCreate: fromArrayToUniqueKeyRecord({
|
||||
array: systemRelationBundles.flatMap(
|
||||
({ forwardFlatFieldMetadata, reverseFlatFieldMetadata }) => [
|
||||
forwardFlatFieldMetadata,
|
||||
reverseFlatFieldMetadata,
|
||||
],
|
||||
),
|
||||
uniqueKey: 'universalIdentifier',
|
||||
}),
|
||||
},
|
||||
index: {
|
||||
flatEntityToCreate: fromArrayToUniqueKeyRecord({
|
||||
array: systemRelationBundles.map(
|
||||
({ flatIndexMetadata }) => flatIndexMetadata,
|
||||
),
|
||||
uniqueKey: 'universalIdentifier',
|
||||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
import { msg, t } from '@lingui/core/macro';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { fromArrayToUniqueKeyRecord, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
|
||||
import { renameRelatedMorphFieldOnObjectNamesUpdate } from 'src/engine/metadata-modules/flat-object-metadata/utils/rename-related-morph-field-on-object-names-update.util';
|
||||
import { MetadataSideEffectExceptionCode } from 'src/engine/metadata-modules/metadata-side-effect/exceptions/metadata-side-effect-exception-code';
|
||||
import {
|
||||
type BuildSideEffectsArgs,
|
||||
MetadataSideEffectHandler,
|
||||
} from 'src/engine/metadata-modules/metadata-side-effect/interfaces/base-metadata-side-effect-handler.service';
|
||||
import { type MetadataSideEffectResult } from 'src/engine/metadata-modules/metadata-side-effect/types/metadata-side-effect-result.type';
|
||||
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
|
||||
|
||||
@Injectable()
|
||||
export class ObjectSystemRelationsOnUpdateSideEffectHandlerService extends MetadataSideEffectHandler(
|
||||
{
|
||||
operation: 'update',
|
||||
metadataName: 'objectMetadata',
|
||||
name: 'objectSystemRelationsOnUpdate',
|
||||
description:
|
||||
'When an object is renamed, rename the reverse MORPH_RELATION fields of its default relations to the standard objects (timelineActivity, attachment, noteTarget, taskTarget) and recompute their join-column index names. These reverse fields are isSystemSideEffect, so the engine is their sole authority on rename across both the API and manifest-sync paths (the API transpiler renames only user-authored morph relations). The reverse field universal identifier is name-free, so a rename stays a lossless update. The computed updates are emitted unconditionally; any universal identifier collision with a caller-provided operation is arbitrated by the engine merge.',
|
||||
},
|
||||
) {
|
||||
buildSideEffects({
|
||||
flatEntity,
|
||||
relatedFlatEntityMaps,
|
||||
}: BuildSideEffectsArgs<'objectMetadata'>): MetadataSideEffectResult {
|
||||
const updatedFlatObjectMetadata = flatEntity as UniversalFlatObjectMetadata;
|
||||
|
||||
const existingFlatObjectMetadata =
|
||||
relatedFlatEntityMaps.flatObjectMetadataMaps.byUniversalIdentifier[
|
||||
updatedFlatObjectMetadata.universalIdentifier
|
||||
];
|
||||
|
||||
if (!isDefined(existingFlatObjectMetadata)) {
|
||||
return {
|
||||
status: 'fail',
|
||||
type: 'update',
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityMinimalInformation: {
|
||||
universalIdentifier: updatedFlatObjectMetadata.universalIdentifier,
|
||||
nameSingular: updatedFlatObjectMetadata.nameSingular,
|
||||
} as Partial<MetadataFlatEntity<'objectMetadata'>>,
|
||||
errors: [
|
||||
{
|
||||
code: MetadataSideEffectExceptionCode.SIDE_EFFECT_PARENT_METADATA_NOT_FOUND,
|
||||
message: t`Could not resolve the existing object "${updatedFlatObjectMetadata.nameSingular}" to rename its default relations`,
|
||||
userFriendlyMessage: msg`The object to rename could not be found to update its default relations`,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const isRenamed =
|
||||
existingFlatObjectMetadata.nameSingular !==
|
||||
updatedFlatObjectMetadata.nameSingular ||
|
||||
existingFlatObjectMetadata.namePlural !==
|
||||
updatedFlatObjectMetadata.namePlural;
|
||||
|
||||
if (!isRenamed) {
|
||||
return { status: 'noop' };
|
||||
}
|
||||
|
||||
const { morphFlatFieldMetadatasToUpdate, morphRelatedFlatIndexesToUpdate } =
|
||||
renameRelatedMorphFieldOnObjectNamesUpdate({
|
||||
fromFlatObjectMetadata: existingFlatObjectMetadata,
|
||||
toFlatObjectMetadata: {
|
||||
...existingFlatObjectMetadata,
|
||||
nameSingular: updatedFlatObjectMetadata.nameSingular,
|
||||
namePlural: updatedFlatObjectMetadata.namePlural,
|
||||
},
|
||||
flatFieldMetadataMaps: relatedFlatEntityMaps.flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps: relatedFlatEntityMaps.flatObjectMetadataMaps,
|
||||
flatIndexMaps: relatedFlatEntityMaps.flatIndexMaps,
|
||||
systemSideEffectMorphFieldsOnly: true,
|
||||
});
|
||||
|
||||
if (
|
||||
morphFlatFieldMetadatasToUpdate.length === 0 &&
|
||||
morphRelatedFlatIndexesToUpdate.length === 0
|
||||
) {
|
||||
return { status: 'noop' };
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'success',
|
||||
operations: {
|
||||
fieldMetadata: {
|
||||
flatEntityToUpdate: fromArrayToUniqueKeyRecord({
|
||||
array: morphFlatFieldMetadatasToUpdate,
|
||||
uniqueKey: 'universalIdentifier',
|
||||
}),
|
||||
},
|
||||
index: {
|
||||
flatEntityToUpdate: fromArrayToUniqueKeyRecord({
|
||||
array: morphRelatedFlatIndexesToUpdate,
|
||||
uniqueKey: 'universalIdentifier',
|
||||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -17,7 +17,7 @@ export class ObjectSystemSideEffectsOnDeleteSideEffectHandlerService extends Met
|
||||
metadataName: 'objectMetadata',
|
||||
name: 'objectSystemSideEffectsOnDelete',
|
||||
description:
|
||||
'When an object is deleted, cascade-delete its engine-owned side effects: the reserved system fields, every system index (including the GIN searchVector index), and its searchFieldMetadata rows. These entities are excluded from manifest deletion inference, so the cascade must be explicit. Caller-provided defaults (name, default relations) are NOT engine-owned and are deleted through normal deletion inference / the object delete transpiler.',
|
||||
'When an object is deleted, cascade-delete its engine-owned side effects: the reserved system fields, the default relation fields (forward field on the deleted object and reverse morph field on the standard object), every system index (reverse join-column indexes, the GIN searchVector index), and its searchFieldMetadata rows. The engine is the sole authority for isSystemSideEffect entities on delete: the API object delete transpiler cascades only user-authored fields and indexes, and manifest deletion inference excludes these entities entirely. Caller-provided defaults (e.g. the name field) are NOT engine-owned and are deleted through normal deletion inference / the object delete transpiler.',
|
||||
},
|
||||
) {
|
||||
buildSideEffects({
|
||||
|
||||
+7
-23
@@ -483,24 +483,11 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
const resolvedOwnerFlatApplication =
|
||||
ownerFlatApplication ?? workspaceCustomFlatApplication;
|
||||
|
||||
const { flatObjectMetadataMaps: existingFlatObjectMetadataMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatObjectMetadataMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const {
|
||||
flatObjectMetadataToCreate,
|
||||
flatFieldMetadataToCreateOnObject,
|
||||
relationTargetFlatFieldMetadataToCreate,
|
||||
flatIndexMetadataToCreate,
|
||||
} = fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreate({
|
||||
createObjectInput,
|
||||
flatApplication: resolvedOwnerFlatApplication,
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
});
|
||||
const { flatObjectMetadataToCreate, flatFieldMetadataToCreateOnObject } =
|
||||
fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreate({
|
||||
createObjectInput,
|
||||
flatApplication: resolvedOwnerFlatApplication,
|
||||
});
|
||||
|
||||
// Default view fields reference the caller-provided fields (reused as-is from
|
||||
// the transpiler output) plus the engine-owned reserved system fields, whose
|
||||
@@ -597,15 +584,12 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
fieldMetadata: {
|
||||
flatEntityToCreate: [
|
||||
...flatFieldMetadataToCreateOnObject,
|
||||
...relationTargetFlatFieldMetadataToCreate,
|
||||
],
|
||||
flatEntityToCreate: [...flatFieldMetadataToCreateOnObject],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
index: {
|
||||
flatEntityToCreate: flatIndexMetadataToCreate,
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
|
||||
-186
@@ -1,186 +0,0 @@
|
||||
import { getFieldUniversalIdentifier } from 'twenty-shared/application';
|
||||
import {
|
||||
STANDARD_OBJECTS,
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS,
|
||||
} from 'twenty-shared/metadata';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT } from 'src/engine/metadata-modules/object-metadata/constants/standard-relation-field-properties.constant';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { i18nLabel } from 'src/engine/workspace-manager/twenty-standard-application/utils/i18n-label.util';
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { generateMorphOrRelationFlatFieldMetadataPair } from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-morph-or-relation-flat-field-metadata-pair.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import {
|
||||
ObjectMetadataException,
|
||||
ObjectMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
|
||||
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-migration/constant/standard-object-icons';
|
||||
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
|
||||
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
|
||||
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
|
||||
|
||||
const morphIdByRelationObjectNameSingular = {
|
||||
timelineActivity:
|
||||
STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
attachment: STANDARD_OBJECTS.attachment.morphIds.targetMorphId.morphId,
|
||||
noteTarget: STANDARD_OBJECTS.noteTarget.morphIds.targetMorphId.morphId,
|
||||
taskTarget: STANDARD_OBJECTS.taskTarget.morphIds.targetMorphId.morphId,
|
||||
} satisfies Record<
|
||||
(typeof DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS)[number],
|
||||
string | null
|
||||
>;
|
||||
|
||||
export type BuildDefaultRelationFieldsForCustomObjectArgs = {
|
||||
existingFlatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
sourceFlatObjectMetadata: UniversalFlatObjectMetadata;
|
||||
flatApplication: FlatApplication;
|
||||
};
|
||||
|
||||
type SourceAndTargetFlatFieldMetadatasRecord = {
|
||||
standardSourceFlatFieldMetadatas: UniversalFlatFieldMetadata[];
|
||||
standardTargetFlatFieldMetadatas: UniversalFlatFieldMetadata[];
|
||||
standardTargetFlatIndexMetadatas: UniversalFlatIndexMetadata[];
|
||||
};
|
||||
const EMPTY_SOURCE_AND_TARGET_FLAT_FIELD_METADATAS_RECORD: SourceAndTargetFlatFieldMetadatasRecord =
|
||||
{
|
||||
standardSourceFlatFieldMetadatas: [],
|
||||
standardTargetFlatFieldMetadatas: [],
|
||||
standardTargetFlatIndexMetadatas: [],
|
||||
};
|
||||
|
||||
export const buildDefaultRelationFlatFieldMetadatasForCustomObject = ({
|
||||
existingFlatObjectMetadataMaps,
|
||||
sourceFlatObjectMetadata,
|
||||
flatApplication,
|
||||
}: BuildDefaultRelationFieldsForCustomObjectArgs): SourceAndTargetFlatFieldMetadatasRecord => {
|
||||
const objectIdByNameSingular = Object.values(
|
||||
existingFlatObjectMetadataMaps.byUniversalIdentifier,
|
||||
).reduce<Record<string, string>>((acc, flatObject) => {
|
||||
if (!isDefined(flatObject)) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
return {
|
||||
...acc,
|
||||
[flatObject.nameSingular]: flatObject.id,
|
||||
};
|
||||
}, {});
|
||||
|
||||
const result =
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS.reduce<SourceAndTargetFlatFieldMetadatasRecord>(
|
||||
(sourceAndTargetFlatFieldMetadatasRecord, objectMetadataNameSingular) => {
|
||||
const isObjectMigratedToMorphRelations =
|
||||
objectMetadataNameSingular === 'timelineActivity' ||
|
||||
objectMetadataNameSingular === 'attachment' ||
|
||||
objectMetadataNameSingular === 'noteTarget' ||
|
||||
objectMetadataNameSingular === 'taskTarget';
|
||||
|
||||
const targetFlatObjectMetadataId =
|
||||
objectIdByNameSingular[objectMetadataNameSingular];
|
||||
|
||||
if (!isDefined(targetFlatObjectMetadataId)) {
|
||||
throw new ObjectMetadataException(
|
||||
`Standard target object metadata id ${targetFlatObjectMetadataId} not found in cache`,
|
||||
ObjectMetadataExceptionCode.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
|
||||
const targetFlatObjectMetadata =
|
||||
findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityMaps: existingFlatObjectMetadataMaps,
|
||||
flatEntityId: targetFlatObjectMetadataId,
|
||||
});
|
||||
|
||||
const targetFieldIcon =
|
||||
STANDARD_OBJECT_ICONS[
|
||||
targetFlatObjectMetadata.nameSingular as keyof typeof STANDARD_OBJECT_ICONS
|
||||
] || 'IconBuildingSkyscraper';
|
||||
|
||||
const standardFieldProperties =
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT[
|
||||
objectMetadataNameSingular
|
||||
];
|
||||
|
||||
const morphFieldName = `target${capitalize(sourceFlatObjectMetadata.nameSingular)}`;
|
||||
const fieldName = isObjectMigratedToMorphRelations
|
||||
? morphFieldName
|
||||
: sourceFlatObjectMetadata.nameSingular;
|
||||
const joinColumnName = computeMorphOrRelationFieldJoinColumnName({
|
||||
name: fieldName,
|
||||
});
|
||||
|
||||
const morphId =
|
||||
morphIdByRelationObjectNameSingular[objectMetadataNameSingular];
|
||||
|
||||
// Default relation fields get deterministic universal identifiers so
|
||||
// that provisioning the same custom object always yields the same
|
||||
// identifiers (matching the SDK manifest derivation).
|
||||
const sourceFieldUniversalIdentifier = getFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
objectUniversalIdentifier:
|
||||
sourceFlatObjectMetadata.universalIdentifier,
|
||||
name: targetFlatObjectMetadata.namePlural,
|
||||
});
|
||||
const targetFieldUniversalIdentifier = getFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
objectUniversalIdentifier:
|
||||
targetFlatObjectMetadata.universalIdentifier,
|
||||
name: fieldName,
|
||||
});
|
||||
|
||||
const { flatFieldMetadatas, indexMetadatas } =
|
||||
generateMorphOrRelationFlatFieldMetadataPair({
|
||||
sourceFlatObjectMetadata,
|
||||
targetFlatObjectMetadata,
|
||||
targetFlatFieldMetadataType: isObjectMigratedToMorphRelations
|
||||
? FieldMetadataType.MORPH_RELATION
|
||||
: FieldMetadataType.RELATION,
|
||||
flatApplication,
|
||||
sourceFlatObjectMetadataJoinColumnName: joinColumnName,
|
||||
morphId,
|
||||
targetFieldName: fieldName,
|
||||
sourceFieldUniversalIdentifier,
|
||||
targetFieldUniversalIdentifier,
|
||||
createFieldInput: {
|
||||
icon: standardFieldProperties.icon,
|
||||
type: FieldMetadataType.RELATION,
|
||||
name: targetFlatObjectMetadata.namePlural,
|
||||
label: i18nLabel(standardFieldProperties.label),
|
||||
isSystem: false,
|
||||
relationCreationPayload: {
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
targetObjectMetadataId: targetFlatObjectMetadata.id,
|
||||
targetFieldLabel: capitalize(
|
||||
sourceFlatObjectMetadata.nameSingular,
|
||||
),
|
||||
targetFieldIcon: targetFieldIcon,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
standardSourceFlatFieldMetadatas: [
|
||||
...sourceAndTargetFlatFieldMetadatasRecord.standardSourceFlatFieldMetadatas,
|
||||
flatFieldMetadatas[0],
|
||||
],
|
||||
standardTargetFlatFieldMetadatas: [
|
||||
...sourceAndTargetFlatFieldMetadatasRecord.standardTargetFlatFieldMetadatas,
|
||||
flatFieldMetadatas[1],
|
||||
],
|
||||
standardTargetFlatIndexMetadatas: [
|
||||
...sourceAndTargetFlatFieldMetadatasRecord.standardTargetFlatIndexMetadatas,
|
||||
...indexMetadatas,
|
||||
],
|
||||
};
|
||||
},
|
||||
EMPTY_SOURCE_AND_TARGET_FLAT_FIELD_METADATAS_RECORD,
|
||||
);
|
||||
|
||||
return result;
|
||||
};
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
import { getSystemRelationFieldUniversalIdentifier } from 'twenty-shared/application';
|
||||
import {
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS,
|
||||
STANDARD_OBJECTS,
|
||||
} from 'twenty-shared/metadata';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { generateMorphOrRelationFlatFieldMetadataPair } from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-morph-or-relation-flat-field-metadata-pair.util';
|
||||
import { STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT } from 'src/engine/metadata-modules/object-metadata/constants/standard-relation-field-properties.constant';
|
||||
import { i18nLabel } from 'src/engine/workspace-manager/twenty-standard-application/utils/i18n-label.util';
|
||||
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-migration/constant/standard-object-icons';
|
||||
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
|
||||
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
|
||||
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
|
||||
|
||||
type DefaultRelationStandardObjectNameSingular =
|
||||
(typeof DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS)[number];
|
||||
|
||||
const MORPH_ID_BY_STANDARD_OBJECT_NAME_SINGULAR = {
|
||||
timelineActivity:
|
||||
STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
attachment: STANDARD_OBJECTS.attachment.morphIds.targetMorphId.morphId,
|
||||
noteTarget: STANDARD_OBJECTS.noteTarget.morphIds.targetMorphId.morphId,
|
||||
taskTarget: STANDARD_OBJECTS.taskTarget.morphIds.targetMorphId.morphId,
|
||||
} satisfies Record<DefaultRelationStandardObjectNameSingular, string | null>;
|
||||
|
||||
export type SystemRelationFlatFieldMetadataBundle = {
|
||||
forwardFlatFieldMetadata: UniversalFlatFieldMetadata;
|
||||
reverseFlatFieldMetadata: UniversalFlatFieldMetadata;
|
||||
flatIndexMetadata: UniversalFlatIndexMetadata;
|
||||
};
|
||||
|
||||
type BuildSystemRelationFlatFieldMetadatasForObjectArgs = {
|
||||
sourceFlatObjectMetadata: UniversalFlatObjectMetadata;
|
||||
standardTargetFlatObjectMetadataByNameSingular: Record<
|
||||
DefaultRelationStandardObjectNameSingular,
|
||||
UniversalFlatObjectMetadata
|
||||
>;
|
||||
applicationUniversalIdentifier: string;
|
||||
};
|
||||
|
||||
export const buildSystemRelationFlatFieldMetadatasForObject = ({
|
||||
sourceFlatObjectMetadata,
|
||||
standardTargetFlatObjectMetadataByNameSingular,
|
||||
applicationUniversalIdentifier,
|
||||
}: BuildSystemRelationFlatFieldMetadatasForObjectArgs): SystemRelationFlatFieldMetadataBundle[] =>
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS.map((standardObjectNameSingular) => {
|
||||
const targetFlatObjectMetadata =
|
||||
standardTargetFlatObjectMetadataByNameSingular[
|
||||
standardObjectNameSingular
|
||||
];
|
||||
|
||||
const reverseFieldName = `target${capitalize(
|
||||
sourceFlatObjectMetadata.nameSingular,
|
||||
)}`;
|
||||
const joinColumnName = computeMorphOrRelationFieldJoinColumnName({
|
||||
name: reverseFieldName,
|
||||
});
|
||||
const morphId =
|
||||
MORPH_ID_BY_STANDARD_OBJECT_NAME_SINGULAR[standardObjectNameSingular];
|
||||
|
||||
const standardFieldProperties =
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT[
|
||||
standardObjectNameSingular
|
||||
];
|
||||
const reverseFieldIcon =
|
||||
STANDARD_OBJECT_ICONS[
|
||||
targetFlatObjectMetadata.nameSingular as keyof typeof STANDARD_OBJECT_ICONS
|
||||
] ?? 'IconBuildingSkyscraper';
|
||||
|
||||
const forwardFieldUniversalIdentifier =
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier: sourceFlatObjectMetadata.universalIdentifier,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
targetFlatObjectMetadata.universalIdentifier,
|
||||
});
|
||||
const reverseFieldUniversalIdentifier =
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier: targetFlatObjectMetadata.universalIdentifier,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
sourceFlatObjectMetadata.universalIdentifier,
|
||||
});
|
||||
|
||||
const { flatFieldMetadatas, indexMetadatas } =
|
||||
generateMorphOrRelationFlatFieldMetadataPair({
|
||||
sourceFlatObjectMetadata,
|
||||
targetFlatObjectMetadata,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.MORPH_RELATION,
|
||||
applicationUniversalIdentifier,
|
||||
sourceFlatObjectMetadataJoinColumnName: joinColumnName,
|
||||
morphId,
|
||||
targetFieldName: reverseFieldName,
|
||||
sourceFieldUniversalIdentifier: forwardFieldUniversalIdentifier,
|
||||
targetFieldUniversalIdentifier: reverseFieldUniversalIdentifier,
|
||||
isSystemSideEffect: true,
|
||||
createFieldInput: {
|
||||
icon: standardFieldProperties.icon,
|
||||
type: FieldMetadataType.RELATION,
|
||||
name: targetFlatObjectMetadata.namePlural,
|
||||
label: i18nLabel(standardFieldProperties.label),
|
||||
relationCreationPayload: {
|
||||
targetObjectMetadataId:
|
||||
targetFlatObjectMetadata.universalIdentifier,
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
targetFieldLabel: capitalize(sourceFlatObjectMetadata.nameSingular),
|
||||
targetFieldIcon: reverseFieldIcon,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const [forwardFlatFieldMetadata, reverseFlatFieldMetadata] =
|
||||
flatFieldMetadatas;
|
||||
|
||||
return {
|
||||
forwardFlatFieldMetadata,
|
||||
reverseFlatFieldMetadata,
|
||||
flatIndexMetadata: indexMetadatas[0],
|
||||
};
|
||||
});
|
||||
+21
-14
@@ -339,11 +339,12 @@ export const buildAttachmentStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.attachment.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetTask',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Task`),
|
||||
description: i18nLabel(msg`Attachment target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'task',
|
||||
targetFieldName: 'attachments',
|
||||
settings: {
|
||||
@@ -364,11 +365,12 @@ export const buildAttachmentStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.attachment.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetNote',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Note`),
|
||||
description: i18nLabel(msg`Attachment target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'note',
|
||||
targetFieldName: 'attachments',
|
||||
settings: {
|
||||
@@ -389,11 +391,12 @@ export const buildAttachmentStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.attachment.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetPerson',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Person`),
|
||||
description: i18nLabel(msg`Attachment target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'person',
|
||||
targetFieldName: 'attachments',
|
||||
settings: {
|
||||
@@ -414,11 +417,12 @@ export const buildAttachmentStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.attachment.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetCompany',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Company`),
|
||||
description: i18nLabel(msg`Attachment target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'company',
|
||||
targetFieldName: 'attachments',
|
||||
settings: {
|
||||
@@ -439,11 +443,12 @@ export const buildAttachmentStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.attachment.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetOpportunity',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Opportunity`),
|
||||
description: i18nLabel(msg`Attachment target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'opportunity',
|
||||
targetFieldName: 'attachments',
|
||||
settings: {
|
||||
@@ -464,11 +469,12 @@ export const buildAttachmentStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.attachment.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetDashboard',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Dashboard`),
|
||||
description: i18nLabel(msg`Attachment target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'dashboard',
|
||||
targetFieldName: 'attachments',
|
||||
settings: {
|
||||
@@ -489,11 +495,12 @@ export const buildAttachmentStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.attachment.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetWorkflow',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Workflow`),
|
||||
description: i18nLabel(msg`Attachment target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'workflow',
|
||||
targetFieldName: 'attachments',
|
||||
settings: {
|
||||
|
||||
+4
@@ -339,6 +339,7 @@ export const buildCompanyStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'taskTargets',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.taskTarget.label,
|
||||
),
|
||||
@@ -365,6 +366,7 @@ export const buildCompanyStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'noteTargets',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.noteTarget.label,
|
||||
),
|
||||
@@ -413,6 +415,7 @@ export const buildCompanyStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'attachments',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.attachment.label,
|
||||
),
|
||||
@@ -438,6 +441,7 @@ export const buildCompanyStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'timelineActivities',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.timelineActivity
|
||||
.label,
|
||||
|
||||
+2
@@ -231,6 +231,7 @@ export const buildDashboardStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'timelineActivities',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.timelineActivity
|
||||
.label,
|
||||
@@ -257,6 +258,7 @@ export const buildDashboardStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'attachments',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.attachment.label,
|
||||
),
|
||||
|
||||
+1
@@ -353,6 +353,7 @@ export const buildMessageCampaignStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'timelineActivities',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(msg`Events`),
|
||||
description: i18nLabel(msg`Events linked to the campaign`),
|
||||
icon: 'IconTimelineEvent',
|
||||
|
||||
+1
@@ -240,6 +240,7 @@ export const buildMessageListStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'timelineActivities',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(msg`Events`),
|
||||
description: i18nLabel(msg`Events linked to the list`),
|
||||
icon: 'IconTimelineEvent',
|
||||
|
||||
+2
@@ -258,6 +258,7 @@ export const buildNoteStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'attachments',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.attachment.label,
|
||||
),
|
||||
@@ -283,6 +284,7 @@ export const buildNoteStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'timelineActivities',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.timelineActivity
|
||||
.label,
|
||||
|
||||
+9
-6
@@ -228,11 +228,12 @@ export const buildNoteTargetStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.noteTarget.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetPerson',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Person`),
|
||||
description: i18nLabel(msg`NoteTarget target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'person',
|
||||
targetFieldName: 'noteTargets',
|
||||
settings: {
|
||||
@@ -253,11 +254,12 @@ export const buildNoteTargetStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.noteTarget.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetCompany',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Company`),
|
||||
description: i18nLabel(msg`NoteTarget target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'company',
|
||||
targetFieldName: 'noteTargets',
|
||||
settings: {
|
||||
@@ -278,11 +280,12 @@ export const buildNoteTargetStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.noteTarget.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetOpportunity',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Opportunity`),
|
||||
description: i18nLabel(msg`NoteTarget target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'opportunity',
|
||||
targetFieldName: 'noteTargets',
|
||||
settings: {
|
||||
|
||||
+4
@@ -355,6 +355,7 @@ export const buildOpportunityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'taskTargets',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.taskTarget.label,
|
||||
),
|
||||
@@ -381,6 +382,7 @@ export const buildOpportunityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'noteTargets',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.noteTarget.label,
|
||||
),
|
||||
@@ -407,6 +409,7 @@ export const buildOpportunityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'attachments',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.attachment.label,
|
||||
),
|
||||
@@ -432,6 +435,7 @@ export const buildOpportunityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'timelineActivities',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.timelineActivity
|
||||
.label,
|
||||
|
||||
+4
@@ -363,6 +363,7 @@ export const buildPersonStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'taskTargets',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.taskTarget.label,
|
||||
),
|
||||
@@ -389,6 +390,7 @@ export const buildPersonStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'noteTargets',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.noteTarget.label,
|
||||
),
|
||||
@@ -415,6 +417,7 @@ export const buildPersonStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'attachments',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.attachment.label,
|
||||
),
|
||||
@@ -484,6 +487,7 @@ export const buildPersonStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'timelineActivities',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(msg`Events`),
|
||||
description: i18nLabel(msg`Events linked to the person`),
|
||||
icon: 'IconTimelineEvent',
|
||||
|
||||
+2
@@ -315,6 +315,7 @@ export const buildTaskStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'attachments',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.attachment.label,
|
||||
),
|
||||
@@ -364,6 +365,7 @@ export const buildTaskStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'timelineActivities',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.timelineActivity
|
||||
.label,
|
||||
|
||||
+9
-6
@@ -228,11 +228,12 @@ export const buildTaskTargetStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.taskTarget.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetPerson',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Person`),
|
||||
description: i18nLabel(msg`TaskTarget target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'person',
|
||||
targetFieldName: 'taskTargets',
|
||||
settings: {
|
||||
@@ -253,11 +254,12 @@ export const buildTaskTargetStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.taskTarget.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetCompany',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Company`),
|
||||
description: i18nLabel(msg`TaskTarget target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'company',
|
||||
targetFieldName: 'taskTargets',
|
||||
settings: {
|
||||
@@ -278,11 +280,12 @@ export const buildTaskTargetStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.taskTarget.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetOpportunity',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Opportunity`),
|
||||
description: i18nLabel(msg`TaskTarget target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'opportunity',
|
||||
targetFieldName: 'taskTargets',
|
||||
settings: {
|
||||
|
||||
+33
-22
@@ -315,11 +315,12 @@ export const buildTimelineActivityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetPerson',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Person`),
|
||||
description: i18nLabel(msg`Event target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'person',
|
||||
targetFieldName: 'timelineActivities',
|
||||
settings: {
|
||||
@@ -340,11 +341,12 @@ export const buildTimelineActivityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetCompany',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Company`),
|
||||
description: i18nLabel(msg`Event target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'company',
|
||||
targetFieldName: 'timelineActivities',
|
||||
settings: {
|
||||
@@ -365,11 +367,12 @@ export const buildTimelineActivityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetOpportunity',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Opportunity`),
|
||||
description: i18nLabel(msg`Event target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'opportunity',
|
||||
targetFieldName: 'timelineActivities',
|
||||
settings: {
|
||||
@@ -390,11 +393,12 @@ export const buildTimelineActivityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetNote',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Note`),
|
||||
description: i18nLabel(msg`Event target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'note',
|
||||
targetFieldName: 'timelineActivities',
|
||||
settings: {
|
||||
@@ -415,11 +419,12 @@ export const buildTimelineActivityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetTask',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Task`),
|
||||
description: i18nLabel(msg`Event target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'task',
|
||||
targetFieldName: 'timelineActivities',
|
||||
settings: {
|
||||
@@ -440,11 +445,12 @@ export const buildTimelineActivityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetWorkflow',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Workflow`),
|
||||
description: i18nLabel(msg`Event target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'workflow',
|
||||
targetFieldName: 'timelineActivities',
|
||||
settings: {
|
||||
@@ -465,11 +471,12 @@ export const buildTimelineActivityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetWorkflowVersion',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`WorkflowVersion`),
|
||||
description: i18nLabel(msg`Event target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'workflowVersion',
|
||||
targetFieldName: 'timelineActivities',
|
||||
settings: {
|
||||
@@ -490,11 +497,12 @@ export const buildTimelineActivityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetWorkflowRun',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`WorkflowRun`),
|
||||
description: i18nLabel(msg`Event target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'workflowRun',
|
||||
targetFieldName: 'timelineActivities',
|
||||
settings: {
|
||||
@@ -515,11 +523,12 @@ export const buildTimelineActivityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetDashboard',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`Dashboard`),
|
||||
description: i18nLabel(msg`Event target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'dashboard',
|
||||
targetFieldName: 'timelineActivities',
|
||||
settings: {
|
||||
@@ -540,11 +549,12 @@ export const buildTimelineActivityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetMessageList',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`MessageList`),
|
||||
description: i18nLabel(msg`Event target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'messageList',
|
||||
targetFieldName: 'timelineActivities',
|
||||
settings: {
|
||||
@@ -565,11 +575,12 @@ export const buildTimelineActivityStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
morphId: STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId,
|
||||
fieldName: 'targetMessageCampaign',
|
||||
label: i18nLabel(msg`Target`),
|
||||
label: i18nLabel(msg`MessageCampaign`),
|
||||
description: i18nLabel(msg`Event target`),
|
||||
icon: 'IconArrowUpRight',
|
||||
icon: 'IconTimelineEvent',
|
||||
isNullable: true,
|
||||
isUIEditable: false,
|
||||
isSystemSideEffect: true,
|
||||
targetObjectName: 'messageCampaign',
|
||||
targetFieldName: 'timelineActivities',
|
||||
settings: {
|
||||
|
||||
+1
@@ -420,6 +420,7 @@ export const buildWorkflowRunStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'timelineActivities',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.timelineActivity
|
||||
.label,
|
||||
|
||||
+2
@@ -357,6 +357,7 @@ export const buildWorkflowStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'timelineActivities',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.timelineActivity
|
||||
.label,
|
||||
@@ -383,6 +384,7 @@ export const buildWorkflowStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'attachments',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(msg`Attachments`),
|
||||
description: i18nLabel(msg`Attachments linked to the workflow`),
|
||||
icon: 'IconFileUpload',
|
||||
|
||||
+1
@@ -364,6 +364,7 @@ export const buildWorkflowVersionStandardFlatFieldMetadatas = ({
|
||||
type: FieldMetadataType.RELATION,
|
||||
morphId: null,
|
||||
fieldName: 'timelineActivities',
|
||||
isSystemSideEffect: true,
|
||||
label: i18nLabel(
|
||||
STANDARD_RELATION_FIELD_PROPERTIES_BY_RELATION_OBJECT.timelineActivity
|
||||
.label,
|
||||
|
||||
+9
-9
@@ -1,3 +1,9 @@
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type';
|
||||
import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type';
|
||||
import { type StandardBuilderArgs } from 'src/engine/workspace-manager/twenty-standard-application/types/metadata-standard-buillder-args.type';
|
||||
import { TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER } from 'twenty-shared/application';
|
||||
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
import {
|
||||
type FieldMetadataComplexOption,
|
||||
type FieldMetadataDefaultOption,
|
||||
@@ -5,14 +11,6 @@ import {
|
||||
type FieldMetadataSettings,
|
||||
type FieldMetadataType,
|
||||
} from 'twenty-shared/types';
|
||||
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
import { TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER } from 'twenty-shared/application';
|
||||
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type';
|
||||
import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type';
|
||||
import { type StandardBuilderArgs } from 'src/engine/workspace-manager/twenty-standard-application/types/metadata-standard-buillder-args.type';
|
||||
|
||||
export type CreateStandardRelationFieldContext<
|
||||
O extends AllStandardObjectName,
|
||||
T extends AllStandardObjectName,
|
||||
@@ -36,6 +34,7 @@ export type CreateStandardMorphOrRelationFieldContext<
|
||||
targetFieldName: AllStandardObjectFieldName<T>;
|
||||
isNullable?: boolean;
|
||||
isUIEditable?: boolean;
|
||||
isSystemSideEffect?: boolean;
|
||||
defaultValue?: FieldMetadataDefaultValueForAnyType;
|
||||
settings: FieldMetadataSettings<F>;
|
||||
options?: FieldMetadataDefaultOption[] | FieldMetadataComplexOption[] | null;
|
||||
@@ -66,6 +65,7 @@ export const createStandardRelationFieldFlatMetadata = <
|
||||
targetFieldName,
|
||||
isNullable = true,
|
||||
isUIEditable = true,
|
||||
isSystemSideEffect = false,
|
||||
defaultValue = null,
|
||||
settings,
|
||||
options: fieldOptions = null,
|
||||
@@ -101,7 +101,7 @@ export const createStandardRelationFieldFlatMetadata = <
|
||||
icon,
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isSystemSideEffect: false,
|
||||
isSystemSideEffect,
|
||||
isNullable,
|
||||
isUnique: false,
|
||||
isUIEditable,
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Sync application default relation name collision should reject a manifest field named after a default relation when it carries a pinned universal identifier 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "METADATA_VALIDATION_FAILED",
|
||||
"errors": {
|
||||
"fieldMetadata": [
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "NOT_AVAILABLE",
|
||||
"message": "Name "attachments" is not available as it is already used by another field",
|
||||
"userFriendlyMessage": "Name "attachments" is not available as it is already used by another field",
|
||||
"value": "attachments",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"name": "attachments",
|
||||
"objectMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "fieldMetadata",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "FIELD_METADATA_NOT_FOUND",
|
||||
"message": "Relation field target metadata not found in both existing and about to be created field metadatas",
|
||||
"userFriendlyMessage": "Relation field target metadata not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"name": "targetDefaultRelationCollisionTarget",
|
||||
"objectMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "fieldMetadata",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
"index": [
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INDEX_FIELD_NOT_FOUND",
|
||||
"message": "Could not find index field related field metadata",
|
||||
"userFriendlyMessage": "Field referenced in index does not exist",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"name": "IDX_6d15112a8688389df51c6dfc321",
|
||||
"universalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "index",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 2 fieldMetadata, 1 index",
|
||||
"summary": {
|
||||
"fieldMetadata": 2,
|
||||
"index": 1,
|
||||
"totalErrors": 3,
|
||||
},
|
||||
"userFriendlyMessage": "Many validation errors",
|
||||
},
|
||||
"message": "Validation errors occurred while syncing application manifest metadata",
|
||||
"name": "GraphQLError",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Sync application default relation name collision should reject a manifest field named after a default relation when it carries the derived universal identifier 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "METADATA_VALIDATION_FAILED",
|
||||
"errors": {
|
||||
"fieldMetadata": [
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "RESERVED_SYSTEM_UNIVERSAL_IDENTIFIER",
|
||||
"message": "Universal identifier is reserved for system-managed metadata",
|
||||
"userFriendlyMessage": "This identifier is reserved by the system",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"name": "attachments",
|
||||
"universalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "fieldMetadata",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"totalErrors": 1,
|
||||
},
|
||||
"userFriendlyMessage": "This identifier is reserved by the system",
|
||||
},
|
||||
"message": "Validation errors occurred while syncing application manifest metadata",
|
||||
"name": "GraphQLError",
|
||||
}
|
||||
`;
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Sync application should reject hijacking the searchVector system field should reject a manifest field declared under the reserved searchVector name 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "METADATA_VALIDATION_FAILED",
|
||||
"errors": {
|
||||
"fieldMetadata": [
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "FIELD_MUTATION_NOT_ALLOWED",
|
||||
"message": "System fields only allow updating: universalSettings, isActive. Forbidden properties: description, icon, isUIEditable",
|
||||
"userFriendlyMessage": "System fields cannot be updated",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"name": "searchVector",
|
||||
"objectMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "fieldMetadata",
|
||||
"status": "fail",
|
||||
"type": "update",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"totalErrors": 1,
|
||||
},
|
||||
"userFriendlyMessage": "System fields cannot be updated",
|
||||
},
|
||||
"message": "Validation errors occurred while syncing application manifest metadata",
|
||||
"name": "GraphQLError",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Sync application should reject hijacking the searchVector system field should reject a manifest field reusing the searchVector name under a foreign universal identifier 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "METADATA_VALIDATION_FAILED",
|
||||
"errors": {
|
||||
"fieldMetadata": [
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "NOT_AVAILABLE",
|
||||
"message": "Name "searchVector" is not available as it is already used by another field",
|
||||
"userFriendlyMessage": "Name "searchVector" is not available as it is already used by another field",
|
||||
"value": "searchVector",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"name": "searchVector",
|
||||
"objectMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "fieldMetadata",
|
||||
"status": "fail",
|
||||
"type": "create",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"totalErrors": 1,
|
||||
},
|
||||
"userFriendlyMessage": "Name "searchVector" is not available as it is already used by another field",
|
||||
},
|
||||
"message": "Validation errors occurred while syncing application manifest metadata",
|
||||
"name": "GraphQLError",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Sync application should reject hijacking the searchVector system field should reject a manifest field squatting the searchVector deterministic universal identifier 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "METADATA_VALIDATION_FAILED",
|
||||
"errors": {
|
||||
"fieldMetadata": [
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "FIELD_MUTATION_NOT_ALLOWED",
|
||||
"message": "System fields only allow updating: universalSettings, isActive. Forbidden properties: description, icon, label, name, isUIEditable",
|
||||
"userFriendlyMessage": "System fields cannot be updated",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Field type TS_VECTOR must be named "searchVector", got "stolenSearchVector"",
|
||||
"userFriendlyMessage": "Field type TS_VECTOR must be named "searchVector"",
|
||||
"value": "stolenSearchVector",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"name": "stolenSearchVector",
|
||||
"objectMetadataUniversalIdentifier": Any<String>,
|
||||
"universalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "fieldMetadata",
|
||||
"status": "fail",
|
||||
"type": "update",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 fieldMetadata",
|
||||
"summary": {
|
||||
"fieldMetadata": 1,
|
||||
"totalErrors": 1,
|
||||
},
|
||||
"userFriendlyMessage": "System fields cannot be updated",
|
||||
},
|
||||
"message": "Validation errors occurred while syncing application manifest metadata",
|
||||
"name": "GraphQLError",
|
||||
}
|
||||
`;
|
||||
+1164
-436
File diff suppressed because it is too large
Load Diff
+123
@@ -0,0 +1,123 @@
|
||||
import { expectOneNotInternalServerErrorSnapshot } from 'test/integration/graphql/utils/expect-one-not-internal-server-error-snapshot.util';
|
||||
import { buildBaseManifest } from 'test/integration/metadata/suites/application/utils/build-base-manifest.util';
|
||||
import { buildDefaultObjectManifest } from 'test/integration/metadata/suites/application/utils/build-default-object-manifest.util';
|
||||
import { cleanupApplicationAndAppRegistration } from 'test/integration/metadata/suites/application/utils/cleanup-application-and-app-registration.util';
|
||||
import { setupApplicationForSync } from 'test/integration/metadata/suites/application/utils/setup-application-for-sync.util';
|
||||
import { syncApplication } from 'test/integration/metadata/suites/application/utils/sync-application.util';
|
||||
import {
|
||||
getSystemRelationFieldUniversalIdentifier,
|
||||
type ObjectManifest,
|
||||
} from 'twenty-shared/application';
|
||||
import { STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-shared/metadata';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
const TEST_APP_ID = uuidv4();
|
||||
const TEST_ROLE_ID = uuidv4();
|
||||
const OBJECT_UNIVERSAL_IDENTIFIER = uuidv4();
|
||||
|
||||
const OBJECT_NAME_SINGULAR = 'defaultRelationCollisionTarget';
|
||||
const OBJECT_NAME_PLURAL = 'defaultRelationCollisionTargets';
|
||||
|
||||
// The engine forward field of the attachment default relation derives its
|
||||
// universal identifier name-free from the host and relation target object
|
||||
// identifiers, so a manifest field can only squat it by pinning that exact
|
||||
// derived value.
|
||||
const DERIVED_ATTACHMENTS_UNIVERSAL_IDENTIFIER =
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: TEST_APP_ID,
|
||||
objectUniversalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
});
|
||||
|
||||
const buildObjectWithAttachmentsField = ({
|
||||
attachmentsFieldUniversalIdentifier,
|
||||
}: {
|
||||
attachmentsFieldUniversalIdentifier: string;
|
||||
}): ObjectManifest =>
|
||||
buildDefaultObjectManifest({
|
||||
applicationUniversalIdentifier: TEST_APP_ID,
|
||||
nameSingular: OBJECT_NAME_SINGULAR,
|
||||
namePlural: OBJECT_NAME_PLURAL,
|
||||
labelSingular: 'Default Relation Collision Target',
|
||||
labelPlural: 'Default Relation Collision Targets',
|
||||
description: 'Object used to test default relation name collisions',
|
||||
universalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
additionalFields: [
|
||||
{
|
||||
universalIdentifier: attachmentsFieldUniversalIdentifier,
|
||||
type: FieldMetadataType.TEXT,
|
||||
name: 'attachments',
|
||||
label: 'Caller Attachments',
|
||||
isNullable: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// The default relations are engine-owned: the create side-effect handler
|
||||
// always emits them, so a manifest field can never take their place. It either
|
||||
// collides on name (random identifier) or on universal identifier (derived
|
||||
// identifier), and both collisions hard-fail the sync.
|
||||
describe('Sync application default relation name collision', () => {
|
||||
beforeAll(async () => {
|
||||
await setupApplicationForSync({
|
||||
applicationUniversalIdentifier: TEST_APP_ID,
|
||||
name: 'Test Default Relation Name Collision App',
|
||||
description: 'App for testing default relation name collisions',
|
||||
sourcePath: 'test-default-relation-name-collision',
|
||||
});
|
||||
}, 60000);
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanupApplicationAndAppRegistration({
|
||||
applicationUniversalIdentifier: TEST_APP_ID,
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject a manifest field named after a default relation when it carries a pinned universal identifier', async () => {
|
||||
// The pinned identifier differs from the derived forward field identifier,
|
||||
// so the side-effect "attachments" RELATION field and the manifest TEXT
|
||||
// field coexist in the create bucket and collide on name in the validator.
|
||||
const { errors } = await syncApplication({
|
||||
manifest: buildBaseManifest({
|
||||
appId: TEST_APP_ID,
|
||||
roleId: TEST_ROLE_ID,
|
||||
overrides: {
|
||||
objects: [
|
||||
buildObjectWithAttachmentsField({
|
||||
attachmentsFieldUniversalIdentifier: uuidv4(),
|
||||
}),
|
||||
],
|
||||
},
|
||||
}),
|
||||
expectToFail: true,
|
||||
});
|
||||
|
||||
expectOneNotInternalServerErrorSnapshot({ errors });
|
||||
}, 60000);
|
||||
|
||||
it('should reject a manifest field named after a default relation when it carries the derived universal identifier', async () => {
|
||||
// With the derived identifier the manifest field collides with the
|
||||
// side-effect forward field on universal identifier: the engine merge
|
||||
// detects a caller entity squatting a system-reserved identifier and
|
||||
// hard-fails (RESERVED_SYSTEM_UNIVERSAL_IDENTIFIER).
|
||||
const { errors } = await syncApplication({
|
||||
manifest: buildBaseManifest({
|
||||
appId: TEST_APP_ID,
|
||||
roleId: TEST_ROLE_ID,
|
||||
overrides: {
|
||||
objects: [
|
||||
buildObjectWithAttachmentsField({
|
||||
attachmentsFieldUniversalIdentifier:
|
||||
DERIVED_ATTACHMENTS_UNIVERSAL_IDENTIFIER,
|
||||
}),
|
||||
],
|
||||
},
|
||||
}),
|
||||
expectToFail: true,
|
||||
});
|
||||
|
||||
expectOneNotInternalServerErrorSnapshot({ errors });
|
||||
}, 60000);
|
||||
});
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
import { expectOneNotInternalServerErrorSnapshot } from 'test/integration/graphql/utils/expect-one-not-internal-server-error-snapshot.util';
|
||||
import { buildBaseManifest } from 'test/integration/metadata/suites/application/utils/build-base-manifest.util';
|
||||
import { buildDefaultObjectManifest } from 'test/integration/metadata/suites/application/utils/build-default-object-manifest.util';
|
||||
import { cleanupApplicationAndAppRegistration } from 'test/integration/metadata/suites/application/utils/cleanup-application-and-app-registration.util';
|
||||
import { setupApplicationForSync } from 'test/integration/metadata/suites/application/utils/setup-application-for-sync.util';
|
||||
import { syncApplication } from 'test/integration/metadata/suites/application/utils/sync-application.util';
|
||||
import {
|
||||
getFieldUniversalIdentifier,
|
||||
type ObjectManifest,
|
||||
} from 'twenty-shared/application';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
const TEST_APP_ID = uuidv4();
|
||||
const TEST_ROLE_ID = uuidv4();
|
||||
const OBJECT_UNIVERSAL_IDENTIFIER = uuidv4();
|
||||
|
||||
const OBJECT_NAME_SINGULAR = 'searchVectorHijackTarget';
|
||||
const OBJECT_NAME_PLURAL = 'searchVectorHijackTargets';
|
||||
|
||||
const SEARCH_VECTOR_UNIVERSAL_IDENTIFIER = getFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: TEST_APP_ID,
|
||||
objectUniversalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
name: 'searchVector',
|
||||
});
|
||||
|
||||
const buildCleanObject = (): ObjectManifest =>
|
||||
buildDefaultObjectManifest({
|
||||
applicationUniversalIdentifier: TEST_APP_ID,
|
||||
nameSingular: OBJECT_NAME_SINGULAR,
|
||||
namePlural: OBJECT_NAME_PLURAL,
|
||||
labelSingular: 'Search Vector Hijack Target',
|
||||
labelPlural: 'Search Vector Hijack Targets',
|
||||
description: 'Object used to test search vector identifier hijack',
|
||||
universalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
// Squat the engine-owned searchVector slot: declare a foreign, non-system
|
||||
// field carrying the deterministic universal identifier the engine derives
|
||||
// for searchVector. This is the exact override a malicious manifest could
|
||||
// attempt on a second sync to hijack a system field.
|
||||
const buildObjectHijackingSearchVectorUniversalIdentifier =
|
||||
(): ObjectManifest => {
|
||||
const cleanObject = buildCleanObject();
|
||||
|
||||
return {
|
||||
...cleanObject,
|
||||
fields: [
|
||||
...cleanObject.fields,
|
||||
{
|
||||
universalIdentifier: SEARCH_VECTOR_UNIVERSAL_IDENTIFIER,
|
||||
type: FieldMetadataType.TEXT,
|
||||
name: 'stolenSearchVector',
|
||||
label: 'Stolen Search Vector',
|
||||
isNullable: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
// Redeclare searchVector under its derived universal identifier: the builder
|
||||
// matches the engine-provisioned field and emits an update, rejected because
|
||||
// the manifest defaults mutate properties system fields do not allow updating.
|
||||
const buildObjectAuthoringSearchVector = (): ObjectManifest => {
|
||||
const cleanObject = buildCleanObject();
|
||||
|
||||
return {
|
||||
...cleanObject,
|
||||
fields: [
|
||||
...cleanObject.fields,
|
||||
{
|
||||
universalIdentifier: SEARCH_VECTOR_UNIVERSAL_IDENTIFIER,
|
||||
type: FieldMetadataType.TS_VECTOR,
|
||||
name: 'searchVector',
|
||||
label: 'Search vector',
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
// Declare a field reusing the reserved searchVector name under a foreign
|
||||
// universal identifier: the builder emits a create colliding with the
|
||||
// engine-provisioned field name.
|
||||
const buildObjectCreatingForeignSearchVector = (): ObjectManifest => {
|
||||
const cleanObject = buildCleanObject();
|
||||
|
||||
return {
|
||||
...cleanObject,
|
||||
fields: [
|
||||
...cleanObject.fields,
|
||||
{
|
||||
universalIdentifier: uuidv4(),
|
||||
type: FieldMetadataType.TEXT,
|
||||
name: 'searchVector',
|
||||
label: 'Foreign Search Vector',
|
||||
isNullable: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
describe('Sync application should reject hijacking the searchVector system field', () => {
|
||||
beforeAll(async () => {
|
||||
await setupApplicationForSync({
|
||||
applicationUniversalIdentifier: TEST_APP_ID,
|
||||
name: 'Test Search Vector Hijack App',
|
||||
description: 'App for testing search vector identifier hijack',
|
||||
sourcePath: 'test-search-vector-hijack',
|
||||
});
|
||||
|
||||
await syncApplication({
|
||||
expectToFail: false,
|
||||
manifest: buildBaseManifest({
|
||||
appId: TEST_APP_ID,
|
||||
roleId: TEST_ROLE_ID,
|
||||
overrides: { objects: [buildCleanObject()] },
|
||||
}),
|
||||
});
|
||||
}, 60000);
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanupApplicationAndAppRegistration({
|
||||
applicationUniversalIdentifier: TEST_APP_ID,
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject a manifest field declared under the reserved searchVector name', async () => {
|
||||
const { errors } = await syncApplication({
|
||||
manifest: buildBaseManifest({
|
||||
appId: TEST_APP_ID,
|
||||
roleId: TEST_ROLE_ID,
|
||||
overrides: { objects: [buildObjectAuthoringSearchVector()] },
|
||||
}),
|
||||
expectToFail: true,
|
||||
});
|
||||
|
||||
expectOneNotInternalServerErrorSnapshot({ errors });
|
||||
}, 60000);
|
||||
|
||||
it('should reject a manifest field reusing the searchVector name under a foreign universal identifier', async () => {
|
||||
const { errors } = await syncApplication({
|
||||
manifest: buildBaseManifest({
|
||||
appId: TEST_APP_ID,
|
||||
roleId: TEST_ROLE_ID,
|
||||
overrides: { objects: [buildObjectCreatingForeignSearchVector()] },
|
||||
}),
|
||||
expectToFail: true,
|
||||
});
|
||||
|
||||
expectOneNotInternalServerErrorSnapshot({ errors });
|
||||
}, 60000);
|
||||
|
||||
it('should reject a manifest field squatting the searchVector deterministic universal identifier', async () => {
|
||||
const { errors } = await syncApplication({
|
||||
manifest: buildBaseManifest({
|
||||
appId: TEST_APP_ID,
|
||||
roleId: TEST_ROLE_ID,
|
||||
overrides: {
|
||||
objects: [buildObjectHijackingSearchVectorUniversalIdentifier()],
|
||||
},
|
||||
}),
|
||||
expectToFail: true,
|
||||
});
|
||||
|
||||
expectOneNotInternalServerErrorSnapshot({ errors });
|
||||
}, 60000);
|
||||
});
|
||||
+150
-2
@@ -8,8 +8,15 @@ import { findManyObjectMetadata } from 'test/integration/metadata/suites/object-
|
||||
import { findRoles } from 'test/integration/metadata/suites/role/utils/find-roles.util';
|
||||
import { findSkills } from 'test/integration/metadata/suites/skill/utils/find-skills.util';
|
||||
import { extractRecordIdsAndDatesAsExpectAny } from 'test/utils/extract-record-ids-and-dates-as-expect-any';
|
||||
import { type FieldManifest, type Manifest } from 'twenty-shared/application';
|
||||
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
import {
|
||||
type FieldManifest,
|
||||
getSystemRelationFieldUniversalIdentifier,
|
||||
type Manifest,
|
||||
} from 'twenty-shared/application';
|
||||
import {
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS,
|
||||
STANDARD_OBJECTS,
|
||||
} from 'twenty-shared/metadata';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
@@ -168,6 +175,147 @@ describe('syncApplication', () => {
|
||||
});
|
||||
}, 60000);
|
||||
|
||||
// The snapshot masks every identifier as Any<String>, so it cannot catch a
|
||||
// regression in the deterministic universal identifiers of the default
|
||||
// relations. This test recomputes them and asserts the emitted migration
|
||||
// actions carry them exactly, on both sides of each relation.
|
||||
it('should provision the four engine-owned default relations on initial sync', async () => {
|
||||
const NAME_PLURAL_BY_STANDARD_OBJECT_NAME_SINGULAR = {
|
||||
timelineActivity: 'timelineActivities',
|
||||
attachment: 'attachments',
|
||||
noteTarget: 'noteTargets',
|
||||
taskTarget: 'taskTargets',
|
||||
} as const;
|
||||
|
||||
const { data: syncData } = await syncApplication({
|
||||
manifest: buildManifest(),
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
type FlatFieldEntity = {
|
||||
universalIdentifier: string;
|
||||
name?: string;
|
||||
type?: string;
|
||||
isSystem?: boolean;
|
||||
isSystemSideEffect?: boolean;
|
||||
morphId?: string | null;
|
||||
objectMetadataUniversalIdentifier?: string;
|
||||
relationTargetObjectMetadataUniversalIdentifier?: string | null;
|
||||
relationTargetFieldMetadataUniversalIdentifier?: string | null;
|
||||
universalSettings?: { joinColumnName?: string } | null;
|
||||
universalFlatIndexFieldMetadatas?: {
|
||||
fieldMetadataUniversalIdentifier: string;
|
||||
}[];
|
||||
};
|
||||
type FlatEntityAction = {
|
||||
type: string;
|
||||
metadataName: string;
|
||||
flatEntity: FlatFieldEntity;
|
||||
// A relation field create action carries its reverse field inline.
|
||||
relatedUniversalFlatFieldMetadata?: FlatFieldEntity;
|
||||
};
|
||||
|
||||
const actions = (
|
||||
syncData as {
|
||||
syncApplication: { actions: FlatEntityAction[] };
|
||||
}
|
||||
).syncApplication.actions;
|
||||
|
||||
const fieldCreateActionByUniversalIdentifier = Object.fromEntries(
|
||||
actions
|
||||
.filter(
|
||||
(action) =>
|
||||
action.metadataName === 'fieldMetadata' && action.type === 'create',
|
||||
)
|
||||
.map((action) => [action.flatEntity.universalIdentifier, action]),
|
||||
);
|
||||
const indexCreateActions = actions.filter(
|
||||
(action) => action.metadataName === 'index' && action.type === 'create',
|
||||
);
|
||||
|
||||
for (const standardObjectNameSingular of DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS) {
|
||||
const standardObjectUniversalIdentifier =
|
||||
STANDARD_OBJECTS[standardObjectNameSingular].universalIdentifier;
|
||||
const standardObjectNamePlural =
|
||||
NAME_PLURAL_BY_STANDARD_OBJECT_NAME_SINGULAR[
|
||||
standardObjectNameSingular
|
||||
];
|
||||
|
||||
const forwardUniversalIdentifier =
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: TEST_APP_ID,
|
||||
objectUniversalIdentifier: TEST_OBJECT.universalIdentifier,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
standardObjectUniversalIdentifier,
|
||||
});
|
||||
const reverseUniversalIdentifier =
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: TEST_APP_ID,
|
||||
objectUniversalIdentifier: standardObjectUniversalIdentifier,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
TEST_OBJECT.universalIdentifier,
|
||||
});
|
||||
|
||||
// Forward RELATION field on the ticket, named after the standard
|
||||
// object's namePlural, under the name-free universal identifier.
|
||||
const forwardCreateAction =
|
||||
fieldCreateActionByUniversalIdentifier[forwardUniversalIdentifier];
|
||||
|
||||
expect(forwardCreateAction?.flatEntity).toMatchObject({
|
||||
name: standardObjectNamePlural,
|
||||
type: FieldMetadataType.RELATION,
|
||||
// Engine-owned (isSystemSideEffect) but not isSystem: the engine
|
||||
// rename/delete cascades must pass the validator system-field gates.
|
||||
isSystem: false,
|
||||
isSystemSideEffect: true,
|
||||
objectMetadataUniversalIdentifier: TEST_OBJECT.universalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
standardObjectUniversalIdentifier,
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
reverseUniversalIdentifier,
|
||||
});
|
||||
|
||||
// Reverse MORPH_RELATION field on the standard object, carried inline on
|
||||
// the forward create action, under the name-free deterministic universal
|
||||
// identifier, with the engine-pinned targetMorphId and the join column.
|
||||
expect(
|
||||
forwardCreateAction?.relatedUniversalFlatFieldMetadata,
|
||||
).toMatchObject({
|
||||
name: 'targetTicket',
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
isSystem: false,
|
||||
isSystemSideEffect: true,
|
||||
universalIdentifier: reverseUniversalIdentifier,
|
||||
morphId:
|
||||
STANDARD_OBJECTS[standardObjectNameSingular].morphIds.targetMorphId
|
||||
.morphId,
|
||||
objectMetadataUniversalIdentifier: standardObjectUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
TEST_OBJECT.universalIdentifier,
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
forwardUniversalIdentifier,
|
||||
universalSettings: expect.objectContaining({
|
||||
joinColumnName: 'targetTicketId',
|
||||
}),
|
||||
});
|
||||
|
||||
// Engine-owned join-column index backing the reverse field.
|
||||
const reverseJoinColumnIndexAction = indexCreateActions.find((action) =>
|
||||
action.flatEntity.universalFlatIndexFieldMetadatas?.some(
|
||||
(indexFieldMetadata) =>
|
||||
indexFieldMetadata.fieldMetadataUniversalIdentifier ===
|
||||
reverseUniversalIdentifier,
|
||||
),
|
||||
);
|
||||
|
||||
expect(reverseJoinColumnIndexAction).toBeDefined();
|
||||
expect(reverseJoinColumnIndexAction?.flatEntity).toMatchObject({
|
||||
isSystemSideEffect: true,
|
||||
objectMetadataUniversalIdentifier: standardObjectUniversalIdentifier,
|
||||
});
|
||||
}
|
||||
}, 60000);
|
||||
|
||||
it('should delete old field and create equivalent one when field universalIdentifier changes', async () => {
|
||||
const originalFieldId = uuidv4();
|
||||
const updatedFieldId = uuidv4();
|
||||
|
||||
+10
-64
@@ -2,11 +2,12 @@ import {
|
||||
getFieldUniversalIdentifier,
|
||||
type ObjectManifest,
|
||||
} from 'twenty-shared/application';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
// System field universal identifiers are server-owned and validated against
|
||||
// the deterministic derivation, so the manifest must carry the derived values.
|
||||
// System fields (id, createdAt, …) are engine-provisioned and must not be
|
||||
// manifest-authored: the sync rejects any reserved field name. The label
|
||||
// identifier still defaults to the engine-derived id field universal
|
||||
// identifier, which is resolvable without declaring the field.
|
||||
export const buildDefaultObjectManifest = ({
|
||||
nameSingular,
|
||||
namePlural,
|
||||
@@ -32,15 +33,11 @@ export const buildDefaultObjectManifest = ({
|
||||
}): ObjectManifest => {
|
||||
const objectUniversalIdentifier = universalIdentifier ?? uuidv4();
|
||||
|
||||
const computeSystemFieldUniversalIdentifier = (fieldName: string) =>
|
||||
getFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier,
|
||||
name: fieldName,
|
||||
});
|
||||
|
||||
const idFieldUniversalIdentifier =
|
||||
computeSystemFieldUniversalIdentifier('id');
|
||||
const idFieldUniversalIdentifier = getFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier,
|
||||
name: 'id',
|
||||
});
|
||||
|
||||
return {
|
||||
universalIdentifier: objectUniversalIdentifier,
|
||||
@@ -53,57 +50,6 @@ export const buildDefaultObjectManifest = ({
|
||||
labelPlural,
|
||||
description,
|
||||
icon,
|
||||
fields: [
|
||||
{
|
||||
universalIdentifier: idFieldUniversalIdentifier,
|
||||
type: FieldMetadataType.UUID,
|
||||
name: 'id',
|
||||
label: 'Id',
|
||||
},
|
||||
{
|
||||
universalIdentifier: computeSystemFieldUniversalIdentifier('createdAt'),
|
||||
type: FieldMetadataType.DATE_TIME,
|
||||
name: 'createdAt',
|
||||
label: 'Creation date',
|
||||
},
|
||||
{
|
||||
universalIdentifier: computeSystemFieldUniversalIdentifier('updatedAt'),
|
||||
type: FieldMetadataType.DATE_TIME,
|
||||
name: 'updatedAt',
|
||||
label: 'Last update',
|
||||
},
|
||||
{
|
||||
universalIdentifier: computeSystemFieldUniversalIdentifier('deletedAt'),
|
||||
type: FieldMetadataType.DATE_TIME,
|
||||
name: 'deletedAt',
|
||||
label: 'Deleted at',
|
||||
},
|
||||
{
|
||||
universalIdentifier: computeSystemFieldUniversalIdentifier('createdBy'),
|
||||
type: FieldMetadataType.ACTOR,
|
||||
name: 'createdBy',
|
||||
label: 'Created by',
|
||||
},
|
||||
{
|
||||
universalIdentifier: computeSystemFieldUniversalIdentifier('updatedBy'),
|
||||
type: FieldMetadataType.ACTOR,
|
||||
name: 'updatedBy',
|
||||
label: 'Updated by',
|
||||
},
|
||||
{
|
||||
universalIdentifier: computeSystemFieldUniversalIdentifier('position'),
|
||||
type: FieldMetadataType.POSITION,
|
||||
name: 'position',
|
||||
label: 'Position',
|
||||
},
|
||||
{
|
||||
universalIdentifier:
|
||||
computeSystemFieldUniversalIdentifier('searchVector'),
|
||||
type: FieldMetadataType.TS_VECTOR,
|
||||
name: 'searchVector',
|
||||
label: 'Search vector',
|
||||
},
|
||||
...additionalFields,
|
||||
],
|
||||
fields: [...additionalFields],
|
||||
};
|
||||
};
|
||||
|
||||
+20
-12
@@ -3,7 +3,10 @@ import { findManyFieldsMetadata } from 'test/integration/metadata/suites/field-m
|
||||
import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util';
|
||||
import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util';
|
||||
|
||||
import { getFieldUniversalIdentifier } from 'twenty-shared/application';
|
||||
import {
|
||||
getFieldUniversalIdentifier,
|
||||
getSystemRelationFieldUniversalIdentifier,
|
||||
} from 'twenty-shared/application';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
const SYSTEM_FIELD_NAMES = [
|
||||
@@ -140,13 +143,6 @@ describe('Custom object creation deterministic field universal identifiers', ()
|
||||
);
|
||||
|
||||
expect(forwardField).toBeDefined();
|
||||
expect(forwardField?.universalIdentifier).toBe(
|
||||
getFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier,
|
||||
name: forwardFieldName,
|
||||
}),
|
||||
);
|
||||
|
||||
const standardRelationObject =
|
||||
forwardField?.relation?.targetObjectMetadata;
|
||||
@@ -174,11 +170,23 @@ describe('Custom object creation deterministic field universal identifiers', ()
|
||||
.find((field: FetchedField) => field.name === storedReverseFieldName);
|
||||
|
||||
expect(reverseField).toBeDefined();
|
||||
expect(reverseField?.universalIdentifier).toBe(
|
||||
getFieldUniversalIdentifier({
|
||||
// Both sides of a system relation use the name-free deterministic
|
||||
// identifier (host + relation target object, direction encoded by
|
||||
// swapping them) so an object rename stays a lossless update.
|
||||
expect(forwardField?.universalIdentifier).toBe(
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier: standardRelationObject.universalIdentifier,
|
||||
name: storedReverseFieldName,
|
||||
objectUniversalIdentifier: objectUniversalIdentifier,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
standardRelationObject.universalIdentifier,
|
||||
}),
|
||||
);
|
||||
expect(reverseField?.universalIdentifier).toBe(
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier:
|
||||
standardRelationObject.universalIdentifier,
|
||||
relationTargetObjectUniversalIdentifier: objectUniversalIdentifier,
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
||||
+99
-1
@@ -1,4 +1,6 @@
|
||||
import { deleteOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/delete-one-field-metadata.util';
|
||||
import { findManyFieldsMetadataQueryFactory } from 'test/integration/metadata/suites/field-metadata/utils/find-many-fields-metadata-query-factory.util';
|
||||
import { updateOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/update-one-field-metadata.util';
|
||||
import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util';
|
||||
import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util';
|
||||
import { findManyObjectMetadataQueryFactory } from 'test/integration/metadata/suites/object-metadata/utils/find-many-object-metadata-query-factory.util';
|
||||
@@ -25,6 +27,7 @@ describe('Custom object renaming', () => {
|
||||
objectMetadataId: '',
|
||||
foreignKeyFieldMetadataId: '',
|
||||
relationFieldMetadataId: '',
|
||||
relationFieldMetadataUniversalIdentifier: '',
|
||||
},
|
||||
}),
|
||||
{},
|
||||
@@ -47,6 +50,7 @@ describe('Custom object renaming', () => {
|
||||
name
|
||||
label
|
||||
type
|
||||
universalIdentifier
|
||||
object {
|
||||
id
|
||||
}
|
||||
@@ -132,10 +136,18 @@ describe('Custom object renaming', () => {
|
||||
const relationFieldMetadataId = relationFieldMetadata?.id;
|
||||
|
||||
expect(relationFieldMetadataId).not.toBeUndefined();
|
||||
// Reverse system relation fields carry the engine-derived label
|
||||
// (capitalized source object nameSingular)
|
||||
expect(relationFieldMetadata?.label).toBe(
|
||||
capitalize(CUSTOM_OBJECT.nameSingular),
|
||||
);
|
||||
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
standardObjectRelationsMap[relation].relationFieldMetadataId =
|
||||
relationFieldMetadataId;
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
standardObjectRelationsMap[relation].relationFieldMetadataUniversalIdentifier =
|
||||
relationFieldMetadata?.universalIdentifier;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -171,9 +183,95 @@ describe('Custom object renaming', () => {
|
||||
expect(data.updateOneObject.namePlural).toBe(HOUSE_NAME_PLURAL);
|
||||
expect(data.updateOneObject.labelSingular).toBe(HOUSE_LABEL_SINGULAR);
|
||||
expect(data.updateOneObject.labelPlural).toBe(HOUSE_LABEL_PLURAL);
|
||||
|
||||
// The reverse morph fields on the standard objects must be renamed in place
|
||||
// (name and engine-derived label follow the new object name) while keeping
|
||||
// their universal identifier stable, so the rename stays lossless.
|
||||
const expectedReverseFieldName = `target${capitalize(HOUSE_NAME_SINGULAR)}`;
|
||||
const expectedReverseFieldLabel = capitalize(HOUSE_NAME_SINGULAR);
|
||||
const fields = await makeMetadataAPIRequest(fieldsGraphqlOperation);
|
||||
|
||||
STANDARD_OBJECT_RELATIONS.forEach((relation) => {
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
const relationEntry = standardObjectRelationsMap[relation];
|
||||
const relationFieldMetadataId = relationEntry.relationFieldMetadataId;
|
||||
const relationFieldMetadataUniversalIdentifier =
|
||||
relationEntry.relationFieldMetadataUniversalIdentifier;
|
||||
|
||||
const renamedReverseField = fields.body.data.fields.edges
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
.map((field) => field.node)
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
.find((field) => field.id === relationFieldMetadataId);
|
||||
|
||||
expect(renamedReverseField).toBeDefined();
|
||||
expect(renamedReverseField.name).toBe(expectedReverseFieldName);
|
||||
expect(renamedReverseField.label).toBe(expectedReverseFieldLabel);
|
||||
expect(renamedReverseField.universalIdentifier).toBe(
|
||||
relationFieldMetadataUniversalIdentifier,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('3. should delete custom object', async () => {
|
||||
it('3. should reject direct deletion of a system side-effect relation field', async () => {
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
const timelineActivityRelation = standardObjectRelationsMap['timelineActivity'];
|
||||
const relationFieldMetadataId =
|
||||
timelineActivityRelation.relationFieldMetadataId;
|
||||
|
||||
const { errors } = await deleteOneFieldMetadata({
|
||||
expectToFail: true,
|
||||
input: { idToDelete: relationFieldMetadataId },
|
||||
});
|
||||
|
||||
expect(errors).toBeDefined();
|
||||
expect(errors.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('4. should reject direct edition of a system side-effect relation field', async () => {
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
const timelineActivityRelation = standardObjectRelationsMap['timelineActivity'];
|
||||
const relationFieldMetadataId =
|
||||
timelineActivityRelation.relationFieldMetadataId;
|
||||
|
||||
const { errors } = await updateOneFieldMetadata({
|
||||
expectToFail: true,
|
||||
input: {
|
||||
idToUpdate: relationFieldMetadataId,
|
||||
updatePayload: { label: 'Should not be editable' },
|
||||
},
|
||||
});
|
||||
|
||||
expect(errors).toBeDefined();
|
||||
expect(errors.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('5. should reject a morph relations update payload on a system side-effect relation field', async () => {
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
const timelineActivityRelation = standardObjectRelationsMap['timelineActivity'];
|
||||
const relationFieldMetadataId =
|
||||
timelineActivityRelation.relationFieldMetadataId;
|
||||
|
||||
// morphRelationsUpdatePayload is not an editable property, so it must be
|
||||
// rejected explicitly for engine-owned fields instead of silently creating
|
||||
// relation fields and indexes on them
|
||||
const { errors } = await updateOneFieldMetadata({
|
||||
expectToFail: true,
|
||||
input: {
|
||||
idToUpdate: relationFieldMetadataId,
|
||||
updatePayload: {
|
||||
morphRelationsUpdatePayload: [
|
||||
{ targetObjectMetadataId: listingObjectId },
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(errors).toBeDefined();
|
||||
expect(errors.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('6. should delete custom object', async () => {
|
||||
await updateOneObjectMetadata({
|
||||
expectToFail: false,
|
||||
input: {
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { getFieldUniversalIdentifier } from '@/application/deterministic-identifier/get-field-universal-identifier.util';
|
||||
import { getSystemRelationFieldUniversalIdentifier } from '@/application/deterministic-identifier/get-system-relation-field-universal-identifier.util';
|
||||
|
||||
const APP = '11111111-1111-4111-8111-111111111111';
|
||||
const HOST_OBJECT = '22222222-2222-4222-8222-222222222222';
|
||||
const RELATION_TARGET_OBJECT = '33333333-3333-4333-8333-333333333333';
|
||||
|
||||
describe('getSystemRelationFieldUniversalIdentifier', () => {
|
||||
it('derives a deterministic id from the host and relation target object identifiers', () => {
|
||||
expect(
|
||||
getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: APP,
|
||||
objectUniversalIdentifier: HOST_OBJECT,
|
||||
relationTargetObjectUniversalIdentifier: RELATION_TARGET_OBJECT,
|
||||
}),
|
||||
).toBe('d3a641a1-f0fd-5213-a28e-af81e00c991e');
|
||||
});
|
||||
|
||||
it('derives distinct ids for the two sides of the same relation (host and target swapped)', () => {
|
||||
const reverseSide = getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: APP,
|
||||
objectUniversalIdentifier: HOST_OBJECT,
|
||||
relationTargetObjectUniversalIdentifier: RELATION_TARGET_OBJECT,
|
||||
});
|
||||
const forwardSide = getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: APP,
|
||||
objectUniversalIdentifier: RELATION_TARGET_OBJECT,
|
||||
relationTargetObjectUniversalIdentifier: HOST_OBJECT,
|
||||
});
|
||||
|
||||
expect(reverseSide).not.toBe(forwardSide);
|
||||
});
|
||||
|
||||
it('cannot collide with a name-based field identifier for any real field name', () => {
|
||||
// The seed collides only if a field name equals
|
||||
// `systemRelation:${relationTargetUID}`, which is unreachable because field
|
||||
// names cannot contain colons. Any real (colon-free) field name on the host
|
||||
// object therefore derives a distinct id.
|
||||
const systemRelationIdentifier = getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: APP,
|
||||
objectUniversalIdentifier: HOST_OBJECT,
|
||||
relationTargetObjectUniversalIdentifier: RELATION_TARGET_OBJECT,
|
||||
});
|
||||
const nameBasedIdentifier = getFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier: APP,
|
||||
objectUniversalIdentifier: HOST_OBJECT,
|
||||
name: 'targetCompany',
|
||||
});
|
||||
|
||||
expect(systemRelationIdentifier).not.toBe(nameBasedIdentifier);
|
||||
});
|
||||
});
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
import { computeDeterministicUuid } from '@/application/deterministic-identifier/compute-deterministic-uuid.util';
|
||||
|
||||
// A field is identified by its name within its object.
|
||||
export const getFieldUniversalIdentifier = ({
|
||||
applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier,
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import { computeDeterministicUuid } from '@/application/deterministic-identifier/compute-deterministic-uuid.util';
|
||||
|
||||
export const getSystemRelationFieldUniversalIdentifier = ({
|
||||
applicationUniversalIdentifier,
|
||||
objectUniversalIdentifier,
|
||||
relationTargetObjectUniversalIdentifier,
|
||||
}: {
|
||||
applicationUniversalIdentifier: string;
|
||||
objectUniversalIdentifier: string;
|
||||
relationTargetObjectUniversalIdentifier: string;
|
||||
}): string =>
|
||||
computeDeterministicUuid({
|
||||
entityNamespace: 'fieldMetadata',
|
||||
value: `${objectUniversalIdentifier}:systemRelation:${relationTargetObjectUniversalIdentifier}`,
|
||||
applicationUniversalIdentifier,
|
||||
});
|
||||
@@ -75,6 +75,7 @@ export { getRoleUniversalIdentifier } from './deterministic-identifier/get-role-
|
||||
export { getSearchFieldUniversalIdentifier } from './deterministic-identifier/get-search-field-universal-identifier.util';
|
||||
export { getSelectOptionUniversalIdentifier } from './deterministic-identifier/get-select-option-universal-identifier.util';
|
||||
export { getSkillUniversalIdentifier } from './deterministic-identifier/get-skill-universal-identifier.util';
|
||||
export { getSystemRelationFieldUniversalIdentifier } from './deterministic-identifier/get-system-relation-field-universal-identifier.util';
|
||||
export { getViewFieldGroupUniversalIdentifier } from './deterministic-identifier/get-view-field-group-universal-identifier.util';
|
||||
export { getViewFieldUniversalIdentifier } from './deterministic-identifier/get-view-field-universal-identifier.util';
|
||||
export { getViewFilterUniversalIdentifier } from './deterministic-identifier/get-view-filter-universal-identifier.util';
|
||||
|
||||
+48
-48
@@ -35,25 +35,25 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "e3222f8c-aad5-5873-9a10-648908f48f81",
|
||||
},
|
||||
"targetCompany": {
|
||||
"universalIdentifier": "20202020-ceab-4a28-b546-73b06b4c08d5",
|
||||
"universalIdentifier": "a69093bb-6f2a-5ad6-90b1-0d78e9528019",
|
||||
},
|
||||
"targetDashboard": {
|
||||
"universalIdentifier": "20202020-5324-43f3-9dbf-1a33e7de0ce6",
|
||||
"universalIdentifier": "3af87717-6757-5d61-940e-3016cff35cdc",
|
||||
},
|
||||
"targetNote": {
|
||||
"universalIdentifier": "20202020-4f4b-4503-a6fc-6b982f3dffb5",
|
||||
"universalIdentifier": "a627557c-db37-53be-8a59-9aa2d45cd7ee",
|
||||
},
|
||||
"targetOpportunity": {
|
||||
"universalIdentifier": "20202020-7374-499d-bea3-9354890755b5",
|
||||
"universalIdentifier": "523ff02a-1af7-5799-8730-01e2beea7150",
|
||||
},
|
||||
"targetPerson": {
|
||||
"universalIdentifier": "20202020-0158-4aa2-965c-5cdafe21ffa2",
|
||||
"universalIdentifier": "721ddb1f-468d-535a-9809-cb3429a52e06",
|
||||
},
|
||||
"targetTask": {
|
||||
"universalIdentifier": "20202020-51e5-4621-9cf8-215487951c4b",
|
||||
"universalIdentifier": "ace06117-9980-5506-adae-74c71556728b",
|
||||
},
|
||||
"targetWorkflow": {
|
||||
"universalIdentifier": "20202020-f1e8-4c9d-8a7b-3f5e1d2c9a8b",
|
||||
"universalIdentifier": "edbe3ea7-b9ff-5b23-9a81-ef53a190c873",
|
||||
},
|
||||
"updatedAt": {
|
||||
"universalIdentifier": "8ac2b742-975b-5633-9f7f-fcf9920a72e8",
|
||||
@@ -734,7 +734,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "60f533b7-2166-4071-a767-ceb0286822fd",
|
||||
},
|
||||
"attachments": {
|
||||
"universalIdentifier": "20202020-c1b5-4120-b0f0-987ca401ed53",
|
||||
"universalIdentifier": "a4399ae3-fe89-59fe-a282-aec77d4e63a8",
|
||||
},
|
||||
"createdAt": {
|
||||
"universalIdentifier": "d206d586-fd61-56e1-80a8-9993beb7be0b",
|
||||
@@ -758,7 +758,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "20202020-4d99-4e2e-a84c-4a27837b1ece",
|
||||
},
|
||||
"noteTargets": {
|
||||
"universalIdentifier": "20202020-bae0-4556-a74a-a9c686f77a88",
|
||||
"universalIdentifier": "0b28db77-8099-5ce3-a11f-86a5778d7740",
|
||||
},
|
||||
"opportunities": {
|
||||
"universalIdentifier": "20202020-add3-4658-8e23-d70dccb6d0ec",
|
||||
@@ -773,10 +773,10 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "d043190d-3335-5463-b98d-eecbf7b41c65",
|
||||
},
|
||||
"taskTargets": {
|
||||
"universalIdentifier": "20202020-cb17-4a61-8f8f-3be6730480de",
|
||||
"universalIdentifier": "9d7b0087-7037-55dc-bb59-456064455694",
|
||||
},
|
||||
"timelineActivities": {
|
||||
"universalIdentifier": "20202020-0414-4daf-9c0d-64fe7b27f89f",
|
||||
"universalIdentifier": "28ec0f8f-ad23-5317-b2d9-1a487bcefee2",
|
||||
},
|
||||
"updatedAt": {
|
||||
"universalIdentifier": "a1add354-649b-5ab6-9fc4-a5ab112110ac",
|
||||
@@ -893,7 +893,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"dashboard": {
|
||||
"fields": {
|
||||
"attachments": {
|
||||
"universalIdentifier": "20202020-bf6f-4220-8c55-2764f1175870",
|
||||
"universalIdentifier": "6e0748cd-8876-53f9-b78d-8bdb3c71883e",
|
||||
},
|
||||
"createdAt": {
|
||||
"universalIdentifier": "78bc7f2f-9060-571d-a690-de20ac22622b",
|
||||
@@ -917,7 +917,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "32804a7c-2b8c-57cd-8a41-963d5f4b1503",
|
||||
},
|
||||
"timelineActivities": {
|
||||
"universalIdentifier": "99c330c0-5b7d-4276-a764-aed84499dfb5",
|
||||
"universalIdentifier": "82711ab6-00a2-57e7-9db8-9f77dde9944c",
|
||||
},
|
||||
"title": {
|
||||
"universalIdentifier": "20202020-20ee-4091-95dc-44b57eda3a89",
|
||||
@@ -1107,7 +1107,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "7251544c-b07a-4f0d-9d0a-48514367f230",
|
||||
},
|
||||
"timelineActivities": {
|
||||
"universalIdentifier": "d4e5f607-1829-4da3-8eb4-25f607182930",
|
||||
"universalIdentifier": "b4dd1932-bcfa-50c6-ada7-37de5d9c2825",
|
||||
},
|
||||
"unsubscribeTopicId": {
|
||||
"universalIdentifier": "0648e7ad-1769-4ff6-a4d5-72da79ef169c",
|
||||
@@ -1403,7 +1403,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "a163f11e-cf13-5a7e-8ac2-ff522d9a7a79",
|
||||
},
|
||||
"timelineActivities": {
|
||||
"universalIdentifier": "e0a5b2c3-4d6f-4e81-9a02-1b3c4d5e6f70",
|
||||
"universalIdentifier": "e0fbfc29-9b77-52c0-935e-a21af8e10325",
|
||||
},
|
||||
"updatedAt": {
|
||||
"universalIdentifier": "fbdc216f-2f82-59c7-af5c-daa6e6009e46",
|
||||
@@ -1668,7 +1668,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"note": {
|
||||
"fields": {
|
||||
"attachments": {
|
||||
"universalIdentifier": "20202020-4986-4c92-bf19-39934b149b16",
|
||||
"universalIdentifier": "b5e03b44-f726-5eae-9ea9-141d074f2120",
|
||||
},
|
||||
"bodyV2": {
|
||||
"universalIdentifier": "20202020-a7bb-4d94-be51-8f25181502c8",
|
||||
@@ -1695,7 +1695,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "0ad23e30-4fe2-5200-88e5-dd14a9e5438a",
|
||||
},
|
||||
"timelineActivities": {
|
||||
"universalIdentifier": "20202020-7030-42f8-929c-1a57b25d6bce",
|
||||
"universalIdentifier": "dd80c0fb-074a-5ca2-8596-dbb967f20155",
|
||||
},
|
||||
"title": {
|
||||
"universalIdentifier": "20202020-faeb-4c76-8ba6-ccbb0b4a965f",
|
||||
@@ -1797,13 +1797,13 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "d853a31b-f266-57a1-9a9f-ecc187864a01",
|
||||
},
|
||||
"targetCompany": {
|
||||
"universalIdentifier": "c500fbc0-d6f2-4982-a959-5a755431696c",
|
||||
"universalIdentifier": "26b5a2d6-3296-5660-8f5b-a5710c11ae33",
|
||||
},
|
||||
"targetOpportunity": {
|
||||
"universalIdentifier": "20202020-4e42-417a-a705-76581c9ade79",
|
||||
"universalIdentifier": "27519e5b-b16a-50cc-8de1-c5d6a2ff5c61",
|
||||
},
|
||||
"targetPerson": {
|
||||
"universalIdentifier": "20202020-38ca-4aab-92f5-8a605ca2e4c5",
|
||||
"universalIdentifier": "b445c148-eacf-56a8-bc21-e67e7ae93302",
|
||||
},
|
||||
"updatedAt": {
|
||||
"universalIdentifier": "18a0222a-d8d3-5a5a-89a7-55f0873b0d20",
|
||||
@@ -1861,7 +1861,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "20202020-583e-4642-8533-db761d5fa82f",
|
||||
},
|
||||
"attachments": {
|
||||
"universalIdentifier": "20202020-87c7-4118-83d6-2f4031005209",
|
||||
"universalIdentifier": "37d15d4b-7441-5bbc-8a5f-228f2d62abf4",
|
||||
},
|
||||
"closeDate": {
|
||||
"universalIdentifier": "20202020-527e-44d6-b1ac-c4158d307b97",
|
||||
@@ -1885,7 +1885,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "20202020-8609-4f65-a2d9-44009eb422b5",
|
||||
},
|
||||
"noteTargets": {
|
||||
"universalIdentifier": "20202020-dd3f-42d5-a382-db58aabf43d3",
|
||||
"universalIdentifier": "ee980fc9-5f51-5986-9fbe-ccf5a103f595",
|
||||
},
|
||||
"owner": {
|
||||
"universalIdentifier": "20202020-be7e-4d1e-8e19-3d5c7c4b9f2a",
|
||||
@@ -1903,10 +1903,10 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "20202020-6f76-477d-8551-28cd65b2b4b9",
|
||||
},
|
||||
"taskTargets": {
|
||||
"universalIdentifier": "20202020-59c0-4179-a208-4a255f04a5be",
|
||||
"universalIdentifier": "3e20f0e5-c0f5-5af4-8cac-02a65ecc4e86",
|
||||
},
|
||||
"timelineActivities": {
|
||||
"universalIdentifier": "20202020-30e2-421f-96c7-19c69d1cf631",
|
||||
"universalIdentifier": "64f26c76-9427-55a1-82e6-332b495878ad",
|
||||
},
|
||||
"updatedAt": {
|
||||
"universalIdentifier": "e0270cd8-986d-5dab-aaa1-1fe813969a6a",
|
||||
@@ -2057,7 +2057,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"person": {
|
||||
"fields": {
|
||||
"attachments": {
|
||||
"universalIdentifier": "20202020-cd97-451f-87fa-bcb789bdbf3a",
|
||||
"universalIdentifier": "54dd92e1-67bf-5381-86f3-c747976dcdaf",
|
||||
},
|
||||
"avatarFile": {
|
||||
"universalIdentifier": "20202020-a7c9-4e3d-8f1b-2d5a6b7c8e9f",
|
||||
@@ -2102,7 +2102,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "20202020-3875-44d5-8c33-a6239011cab8",
|
||||
},
|
||||
"noteTargets": {
|
||||
"universalIdentifier": "20202020-c8fc-4258-8250-15905d3fcfec",
|
||||
"universalIdentifier": "1c0e0dfe-a01f-58d6-8948-08b93164d03c",
|
||||
},
|
||||
"phones": {
|
||||
"universalIdentifier": "20202020-0638-448e-8825-439134618022",
|
||||
@@ -2117,10 +2117,10 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "efe6cbc6-1c6e-5a6e-91c9-17142d3bd947",
|
||||
},
|
||||
"taskTargets": {
|
||||
"universalIdentifier": "20202020-584b-4d3e-88b6-53ab1fa03c3a",
|
||||
"universalIdentifier": "ddea86e6-5766-5798-ac32-14fbab6089f6",
|
||||
},
|
||||
"timelineActivities": {
|
||||
"universalIdentifier": "20202020-a43e-4873-9c23-e522de906ce5",
|
||||
"universalIdentifier": "32d7483f-6227-528b-bc65-62d9cf858cd8",
|
||||
},
|
||||
"updatedAt": {
|
||||
"universalIdentifier": "962cedc2-cb8f-5f33-b5e1-256aabe6f14e",
|
||||
@@ -2252,7 +2252,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "20202020-065a-4f42-a906-e20422c1753f",
|
||||
},
|
||||
"attachments": {
|
||||
"universalIdentifier": "20202020-794d-4783-a8ff-cecdb15be139",
|
||||
"universalIdentifier": "d88469f5-b558-5e11-ab85-66f9ffcaecc0",
|
||||
},
|
||||
"bodyV2": {
|
||||
"universalIdentifier": "20202020-4aa0-4ae8-898d-7df0afd47ab1",
|
||||
@@ -2285,7 +2285,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "20202020-de9c-4d0e-a452-713d4a3e5fc7",
|
||||
},
|
||||
"timelineActivities": {
|
||||
"universalIdentifier": "20202020-c778-4278-99ee-23a2837aee64",
|
||||
"universalIdentifier": "9058db0a-b156-5c9e-999f-c89387ef4a9b",
|
||||
},
|
||||
"title": {
|
||||
"universalIdentifier": "20202020-b386-4cb7-aa5a-08d4a4d92680",
|
||||
@@ -2481,13 +2481,13 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "821c713e-bf1c-569d-9f0c-8e10e80eee5e",
|
||||
},
|
||||
"targetCompany": {
|
||||
"universalIdentifier": "20202020-4703-4a4e-948c-487b0c60a92c",
|
||||
"universalIdentifier": "805997f5-d539-5676-9aa8-0de602ac4152",
|
||||
},
|
||||
"targetOpportunity": {
|
||||
"universalIdentifier": "20202020-6cb2-4c01-a9a5-aca3dbc11d41",
|
||||
"universalIdentifier": "ca354769-b50e-531b-b745-12ca12ad44ee",
|
||||
},
|
||||
"targetPerson": {
|
||||
"universalIdentifier": "20202020-c8a0-4e85-a016-87e2349cfbec",
|
||||
"universalIdentifier": "c0a02b7a-a356-537a-96c8-66d1f8994100",
|
||||
},
|
||||
"task": {
|
||||
"universalIdentifier": "20202020-e881-457a-8758-74aaef4ae78a",
|
||||
@@ -2581,37 +2581,37 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "23a0482b-f41b-5e13-9b3e-356c5aaa90a3",
|
||||
},
|
||||
"targetCompany": {
|
||||
"universalIdentifier": "20202020-04ad-4221-a744-7a8278a5ce21",
|
||||
"universalIdentifier": "500e6797-19a2-5f11-b239-259b58765533",
|
||||
},
|
||||
"targetDashboard": {
|
||||
"universalIdentifier": "20202020-7864-48f5-af7c-9e4b60140948",
|
||||
"universalIdentifier": "0a1c0f53-5cbe-5ae8-8dde-e0dd7a7d136f",
|
||||
},
|
||||
"targetMessageCampaign": {
|
||||
"universalIdentifier": "b2c3d4e5-6f70-4b81-8c92-03d4e5f60718",
|
||||
"universalIdentifier": "22194f8d-a9f3-5f13-ae0f-eb23c6338cea",
|
||||
},
|
||||
"targetMessageList": {
|
||||
"universalIdentifier": "d9f4a1b2-3c5e-4d70-8e91-0a2b3c4d5e6f",
|
||||
"universalIdentifier": "e4367803-1b53-537c-b380-aa7c31a2a2cf",
|
||||
},
|
||||
"targetNote": {
|
||||
"universalIdentifier": "20202020-ec55-4135-8da5-3a20badc0156",
|
||||
"universalIdentifier": "c2202780-3676-511d-810f-725b0f3a4fdb",
|
||||
},
|
||||
"targetOpportunity": {
|
||||
"universalIdentifier": "20202020-7664-4a35-a3df-580d389fd527",
|
||||
"universalIdentifier": "1598c13c-d539-52c8-a56c-974a6b724393",
|
||||
},
|
||||
"targetPerson": {
|
||||
"universalIdentifier": "20202020-c414-45b9-a60a-ac27aa96229f",
|
||||
"universalIdentifier": "e2477375-5aeb-53bd-8ee1-97e804a73f9d",
|
||||
},
|
||||
"targetTask": {
|
||||
"universalIdentifier": "20202020-b2f5-415c-9135-a31dfe49501b",
|
||||
"universalIdentifier": "9022391d-5b5b-519e-be9f-fa954856bb29",
|
||||
},
|
||||
"targetWorkflow": {
|
||||
"universalIdentifier": "20202020-616c-4ad3-a2e9-c477c341e295",
|
||||
"universalIdentifier": "7bdf04f6-a598-57b2-b485-5263c25e1257",
|
||||
},
|
||||
"targetWorkflowRun": {
|
||||
"universalIdentifier": "20202020-96f0-401b-9186-a3a0759225ac",
|
||||
"universalIdentifier": "b1df837a-e304-5cde-97e6-ab8348739774",
|
||||
},
|
||||
"targetWorkflowVersion": {
|
||||
"universalIdentifier": "20202020-74f1-4711-a129-e14ca0ecd744",
|
||||
"universalIdentifier": "2da44ef9-dc63-5c9c-a9fb-58933ed03bc2",
|
||||
},
|
||||
"updatedAt": {
|
||||
"universalIdentifier": "01b33b31-f011-5b55-942f-5bf3ec56f9b3",
|
||||
@@ -2714,7 +2714,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"workflow": {
|
||||
"fields": {
|
||||
"attachments": {
|
||||
"universalIdentifier": "20202020-4a8c-4e2d-9b1c-7e5f3a2b4c6d",
|
||||
"universalIdentifier": "78d27c16-be35-54d2-988a-451dc24f77ff",
|
||||
},
|
||||
"automatedTriggers": {
|
||||
"universalIdentifier": "20202020-3319-4234-a34c-117ecad2b8a9",
|
||||
@@ -2753,7 +2753,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "20202020-357c-4432-8c50-8c31b4a552d9",
|
||||
},
|
||||
"timelineActivities": {
|
||||
"universalIdentifier": "20202020-906e-486a-a798-131a5f081faf",
|
||||
"universalIdentifier": "0ca041cd-598d-5c6b-881c-fe89ee97a0bc",
|
||||
},
|
||||
"updatedAt": {
|
||||
"universalIdentifier": "b277195f-91aa-5e90-9362-3b2a162aaa63",
|
||||
@@ -2923,7 +2923,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "20202020-7c4e-4e1a-8fc1-1e3a55d6c2a1",
|
||||
},
|
||||
"timelineActivities": {
|
||||
"universalIdentifier": "20202020-af4d-4eb0-babc-eb960a45b356",
|
||||
"universalIdentifier": "1e8e4e87-48c3-54d5-bd75-5cda9cf393b0",
|
||||
},
|
||||
"updatedAt": {
|
||||
"universalIdentifier": "363b5eb8-c334-5c0f-9568-7e1320d4c76c",
|
||||
@@ -3061,7 +3061,7 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e
|
||||
"universalIdentifier": "20202020-5988-4a64-b94a-1f9b7b989039",
|
||||
},
|
||||
"timelineActivities": {
|
||||
"universalIdentifier": "20202020-fcb0-4695-b17e-3b43a421c633",
|
||||
"universalIdentifier": "4be90325-f6ca-5931-a977-1194bb4b3d5c",
|
||||
},
|
||||
"trigger": {
|
||||
"universalIdentifier": "20202020-4eae-43e7-86e0-212b41a30b48",
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// Object universal identifiers referenced from another object's declaration
|
||||
// (default relation builders need both the host and the source object
|
||||
// identifiers, and an object literal cannot reference its sibling keys).
|
||||
// Each STANDARD_OBJECTS entry involved in the default relations reads its own
|
||||
// universalIdentifier from this record so there is a single source of truth.
|
||||
export const STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS = {
|
||||
timelineActivity: '20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
attachment: '20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
noteTarget: '20202020-fff0-4b44-be82-bda313884400',
|
||||
taskTarget: '20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
person: '20202020-e674-48e5-a542-72570eee7213',
|
||||
company: '20202020-b374-4779-a561-80086cb2e17f',
|
||||
opportunity: '20202020-9549-49dd-b2b2-883999db8938',
|
||||
note: '20202020-0b00-45cd-b6f6-6cd806fc6804',
|
||||
task: '20202020-1ba1-48ba-bc83-ef7e5990ed10',
|
||||
workflow: '20202020-62be-406c-b9ca-8caa50d51392',
|
||||
workflowVersion: '20202020-d65d-4ab9-9344-d77bfb376a3d',
|
||||
workflowRun: '20202020-4e28-4e95-a9d7-6c00874f843c',
|
||||
dashboard: '20202020-3840-4b6d-9425-0c5188b05ca8',
|
||||
messageList: '826561ea-4816-411c-baa0-eec5e6ca8866',
|
||||
messageCampaign: '238acb94-dd4c-4036-bc55-19b99d821efd',
|
||||
} as const;
|
||||
|
||||
export type StandardObjectWithUniversalIdentifierName =
|
||||
keyof typeof STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS;
|
||||
@@ -1,3 +1,6 @@
|
||||
import { TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER } from '@/application/constants/TwentyStandardApplicationUniversalIdentifier';
|
||||
import { getSystemRelationFieldUniversalIdentifier } from '@/application/deterministic-identifier/get-system-relation-field-universal-identifier.util';
|
||||
import { STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from '@/metadata/constants/standard-object-universal-identifiers.constant';
|
||||
import { buildStandardObjectSystemFields } from '@/metadata/utils/internal/build-standard-object-system-fields.util';
|
||||
|
||||
// Important notice:
|
||||
@@ -11,10 +14,10 @@ import { buildStandardObjectSystemFields } from '@/metadata/utils/internal/build
|
||||
// hardcoded universal identifier.
|
||||
export const STANDARD_OBJECTS = {
|
||||
attachment: {
|
||||
universalIdentifier: '20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-bd3d-4c60-8dca-571c71d4447a',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
),
|
||||
name: { universalIdentifier: '20202020-87a5-48f8-bbf7-ade388825a57' },
|
||||
file: { universalIdentifier: '20202020-15db-460e-8166-c7b5d87ad4be' },
|
||||
@@ -25,25 +28,74 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '20202020-8c3f-4d9e-9a1b-2e5f7a8c9d0e',
|
||||
},
|
||||
targetTask: {
|
||||
universalIdentifier: '20202020-51e5-4621-9cf8-215487951c4b',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.task,
|
||||
}),
|
||||
},
|
||||
targetNote: {
|
||||
universalIdentifier: '20202020-4f4b-4503-a6fc-6b982f3dffb5',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
}),
|
||||
},
|
||||
targetPerson: {
|
||||
universalIdentifier: '20202020-0158-4aa2-965c-5cdafe21ffa2',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person,
|
||||
}),
|
||||
},
|
||||
targetCompany: {
|
||||
universalIdentifier: '20202020-ceab-4a28-b546-73b06b4c08d5',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company,
|
||||
}),
|
||||
},
|
||||
targetOpportunity: {
|
||||
universalIdentifier: '20202020-7374-499d-bea3-9354890755b5',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.opportunity,
|
||||
}),
|
||||
},
|
||||
targetDashboard: {
|
||||
universalIdentifier: '20202020-5324-43f3-9dbf-1a33e7de0ce6',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.dashboard,
|
||||
}),
|
||||
},
|
||||
targetWorkflow: {
|
||||
universalIdentifier: '20202020-f1e8-4c9d-8a7b-3f5e1d2c9a8b',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflow,
|
||||
}),
|
||||
},
|
||||
},
|
||||
morphIds: {
|
||||
@@ -593,10 +645,10 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
company: {
|
||||
universalIdentifier: '20202020-b374-4779-a561-80086cb2e17f',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-b374-4779-a561-80086cb2e17f',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company,
|
||||
),
|
||||
name: { universalIdentifier: '20202020-4d99-4e2e-a84c-4a27837b1ece' },
|
||||
domainName: {
|
||||
@@ -614,19 +666,47 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '20202020-95b8-4e10-9881-edb5d4765f9d',
|
||||
},
|
||||
taskTargets: {
|
||||
universalIdentifier: '20202020-cb17-4a61-8f8f-3be6730480de',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.taskTarget,
|
||||
}),
|
||||
},
|
||||
noteTargets: {
|
||||
universalIdentifier: '20202020-bae0-4556-a74a-a9c686f77a88',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.noteTarget,
|
||||
}),
|
||||
},
|
||||
opportunities: {
|
||||
universalIdentifier: '20202020-add3-4658-8e23-d70dccb6d0ec',
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-c1b5-4120-b0f0-987ca401ed53',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
}),
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-0414-4daf-9c0d-64fe7b27f89f',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
}),
|
||||
},
|
||||
},
|
||||
indexes: {
|
||||
@@ -734,20 +814,34 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
dashboard: {
|
||||
universalIdentifier: '20202020-3840-4b6d-9425-0c5188b05ca8',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.dashboard,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-3840-4b6d-9425-0c5188b05ca8',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.dashboard,
|
||||
),
|
||||
title: { universalIdentifier: '20202020-20ee-4091-95dc-44b57eda3a89' },
|
||||
pageLayoutId: {
|
||||
universalIdentifier: '20202020-bb53-4648-aa36-1d9d54e6f7f2',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '99c330c0-5b7d-4276-a764-aed84499dfb5',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.dashboard,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
}),
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-bf6f-4220-8c55-2764f1175870',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.dashboard,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
}),
|
||||
},
|
||||
},
|
||||
indexes: {
|
||||
@@ -776,10 +870,10 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
messageCampaign: {
|
||||
universalIdentifier: '238acb94-dd4c-4036-bc55-19b99d821efd',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.messageCampaign,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'238acb94-dd4c-4036-bc55-19b99d821efd',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.messageCampaign,
|
||||
),
|
||||
subject: { universalIdentifier: '7251544c-b07a-4f0d-9d0a-48514367f230' },
|
||||
bodyTemplate: {
|
||||
@@ -807,7 +901,14 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
list: { universalIdentifier: 'cb24dcdf-f0e8-4c71-8cff-70b714e86530' },
|
||||
timelineActivities: {
|
||||
universalIdentifier: 'd4e5f607-1829-4da3-8eb4-25f607182930',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.messageCampaign,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
}),
|
||||
},
|
||||
messages: { universalIdentifier: 'e5a177a7-512b-4778-928e-69777a528f7c' },
|
||||
recipients: {
|
||||
@@ -867,10 +968,10 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
messageList: {
|
||||
universalIdentifier: '826561ea-4816-411c-baa0-eec5e6ca8866',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.messageList,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'826561ea-4816-411c-baa0-eec5e6ca8866',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.messageList,
|
||||
),
|
||||
name: { universalIdentifier: '69b9ed8b-7b26-4108-894f-05700ef7e8ee' },
|
||||
members: {
|
||||
@@ -880,7 +981,14 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: 'e098d838-31ab-4812-91a8-f055f45a6832',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: 'e0a5b2c3-4d6f-4e81-9a02-1b3c4d5e6f70',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.messageList,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
}),
|
||||
},
|
||||
},
|
||||
indexes: {
|
||||
@@ -1300,10 +1408,10 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
note: {
|
||||
universalIdentifier: '20202020-0b00-45cd-b6f6-6cd806fc6804',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-0b00-45cd-b6f6-6cd806fc6804',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
),
|
||||
title: { universalIdentifier: '20202020-faeb-4c76-8ba6-ccbb0b4a965f' },
|
||||
bodyV2: { universalIdentifier: '20202020-a7bb-4d94-be51-8f25181502c8' },
|
||||
@@ -1311,10 +1419,22 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '20202020-1f25-43fe-8b00-af212fdde823',
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-4986-4c92-bf19-39934b149b16',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
}),
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-7030-42f8-929c-1a57b25d6bce',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
}),
|
||||
},
|
||||
},
|
||||
indexes: {
|
||||
@@ -1383,20 +1503,41 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
noteTarget: {
|
||||
universalIdentifier: '20202020-fff0-4b44-be82-bda313884400',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.noteTarget,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-fff0-4b44-be82-bda313884400',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.noteTarget,
|
||||
),
|
||||
note: { universalIdentifier: '20202020-57f3-4f50-9599-fc0f671df003' },
|
||||
targetPerson: {
|
||||
universalIdentifier: '20202020-38ca-4aab-92f5-8a605ca2e4c5',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.noteTarget,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person,
|
||||
}),
|
||||
},
|
||||
targetCompany: {
|
||||
universalIdentifier: 'c500fbc0-d6f2-4982-a959-5a755431696c',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.noteTarget,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company,
|
||||
}),
|
||||
},
|
||||
targetOpportunity: {
|
||||
universalIdentifier: '20202020-4e42-417a-a705-76581c9ade79',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.noteTarget,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.opportunity,
|
||||
}),
|
||||
},
|
||||
},
|
||||
morphIds: {
|
||||
@@ -1440,10 +1581,10 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
opportunity: {
|
||||
universalIdentifier: '20202020-9549-49dd-b2b2-883999db8938',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.opportunity,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-9549-49dd-b2b2-883999db8938',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.opportunity,
|
||||
),
|
||||
name: { universalIdentifier: '20202020-8609-4f65-a2d9-44009eb422b5' },
|
||||
amount: { universalIdentifier: '20202020-583e-4642-8533-db761d5fa82f' },
|
||||
@@ -1457,16 +1598,44 @@ export const STANDARD_OBJECTS = {
|
||||
company: { universalIdentifier: '20202020-cbac-457e-b565-adece5fc815f' },
|
||||
owner: { universalIdentifier: '20202020-be7e-4d1e-8e19-3d5c7c4b9f2a' },
|
||||
taskTargets: {
|
||||
universalIdentifier: '20202020-59c0-4179-a208-4a255f04a5be',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.opportunity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.taskTarget,
|
||||
}),
|
||||
},
|
||||
noteTargets: {
|
||||
universalIdentifier: '20202020-dd3f-42d5-a382-db58aabf43d3',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.opportunity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.noteTarget,
|
||||
}),
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-87c7-4118-83d6-2f4031005209',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.opportunity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
}),
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-30e2-421f-96c7-19c69d1cf631',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.opportunity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
}),
|
||||
},
|
||||
},
|
||||
indexes: {
|
||||
@@ -1608,10 +1777,10 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
person: {
|
||||
universalIdentifier: '20202020-e674-48e5-a542-72570eee7213',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-e674-48e5-a542-72570eee7213',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person,
|
||||
),
|
||||
name: { universalIdentifier: '20202020-3875-44d5-8c33-a6239011cab8' },
|
||||
emails: { universalIdentifier: '20202020-3c51-43fa-8b6e-af39e29368ab' },
|
||||
@@ -1631,13 +1800,34 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '20202020-911b-4a7d-b67b-918aa9a5b33a',
|
||||
},
|
||||
taskTargets: {
|
||||
universalIdentifier: '20202020-584b-4d3e-88b6-53ab1fa03c3a',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.taskTarget,
|
||||
}),
|
||||
},
|
||||
noteTargets: {
|
||||
universalIdentifier: '20202020-c8fc-4258-8250-15905d3fcfec',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.noteTarget,
|
||||
}),
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-cd97-451f-87fa-bcb789bdbf3a',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
}),
|
||||
},
|
||||
messageParticipants: {
|
||||
universalIdentifier: '20202020-498e-4c61-8158-fa04f0638334',
|
||||
@@ -1646,7 +1836,14 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '20202020-52ee-45e9-a702-b64b3753e3a9',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-a43e-4873-9c23-e522de906ce5',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
}),
|
||||
},
|
||||
listMemberships: {
|
||||
universalIdentifier: '8b8d1be0-4c94-4413-a2c9-c7ede205a81d',
|
||||
@@ -1769,10 +1966,10 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
task: {
|
||||
universalIdentifier: '20202020-1ba1-48ba-bc83-ef7e5990ed10',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.task,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-1ba1-48ba-bc83-ef7e5990ed10',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.task,
|
||||
),
|
||||
title: { universalIdentifier: '20202020-b386-4cb7-aa5a-08d4a4d92680' },
|
||||
bodyV2: { universalIdentifier: '20202020-4aa0-4ae8-898d-7df0afd47ab1' },
|
||||
@@ -1782,11 +1979,23 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '20202020-de9c-4d0e-a452-713d4a3e5fc7',
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-794d-4783-a8ff-cecdb15be139',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.task,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
}),
|
||||
},
|
||||
assignee: { universalIdentifier: '20202020-065a-4f42-a906-e20422c1753f' },
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-c778-4278-99ee-23a2837aee64',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.task,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
}),
|
||||
},
|
||||
},
|
||||
indexes: {
|
||||
@@ -1952,20 +2161,41 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
taskTarget: {
|
||||
universalIdentifier: '20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.taskTarget,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-5a9a-44e8-95df-771cd06d0fb1',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.taskTarget,
|
||||
),
|
||||
task: { universalIdentifier: '20202020-e881-457a-8758-74aaef4ae78a' },
|
||||
targetPerson: {
|
||||
universalIdentifier: '20202020-c8a0-4e85-a016-87e2349cfbec',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.taskTarget,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person,
|
||||
}),
|
||||
},
|
||||
targetCompany: {
|
||||
universalIdentifier: '20202020-4703-4a4e-948c-487b0c60a92c',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.taskTarget,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company,
|
||||
}),
|
||||
},
|
||||
targetOpportunity: {
|
||||
universalIdentifier: '20202020-6cb2-4c01-a9a5-aca3dbc11d41',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.taskTarget,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.opportunity,
|
||||
}),
|
||||
},
|
||||
},
|
||||
morphIds: {
|
||||
@@ -2009,10 +2239,10 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
timelineActivity: {
|
||||
universalIdentifier: '20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-6736-4337-b5c4-8b39fae325a5',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
),
|
||||
name: { universalIdentifier: '20202020-7207-46e8-9dab-849505ae8497' },
|
||||
happensAt: {
|
||||
@@ -2025,37 +2255,114 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '20202020-af23-4479-9a30-868edc474b36',
|
||||
},
|
||||
targetPerson: {
|
||||
universalIdentifier: '20202020-c414-45b9-a60a-ac27aa96229f',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person,
|
||||
}),
|
||||
},
|
||||
targetCompany: {
|
||||
universalIdentifier: '20202020-04ad-4221-a744-7a8278a5ce21',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company,
|
||||
}),
|
||||
},
|
||||
targetOpportunity: {
|
||||
universalIdentifier: '20202020-7664-4a35-a3df-580d389fd527',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.opportunity,
|
||||
}),
|
||||
},
|
||||
targetTask: {
|
||||
universalIdentifier: '20202020-b2f5-415c-9135-a31dfe49501b',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.task,
|
||||
}),
|
||||
},
|
||||
targetNote: {
|
||||
universalIdentifier: '20202020-ec55-4135-8da5-3a20badc0156',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.note,
|
||||
}),
|
||||
},
|
||||
targetWorkflow: {
|
||||
universalIdentifier: '20202020-616c-4ad3-a2e9-c477c341e295',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflow,
|
||||
}),
|
||||
},
|
||||
targetWorkflowVersion: {
|
||||
universalIdentifier: '20202020-74f1-4711-a129-e14ca0ecd744',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflowVersion,
|
||||
}),
|
||||
},
|
||||
targetWorkflowRun: {
|
||||
universalIdentifier: '20202020-96f0-401b-9186-a3a0759225ac',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflowRun,
|
||||
}),
|
||||
},
|
||||
targetDashboard: {
|
||||
universalIdentifier: '20202020-7864-48f5-af7c-9e4b60140948',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.dashboard,
|
||||
}),
|
||||
},
|
||||
targetMessageList: {
|
||||
universalIdentifier: 'd9f4a1b2-3c5e-4d70-8e91-0a2b3c4d5e6f',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.messageList,
|
||||
}),
|
||||
},
|
||||
targetMessageCampaign: {
|
||||
universalIdentifier: 'b2c3d4e5-6f70-4b81-8c92-03d4e5f60718',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.messageCampaign,
|
||||
}),
|
||||
},
|
||||
linkedRecordCachedName: {
|
||||
universalIdentifier: '20202020-cfdb-4bef-bbce-a29f41230934',
|
||||
@@ -2153,10 +2460,10 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
workflow: {
|
||||
universalIdentifier: '20202020-62be-406c-b9ca-8caa50d51392',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflow,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-62be-406c-b9ca-8caa50d51392',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflow,
|
||||
),
|
||||
name: { universalIdentifier: '20202020-b3d3-478f-acc0-5d901e725b20' },
|
||||
lastPublishedVersionId: {
|
||||
@@ -2172,10 +2479,24 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '20202020-3319-4234-a34c-117ecad2b8a9',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-906e-486a-a798-131a5f081faf',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflow,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
}),
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-4a8c-4e2d-9b1c-7e5f3a2b4c6d',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflow,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment,
|
||||
}),
|
||||
},
|
||||
},
|
||||
indexes: {
|
||||
@@ -2273,10 +2594,10 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
workflowRun: {
|
||||
universalIdentifier: '20202020-4e28-4e95-a9d7-6c00874f843c',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflowRun,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-4e28-4e95-a9d7-6c00874f843c',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflowRun,
|
||||
),
|
||||
name: { universalIdentifier: '20202020-b840-4253-aef9-4e5013694587' },
|
||||
workflowVersion: {
|
||||
@@ -2298,7 +2619,14 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '20202020-7c4e-4e1a-8fc1-1e3a55d6c2a1',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-af4d-4eb0-babc-eb960a45b356',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflowRun,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
}),
|
||||
},
|
||||
},
|
||||
indexes: {
|
||||
@@ -2388,10 +2716,10 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
workflowVersion: {
|
||||
universalIdentifier: '20202020-d65d-4ab9-9344-d77bfb376a3d',
|
||||
universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflowVersion,
|
||||
fields: {
|
||||
...buildStandardObjectSystemFields(
|
||||
'20202020-d65d-4ab9-9344-d77bfb376a3d',
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflowVersion,
|
||||
),
|
||||
name: { universalIdentifier: '20202020-a12f-4cca-9937-a2e40cc65509' },
|
||||
workflow: {
|
||||
@@ -2409,7 +2737,14 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: '20202020-58b4-46e8-b6d2-f1f3c74cf7f4',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-fcb0-4695-b17e-3b43a421c633',
|
||||
universalIdentifier: getSystemRelationFieldUniversalIdentifier({
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.workflowVersion,
|
||||
relationTargetObjectUniversalIdentifier:
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.timelineActivity,
|
||||
}),
|
||||
},
|
||||
},
|
||||
indexes: {
|
||||
|
||||
@@ -16,6 +16,8 @@ export { ALL_METADATA_NAME } from './constants/all-metadata-name.constant';
|
||||
export { DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS } from './constants/default-relations-object-standard-ids.constant';
|
||||
export { IDENTIFIER_MAX_CHAR_LENGTH } from './constants/identifier-max-char-length.constant';
|
||||
export { RESERVED_METADATA_NAME_KEYWORDS } from './constants/reserved-metadata-name-keywords.constant';
|
||||
export type { StandardObjectWithUniversalIdentifierName } from './constants/standard-object-universal-identifiers.constant';
|
||||
export { STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from './constants/standard-object-universal-identifiers.constant';
|
||||
export { STANDARD_OBJECTS } from './constants/standard-object.constant';
|
||||
export { STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS } from './constants/standard-page-layout-universal-identifiers.constant';
|
||||
export type { AllMetadataName } from './types/all-metadata-name.type';
|
||||
|
||||
Reference in New Issue
Block a user