58ebbe0394
Created by Github action <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/23523?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. --> Co-authored-by: github-actions <github-actions@twenty.com>
211 lines
11 KiB
Plaintext
211 lines
11 KiB
Plaintext
---
|
|
title: Țintirea metadatelor de sistem
|
|
description: Rezolvă identificatorii universali determinați ai metadatelor pe care Twenty le provizionează automat pe fiecare obiect, astfel încât aplicația ta să le poată referenția fără hardcodare.
|
|
icon: gears
|
|
---
|
|
|
|
Fiecare obiect din Twenty vine cu **metadate de sistem** pe care nu le declari niciodată tu însuți, cum ar fi un set de câmpuri și o vizualizare principală de listă cu coloanele sale. Serverul le creează pe toate atunci când obiectul este provizionat, iar setul crește pe măsură ce Twenty evoluează.
|
|
|
|
Deoarece nu îl declari, nu există nicio constantă `universalIdentifier` pe care să o imporți. În schimb, serverul **derivează** fiecare identificator într-un mod determinist, iar `twenty-sdk` expune aceeași derivare astfel încât manifestul tău să poată rezolva exact valoarea pe care o folosește serverul.
|
|
|
|
## Câmpuri de sistem
|
|
|
|
Câmpurile scalare prezente pe fiecare obiect, niciunul dintre ele nu este declarat de tine cu [`defineField()`](/l/ro/developers/extend/apps/data/extending-objects):
|
|
|
|
`id`, `createdAt`, `updatedAt`, `deletedAt`, `createdBy`, `updatedBy`, `position`, `searchVector`
|
|
|
|
Deci cum faci referire la `createdAt` ca o coloană într-o [vizualizare](/l/ro/developers/extend/apps/layout/views)?
|
|
|
|
### Problema
|
|
|
|
Începând cu Twenty 2.19, identificatorul universal al unui câmp de sistem este **derivat deterministic** de server din trei intrări: identificatorul universal al aplicației, identificatorul universal al obiectului și numele câmpului. Inventarea unui id și hardcodarea lui nu va funcționa: acesta nu se potrivește cu nimic de pe server, iar sincronizarea respinge referința rămasă în aer:
|
|
|
|
```
|
|
Dev sync failed: viewField: INVALID_VIEW_DATA: Field metadata not found
|
|
```
|
|
|
|
### Soluția
|
|
|
|
<Note>
|
|
`getFieldUniversalIdentifier` este disponibil începând cu `twenty-sdk` 2.21.
|
|
</Note>
|
|
|
|
Folosește `getFieldUniversalIdentifier` pentru a obține exact aceeași valoare pe care o folosește serverul. Aceasta primește cele trei intrări și returnează identificatorul universal al câmpului:
|
|
|
|
```ts
|
|
import { getFieldUniversalIdentifier } from 'twenty-sdk/define';
|
|
|
|
const createdAtFieldId = getFieldUniversalIdentifier({
|
|
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
|
objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
name: 'createdAt',
|
|
});
|
|
```
|
|
|
|
* `applicationUniversalIdentifier` este identificatorul aplicației tale, cel pe care îl transmiți către [`defineApplication()`](/l/ro/developers/extend/apps/config/application).
|
|
* `objectUniversalIdentifier` este identificatorul obiectului căruia îi aparține câmpul.
|
|
* `name` este numele câmpului de sistem, una dintre valorile listate mai sus.
|
|
|
|
### Exemplu: o coloană createdAt într-o vizualizare
|
|
|
|
Cazul tipic este adăugarea unei coloane `createdAt` la o vizualizare a unuia dintre obiectele tale personalizate. Calculează id-ul câmpului și fă referire la el ca la orice alt `fieldMetadataUniversalIdentifier`:
|
|
|
|
```ts src/views/example-view.ts
|
|
import {
|
|
defineView,
|
|
getFieldUniversalIdentifier,
|
|
} from 'twenty-sdk/define';
|
|
|
|
const APPLICATION_UNIVERSAL_IDENTIFIER =
|
|
'0b04e15c-27b2-4741-9046-b32e07469072';
|
|
const MY_OBJECT_UNIVERSAL_IDENTIFIER =
|
|
'c782b61c-70fd-4c88-9cd6-4e61ab8d7591';
|
|
|
|
export default defineView({
|
|
universalIdentifier: '70f10d44-144a-4da8-8c6f-3ec2422138c0',
|
|
name: 'All records',
|
|
objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
icon: 'IconList',
|
|
position: 0,
|
|
fields: [
|
|
{
|
|
universalIdentifier: '75a90bc4-d901-4df4-85e0-af29db5e0104',
|
|
fieldMetadataUniversalIdentifier: getFieldUniversalIdentifier({
|
|
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
|
objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
name: 'createdAt',
|
|
}),
|
|
position: 0,
|
|
isVisible: true,
|
|
size: 200,
|
|
},
|
|
],
|
|
});
|
|
```
|
|
|
|
Același id calculat funcționează oriunde este așteptat un `fieldMetadataUniversalIdentifier`: câmpuri de vizualizare, filtre, sortări, grupări și widget-uri de tip page-layout.
|
|
|
|
<Note>
|
|
Calculează id-ul, nu îl hardcoda. Deoarece serverul derivă valoarea din
|
|
id-ul aplicației, id-ul obiectului și numele câmpului, apelarea
|
|
`getFieldUniversalIdentifier` menține referința corectă chiar dacă aceste
|
|
intrări se schimbă și evită divergența dacă metoda de derivare evoluează vreodată.
|
|
</Note>
|
|
|
|
### Câmpuri de relație de sistem
|
|
|
|
<Note>
|
|
`getSystemRelationFieldUniversalIdentifier` este disponibil începând cu versiunea 2.23 a `twenty-sdk` și necesită un server Twenty pe versiunea 2.23 sau o versiune ulterioară.
|
|
</Note>
|
|
|
|
Pe lângă câmpurile scalare de sistem de mai sus, serverul mai pune la dispoziție patru **câmpuri de relație de sistem** pentru fiecare obiect: `timelineActivities`, `attachments`, `noteTargets` și `taskTargets`, fiecare indicând către obiectul de relație standard corespunzător.
|
|
|
|
Aceste câmpuri nu sunt rezolvate cu `getFieldUniversalIdentifier`: identificatorul lor este derivat **independent de nume**, din obiectul care găzduiește câmpul și obiectul către care indică acest câmp. Astfel, redenumirea unui obiect nu modifică niciodată identificatorii câmpurilor sale de relație.
|
|
|
|
Folosește `getSystemRelationFieldUniversalIdentifier` pentru a le rezolva:
|
|
|
|
```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` este obiectul care **găzduiește** câmpul.
|
|
* `relationTargetObjectUniversalIdentifier` este obiectul către care **indică** câmpul.
|
|
|
|
Direcția este codificată prin ordinea argumentelor. Pentru a rezolva partea inversă (de ex. `attachment.targetRocket`, câmpul morfic pe care serverul îl creează pe obiectul de relație standard), inversează-le pe cele două:
|
|
|
|
```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,
|
|
});
|
|
```
|
|
|
|
Ca și în cazul câmpurilor de sistem scalare, id-ul rezolvat funcționează oriunde este așteptat un `fieldMetadataUniversalIdentifier`.
|
|
|
|
## Vizualizări de sistem
|
|
|
|
<Note>
|
|
`getSystemViewUniversalIdentifier` și `getSystemViewFieldUniversalIdentifier`
|
|
sunt disponibile începând cu versiunea 2.26 a `twenty-sdk` și necesită un server Twenty pe
|
|
versiunea 2.26 sau o versiune ulterioară.
|
|
</Note>
|
|
|
|
Serverul provizionează, de asemenea, o **vizualizare de sistem** pe fiecare obiect: vizualizarea principală de listă (`All {objectLabelPlural}`, indexată prin `ViewKey.INDEX`), cu câte o coloană pentru fiecare câmp afișabil. La fel ca în cazul câmpurilor de relație de sistem, identificatorii lor sunt derivați **fără nume**, astfel încât redenumirea unui obiect sau a unui câmp nu îi schimbă niciodată.
|
|
|
|
Folosește `getSystemViewUniversalIdentifier` pentru a rezolva vizualizarea:
|
|
|
|
```ts
|
|
import { getSystemViewUniversalIdentifier, ViewKey } from 'twenty-sdk/define';
|
|
|
|
const rocketIndexViewId = getSystemViewUniversalIdentifier({
|
|
objectMetadataApplicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
|
objectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
|
|
viewKey: ViewKey.INDEX,
|
|
});
|
|
```
|
|
|
|
* `objectMetadataApplicationUniversalIdentifier` este aplicația care deține **obiectul**, ceea ce reprezintă spațiul de nume pentru vizualizare.
|
|
* `objectUniversalIdentifier` este obiectul pe care îl listează vizualizarea.
|
|
* `viewKey` este cheia vizualizării de sistem, astăzi `ViewKey.INDEX`.
|
|
|
|
ID-ul rezolvat funcționează oriunde este așteptat un `viewUniversalIdentifier`, cum ar fi o intrare în bara laterală [`NavigationMenuItemType.VIEW`](/l/ro/developers/extend/apps/layout/navigation-menu-items). Pentru a deschide pur și simplu lista principală a unui obiect, preferă `NavigationMenuItemType.OBJECT` cu `targetObjectUniversalIdentifier`: nu are nevoie de derivare.
|
|
|
|
`getSystemViewFieldUniversalIdentifier` rezolvă o singură **coloană** dintr-o vizualizare de sistem, pornind de la vizualizare și câmpul pe care îl afișează:
|
|
|
|
```ts
|
|
import { getSystemViewFieldUniversalIdentifier } from 'twenty-sdk/define';
|
|
|
|
const rocketNameColumnId = getSystemViewFieldUniversalIdentifier({
|
|
fieldMetadataApplicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
|
viewUniversalIdentifier: rocketIndexViewId,
|
|
fieldMetadataUniversalIdentifier: ROCKET_NAME_FIELD_UNIVERSAL_IDENTIFIER,
|
|
});
|
|
```
|
|
|
|
Observă primul argument: o coloană este plasată în spațiul de nume al aplicației care deține **câmpul pe care îl afișează**, nu al celei care deține vizualizarea. Un câmp pe care aplicația ta îl adaugă la un obiect standard își obține coloana derivată sub aplicația ta, pe o vizualizare deținută de Twenty.
|
|
|
|
<Warning>
|
|
Vizualizările de sistem și coloanele lor sunt **deținute de server**: rezolvă-le identificatorii
|
|
pentru a le referenția, niciodată pentru a le declara. `key` pe
|
|
[`defineView()`](/l/ro/developers/extend/apps/layout/views) este depreciat și
|
|
ignorat, astfel încât o vizualizare din manifest nu poate revendica niciodată cheia `INDEX`, iar serverul
|
|
provizionează deja o coloană pentru fiecare câmp pe care îl adaugi, deci declararea propriului tău
|
|
`defineViewField()` pentru același câmp într-o vizualizare de sistem intră în conflict cu aceasta.
|
|
</Warning>
|
|
|
|
## Obiecte standard Twenty
|
|
|
|
Pentru un obiect Twenty **standard** (Person, Company, Opportunity, …), nu trebuie să derivezi nimic: identificatorii sunt constante pre-calculate pe care le poți importa direct, atât pentru câmpuri, cât și pentru vizualizări.
|
|
|
|
```ts
|
|
import { STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
|
|
|
// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.createdAt.universalIdentifier
|
|
// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.fields.updatedAt.universalIdentifier
|
|
// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.views.allPeople.universalIdentifier
|
|
```
|
|
|
|
Apelează la utilitarele de mai sus atunci când obiectul este unul pe care aplicația ta îl definește cu [`defineObject()`](/l/ro/developers/extend/apps/data/objects), unde nu există o astfel de constantă.
|
|
|
|
<Note>
|
|
`name` este un câmp **implicit**, nu un câmp de sistem. Acesta își păstrează propriul identificator universal
|
|
hardcodat și nu este obținut prin
|
|
`getFieldUniversalIdentifier`. În obiectele pe care le definești, fă referire la câmpul
|
|
`name` prin identificatorul pe care i l-ai dat în `defineObject()`.
|
|
</Note>
|