Files
twenty/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/people-all.view.ts
T
Paul Rastoin f9ab09c404 Metadata api create entity in workspace custom app (#15911)
# Introduction
Cleaner and fewer scope version of
https://github.com/twentyhq/twenty/pull/15745 ( removed sync-metadata
hack through, too ambitious migration and upgrade )

Please note that this PR won't have any interaction with the existing
sync-metadata
Which mean that the sync metadata does not update the standard entities
applicationId and universalIdentifier, and it won't we will deprecate it
on favor of a workspace migration aka twenty-standard app installation

## API Metadata
Any operation going through the api metadata nows automatically scope
the related entity to the workspace custom application instance. (
optionally passing an applicationId to allow current hacky implem of app
sync service )

We need to either ignore the tests or remove the cli status check from
the blocking status badges for a PR to be merged

## New workspace
Already handled in previous
https://github.com/twentyhq/twenty/pull/15625, when a workspace is
created it gets created a twenty standard and custom workspace instance

All his views and permissions will be prefilled to the its twenty
standard app instance with a specific universalIdentifier

## New universalIdentifier
At the contrary as before with standardIds, universalIdentifier are
unique for a given workspace
This means that createdAt field of both object company and opportunity
will have a unique universalIdentifier whereas they share the same
standardId

## FlatApplication
Introduced the flatApplication and cache. Will migrate existing
`MetadataName` to be `SyncableMetadataName` in a following PR

## What's next
Next we will describe a twenty standard app configuration as json that
will be used to generate a workspace migration that will be run instead
of the sync metadata, in a nutshell we aim to deprecated the sync
metadata
So we can standardize any entity to have a non nullable applicationId
and universalIdentifier

## Upgrade command
Introduced an upgrade command that will create a custom workspace
instance for any workspace that do not have one in order to align with
the new behavior when creating a new workspace
2025-11-23 22:35:17 +01:00

176 lines
5.8 KiB
TypeScript

import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
PERSON_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const peopleAllView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const personObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.person,
);
if (!personObjectMetadata) {
throw new Error('Person object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.person.views.allPeople.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All People',
objectMetadataId: personObjectMetadata.id,
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconList',
kanbanFieldMetadataId: '',
filters: [],
fields: [
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.name,
)?.id ?? '',
position: 0,
isVisible: true,
size: 210,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.name
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.emails,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
aggregateOperation: AggregateOperations.COUNT_UNIQUE_VALUES,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.emails
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.createdBy,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.createdBy
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.company,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.company
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.phones,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
aggregateOperation: AggregateOperations.PERCENTAGE_EMPTY,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.phones
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 5,
isVisible: true,
size: 150,
aggregateOperation: AggregateOperations.MIN,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.createdAt
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.city,
)?.id ?? '',
position: 6,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.city
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.jobTitle,
)?.id ?? '',
position: 7,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.jobTitle
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) =>
field.standardId === PERSON_STANDARD_FIELD_IDS.linkedinLink,
)?.id ?? '',
position: 8,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.linkedinLink
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.xLink,
)?.id ?? '',
position: 9,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.xLink
.universalIdentifier,
},
],
};
};