i18n - docs translations (#19227)
Created by Github action Co-authored-by: github-actions <github-actions@twenty.com>
This commit is contained in:
committed by
GitHub
parent
ae202a1b59
commit
6eb4c4ca4b
@@ -1299,7 +1299,7 @@ yarn twenty add frontComponent
|
||||
| مكوّن أمامي | `yarn twenty add frontComponent` | `src/front-components/<name>.tsx` |
|
||||
| دور | `yarn twenty add role` | `src/roles/<name>.ts` |
|
||||
| مهارة | `yarn twenty add skill` | `src/skills/<name>.ts` |
|
||||
| Agent | `yarn twenty add agent` | `src/agents/<name>.ts` |
|
||||
| وكيل | `yarn twenty add agent` | `src/agents/<name>.ts` |
|
||||
| عرض | `yarn twenty add view` | `src/views/<name>.ts` |
|
||||
| عنصر قائمة التنقّل | `yarn twenty add navigationMenuItem` | `src/navigation-menu-items/<name>.ts` |
|
||||
| تخطيط الصفحة | `yarn twenty add pageLayout` | `src/page-layouts/<name>.ts` |
|
||||
@@ -1436,7 +1436,7 @@ const { objects } = await metadataClient.query({
|
||||
|
||||
#### رفع الملفات
|
||||
|
||||
`MetadataApiClient` includes an `uploadFile` method for attaching files to file-type fields:
|
||||
يتضمن `MetadataApiClient` طريقة `uploadFile` لإرفاق الملفات بالحقول من نوع الملف:
|
||||
|
||||
```ts
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
|
||||
@@ -924,24 +924,24 @@ export default defineFrontComponent({
|
||||
|
||||
**Operátory** — kombinují proměnné do logických výrazů:
|
||||
|
||||
| Operátor | Popis |
|
||||
| ----------------------------------- | -------------------------------------------------------------------- |
|
||||
| `isDefined(value)` | `true`, pokud hodnota není null/undefined |
|
||||
| `isNonEmptyString(value)` | `true`, pokud je hodnota neprázdný řetězec |
|
||||
| `includes(array, value)` | `true`, pokud pole obsahuje danou hodnotu |
|
||||
| `includesEvery(array, prop, value)` | `true`, pokud vlastnost každé položky zahrnuje danou hodnotu |
|
||||
| `every(array, prop)` | `true`, pokud je vlastnost u každé položky pravdivá (truthy) |
|
||||
| `everyDefined(array, prop)` | `true`, pokud je vlastnost definována u každé položky |
|
||||
| `everyEquals(array, prop, value)` | `true`, pokud se vlastnost rovná hodnotě u každé položky |
|
||||
| `some(array, prop)` | `true`, pokud je vlastnost pravdivá (truthy) alespoň u jedné položky |
|
||||
| `someDefined(array, prop)` | `true`, pokud je vlastnost definována alespoň u jedné položky |
|
||||
| `someEquals(array, prop, value)` | `true`, pokud se vlastnost rovná hodnotě alespoň u jedné položky |
|
||||
| `someNonEmptyString(array, prop)` | `true`, pokud je vlastnost neprázdný řetězec alespoň u jedné položky |
|
||||
| `none(array, prop)` | `true`, pokud je vlastnost u všech položek nepravdivá (falsy) |
|
||||
| `noneDefined(array, prop)` | `true`, pokud je vlastnost u všech položek nedefinovaná |
|
||||
| `noneEquals(array, prop, value)` | `true`, pokud se vlastnost nerovná hodnotě u žádné položky |
|
||||
| Operátor | Popis |
|
||||
| ----------------------------------- | ------------------------------------------------------------------------------ |
|
||||
| `isDefined(value)` | `true`, pokud hodnota není null/undefined |
|
||||
| `isNonEmptyString(value)` | `true`, pokud je hodnota neprázdný řetězec |
|
||||
| `includes(array, value)` | `true`, pokud pole obsahuje danou hodnotu |
|
||||
| `includesEvery(array, prop, value)` | `true`, pokud vlastnost každé položky zahrnuje danou hodnotu |
|
||||
| `every(array, prop)` | `true`, pokud je vlastnost u každé položky pravdivá (truthy) |
|
||||
| `everyDefined(array, prop)` | `true`, pokud je vlastnost definována u každé položky |
|
||||
| `everyEquals(array, prop, value)` | `true`, pokud se vlastnost rovná hodnotě u každé položky |
|
||||
| `some(array, prop)` | `true`, pokud je vlastnost pravdivá (truthy) alespoň u jedné položky |
|
||||
| `someDefined(array, prop)` | `true`, pokud je vlastnost definována alespoň u jedné položky |
|
||||
| `someEquals(array, prop, value)` | `true`, pokud se vlastnost rovná hodnotě alespoň u jedné položky |
|
||||
| `someNonEmptyString(array, prop)` | `true`, pokud má vlastnost alespoň u jedné položky hodnotu neprázdného řetězce |
|
||||
| `none(array, prop)` | `true`, pokud je vlastnost u všech položek nepravdivá (falsy) |
|
||||
| `noneDefined(array, prop)` | `true`, pokud je vlastnost u všech položek nedefinovaná |
|
||||
| `noneEquals(array, prop, value)` | `true`, pokud se vlastnost nerovná hodnotě u žádné položky |
|
||||
|
||||
#### Veřejná aktiva
|
||||
#### Veřejné soubory
|
||||
|
||||
Frontendové komponenty mohou přistupovat k souborům ze složky aplikace `public/` pomocí `getPublicAssetUrl`:
|
||||
|
||||
@@ -957,7 +957,7 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
Podrobnosti viz [sekce veřejných aktiv](#accessing-public-assets-with-getpublicasseturl).
|
||||
Podrobnosti viz [sekci veřejných souborů](#accessing-public-assets-with-getpublicasseturl).
|
||||
|
||||
#### Styling
|
||||
|
||||
|
||||
@@ -4,24 +4,24 @@ description: Definieren Sie Objekte, Logikfunktionen, Frontend-Komponenten und m
|
||||
---
|
||||
|
||||
<Warning>
|
||||
Apps are currently in alpha. The feature works but is still evolving.
|
||||
Apps befinden sich derzeit in der Alpha-Phase. Die Funktion ist funktionsfähig, entwickelt sich jedoch noch weiter.
|
||||
</Warning>
|
||||
|
||||
The `twenty-sdk` package provides typed building blocks to create your app. This page covers every entity type and API client available in the SDK.
|
||||
Das Paket `twenty-sdk` stellt typisierte Bausteine zum Erstellen Ihrer App bereit. Diese Seite behandelt alle im SDK verfügbaren Entitätstypen und API-Clients.
|
||||
|
||||
## DefineEntity functions
|
||||
## DefineEntity-Funktionen
|
||||
|
||||
The SDK provides functions to define your app entities. You must use `export default defineEntity({...})` for the SDK to detect your entities. Diese Funktionen validieren Ihre Konfiguration zur Build-Zeit und bieten IDE-Autovervollständigung sowie Typsicherheit.
|
||||
Das SDK stellt Funktionen bereit, um die Entitäten Ihrer App zu definieren. Sie müssen `export default defineEntity({...})` verwenden, damit das SDK Ihre Entitäten erkennt. Diese Funktionen validieren Ihre Konfiguration zur Build-Zeit und bieten IDE-Autovervollständigung sowie Typsicherheit.
|
||||
|
||||
<Note>
|
||||
**File organization is up to you.**
|
||||
Entity detection is AST-based — the SDK finds `export default defineEntity(...)` calls regardless of where the file lives. Grouping files by type (e.g., `logic-functions/`, `roles/`) is just a convention, not a requirement.
|
||||
**Die Dateiorganisation liegt bei Ihnen.**
|
||||
Die Entitätserkennung ist AST-basiert — das SDK findet Aufrufe von `export default defineEntity(...)`, unabhängig davon, wo sich die Datei befindet. Das Gruppieren von Dateien nach Typ (z. B. `logic-functions/`, `roles/`) ist lediglich eine Konvention, keine Voraussetzung.
|
||||
</Note>
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Rolle definieren" description="Rollenberechtigungen und Objektzugriff konfigurieren">
|
||||
|
||||
Roles encapsulate permissions on your workspace's objects and actions.
|
||||
Rollen kapseln Berechtigungen für die Objekte und Aktionen Ihres Workspaces.
|
||||
|
||||
```ts restricted-company-role.ts
|
||||
import {
|
||||
@@ -69,12 +69,12 @@ export default defineRole({
|
||||
</Accordion>
|
||||
<Accordion title="Anwendung definieren" description="Anwendungsmetadaten konfigurieren (erforderlich, eine pro App)">
|
||||
|
||||
Every app must have exactly one `defineApplication` call that describes:
|
||||
Jede App muss genau einen Aufruf von `defineApplication` haben, der Folgendes beschreibt:
|
||||
|
||||
* **Identity**: identifiers, display name, and description.
|
||||
* **Permissions**: which role its functions and front components use.
|
||||
* **(Optional) Variables**: key–value pairs exposed to your functions as environment variables.
|
||||
* **(Optional) Pre-install / post-install functions**: logic functions that run before or after installation.
|
||||
* **Identität**: Bezeichner, Anzeigename und Beschreibung.
|
||||
* **Berechtigungen**: welche Rolle ihre Funktionen und Frontend-Komponenten verwenden.
|
||||
* **(Optional) Variablen**: Schlüssel–Wert-Paare, die Ihren Funktionen als Umgebungsvariablen zur Verfügung gestellt werden.
|
||||
* **(Optional) Pre-/Post-Installationsfunktionen**: Logikfunktionen, die vor oder nach der Installation ausgeführt werden.
|
||||
|
||||
```ts src/application-config.ts
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
@@ -98,21 +98,21 @@ export default defineApplication({
|
||||
```
|
||||
|
||||
Notizen:
|
||||
* `universalIdentifier` fields are deterministic IDs you own. Generate them once and keep them stable across syncs.
|
||||
* `applicationVariables` become environment variables for your functions and front components (e.g., `DEFAULT_RECIPIENT_NAME` is available as `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
* `defaultRoleUniversalIdentifier` must reference a role defined with `defineRole()` (see above).
|
||||
* Pre-install and post-install functions are detected automatically during the manifest build — you do not need to reference them in `defineApplication()`.
|
||||
* `universalIdentifier`-Felder sind deterministische IDs, die Ihnen gehören. Erzeugen Sie sie einmal und halten Sie sie über Synchronisierungen hinweg stabil.
|
||||
* `applicationVariables` werden zu Umgebungsvariablen für Ihre Funktionen und Frontend-Komponenten (z. B. ist `DEFAULT_RECIPIENT_NAME` als `process.env.DEFAULT_RECIPIENT_NAME` verfügbar).
|
||||
* `defaultRoleUniversalIdentifier` muss auf eine mit `defineRole()` definierte Rolle verweisen (siehe oben).
|
||||
* Pre- und Post-Installationsfunktionen werden während des Manifest-Builds automatisch erkannt — Sie müssen sie in `defineApplication()` nicht referenzieren.
|
||||
|
||||
#### Marktplatz-Metadaten
|
||||
|
||||
If you plan to [publish your app](/l/de/developers/extend/apps/publishing), these optional fields control how it appears in the marketplace:
|
||||
Wenn Sie planen, [Ihre App zu veröffentlichen](/l/de/developers/extend/apps/publishing), steuern diese optionalen Felder, wie Ihre App im Marktplatz erscheint:
|
||||
|
||||
| Feld | Beschreibung |
|
||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `author` | Name des Autors oder des Unternehmens |
|
||||
| `category` | App-Kategorie für die Filterung im Marktplatz |
|
||||
| `logoUrl` | Path to your app logo (e.g., `public/logo.png`) |
|
||||
| `screenshots` | Array of screenshot paths (e.g., `public/screenshot-1.png`) |
|
||||
| `logoUrl` | Pfad zu Ihrem App-Logo (z. B. `public/logo.png`) |
|
||||
| `screenshots` | Array von Screenshot-Pfaden (z. B. `public/screenshot-1.png`) |
|
||||
| `aboutDescription` | Längere Markdown-Beschreibung für den Tab "Info". Wenn weggelassen, verwendet der Marketplace die `README.md` des Pakets von npm |
|
||||
| `websiteUrl` | Link zu Ihrer Website |
|
||||
| `termsUrl` | Link zu den Nutzungsbedingungen |
|
||||
@@ -121,15 +121,15 @@ If you plan to [publish your app](/l/de/developers/extend/apps/publishing), thes
|
||||
|
||||
#### Rollen und Berechtigungen
|
||||
|
||||
The `defaultRoleUniversalIdentifier` in `application-config.ts` designates the default role used by your app's logic functions and front components. See `defineRole` above for details.
|
||||
Das Feld `defaultRoleUniversalIdentifier` in `application-config.ts` legt die Standardrolle fest, die von den Logikfunktionen und Frontend-Komponenten Ihrer App verwendet wird. Details finden Sie oben unter `defineRole`.
|
||||
|
||||
* The runtime token injected as `TWENTY_APP_ACCESS_TOKEN` is derived from this role.
|
||||
* The typed client is restricted to the permissions granted to that role.
|
||||
* Follow least-privilege: create a dedicated role with only the permissions your functions need.
|
||||
* Das zur Laufzeit als `TWENTY_APP_ACCESS_TOKEN` injizierte Token wird aus dieser Rolle abgeleitet.
|
||||
* Der typisierte Client ist auf die dieser Rolle gewährten Berechtigungen beschränkt.
|
||||
* Befolgen Sie das Least-Privilege-Prinzip: Erstellen Sie eine dedizierte Rolle nur mit den Berechtigungen, die Ihre Funktionen benötigen.
|
||||
|
||||
##### Default function role
|
||||
##### Standard-Funktionsrolle
|
||||
|
||||
When you scaffold a new app, the CLI creates a default role file:
|
||||
Wenn Sie eine neue App erzeugen, erstellt die CLI eine Standard-Rolldatei:
|
||||
|
||||
```ts src/roles/default-role.ts
|
||||
import { defineRole, PermissionFlag } from 'twenty-sdk';
|
||||
@@ -155,16 +155,16 @@ export default defineRole({
|
||||
});
|
||||
```
|
||||
|
||||
This role's `universalIdentifier` is referenced in `application-config.ts` as `defaultRoleUniversalIdentifier`:
|
||||
Der `universalIdentifier` dieser Rolle wird in `application-config.ts` als `defaultRoleUniversalIdentifier` referenziert:
|
||||
|
||||
* **\*.role.ts** defines what the role can do.
|
||||
* **\*.role.ts** definiert, was die Rolle darf.
|
||||
* **application-config.ts** verweist auf diese Rolle, sodass Ihre Funktionen deren Berechtigungen erben.
|
||||
|
||||
Notizen:
|
||||
* Beginnen Sie mit der vorab erstellten Rolle und schränken Sie sie schrittweise gemäß dem Least-Privilege-Prinzip ein.
|
||||
* Replace `objectPermissions` and `fieldPermissions` with the objects and fields your functions actually need.
|
||||
* `permissionFlags` steuern den Zugriff auf Funktionen auf Plattformebene. Keep them minimal.
|
||||
* See a working example: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
|
||||
* Ersetzen Sie `objectPermissions` und `fieldPermissions` durch die Objekte und Felder, die Ihre Funktionen tatsächlich benötigen.
|
||||
* `permissionFlags` steuern den Zugriff auf Funktionen auf Plattformebene. Halten Sie sie minimal.
|
||||
* Ein funktionierendes Beispiel finden Sie unter: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Objekt definieren" description="Benutzerdefinierte Objekte mit Feldern definieren">
|
||||
@@ -256,7 +256,7 @@ dies wird jedoch nicht empfohlen.
|
||||
</Note>
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineField — Standard fields" description="Bestehende Objekte mit zusätzlichen Feldern erweitern">
|
||||
<Accordion title="defineField — Standardfelder" description="Bestehende Objekte mit zusätzlichen Feldern erweitern">
|
||||
|
||||
Verwenden Sie `defineField()`, um Objekten, die Ihnen nicht gehören — etwa Standardobjekten von Twenty (Person, Company usw.) — Felder hinzuzufügen oder Objekten aus anderen Apps. Im Gegensatz zu Inline-Feldern in `defineObject()` benötigen eigenständige Felder einen `objectUniversalIdentifier`, um anzugeben, welches Objekt sie erweitern:
|
||||
|
||||
@@ -284,7 +284,7 @@ Hauptpunkte:
|
||||
* `defineField()` ist die einzige Möglichkeit, Felder zu Objekten hinzuzufügen, die Sie nicht mit `defineObject()` erstellt haben.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineField — Relation fields" description="Connect objects together with bidirectional relations">
|
||||
<Accordion title="defineField — Relationsfelder" description="Objekte mit bidirektionalen Relationen verbinden">
|
||||
|
||||
Relationen verbinden Objekte miteinander. In Twenty sind Relationen stets **bidirektional** — Sie definieren beide Seiten, und jede Seite referenziert die andere.
|
||||
|
||||
@@ -443,7 +443,7 @@ export default defineObject({
|
||||
});
|
||||
```
|
||||
</Accordion>
|
||||
<Accordion title="defineLogicFunction" description="Define logic functions and their triggers">
|
||||
<Accordion title="defineLogicFunction" description="Logikfunktionen und deren Trigger definieren">
|
||||
|
||||
Jede Funktionsdatei verwendet `defineLogicFunction()`, um eine Konfiguration mit einem Handler und optionalen Triggern zu exportieren.
|
||||
|
||||
@@ -487,15 +487,15 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
Available trigger types:
|
||||
* **httpRoute**: Exposes your function on an HTTP path and method **under the `/s/` endpoint**:
|
||||
> e.g. `path: '/post-card/create'` is callable at `https://your-twenty-server.com/s/post-card/create`
|
||||
Verfügbare Trigger-Typen:
|
||||
* **httpRoute**: Stellt Ihre Funktion unter einem HTTP-Pfad und einer Methode **unter dem Endpunkt `/s/`** bereit:
|
||||
> z. B. `path: '/post-card/create'` ist unter `https://your-twenty-server.com/s/post-card/create` aufrufbar
|
||||
* **cron**: Führt Ihre Funktion nach Zeitplan mithilfe eines CRON-Ausdrucks aus.
|
||||
* **databaseEvent**: Wird bei Lebenszyklusereignissen von Workspace-Objekten ausgeführt. Wenn die Ereignisoperation `updated` ist, können bestimmte zu überwachende Felder im Array `updatedFields` angegeben werden. Wenn das Array undefiniert oder leer ist, löst jede Aktualisierung die Funktion aus.
|
||||
> e.g. `person.updated`, `*.created`, `company.*`
|
||||
> z. B. `person.updated`, `*.created`, `company.*`
|
||||
|
||||
<Note>
|
||||
You can also manually execute a function using the CLI:
|
||||
Sie können eine Funktion auch manuell über die CLI ausführen:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty exec -n create-new-post-card -p '{"key": "value"}'
|
||||
@@ -505,7 +505,7 @@ yarn twenty exec -n create-new-post-card -p '{"key": "value"}'
|
||||
yarn twenty exec -y e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf
|
||||
```
|
||||
|
||||
You can watch logs with:
|
||||
Sie können Protokolle mit folgendem Befehl ansehen:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty logs
|
||||
@@ -514,9 +514,8 @@ yarn twenty logs
|
||||
|
||||
#### Routen-Trigger-Payload
|
||||
|
||||
When a route trigger invokes your logic function, it receives a `RoutePayload` object that follows the
|
||||
[AWS HTTP API v2 format](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html).
|
||||
Import the `RoutePayload` type from `twenty-sdk`:
|
||||
Wenn ein Route-Trigger Ihre Logikfunktion aufruft, erhält sie ein `RoutePayload`-Objekt, das dem [AWS-HTTP-API-v2-Format](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html) folgt.
|
||||
Importieren Sie den Typ `RoutePayload` aus `twenty-sdk`:
|
||||
|
||||
```ts
|
||||
import { defineLogicFunction, type RoutePayload } from 'twenty-sdk';
|
||||
@@ -533,9 +532,9 @@ Der Typ `RoutePayload` hat die folgende Struktur:
|
||||
|
||||
| Eigenschaft | Typ | Beschreibung | Beispiel |
|
||||
| ---------------------------- | ------------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record<string, string \| undefined>` | HTTP-Header (nur die in `forwardedRequestHeaders` aufgelisteten) | see section below |
|
||||
| `headers` | `Record<string, string \| undefined>` | HTTP-Header (nur die in `forwardedRequestHeaders` aufgelisteten) | siehe Abschnitt unten |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Query-String-Parameter (mehrere Werte mit Kommas verbunden) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Path parameters extracted from the route pattern | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Aus dem Routenmuster extrahierte Pfadparameter | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Geparster Request-Body (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `isBase64Encoded` | `boolean` | Gibt an, ob der Body Base64-codiert ist | |
|
||||
| `requestContext.http.method` | `string` | HTTP-Methode (GET, POST, PUT, PATCH, DELETE) | |
|
||||
@@ -545,7 +544,7 @@ Der Typ `RoutePayload` hat die folgende Struktur:
|
||||
#### forwardedRequestHeaders
|
||||
|
||||
Standardmäßig werden HTTP-Header von eingehenden Anfragen aus Sicherheitsgründen nicht an Ihre Logikfunktion weitergegeben.
|
||||
To access specific headers, list them in the `forwardedRequestHeaders` array:
|
||||
Um auf bestimmte Header zuzugreifen, listen Sie diese im Array `forwardedRequestHeaders` auf:
|
||||
|
||||
```ts
|
||||
export default defineLogicFunction({
|
||||
@@ -561,7 +560,7 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
In your handler, access the forwarded headers like this:
|
||||
Greifen Sie in Ihrem Handler wie folgt auf die weitergeleiteten Header zu:
|
||||
|
||||
```ts
|
||||
const handler = async (event: RoutePayload) => {
|
||||
@@ -574,14 +573,14 @@ const handler = async (event: RoutePayload) => {
|
||||
```
|
||||
|
||||
<Note>
|
||||
Header-Namen werden in Kleinbuchstaben normalisiert. Access them using lowercase keys (e.g., `event.headers['content-type']`).
|
||||
Header-Namen werden in Kleinbuchstaben normalisiert. Greifen Sie mit Schlüsseln in Kleinbuchstaben darauf zu (z. B. `event.headers['content-type']`).
|
||||
</Note>
|
||||
|
||||
#### Exposing a function as a tool
|
||||
#### Eine Funktion als Tool bereitstellen
|
||||
|
||||
Logikfunktionen können als **Tools** für KI-Agenten und Workflows verfügbar gemacht werden. When marked as a tool, a function becomes discoverable by Twenty's AI features and can be used in workflow automations.
|
||||
Logikfunktionen können als **Tools** für KI-Agenten und Workflows verfügbar gemacht werden. Wenn eine Funktion als Tool markiert ist, wird sie von den KI-Funktionen von Twenty auffindbar und kann in Workflow-Automatisierungen verwendet werden.
|
||||
|
||||
To mark a logic function as a tool, set `isTool: true`:
|
||||
Um eine Logikfunktion als Tool zu markieren, setzen Sie `isTool: true`:
|
||||
|
||||
```ts src/logic-functions/enrich-company.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
@@ -617,8 +616,8 @@ export default defineLogicFunction({
|
||||
|
||||
Hauptpunkte:
|
||||
|
||||
* You can combine `isTool` with triggers — a function can be both a tool (callable by AI agents) and triggered by events at the same time.
|
||||
* **`toolInputSchema`** (optional): A JSON Schema object describing the parameters your function accepts. The schema is computed automatically from source code static analysis, but you can set it explicitly:
|
||||
* Sie können `isTool` mit Triggern kombinieren — eine Funktion kann gleichzeitig sowohl ein Tool (von KI-Agenten aufrufbar) als auch durch Ereignisse ausgelöst werden.
|
||||
* **`toolInputSchema`** (optional): Ein JSON-Schema-Objekt, das die Parameter beschreibt, die Ihre Funktion akzeptiert. Das Schema wird automatisch durch statische Analyse des Quellcodes ermittelt, Sie können es jedoch auch explizit festlegen:
|
||||
|
||||
```ts
|
||||
export default defineLogicFunction({
|
||||
@@ -715,11 +714,11 @@ Hauptpunkte:
|
||||
</Accordion>
|
||||
<Accordion title="defineFrontComponent" description="Frontend-Komponenten für benutzerdefinierte UI definieren">
|
||||
|
||||
Front components are React components that render directly inside Twenty's UI. They run in an **isolated Web Worker** using Remote DOM — your code is sandboxed but renders natively in the page, not in an iframe.
|
||||
Frontend-Komponenten sind React-Komponenten, die direkt innerhalb der Twenty-UI gerendert werden. Sie laufen in einem **isolierten Web Worker** unter Verwendung von Remote DOM — Ihr Code wird in einer Sandbox ausgeführt, rendert jedoch nativ auf der Seite, nicht in einem iframe.
|
||||
|
||||
#### Basic example
|
||||
#### Einfaches Beispiel
|
||||
|
||||
The quickest way to see a front component in action is to register it as a **command**. Adding a `command` field with `isPinned: true` makes it appear as a quick-action button in the top-right corner of the page — no page layout needed:
|
||||
Der schnellste Weg, eine Frontend-Komponente in Aktion zu sehen, ist, sie als Befehl zu registrieren. Das Hinzufügen eines `command`-Felds mit `isPinned: true` lässt sie als Schnellaktionsschaltfläche oben rechts auf der Seite erscheinen — kein Seitenlayout erforderlich:
|
||||
|
||||
```tsx src/front-components/hello-world.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
@@ -749,34 +748,34 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
After syncing with `yarn twenty dev`, the quick action appears in the top-right corner of the page:
|
||||
Nach dem Synchronisieren mit `yarn twenty dev` erscheint die Schnellaktion oben rechts auf der Seite:
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img src="/images/docs/developers/extends/apps/quick-action.png" alt="Quick action button in the top-right corner" />
|
||||
<img src="/images/docs/developers/extends/apps/quick-action.png" alt="Schnellaktionsschaltfläche oben rechts" />
|
||||
</div>
|
||||
|
||||
Click it to render the component inline.
|
||||
Klicken Sie darauf, um die Komponente inline zu rendern.
|
||||
|
||||
{/* TODO: add screenshot of the rendered front component */}
|
||||
|
||||
#### Configuration fields
|
||||
#### Konfigurationsfelder
|
||||
|
||||
| Feld | Erforderlich | Beschreibung |
|
||||
| --------------------- | ------------ | ----------------------------------------------------------------------------------- |
|
||||
| `universalIdentifier` | Ja | Stable unique ID for this component |
|
||||
| `component` | Ja | A React component function |
|
||||
| `name` | Nein | Display name |
|
||||
| `description` | Nein | Description of what the component does |
|
||||
| `isHeadless` | Nein | Set to `true` if the component has no visible UI (see below) |
|
||||
| `command` | Nein | Register the component as a command (see [command options](#command-options) below) |
|
||||
| Feld | Erforderlich | Beschreibung |
|
||||
| --------------------- | ------------ | ---------------------------------------------------------------------------------------- |
|
||||
| `universalIdentifier` | Ja | Stabile eindeutige ID für diese Komponente |
|
||||
| `component` | Ja | Eine React-Komponentenfunktion |
|
||||
| `name` | Nein | Anzeigename |
|
||||
| `description` | Nein | Beschreibung dessen, was die Komponente macht |
|
||||
| `isHeadless` | Nein | Auf `true` setzen, wenn die Komponente keine sichtbare UI hat (siehe unten) |
|
||||
| `command` | Nein | Die Komponente als Befehl registrieren (siehe unten [Befehlsoptionen](#command-options)) |
|
||||
|
||||
#### Placing a front component on a page
|
||||
#### Eine Frontend-Komponente auf einer Seite platzieren
|
||||
|
||||
Beyond commands, you can embed a front component directly into a record page by adding it as a widget in a **page layout**. See the [definePageLayout](#definepagelayout) section for details.
|
||||
Über Befehle hinaus können Sie eine Frontend-Komponente direkt in eine Datensatzseite einbetten, indem Sie sie als Widget in einem **Seitenlayout** hinzufügen. Details finden Sie im Abschnitt [definePageLayout](#definepagelayout).
|
||||
|
||||
#### Headless components (`isHeadless: true`)
|
||||
#### Headless-Komponenten (`isHeadless: true`)
|
||||
|
||||
Headless components render no visible UI but still run React logic. This is useful for **effect components** — components that perform side effects when mounted, such as syncing data, starting a timer, listening to events, or triggering a notification.
|
||||
Headless-Komponenten rendern keine sichtbare UI, führen aber dennoch React-Logik aus. Dies ist nützlich für **Effekt-Komponenten** — Komponenten, die beim Mounten Seiteneffekte ausführen, wie z. B. das Synchronisieren von Daten, Starten eines Timers, Lauschen auf Ereignisse oder Auslösen einer Benachrichtigung.
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent, useRecordId, enqueueSnackbar } from 'twenty-sdk';
|
||||
@@ -801,11 +800,11 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
Because the component returns `null`, Twenty skips rendering a container for it — no empty space appears in the layout. The component still has access to all hooks and the host communication API.
|
||||
Da die Komponente `null` zurückgibt, überspringt Twenty das Rendern eines Containers dafür — im Layout entsteht kein Leerraum. Die Komponente hat dennoch Zugriff auf alle Hooks und die Host-Kommunikations-API.
|
||||
|
||||
#### Accessing runtime context
|
||||
#### Zugriff auf den Laufzeitkontext
|
||||
|
||||
Inside your component, use SDK hooks to access the current user, record, and component instance:
|
||||
Verwenden Sie innerhalb Ihrer Komponente SDK-Hooks, um auf den aktuellen Benutzer, den Datensatz und die Komponenteninstanz zuzugreifen:
|
||||
|
||||
```tsx src/front-components/record-info.tsx
|
||||
import {
|
||||
@@ -836,47 +835,47 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
Available hooks:
|
||||
Verfügbare Hooks:
|
||||
|
||||
| Hook | Returns | Beschreibung |
|
||||
| --------------------------------------------- | ------------------ | ---------------------------------------------------------- |
|
||||
| `useUserId()` | `string` or `null` | The current user's ID |
|
||||
| `useRecordId()` | `string` or `null` | The current record's ID (when placed on a record page) |
|
||||
| `useFrontComponentId()` | `string` | This component instance's ID |
|
||||
| `useFrontComponentExecutionContext(selector)` | variiert | Access the full execution context with a selector function |
|
||||
| Hook | Gibt zurück | Beschreibung |
|
||||
| --------------------------------------------- | -------------------- | --------------------------------------------------------------------------- |
|
||||
| `useUserId()` | `string` oder `null` | Die ID des aktuellen Benutzers |
|
||||
| `useRecordId()` | `string` oder `null` | Die ID des aktuellen Datensatzes (wenn auf einer Datensatzseite platziert) |
|
||||
| `useFrontComponentId()` | `string` | Die ID dieser Komponenteninstanz |
|
||||
| `useFrontComponentExecutionContext(selector)` | variiert | Zugriff auf den vollständigen Ausführungskontext mit einer Selektorfunktion |
|
||||
|
||||
#### Host communication API
|
||||
#### Host-Kommunikations-API
|
||||
|
||||
Front components can trigger navigation, modals, and notifications using functions from `twenty-sdk`:
|
||||
Frontend-Komponenten können Navigation, Modals und Benachrichtigungen mittels Funktionen aus `twenty-sdk` auslösen:
|
||||
|
||||
| Funktion | Beschreibung |
|
||||
| ----------------------------------------------- | ----------------------------- |
|
||||
| `navigate(to, params?, queryParams?, options?)` | Navigate to a page in the app |
|
||||
| `openSidePanelPage(params)` | Open a side panel |
|
||||
| `closeSidePanel()` | Seitenpanel schließen |
|
||||
| `openCommandConfirmationModal(params)` | Show a confirmation dialog |
|
||||
| `enqueueSnackbar(params)` | Show a toast notification |
|
||||
| `unmountFrontComponent()` | Unmount the component |
|
||||
| `updateProgress(progress)` | Update a progress indicator |
|
||||
| Funktion | Beschreibung |
|
||||
| ----------------------------------------------- | ----------------------------------------- |
|
||||
| `navigate(to, params?, queryParams?, options?)` | Zu einer Seite in der App navigieren |
|
||||
| `openSidePanelPage(params)` | Ein Seitenpanel öffnen |
|
||||
| `closeSidePanel()` | Seitenpanel schließen |
|
||||
| `openCommandConfirmationModal(params)` | Einen Bestätigungsdialog anzeigen |
|
||||
| `enqueueSnackbar(params)` | Eine Toast-Benachrichtigung anzeigen |
|
||||
| `unmountFrontComponent()` | Die Komponente entfernen |
|
||||
| `updateProgress(progress)` | Einen Fortschrittsindikator aktualisieren |
|
||||
|
||||
#### Command options
|
||||
#### Befehlsoptionen
|
||||
|
||||
Adding a `command` field to `defineFrontComponent` registers the component in the command menu (Cmd+K). If `isPinned` is `true`, it also appears as a quick-action button in the top-right corner of the page.
|
||||
Das Hinzufügen eines `command`-Felds zu `defineFrontComponent` registriert die Komponente im Befehlsmenü (Cmd+K). Wenn `isPinned` `true` ist, erscheint sie außerdem als Schnellaktionsschaltfläche oben rechts auf der Seite.
|
||||
|
||||
| Feld | Erforderlich | Beschreibung |
|
||||
| --------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `universalIdentifier` | Ja | Stable unique ID for the command |
|
||||
| `label` | Ja | Full label shown in the command menu (Cmd+K) |
|
||||
| `shortLabel` | Nein | Shorter label displayed on the pinned quick-action button |
|
||||
| `icon` | Nein | Icon name displayed next to the label (e.g. `'IconBolt'`, `'IconSend'`) |
|
||||
| `isPinned` | Nein | When `true`, shows the command as a quick-action button in the top-right corner of the page |
|
||||
| `availabilityType` | Nein | Controls where the command appears: `'GLOBAL'` (always available), `'RECORD_SELECTION'` (only when records are selected), or `'FALLBACK'` (shown when no other commands match) |
|
||||
| `availabilityObjectUniversalIdentifier` | Nein | Restrict the command to pages of a specific object type (e.g. only on Company records) |
|
||||
| `conditionalAvailabilityExpression` | Nein | A boolean expression to dynamically control whether the command is visible (see below) |
|
||||
| Feld | Erforderlich | Beschreibung |
|
||||
| --------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `universalIdentifier` | Ja | Stabile eindeutige ID für den Befehl |
|
||||
| `label` | Ja | Vollständiges Label, das im Befehlsmenü (Cmd+K) angezeigt wird |
|
||||
| `shortLabel` | Nein | Kürzeres Label, das auf der angehefteten Schnellaktionsschaltfläche angezeigt wird |
|
||||
| `icon` | Nein | Neben dem Label angezeigter Icon-Name (z. B. 'IconBolt', 'IconSend') |
|
||||
| `isPinned` | Nein | Bei `true` wird der Befehl als Schnellaktionsschaltfläche oben rechts auf der Seite angezeigt |
|
||||
| `availabilityType` | Nein | Steuert, wo der Befehl erscheint: 'GLOBAL' (immer verfügbar), 'RECORD_SELECTION' (nur wenn Datensätze ausgewählt sind) oder 'FALLBACK' (wird angezeigt, wenn keine anderen Befehle passen) |
|
||||
| `availabilityObjectUniversalIdentifier` | Nein | Beschränken Sie den Befehl auf Seiten eines bestimmten Objekttyps (z. B. nur bei Company-Datensätzen) |
|
||||
| `conditionalAvailabilityExpression` | Nein | Ein boolescher Ausdruck, um dynamisch zu steuern, ob der Befehl sichtbar ist (siehe unten) |
|
||||
|
||||
#### Conditional availability expressions
|
||||
#### Bedingte Verfügbarkeitsausdrücke
|
||||
|
||||
The `conditionalAvailabilityExpression` field lets you control when a command is visible based on the current page context. Import typed variables and operators from `twenty-sdk` to build expressions:
|
||||
Mit dem Feld `conditionalAvailabilityExpression` können Sie basierend auf dem aktuellen Seitenkontext steuern, wann ein Befehl sichtbar ist. Importieren Sie typisierte Variablen und Operatoren aus `twenty-sdk`, um Ausdrücke zu erstellen:
|
||||
|
||||
```tsx
|
||||
import {
|
||||
@@ -905,45 +904,45 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
**Context variables** — these represent the current state of the page:
|
||||
**Kontextvariablen** — sie repräsentieren den aktuellen Zustand der Seite:
|
||||
|
||||
| Variable | Typ | Beschreibung |
|
||||
| ------------------------------ | --------- | ---------------------------------------------------------------- |
|
||||
| `pageType` | `string` | Current page type (e.g. `'RecordIndexPage'`, `'RecordShowPage'`) |
|
||||
| `isInSidePanel` | `boolean` | Whether the component is rendered in a side panel |
|
||||
| `numberOfSelectedRecords` | `number` | Number of currently selected records |
|
||||
| `isSelectAll` | `boolean` | Whether "select all" is active |
|
||||
| `selectedRecords` | `array` | The selected record objects |
|
||||
| `favoriteRecordIds` | `array` | IDs of favorited records |
|
||||
| `objectPermissions` | `object` | Permissions for the current object type |
|
||||
| `targetObjectReadPermissions` | `object` | Read permissions for the target object |
|
||||
| `targetObjectWritePermissions` | `object` | Write permissions for the target object |
|
||||
| `featureFlags` | `object` | Active feature flags |
|
||||
| `objectMetadataItem` | `object` | Metadata of the current object type |
|
||||
| `hasAnySoftDeleteFilterOnView` | `boolean` | Whether the current view has a soft-delete filter |
|
||||
| Variable | Typ | Beschreibung |
|
||||
| ------------------------------ | --------- | --------------------------------------------------------------- |
|
||||
| `pageType` | `string` | Aktueller Seitentyp (z. B. 'RecordIndexPage', 'RecordShowPage') |
|
||||
| `isInSidePanel` | `boolean` | Ob die Komponente in einem Seitenpanel gerendert wird |
|
||||
| `numberOfSelectedRecords` | `number` | Anzahl der aktuell ausgewählten Datensätze |
|
||||
| `isSelectAll` | `boolean` | Ob „Alle auswählen“ aktiv ist |
|
||||
| `selectedRecords` | `array` | Die ausgewählten Datensatzobjekte |
|
||||
| `favoriteRecordIds` | `array` | IDs der favorisierten Datensätze |
|
||||
| `objectPermissions` | `object` | Berechtigungen für den aktuellen Objekttyp |
|
||||
| `targetObjectReadPermissions` | `object` | Leseberechtigungen für das Zielobjekt |
|
||||
| `targetObjectWritePermissions` | `object` | Schreibberechtigungen für das Zielobjekt |
|
||||
| `featureFlags` | `object` | Aktive Feature-Flags |
|
||||
| `objectMetadataItem` | `object` | Metadaten des aktuellen Objekttyps |
|
||||
| `hasAnySoftDeleteFilterOnView` | `boolean` | Ob die aktuelle Ansicht einen Soft-Delete-Filter hat |
|
||||
|
||||
**Operators** — combine variables into boolean expressions:
|
||||
**Operatoren** — Variablen zu booleschen Ausdrücken kombinieren:
|
||||
|
||||
| Operator | Beschreibung |
|
||||
| ----------------------------------- | ----------------------------------------------------------------- |
|
||||
| `isDefined(value)` | `true` if the value is not null/undefined |
|
||||
| `isNonEmptyString(value)` | `true` if the value is a non-empty string |
|
||||
| `includes(array, value)` | `true` if the array contains the value |
|
||||
| `includesEvery(array, prop, value)` | `true` if every item's property includes the value |
|
||||
| `every(array, prop)` | `true` if the property is truthy on every item |
|
||||
| `everyDefined(array, prop)` | `true` if the property is defined on every item |
|
||||
| `everyEquals(array, prop, value)` | `true` if the property equals the value on every item |
|
||||
| `some(array, prop)` | `true` if the property is truthy on at least one item |
|
||||
| `someDefined(array, prop)` | `true` if the property is defined on at least one item |
|
||||
| `someEquals(array, prop, value)` | `true` if the property equals the value on at least one item |
|
||||
| `someNonEmptyString(array, prop)` | `true` if the property is a non-empty string on at least one item |
|
||||
| `none(array, prop)` | `true` if the property is falsy on every item |
|
||||
| `noneDefined(array, prop)` | `true` if the property is undefined on every item |
|
||||
| `noneEquals(array, prop, value)` | `true` if the property does not equal the value on any item |
|
||||
| Operator | Beschreibung |
|
||||
| ----------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| `isDefined(value)` | `true`, wenn der Wert nicht null/undefined ist |
|
||||
| `isNonEmptyString(value)` | `true`, wenn der Wert eine nicht leere Zeichenfolge ist |
|
||||
| `includes(array, value)` | `true`, wenn das Array den Wert enthält |
|
||||
| `includesEvery(array, prop, value)` | `true`, wenn die Eigenschaft jedes Elements den Wert enthält |
|
||||
| `every(array, prop)` | `true`, wenn die Eigenschaft bei jedem Element truthy ist |
|
||||
| `everyDefined(array, prop)` | `true`, wenn die Eigenschaft bei jedem Element definiert ist |
|
||||
| `everyEquals(array, prop, value)` | `true`, wenn die Eigenschaft bei jedem Element dem Wert entspricht |
|
||||
| `some(array, prop)` | `true`, wenn die Eigenschaft bei mindestens einem Element truthy ist |
|
||||
| `someDefined(array, prop)` | `true`, wenn die Eigenschaft bei mindestens einem Element definiert ist |
|
||||
| `someEquals(array, prop, value)` | `true`, wenn die Eigenschaft bei mindestens einem Element dem Wert entspricht |
|
||||
| `someNonEmptyString(array, prop)` | `true`, wenn die Eigenschaft bei mindestens einem Element eine nicht leere Zeichenfolge ist |
|
||||
| `none(array, prop)` | `true`, wenn die Eigenschaft bei jedem Element falsy ist |
|
||||
| `noneDefined(array, prop)` | `true`, wenn die Eigenschaft bei jedem Element undefined ist |
|
||||
| `noneEquals(array, prop, value)` | `true`, wenn die Eigenschaft bei keinem Element dem Wert entspricht |
|
||||
|
||||
#### Public assets
|
||||
#### Öffentliche Assets
|
||||
|
||||
Front components can access files from the app's `public/` directory using `getPublicAssetUrl`:
|
||||
Frontend-Komponenten können mit `getPublicAssetUrl` auf Dateien aus dem `public/`-Verzeichnis der App zugreifen:
|
||||
|
||||
```tsx
|
||||
import { defineFrontComponent, getPublicAssetUrl } from 'twenty-sdk';
|
||||
@@ -957,18 +956,18 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
See the [public assets section](#accessing-public-assets-with-getpublicasseturl) for details.
|
||||
Details finden Sie im Abschnitt [Öffentliche Assets](#accessing-public-assets-with-getpublicasseturl).
|
||||
|
||||
#### Styling
|
||||
|
||||
Front components support multiple styling approaches. You can use:
|
||||
Frontend-Komponenten unterstützen mehrere Styling-Ansätze. Sie können verwenden:
|
||||
|
||||
* **Inline styles** — `style={{ color: 'red' }}`
|
||||
* **Twenty UI components** — import from `twenty-sdk/ui` (Button, Tag, Status, Chip, Avatar, and more)
|
||||
* **Emotion** — CSS-in-JS with `@emotion/react`
|
||||
* **Styled-components** — `styled.div` patterns
|
||||
* **Tailwind CSS** — utility classes
|
||||
* **Any CSS-in-JS library** compatible with React
|
||||
* **Inline-Styles** — `style={{ color: 'red' }}`
|
||||
* **Twenty-UI-Komponenten** — Import aus `twenty-sdk/ui` (Button, Tag, Status, Chip, Avatar und mehr)
|
||||
* **Emotion** — CSS-in-JS mit `@emotion/react`
|
||||
* **Styled-components** — `styled.div`-Muster
|
||||
* **Tailwind CSS** — Utility-Klassen
|
||||
* **Beliebige CSS-in-JS-Bibliothek**, die mit React kompatibel ist
|
||||
|
||||
```tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
@@ -1022,9 +1021,9 @@ Hauptpunkte:
|
||||
* `description` (optional) liefert zusätzlichen Kontext zum Zweck des Skills.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineAgent" description="Define AI agents with custom prompts">
|
||||
<Accordion title="defineAgent" description="KI-Agenten mit benutzerdefinierten Prompts definieren">
|
||||
|
||||
Agents are AI assistants that live inside your workspace. Use `defineAgent()` to create agents with a custom system prompt:
|
||||
Agenten sind KI-Assistenten, die innerhalb Ihres Workspaces leben. Verwenden Sie `defineAgent()`, um Agenten mit einem benutzerdefinierten System-Prompt zu erstellen:
|
||||
|
||||
```ts src/agents/example-agent.ts
|
||||
import { defineAgent } from 'twenty-sdk';
|
||||
@@ -1040,17 +1039,17 @@ export default defineAgent({
|
||||
```
|
||||
|
||||
Hauptpunkte:
|
||||
* `name` is the unique identifier string for the agent (kebab-case recommended).
|
||||
* `label` is the display name shown in the UI.
|
||||
* `prompt` is the system prompt that defines the agent's behavior.
|
||||
* `description` (optional) provides context about what the agent does.
|
||||
* `name` ist die eindeutige Kennzeichnungs-Zeichenfolge für den Agenten (kebab-case empfohlen).
|
||||
* `label` ist der in der UI angezeigte Anzeigename.
|
||||
* `prompt` ist der System-Prompt, der das Verhalten des Agenten definiert.
|
||||
* `description` (optional) liefert Kontext dazu, was der Agent tut.
|
||||
* `icon` (optional) legt das in der UI angezeigte Symbol fest.
|
||||
* `modelId` (optional) overrides the default AI model used by the agent.
|
||||
* `modelId` (optional) überschreibt das vom Agenten verwendete Standard-KI-Modell.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineView" description="Gespeicherte Views für Objekte definieren">
|
||||
|
||||
Views are saved configurations for how records of an object are displayed — including which fields are visible, their order, and any filters or groups applied. Use `defineView()` to ship pre-configured views with your app:
|
||||
Ansichten sind gespeicherte Konfigurationen dafür, wie Datensätze eines Objekts angezeigt werden — einschließlich sichtbarer Felder, deren Reihenfolge sowie angewendeter Filter oder Gruppen. Verwenden Sie `defineView()`, um vorkonfigurierte Ansichten mit Ihrer App auszuliefern:
|
||||
|
||||
```ts src/views/example-view.ts
|
||||
import { defineView, ViewKey } from 'twenty-sdk';
|
||||
@@ -1077,16 +1076,16 @@ export default defineView({
|
||||
```
|
||||
|
||||
Hauptpunkte:
|
||||
* `objectUniversalIdentifier` specifies which object this view applies to.
|
||||
* `key` determines the view type (e.g., `ViewKey.INDEX` for the main list view).
|
||||
* `fields` controls which columns appear and their order. Each field references a `fieldMetadataUniversalIdentifier`.
|
||||
* You can also define `filters`, `filterGroups`, `groups`, and `fieldGroups` for more advanced configurations.
|
||||
* `position` controls the ordering when multiple views exist for the same object.
|
||||
* `objectUniversalIdentifier` gibt an, auf welches Objekt diese Ansicht angewendet wird.
|
||||
* `key` bestimmt den Ansichtstyp (z. B. `ViewKey.INDEX` für die Hauptlistenansicht).
|
||||
* `fields` steuert, welche Spalten erscheinen und in welcher Reihenfolge. Jedes Feld referenziert einen `fieldMetadataUniversalIdentifier`.
|
||||
* Für erweiterte Konfigurationen können Sie außerdem `filters`, `filterGroups`, `groups` und `fieldGroups` definieren.
|
||||
* `position` steuert die Reihenfolge, wenn mehrere Ansichten für dasselbe Objekt existieren.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineNavigationMenuItem" description="Seitenleisten-Navigationslinks definieren">
|
||||
|
||||
Navigation menu items add custom entries to the workspace sidebar. Use `defineNavigationMenuItem()` to link to views, external URLs, or objects:
|
||||
Navigationsmenüeinträge fügen der Workspace-Seitenleiste benutzerdefinierte Einträge hinzu. Verwenden Sie `defineNavigationMenuItem()`, um auf Ansichten, externe URLs oder Objekte zu verlinken:
|
||||
|
||||
```ts src/navigation-menu-items/example-navigation-menu-item.ts
|
||||
import { defineNavigationMenuItem, NavigationMenuItemType } from 'twenty-sdk';
|
||||
@@ -1104,15 +1103,15 @@ export default defineNavigationMenuItem({
|
||||
```
|
||||
|
||||
Hauptpunkte:
|
||||
* `type` determines what the menu item links to: `NavigationMenuItemType.VIEW` for a saved view, or `NavigationMenuItemType.LINK` for an external URL.
|
||||
* For view links, set `viewUniversalIdentifier`. For external links, set `link`.
|
||||
* `position` controls the ordering in the sidebar.
|
||||
* `icon` and `color` (optional) customize the appearance.
|
||||
* `type` bestimmt, worauf der Menüeintrag verweist: `NavigationMenuItemType.VIEW` für eine gespeicherte Ansicht oder `NavigationMenuItemType.LINK` für eine externe URL.
|
||||
* Für Ansichtslinks setzen Sie `viewUniversalIdentifier`. Für externe Links setzen Sie `link`.
|
||||
* `position` steuert die Reihenfolge in der Seitenleiste.
|
||||
* `icon` und `color` (optional) passen das Erscheinungsbild an.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="definePageLayout" description="Define custom page layouts for record views">
|
||||
<Accordion title="definePageLayout" description="Benutzerdefinierte Seitenlayouts für Datensatzansichten definieren">
|
||||
|
||||
Page layouts let you customize how a record detail page looks — which tabs appear, what widgets are inside each tab, and how they are arranged. Use `definePageLayout()` to ship custom layouts with your app:
|
||||
Seitenlayouts ermöglichen es Ihnen, das Aussehen einer Datensatzdetailseite anzupassen — welche Tabs erscheinen, welche Widgets sich in jedem Tab befinden und wie sie angeordnet sind. Verwenden Sie `definePageLayout()`, um benutzerdefinierte Layouts mit Ihrer App auszuliefern:
|
||||
|
||||
```ts src/page-layouts/example-record-page-layout.ts
|
||||
import { definePageLayout, PageLayoutTabLayoutMode } from 'twenty-sdk';
|
||||
@@ -1149,33 +1148,33 @@ export default definePageLayout({
|
||||
```
|
||||
|
||||
Hauptpunkte:
|
||||
* `type` is typically `'RECORD_PAGE'` to customize the detail view of a specific object.
|
||||
* `objectUniversalIdentifier` specifies which object this layout applies to.
|
||||
* Each `tab` defines a section of the page with a `title`, `position`, and `layoutMode` (`CANVAS` for free-form layout).
|
||||
* Each `widget` inside a tab can render a front component, a relation list, or other built-in widget types.
|
||||
* `position` on tabs controls their order. Use higher values (e.g., 50) to place custom tabs after built-in ones.
|
||||
* `type` ist typischerweise `'RECORD_PAGE'`, um die Detailansicht eines bestimmten Objekts anzupassen.
|
||||
* `objectUniversalIdentifier` gibt an, auf welches Objekt dieses Layout angewendet wird.
|
||||
* Jeder `tab` definiert einen Abschnitt der Seite mit `title`, `position` und `layoutMode` (`CANVAS` für ein freies Layout).
|
||||
* Jedes `widget` innerhalb eines Tabs kann eine Frontend-Komponente, eine Relationenliste oder andere eingebaute Widget-Typen rendern.
|
||||
* `position` auf Tabs steuert deren Reihenfolge. Verwenden Sie höhere Werte (z. B. 50), um benutzerdefinierte Tabs hinter den integrierten zu platzieren.
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Public assets (`public/` folder)
|
||||
## Öffentliche Assets (Ordner `public/`)
|
||||
|
||||
The `public/` folder at the root of your app holds static files — images, icons, fonts, or any other assets your app needs at runtime. These files are automatically included in builds, synced during dev mode, and uploaded to the server.
|
||||
Der Ordner `public/` im Stammverzeichnis Ihrer App enthält statische Dateien — Bilder, Icons, Schriftarten oder sonstige Assets, die Ihre App zur Laufzeit benötigt. Diese Dateien werden automatisch in Builds aufgenommen, während des Dev-Modus synchronisiert und auf den Server hochgeladen.
|
||||
|
||||
Files placed in `public/` are:
|
||||
Für Dateien im Verzeichnis `public/` gilt:
|
||||
|
||||
* **Publicly accessible** — once synced to the server, assets are served at a public URL. No authentication is needed to access them.
|
||||
* **Available in front components** — use asset URLs to display images, icons, or any media inside your React components.
|
||||
* **Available in logic functions** — reference asset URLs in emails, API responses, or any server-side logic.
|
||||
* **Used for marketplace metadata** — the `logoUrl` and `screenshots` fields in `defineApplication()` reference files from this folder (e.g., `public/logo.png`). These are displayed in the marketplace when your app is published.
|
||||
* **Auto-synced in dev mode** — when you add, update, or delete a file in `public/`, it is synced to the server automatically. No restart needed.
|
||||
* **Included in builds** — `yarn twenty build` bundles all public assets into the distribution output.
|
||||
* **Öffentlich zugänglich** — nach der Synchronisierung mit dem Server werden Assets unter einer öffentlichen URL bereitgestellt. Zum Zugriff ist keine Authentifizierung erforderlich.
|
||||
* **In Frontend-Komponenten verfügbar** — verwenden Sie Asset-URLs, um Bilder, Icons oder andere Medien in Ihren React-Komponenten anzuzeigen.
|
||||
* **In Logikfunktionen verfügbar** — referenzieren Sie Asset-URLs in E-Mails, API-Antworten oder in beliebiger serverseitiger Logik.
|
||||
* **Für Marketplace-Metadaten verwendet** — die Felder `logoUrl` und `screenshots` in `defineApplication()` referenzieren Dateien aus diesem Ordner (z. B. `public/logo.png`). Diese werden im Marketplace angezeigt, wenn Ihre App veröffentlicht wird.
|
||||
* **Im Dev-Modus automatisch synchronisiert** — wenn Sie in `public/` eine Datei hinzufügen, aktualisieren oder löschen, wird sie automatisch mit dem Server synchronisiert. Kein Neustart erforderlich.
|
||||
* **In Builds enthalten** — `yarn twenty build` bündelt alle öffentlichen Assets in der Distributionsausgabe.
|
||||
|
||||
### Accessing public assets with `getPublicAssetUrl`
|
||||
### Zugriff auf öffentliche Assets mit `getPublicAssetUrl`
|
||||
|
||||
Use the `getPublicAssetUrl` helper from `twenty-sdk` to get the full URL of a file in your `public/` directory. It works in both **logic functions** and **front components**.
|
||||
Verwenden Sie den Helper `getPublicAssetUrl` aus `twenty-sdk`, um die vollständige URL einer Datei in Ihrem `public/`-Verzeichnis zu erhalten. Dies funktioniert sowohl in Logikfunktionen als auch in Frontend-Komponenten.
|
||||
|
||||
**In a logic function:**
|
||||
**In einer Logikfunktion:**
|
||||
|
||||
```ts src/logic-functions/send-invoice.ts
|
||||
import { defineLogicFunction, getPublicAssetUrl } from 'twenty-sdk';
|
||||
@@ -1200,7 +1199,7 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
**In a front component:**
|
||||
**In einer Frontend-Komponente:**
|
||||
|
||||
```tsx src/front-components/company-card.tsx
|
||||
import { defineFrontComponent, getPublicAssetUrl } from 'twenty-sdk';
|
||||
@@ -1212,19 +1211,19 @@ export default defineFrontComponent(() => {
|
||||
});
|
||||
```
|
||||
|
||||
The `path` argument is relative to your app's `public/` folder. Both `getPublicAssetUrl('logo.png')` and `getPublicAssetUrl('public/logo.png')` resolve to the same URL — the `public/` prefix is stripped automatically if present.
|
||||
Das Argument `path` ist relativ zum `public/`-Ordner Ihrer App. Sowohl `getPublicAssetUrl('logo.png')` als auch `getPublicAssetUrl('public/logo.png')` ergeben dieselbe URL — das Präfix `public/` wird, falls vorhanden, automatisch entfernt.
|
||||
|
||||
## Using npm packages
|
||||
## Verwendung von npm-Paketen
|
||||
|
||||
You can install and use any npm package in your app. Both logic functions and front components are bundled with [esbuild](https://esbuild.github.io/), which inlines all dependencies into the output — no `node_modules` are needed at runtime.
|
||||
Sie können in Ihrer App beliebige npm-Pakete installieren und verwenden. Sowohl Logikfunktionen als auch Frontend-Komponenten werden mit [esbuild](https://esbuild.github.io/) gebündelt, das alle Abhängigkeiten in die Ausgabe einbettet — zur Laufzeit sind keine `node_modules` erforderlich.
|
||||
|
||||
### Installing a package
|
||||
### Ein Paket installieren
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn add axios
|
||||
```
|
||||
|
||||
Then import it in your code:
|
||||
Importieren Sie es anschließend in Ihrem Code:
|
||||
|
||||
```ts src/logic-functions/fetch-data.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
@@ -1245,7 +1244,7 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
The same works for front components:
|
||||
Dasselbe funktioniert für Frontend-Komponenten:
|
||||
|
||||
```tsx src/front-components/chart.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
@@ -1262,27 +1261,27 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
### How bundling works
|
||||
### Wie das Bundling funktioniert
|
||||
|
||||
The build step (`yarn twenty dev` or `yarn twenty build`) uses esbuild to produce a single self-contained file per logic function and per front component. All imported packages are inlined into the bundle.
|
||||
Der Build-Schritt (`yarn twenty dev` oder `yarn twenty build`) verwendet esbuild, um pro Logikfunktion und pro Frontend-Komponente eine einzelne, in sich geschlossene Datei zu erzeugen. Alle importierten Pakete werden in das Bundle eingebettet.
|
||||
|
||||
**Logic functions** run in a Node.js environment. Node built-in modules (`fs`, `path`, `crypto`, `http`, etc.) are available and do not need to be installed.
|
||||
**Logikfunktionen** laufen in einer Node.js-Umgebung. Eingebaute Node.js-Module (`fs`, `path`, `crypto`, `http` usw.) stehen zur Verfügung und müssen nicht installiert werden.
|
||||
|
||||
**Front components** run in a Web Worker. Node built-in modules are **not** available — only browser APIs and npm packages that work in a browser environment.
|
||||
**Frontend-Komponenten** laufen in einem Web Worker. Eingebaute Node.js-Module sind **nicht** verfügbar — nur Browser-APIs und npm-Pakete, die in einer Browserumgebung funktionieren.
|
||||
|
||||
Both environments have `twenty-client-sdk/core` and `twenty-client-sdk/metadata` available as pre-provided modules — these are not bundled but resolved at runtime by the server.
|
||||
In beiden Umgebungen stehen `twenty-client-sdk/core` und `twenty-client-sdk/metadata` als vorab bereitgestellte Module zur Verfügung — sie werden nicht gebündelt, sondern zur Laufzeit vom Server aufgelöst.
|
||||
|
||||
## Scaffolding entities with `yarn twenty add`
|
||||
## Entitäten mit `yarn twenty add` erstellen
|
||||
|
||||
Instead of creating entity files by hand, you can use the interactive scaffolder:
|
||||
Anstatt Entitätsdateien manuell zu erstellen, können Sie den interaktiven Scaffolder verwenden:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty add
|
||||
```
|
||||
|
||||
This prompts you to pick an entity type and walks you through the required fields. It generates a ready-to-use file with a stable `universalIdentifier` and the correct `defineEntity()` call.
|
||||
Dies fordert Sie auf, einen Entitätstyp auszuwählen, und führt Sie durch die erforderlichen Felder. Er erzeugt eine einsatzbereite Datei mit einem stabilen `universalIdentifier` und dem korrekten `defineEntity()`-Aufruf.
|
||||
|
||||
You can also pass the entity type directly to skip the first prompt:
|
||||
Sie können den Entitätstyp auch direkt übergeben, um die erste Eingabeaufforderung zu überspringen:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty add object
|
||||
@@ -1290,44 +1289,44 @@ yarn twenty add logicFunction
|
||||
yarn twenty add frontComponent
|
||||
```
|
||||
|
||||
### Available entity types
|
||||
### Verfügbare Entitätstypen
|
||||
|
||||
| Entitätstyp | Befehl | Generated file |
|
||||
| -------------------- | ------------------------------------ | ------------------------------------- |
|
||||
| Objekt | `yarn twenty add object` | `src/objects/<name>.ts` |
|
||||
| Feld | `yarn twenty add field` | `src/fields/<name>.ts` |
|
||||
| Logic function | `yarn twenty add logicFunction` | `src/logic-functions/<name>.ts` |
|
||||
| Front component | `yarn twenty add frontComponent` | `src/front-components/<name>.tsx` |
|
||||
| Rolle | `yarn twenty add role` | `src/roles/<name>.ts` |
|
||||
| Skill | `yarn twenty add skill` | `src/skills/<name>.ts` |
|
||||
| Agent | `yarn twenty add agent` | `src/agents/<name>.ts` |
|
||||
| Ansicht | `yarn twenty add view` | `src/views/<name>.ts` |
|
||||
| Navigation menu item | `yarn twenty add navigationMenuItem` | `src/navigation-menu-items/<name>.ts` |
|
||||
| Page layout | `yarn twenty add pageLayout` | `src/page-layouts/<name>.ts` |
|
||||
| Entitätstyp | Befehl | Generierte Datei |
|
||||
| ---------------------- | ------------------------------------ | ------------------------------------- |
|
||||
| Objekt | `yarn twenty add object` | `src/objects/<name>.ts` |
|
||||
| Feld | `yarn twenty add field` | `src/fields/<name>.ts` |
|
||||
| Logikfunktion | `yarn twenty add logicFunction` | `src/logic-functions/<name>.ts` |
|
||||
| Frontend-Komponente | `yarn twenty add frontComponent` | `src/front-components/<name>.tsx` |
|
||||
| Rolle | `yarn twenty add role` | `src/roles/<name>.ts` |
|
||||
| Skill | `yarn twenty add skill` | `src/skills/<name>.ts` |
|
||||
| Agent | `yarn twenty add agent` | `src/agents/<name>.ts` |
|
||||
| Ansicht | `yarn twenty add view` | `src/views/<name>.ts` |
|
||||
| Navigationsmenüeintrag | `yarn twenty add navigationMenuItem` | `src/navigation-menu-items/<name>.ts` |
|
||||
| Seitenlayout | `yarn twenty add pageLayout` | `src/page-layouts/<name>.ts` |
|
||||
|
||||
### What the scaffolder generates
|
||||
### Was der Scaffolder generiert
|
||||
|
||||
Each entity type has its own template. For example, `yarn twenty add object` asks for:
|
||||
Jeder Entitätstyp hat seine eigene Vorlage. Zum Beispiel fragt `yarn twenty add object` nach:
|
||||
|
||||
1. **Name (singular)** — e.g., `invoice`
|
||||
2. **Name (plural)** — e.g., `invoices`
|
||||
3. **Label (singular)** — auto-populated from the name (e.g., `Invoice`)
|
||||
4. **Label (plural)** — auto-populated (e.g., `Invoices`)
|
||||
5. **Create a view and navigation item?** — if you answer yes, the scaffolder also generates a matching view and sidebar link for the new object.
|
||||
1. **Name (Singular)** — z. B. `invoice`
|
||||
2. **Name (Plural)** — z. B. `invoices`
|
||||
3. **Label (Singular)** — automatisch aus dem Namen befüllt (z. B. `Invoice`)
|
||||
4. **Label (Plural)** — automatisch befüllt (z. B. `Invoices`)
|
||||
5. **Ansicht und Navigationseintrag erstellen?** — wenn Sie mit Ja antworten, erzeugt der Scaffolder außerdem eine passende Ansicht und einen Sidebar-Link für das neue Objekt.
|
||||
|
||||
Other entity types have simpler prompts — most only ask for a name.
|
||||
Andere Entitätstypen haben einfachere Eingabeaufforderungen — die meisten fragen nur nach einem Namen.
|
||||
|
||||
The `field` entity type is more detailed: it asks for the field name, label, type (from a list of all available field types like `TEXT`, `NUMBER`, `SELECT`, `RELATION`, etc.), and the target object's `universalIdentifier`.
|
||||
Der Entitätstyp `field` ist detaillierter: Er fragt nach Feldname, Label, Typ (aus einer Liste aller verfügbaren Feldtypen wie `TEXT`, `NUMBER`, `SELECT`, `RELATION` usw.) sowie dem `universalIdentifier` des Zielobjekts.
|
||||
|
||||
### Custom output path
|
||||
### Benutzerdefinierter Ausgabepfad
|
||||
|
||||
Use the `--path` flag to place the generated file in a custom location:
|
||||
Verwenden Sie den Schalter `--path`, um die generierte Datei an einem benutzerdefinierten Ort abzulegen:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty add logicFunction --path src/custom-folder
|
||||
```
|
||||
|
||||
## Typed API clients (twenty-client-sdk)
|
||||
## Typisierte API-Clients (twenty-client-sdk)
|
||||
|
||||
Das Paket `twenty-client-sdk` stellt zwei typisierte GraphQL-Clients bereit, um aus Ihren Logikfunktionen und Frontend-Komponenten mit der Twenty-API zu interagieren.
|
||||
|
||||
@@ -1337,9 +1336,9 @@ Das Paket `twenty-client-sdk` stellt zwei typisierte GraphQL-Clients bereit, um
|
||||
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — Arbeitsbereichskonfiguration, Datei-Uploads | Nein, wird vorgefertigt ausgeliefert |
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="CoreApiClient" description="Query and mutate workspace data (records, objects)">
|
||||
<Accordion title="CoreApiClient" description="Arbeitsbereichsdaten (Datensätze, Objekte) abfragen und ändern">
|
||||
|
||||
Der `CoreApiClient` ist der Haupt-Client zum Abfragen und Ändern von Arbeitsbereichsdaten. It is **generated from your workspace schema** during `yarn twenty dev` or `yarn twenty build`, so it is fully typed to match your objects and fields.
|
||||
Der `CoreApiClient` ist der Haupt-Client zum Abfragen und Ändern von Arbeitsbereichsdaten. Er wird während `yarn twenty dev` oder `yarn twenty build` **aus Ihrem Arbeitsbereichsschema generiert** und ist daher vollständig typisiert, passend zu Ihren Objekten und Feldern.
|
||||
|
||||
```ts
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
@@ -1379,12 +1378,12 @@ const { createCompany } = await client.mutation({
|
||||
Der Client verwendet eine Selection-Set-Syntax: Übergeben Sie `true`, um ein Feld einzuschließen, verwenden Sie `__args` für Argumente, und verschachteln Sie Objekte für Relationen. Sie erhalten vollständige Autovervollständigung und Typprüfung basierend auf Ihrem Arbeitsbereichsschema.
|
||||
|
||||
<Note>
|
||||
**CoreApiClient is generated at dev/build time.** If you use it without running `yarn twenty dev` or `yarn twenty build` first, it throws an error. The generation happens automatically — the CLI introspects your workspace's GraphQL schema and generates a typed client using `@genql/cli`.
|
||||
**Der CoreApiClient wird zur Entwicklungs-/Build-Zeit generiert.** Wenn Sie ihn verwenden, ohne zuvor `yarn twenty dev` oder `yarn twenty build` ausgeführt zu haben, wird ein Fehler ausgelöst. Die Generierung erfolgt automatisch — die CLI inspiziert das GraphQL-Schema Ihres Arbeitsbereichs und erzeugt mit `@genql/cli` einen typisierten Client.
|
||||
</Note>
|
||||
|
||||
#### Verwendung von CoreSchema für Typannotationen
|
||||
|
||||
`CoreSchema` provides TypeScript types matching your workspace objects — useful for typing component state or function parameters:
|
||||
`CoreSchema` stellt TypeScript-Typen bereit, die Ihren Arbeitsbereichsobjekten entsprechen — nützlich zum Typisieren von Komponentenzustand oder Funktionsparametern:
|
||||
|
||||
```ts
|
||||
import { CoreApiClient, CoreSchema } from 'twenty-client-sdk/core';
|
||||
@@ -1406,7 +1405,7 @@ setCompany(result.company);
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="MetadataApiClient" description="Workspace config, applications, and file uploads">
|
||||
<Accordion title="MetadataApiClient" description="Konfiguration des Arbeitsbereichs, Anwendungen und Dateiuploads">
|
||||
|
||||
`MetadataApiClient` ist im SDK bereits vorgefertigt enthalten (keine Generierung erforderlich). Er fragt den Endpunkt `/metadata` nach Arbeitsbereichskonfiguration, Anwendungen und Datei-Uploads ab.
|
||||
|
||||
@@ -1437,7 +1436,7 @@ const { objects } = await metadataClient.query({
|
||||
|
||||
#### Dateien hochladen
|
||||
|
||||
`MetadataApiClient` includes an `uploadFile` method for attaching files to file-type fields:
|
||||
Der `MetadataApiClient` enthält eine Methode `uploadFile`, um Dateien an Felder des Typs Datei anzuhängen:
|
||||
|
||||
```ts
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
@@ -1458,12 +1457,12 @@ console.log(uploadedFile);
|
||||
// { id: '...', path: '...', size: 12345, createdAt: '...', url: 'https://...' }
|
||||
```
|
||||
|
||||
| Parameter | Typ | Beschreibung |
|
||||
| ---------------------------------- | -------- | --------------------------------------------------------------- |
|
||||
| `fileBuffer` | `Buffer` | Der Rohinhalt der Datei |
|
||||
| `filename` | `string` | Der Name der Datei (wird für Speicherung und Anzeige verwendet) |
|
||||
| `contentType` | `string` | MIME type (defaults to `application/octet-stream` if omitted) |
|
||||
| `fieldMetadataUniversalIdentifier` | `string` | Der `universalIdentifier` des Dateityp-Felds in Ihrem Objekt |
|
||||
| Parameter | Typ | Beschreibung |
|
||||
| ---------------------------------- | -------- | --------------------------------------------------------------------- |
|
||||
| `fileBuffer` | `Buffer` | Der Rohinhalt der Datei |
|
||||
| `filename` | `string` | Der Name der Datei (wird für Speicherung und Anzeige verwendet) |
|
||||
| `contentType` | `string` | MIME-Typ (standardmäßig `application/octet-stream`, wenn weggelassen) |
|
||||
| `fieldMetadataUniversalIdentifier` | `string` | Der `universalIdentifier` des Dateityp-Felds in Ihrem Objekt |
|
||||
|
||||
Hauptpunkte:
|
||||
* Sie verwendet den `universalIdentifier` des Feldes (nicht dessen arbeitsbereichsspezifische ID), sodass Ihr Upload-Code in jedem Arbeitsbereich funktioniert, in dem Ihre App installiert ist.
|
||||
@@ -1476,24 +1475,24 @@ Hauptpunkte:
|
||||
Wenn Ihr Code auf Twenty ausgeführt wird (Logikfunktionen oder Frontend-Komponenten), injiziert die Plattform Anmeldedaten als Umgebungsvariablen:
|
||||
|
||||
* `TWENTY_API_URL` — Basis-URL der Twenty-API
|
||||
* `TWENTY_APP_ACCESS_TOKEN` — Short-lived key scoped to your application's default function role
|
||||
* `TWENTY_APP_ACCESS_TOKEN` — Kurzlebiger Schlüssel, der auf die Standard-Funktionsrolle Ihrer Anwendung begrenzt ist
|
||||
|
||||
Sie müssen diese **nicht** an die Clients übergeben — sie lesen automatisch aus `process.env`. Die Berechtigungen des API-Schlüssels werden durch die Rolle bestimmt, auf die in `defaultRoleUniversalIdentifier` in Ihrer `application-config.ts` verwiesen wird.
|
||||
</Note>
|
||||
|
||||
## Testing your app
|
||||
## Ihre App testen
|
||||
|
||||
The SDK provides programmatic APIs that let you build, deploy, install, and uninstall your app from test code. Combined with [Vitest](https://vitest.dev/) and the typed API clients, you can write integration tests that verify your app works end-to-end against a real Twenty server.
|
||||
Das SDK stellt programmgesteuerte APIs bereit, mit denen Sie Ihre App aus Testcode heraus bauen, bereitstellen, installieren und deinstallieren können. In Kombination mit [Vitest](https://vitest.dev/) und den typisierten API-Clients können Sie Integrationstests schreiben, die prüfen, dass Ihre App End-to-End gegen einen echten Twenty-Server funktioniert.
|
||||
|
||||
### Einrichtung
|
||||
|
||||
The scaffolded app already includes Vitest. If you set it up manually, install the dependencies:
|
||||
Die erzeugte App enthält bereits Vitest. Wenn Sie es manuell einrichten, installieren Sie die Abhängigkeiten:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn add -D vitest vite-tsconfig-paths
|
||||
```
|
||||
|
||||
Create a `vitest.config.ts` at the root of your app:
|
||||
Erstellen Sie eine `vitest.config.ts` im Stammverzeichnis Ihrer App:
|
||||
|
||||
```ts vitest.config.ts
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
@@ -1519,7 +1518,7 @@ export default defineConfig({
|
||||
});
|
||||
```
|
||||
|
||||
Create a setup file that verifies the server is reachable before tests run:
|
||||
Erstellen Sie eine Setup-Datei, die vor dem Testlauf überprüft, dass der Server erreichbar ist:
|
||||
|
||||
```ts src/__tests__/setup-test.ts
|
||||
import * as fs from 'fs';
|
||||
@@ -1559,22 +1558,22 @@ beforeAll(async () => {
|
||||
});
|
||||
```
|
||||
|
||||
### Programmatic SDK APIs
|
||||
### Programmgesteuerte SDK-APIs
|
||||
|
||||
The `twenty-sdk/cli` subpath exports functions you can call directly from test code:
|
||||
Der Subpfad `twenty-sdk/cli` exportiert Funktionen, die Sie direkt aus Testcode aufrufen können:
|
||||
|
||||
| Funktion | Beschreibung |
|
||||
| -------------- | ------------------------------------------- |
|
||||
| `appBuild` | Build the app and optionally pack a tarball |
|
||||
| `appDeploy` | Upload a tarball to the server |
|
||||
| `appInstall` | Install the app on the active workspace |
|
||||
| `appUninstall` | Uninstall the app from the active workspace |
|
||||
| Funktion | Beschreibung |
|
||||
| -------------- | ----------------------------------------------------- |
|
||||
| `appBuild` | Die App bauen und optional ein Tarball packen |
|
||||
| `appDeploy` | Ein Tarball auf den Server hochladen |
|
||||
| `appInstall` | Die App im aktiven Arbeitsbereich installieren |
|
||||
| `appUninstall` | Die App aus dem aktiven Arbeitsbereich deinstallieren |
|
||||
|
||||
Each function returns a result object with `success: boolean` and either `data` or `error`.
|
||||
Jede Funktion gibt ein Ergebnisobjekt mit `success: boolean` und entweder `data` oder `error` zurück.
|
||||
|
||||
### Writing an integration test
|
||||
### Einen Integrationstest schreiben
|
||||
|
||||
Here is a full example that builds, deploys, and installs the app, then verifies it appears in the workspace:
|
||||
Hier ist ein vollständiges Beispiel, das die App baut, bereitstellt und installiert und anschließend prüft, dass sie im Arbeitsbereich erscheint:
|
||||
|
||||
```ts src/__tests__/app-install.integration-test.ts
|
||||
import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/application-config';
|
||||
@@ -1637,37 +1636,37 @@ describe('App installation', () => {
|
||||
});
|
||||
```
|
||||
|
||||
### Running tests
|
||||
### Tests ausführen
|
||||
|
||||
Make sure your local Twenty server is running, then:
|
||||
Stellen Sie sicher, dass Ihr lokaler Twenty-Server läuft, und führen Sie dann Folgendes aus:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn test
|
||||
```
|
||||
|
||||
Or in watch mode during development:
|
||||
Oder im Watch-Modus während der Entwicklung:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn test:watch
|
||||
```
|
||||
|
||||
### Type checking
|
||||
### Typprüfung
|
||||
|
||||
You can also run type checking on your app without running tests:
|
||||
Sie können die Typprüfung Ihrer App auch ohne Tests ausführen:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty typecheck
|
||||
```
|
||||
|
||||
This runs `tsc --noEmit` and reports any type errors.
|
||||
Dies führt `tsc --noEmit` aus und meldet etwaige Typfehler.
|
||||
|
||||
## CLI-Referenz
|
||||
|
||||
Beyond `dev`, `build`, `add`, and `typecheck`, the CLI provides commands for executing functions, viewing logs, and managing app installations.
|
||||
Zusätzlich zu `dev`, `build`, `add` und `typecheck` bietet die CLI Befehle zum Ausführen von Funktionen, Anzeigen von Logs und Verwalten von App-Installationen.
|
||||
|
||||
### Executing functions (`yarn twenty exec`)
|
||||
### Funktionen ausführen (`yarn twenty exec`)
|
||||
|
||||
Run a logic function manually without triggering it via HTTP, cron, or database event:
|
||||
Eine Logikfunktion manuell ausführen, ohne sie über HTTP, Cron oder ein Datenbankereignis auszulösen:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Execute by function name
|
||||
@@ -1684,9 +1683,9 @@ yarn twenty exec --preInstall
|
||||
yarn twenty exec --postInstall
|
||||
```
|
||||
|
||||
### Viewing function logs (`yarn twenty logs`)
|
||||
### Funktionsprotokolle ansehen (`yarn twenty logs`)
|
||||
|
||||
Stream execution logs for your app's logic functions:
|
||||
Ausführungsprotokolle für die Logikfunktionen Ihrer App streamen:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Stream all function logs
|
||||
@@ -1700,12 +1699,12 @@ yarn twenty logs -u e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf
|
||||
```
|
||||
|
||||
<Note>
|
||||
This is different from `yarn twenty server logs`, which shows the Docker container logs. `yarn twenty logs` shows your app's function execution logs from the Twenty server.
|
||||
Dies unterscheidet sich von `yarn twenty server logs`, das die Docker-Container-Logs anzeigt. `yarn twenty logs` zeigt die Funktionsausführungsprotokolle Ihrer App vom Twenty-Server.
|
||||
</Note>
|
||||
|
||||
### Uninstalling an app (`yarn twenty uninstall`)
|
||||
### Eine App deinstallieren (`yarn twenty uninstall`)
|
||||
|
||||
Remove your app from the active workspace:
|
||||
Entfernen Sie Ihre App aus dem aktiven Arbeitsbereich:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty uninstall
|
||||
|
||||
@@ -4,24 +4,24 @@ description: Definisci oggetti, funzioni logiche, componenti front-end e molto a
|
||||
---
|
||||
|
||||
<Warning>
|
||||
Apps are currently in alpha. The feature works but is still evolving.
|
||||
Le app sono attualmente in fase alfa. La funzionalità funziona ma è ancora in evoluzione.
|
||||
</Warning>
|
||||
|
||||
The `twenty-sdk` package provides typed building blocks to create your app. This page covers every entity type and API client available in the SDK.
|
||||
Il pacchetto `twenty-sdk` fornisce blocchi costruttivi tipizzati per creare la tua app. Questa pagina copre tutti i tipi di entità e i client API disponibili nell'SDK.
|
||||
|
||||
## DefineEntity functions
|
||||
## Funzioni DefineEntity
|
||||
|
||||
The SDK provides functions to define your app entities. You must use `export default defineEntity({...})` for the SDK to detect your entities. Queste funzioni convalidano la configurazione in fase di build e offrono il completamento automatico nell'IDE e la sicurezza dei tipi.
|
||||
L'SDK fornisce funzioni per definire le entità della tua app. Devi usare `export default defineEntity({...})` affinché l'SDK rilevi le tue entità. Queste funzioni convalidano la configurazione in fase di build e offrono il completamento automatico nell'IDE e la sicurezza dei tipi.
|
||||
|
||||
<Note>
|
||||
**File organization is up to you.**
|
||||
Entity detection is AST-based — the SDK finds `export default defineEntity(...)` calls regardless of where the file lives. Grouping files by type (e.g., `logic-functions/`, `roles/`) is just a convention, not a requirement.
|
||||
**L'organizzazione dei file dipende da te.**
|
||||
Il rilevamento delle entità è basato sull'AST — l'SDK trova le chiamate a `export default defineEntity(...)` indipendentemente da dove si trova il file. Raggruppare i file per tipo (ad es., `logic-functions/`, `roles/`) è solo una convenzione, non un requisito.
|
||||
</Note>
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineRole" description="Configura i permessi dei ruoli e l'accesso agli oggetti">
|
||||
|
||||
Roles encapsulate permissions on your workspace's objects and actions.
|
||||
I ruoli incapsulano i permessi sugli oggetti e sulle azioni del tuo spazio di lavoro.
|
||||
|
||||
```ts restricted-company-role.ts
|
||||
import {
|
||||
@@ -69,12 +69,12 @@ export default defineRole({
|
||||
</Accordion>
|
||||
<Accordion title="defineApplication" description="Configura i metadati dell'applicazione (obbligatorio, uno per app)">
|
||||
|
||||
Every app must have exactly one `defineApplication` call that describes:
|
||||
Ogni app deve avere esattamente una chiamata a `defineApplication` che descrive:
|
||||
|
||||
* **Identity**: identifiers, display name, and description.
|
||||
* **Permissions**: which role its functions and front components use.
|
||||
* **(Optional) Variables**: key–value pairs exposed to your functions as environment variables.
|
||||
* **(Optional) Pre-install / post-install functions**: logic functions that run before or after installation.
|
||||
* **Identità**: identificatori, nome visualizzato e descrizione.
|
||||
* **Autorizzazioni**: quale ruolo usano le sue funzioni e i componenti front-end.
|
||||
* **Variabili (opzionali)**: coppie chiave–valore esposte alle funzioni come variabili d'ambiente.
|
||||
* **(Opzionali) Funzioni di pre-installazione/post-installazione**: funzioni logiche che vengono eseguite prima o dopo l'installazione.
|
||||
|
||||
```ts src/application-config.ts
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
@@ -98,21 +98,21 @@ export default defineApplication({
|
||||
```
|
||||
|
||||
Note:
|
||||
* `universalIdentifier` fields are deterministic IDs you own. Generate them once and keep them stable across syncs.
|
||||
* `applicationVariables` become environment variables for your functions and front components (e.g., `DEFAULT_RECIPIENT_NAME` is available as `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
* `defaultRoleUniversalIdentifier` must reference a role defined with `defineRole()` (see above).
|
||||
* Pre-install and post-install functions are detected automatically during the manifest build — you do not need to reference them in `defineApplication()`.
|
||||
* I campi `universalIdentifier` sono ID deterministici che possiedi. Generali una volta e mantienili stabili tra una sincronizzazione e l'altra.
|
||||
* `applicationVariables` diventano variabili d'ambiente per le tue funzioni e i componenti front-end (ad esempio, `DEFAULT_RECIPIENT_NAME` è disponibile come `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
* `defaultRoleUniversalIdentifier` deve fare riferimento a un ruolo definito con `defineRole()` (vedi sopra).
|
||||
* Le funzioni di pre-installazione e post-installazione vengono rilevate automaticamente durante il build del manifesto — non è necessario farvi riferimento in `defineApplication()`.
|
||||
|
||||
#### Metadati del marketplace
|
||||
|
||||
If you plan to [publish your app](/l/it/developers/extend/apps/publishing), these optional fields control how it appears in the marketplace:
|
||||
Se prevedi di [pubblicare la tua app](/l/it/developers/extend/apps/publishing), questi campi opzionali controllano come appare nel marketplace:
|
||||
|
||||
| Campo | Descrizione |
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `autore` | Nome dell'autore o dell'azienda |
|
||||
| `categoria` | Categoria dell'app per il filtraggio nel marketplace |
|
||||
| `logoUrl` | Path to your app logo (e.g., `public/logo.png`) |
|
||||
| `screenshots` | Array of screenshot paths (e.g., `public/screenshot-1.png`) |
|
||||
| `logoUrl` | Percorso al logo della tua app (ad es., `public/logo.png`) |
|
||||
| `screenshots` | Array di percorsi degli screenshot (ad es., `public/screenshot-1.png`) |
|
||||
| `aboutDescription` | Descrizione markdown più lunga per la scheda "Informazioni". Se omesso, il marketplace utilizza il `README.md` del pacchetto da npm |
|
||||
| `websiteUrl` | Link al tuo sito web |
|
||||
| `termsUrl` | Link ai Termini di servizio |
|
||||
@@ -121,15 +121,15 @@ If you plan to [publish your app](/l/it/developers/extend/apps/publishing), thes
|
||||
|
||||
#### Ruoli e permessi
|
||||
|
||||
The `defaultRoleUniversalIdentifier` in `application-config.ts` designates the default role used by your app's logic functions and front components. See `defineRole` above for details.
|
||||
Il `defaultRoleUniversalIdentifier` in `application-config.ts` indica il ruolo predefinito utilizzato dalle funzioni logiche e dai componenti front-end della tua app. Vedi `defineRole` sopra per i dettagli.
|
||||
|
||||
* The runtime token injected as `TWENTY_APP_ACCESS_TOKEN` is derived from this role.
|
||||
* The typed client is restricted to the permissions granted to that role.
|
||||
* Follow least-privilege: create a dedicated role with only the permissions your functions need.
|
||||
* Il token di runtime iniettato come `TWENTY_APP_ACCESS_TOKEN` è derivato da questo ruolo.
|
||||
* Il client tipizzato è limitato ai permessi concessi a quel ruolo.
|
||||
* Segui il principio del privilegio minimo: crea un ruolo dedicato con solo i permessi necessari alle tue funzioni.
|
||||
|
||||
##### Default function role
|
||||
##### Ruolo funzione predefinito
|
||||
|
||||
When you scaffold a new app, the CLI creates a default role file:
|
||||
Quando esegui lo scaffolding di una nuova app, la CLI crea un file di ruolo predefinito:
|
||||
|
||||
```ts src/roles/default-role.ts
|
||||
import { defineRole, PermissionFlag } from 'twenty-sdk';
|
||||
@@ -155,16 +155,16 @@ export default defineRole({
|
||||
});
|
||||
```
|
||||
|
||||
This role's `universalIdentifier` is referenced in `application-config.ts` as `defaultRoleUniversalIdentifier`:
|
||||
L'`universalIdentifier` di questo ruolo viene referenziato in `application-config.ts` come `defaultRoleUniversalIdentifier`:
|
||||
|
||||
* **\*.role.ts** defines what the role can do.
|
||||
* **\*.role.ts** definisce ciò che il ruolo può fare.
|
||||
* **application-config.ts** punta a quel ruolo in modo che le tue funzioni ne ereditino i permessi.
|
||||
|
||||
Note:
|
||||
* Parti dal ruolo generato dallo scaffolder, quindi restringilo progressivamente seguendo il principio del privilegio minimo.
|
||||
* Replace `objectPermissions` and `fieldPermissions` with the objects and fields your functions actually need.
|
||||
* `permissionFlags` controllano l'accesso alle funzionalità a livello di piattaforma. Keep them minimal.
|
||||
* See a working example: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
|
||||
* Sostituisci `objectPermissions` e `fieldPermissions` con gli oggetti e i campi di cui le tue funzioni hanno realmente bisogno.
|
||||
* `permissionFlags` controllano l'accesso alle funzionalità a livello di piattaforma. Mantienili al minimo.
|
||||
* Vedi un esempio funzionante: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineObject" description="Definisci oggetti personalizzati con campi">
|
||||
@@ -256,7 +256,7 @@ ma non è consigliato.
|
||||
</Note>
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineField — Standard fields" description="Estendi gli oggetti esistenti con campi aggiuntivi">
|
||||
<Accordion title="defineField — Campi standard" description="Estendi gli oggetti esistenti con campi aggiuntivi">
|
||||
|
||||
Usa `defineField()` per aggiungere campi a oggetti che non possiedi — come gli oggetti standard di Twenty (Person, Company, ecc.) o oggetti di altre app. A differenza dei campi inline in `defineObject()`, i campi autonomi richiedono un `objectUniversalIdentifier` per specificare quale oggetto estendono:
|
||||
|
||||
@@ -284,7 +284,7 @@ Punti chiave:
|
||||
* `defineField()` è l'unico modo per aggiungere campi a oggetti che non hai creato con `defineObject()`.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineField — Relation fields" description="Connect objects together with bidirectional relations">
|
||||
<Accordion title="defineField — Campi di relazione" description="Collega gli oggetti tra loro con relazioni bidirezionali">
|
||||
|
||||
Le relazioni collegano gli oggetti tra loro. In Twenty, le relazioni sono sempre **bidirezionali** — definisci entrambi i lati e ciascun lato fa riferimento all'altro.
|
||||
|
||||
@@ -443,7 +443,7 @@ export default defineObject({
|
||||
});
|
||||
```
|
||||
</Accordion>
|
||||
<Accordion title="defineLogicFunction" description="Define logic functions and their triggers">
|
||||
<Accordion title="defineLogicFunction" description="Definisci funzioni logiche e i relativi trigger">
|
||||
|
||||
Ogni file di funzione usa `defineLogicFunction()` per esportare una configurazione con un handler e trigger opzionali.
|
||||
|
||||
@@ -487,15 +487,15 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
Available trigger types:
|
||||
* **httpRoute**: Exposes your function on an HTTP path and method **under the `/s/` endpoint**:
|
||||
> e.g. `path: '/post-card/create'` is callable at `https://your-twenty-server.com/s/post-card/create`
|
||||
Tipi di trigger disponibili:
|
||||
* **httpRoute**: Espone la tua funzione su un percorso e metodo HTTP **sotto l'endpoint `/s/`**:
|
||||
> ad es. `path: '/post-card/create'` è invocabile su `https://your-twenty-server.com/s/post-card/create`
|
||||
* **cron**: Esegue la tua funzione secondo una pianificazione utilizzando un'espressione CRON.
|
||||
* **databaseEvent**: Viene eseguito sugli eventi del ciclo di vita degli oggetti dello spazio di lavoro. Quando l'operazione dell'evento è `updated`, è possibile specificare campi specifici da monitorare nell'array `updatedFields`. Se lasciato non definito o vuoto, qualsiasi aggiornamento attiverà la funzione.
|
||||
> e.g. `person.updated`, `*.created`, `company.*`
|
||||
> ad es. `person.updated`, `*.created`, `company.*`
|
||||
|
||||
<Note>
|
||||
You can also manually execute a function using the CLI:
|
||||
Puoi anche eseguire manualmente una funzione utilizzando la CLI:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty exec -n create-new-post-card -p '{"key": "value"}'
|
||||
@@ -505,7 +505,7 @@ yarn twenty exec -n create-new-post-card -p '{"key": "value"}'
|
||||
yarn twenty exec -y e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf
|
||||
```
|
||||
|
||||
You can watch logs with:
|
||||
Puoi osservare i log con:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty logs
|
||||
@@ -514,9 +514,8 @@ yarn twenty logs
|
||||
|
||||
#### Payload del trigger di route
|
||||
|
||||
When a route trigger invokes your logic function, it receives a `RoutePayload` object that follows the
|
||||
[AWS HTTP API v2 format](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html).
|
||||
Import the `RoutePayload` type from `twenty-sdk`:
|
||||
Quando un trigger di tipo route invoca la tua funzione logica, questa riceve un oggetto `RoutePayload` che segue il [formato AWS HTTP API v2](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html).
|
||||
Importa il tipo `RoutePayload` da `twenty-sdk`:
|
||||
|
||||
```ts
|
||||
import { defineLogicFunction, type RoutePayload } from 'twenty-sdk';
|
||||
@@ -533,9 +532,9 @@ Il tipo `RoutePayload` ha la seguente struttura:
|
||||
|
||||
| Proprietà | Tipo | Descrizione | Esempio |
|
||||
| ---------------------------- | ------------------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record<string, string \| undefined>` | Intestazioni HTTP (solo quelle elencate in `forwardedRequestHeaders`) | see section below |
|
||||
| `headers` | `Record<string, string \| undefined>` | Intestazioni HTTP (solo quelle elencate in `forwardedRequestHeaders`) | vedi la sezione sotto |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Parametri della query string (valori multipli uniti da virgole) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Path parameters extracted from the route pattern | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Parametri di percorso estratti dal pattern della route | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Corpo della richiesta analizzato (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `isBase64Encoded` | `boolean` | Indica se il corpo è codificato in base64 | |
|
||||
| `requestContext.http.method` | `string` | Metodo HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
@@ -545,7 +544,7 @@ Il tipo `RoutePayload` ha la seguente struttura:
|
||||
#### forwardedRequestHeaders
|
||||
|
||||
Per impostazione predefinita, le intestazioni HTTP delle richieste in ingresso **non** vengono passate alla tua funzione logica per motivi di sicurezza.
|
||||
To access specific headers, list them in the `forwardedRequestHeaders` array:
|
||||
Per accedere a intestazioni specifiche, elencale nell'array `forwardedRequestHeaders`:
|
||||
|
||||
```ts
|
||||
export default defineLogicFunction({
|
||||
@@ -561,7 +560,7 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
In your handler, access the forwarded headers like this:
|
||||
Nel tuo handler, accedi alle intestazioni inoltrate in questo modo:
|
||||
|
||||
```ts
|
||||
const handler = async (event: RoutePayload) => {
|
||||
@@ -574,14 +573,14 @@ const handler = async (event: RoutePayload) => {
|
||||
```
|
||||
|
||||
<Note>
|
||||
I nomi delle intestazioni vengono normalizzati in minuscolo. Access them using lowercase keys (e.g., `event.headers['content-type']`).
|
||||
I nomi delle intestazioni vengono normalizzati in minuscolo. Accedile usando chiavi in minuscolo (ad es., `event.headers['content-type']`).
|
||||
</Note>
|
||||
|
||||
#### Exposing a function as a tool
|
||||
#### Esporre una funzione come strumento
|
||||
|
||||
Le funzioni logiche possono essere esposte come **strumenti** per gli agenti di IA e i flussi di lavoro. When marked as a tool, a function becomes discoverable by Twenty's AI features and can be used in workflow automations.
|
||||
Le funzioni logiche possono essere esposte come **strumenti** per gli agenti di IA e i flussi di lavoro. Quando una funzione è contrassegnata come strumento, diventa individuabile dalle funzionalità di IA di Twenty e può essere utilizzata nelle automazioni dei flussi di lavoro.
|
||||
|
||||
To mark a logic function as a tool, set `isTool: true`:
|
||||
Per contrassegnare una funzione logica come strumento, imposta `isTool: true`:
|
||||
|
||||
```ts src/logic-functions/enrich-company.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
@@ -617,8 +616,8 @@ export default defineLogicFunction({
|
||||
|
||||
Punti chiave:
|
||||
|
||||
* You can combine `isTool` with triggers — a function can be both a tool (callable by AI agents) and triggered by events at the same time.
|
||||
* **`toolInputSchema`** (optional): A JSON Schema object describing the parameters your function accepts. The schema is computed automatically from source code static analysis, but you can set it explicitly:
|
||||
* Puoi combinare `isTool` con i trigger — una funzione può essere sia uno strumento (invocabile dagli agenti IA) sia attivata da eventi allo stesso tempo.
|
||||
* **`toolInputSchema`** (opzionale): un oggetto JSON Schema che descrive i parametri accettati dalla funzione. Lo schema viene calcolato automaticamente dall'analisi statica del codice sorgente, ma puoi impostarlo esplicitamente:
|
||||
|
||||
```ts
|
||||
export default defineLogicFunction({
|
||||
@@ -715,11 +714,11 @@ Punti chiave:
|
||||
</Accordion>
|
||||
<Accordion title="defineFrontComponent" description="Definisci componenti front-end per un'interfaccia utente personalizzata">
|
||||
|
||||
Front components are React components that render directly inside Twenty's UI. They run in an **isolated Web Worker** using Remote DOM — your code is sandboxed but renders natively in the page, not in an iframe.
|
||||
I componenti front-end sono componenti React che vengono renderizzati direttamente all'interno della UI di Twenty. Vengono eseguiti in un **Web Worker** isolato utilizzando Remote DOM — il tuo codice è in sandbox ma viene renderizzato in modo nativo nella pagina, non in un iframe.
|
||||
|
||||
#### Basic example
|
||||
#### Esempio di base
|
||||
|
||||
The quickest way to see a front component in action is to register it as a **command**. Adding a `command` field with `isPinned: true` makes it appear as a quick-action button in the top-right corner of the page — no page layout needed:
|
||||
Il modo più rapido per vedere in azione un componente front-end è registrarlo come **comando**. Aggiungere un campo `command` con `isPinned: true` lo fa apparire come pulsante di azione rapida nell'angolo in alto a destra della pagina — nessun layout di pagina necessario:
|
||||
|
||||
```tsx src/front-components/hello-world.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
@@ -749,34 +748,34 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
After syncing with `yarn twenty dev`, the quick action appears in the top-right corner of the page:
|
||||
Dopo la sincronizzazione con `yarn twenty dev`, l'azione rapida appare nell'angolo in alto a destra della pagina:
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img src="/images/docs/developers/extends/apps/quick-action.png" alt="Quick action button in the top-right corner" />
|
||||
<img src="/images/docs/developers/extends/apps/quick-action.png" alt="Pulsante di azione rapida nell'angolo in alto a destra" />
|
||||
</div>
|
||||
|
||||
Click it to render the component inline.
|
||||
Fai clic per renderizzare il componente in linea.
|
||||
|
||||
{/* TODO: add screenshot of the rendered front component */}
|
||||
|
||||
#### Configuration fields
|
||||
#### Campi di configurazione
|
||||
|
||||
| Campo | Obbligatorio | Descrizione |
|
||||
| --------------------- | ------------ | ----------------------------------------------------------------------------------- |
|
||||
| `universalIdentifier` | Sì | Stable unique ID for this component |
|
||||
| `component` | Sì | A React component function |
|
||||
| `name` | No | Display name |
|
||||
| `descrizione` | No | Description of what the component does |
|
||||
| `isHeadless` | No | Set to `true` if the component has no visible UI (see below) |
|
||||
| `comando` | No | Register the component as a command (see [command options](#command-options) below) |
|
||||
| Campo | Obbligatorio | Descrizione |
|
||||
| --------------------- | ------------ | ---------------------------------------------------------------------------------------- |
|
||||
| `universalIdentifier` | Sì | ID univoco stabile per questo componente |
|
||||
| `component` | Sì | Una funzione di componente React |
|
||||
| `name` | No | Nome visualizzato |
|
||||
| `descrizione` | No | Descrizione di ciò che fa il componente |
|
||||
| `isHeadless` | No | Imposta su `true` se il componente non ha una UI visibile (vedi sotto) |
|
||||
| `comando` | No | Registra il componente come comando (vedi [opzioni del comando](#command-options) sotto) |
|
||||
|
||||
#### Placing a front component on a page
|
||||
#### Posizionare un componente front-end su una pagina
|
||||
|
||||
Beyond commands, you can embed a front component directly into a record page by adding it as a widget in a **page layout**. See the [definePageLayout](#definepagelayout) section for details.
|
||||
Oltre ai comandi, puoi incorporare un componente front-end direttamente in una pagina di record aggiungendolo come widget in un **layout di pagina**. Vedi la sezione [definePageLayout](#definepagelayout) per i dettagli.
|
||||
|
||||
#### Headless components (`isHeadless: true`)
|
||||
#### Componenti headless (`isHeadless: true`)
|
||||
|
||||
Headless components render no visible UI but still run React logic. This is useful for **effect components** — components that perform side effects when mounted, such as syncing data, starting a timer, listening to events, or triggering a notification.
|
||||
I componenti headless non renderizzano alcuna UI visibile ma eseguono comunque la logica React. Questo è utile per i componenti di effetto — componenti che eseguono effetti collaterali quando vengono montati, come sincronizzare dati, avviare un timer, ascoltare eventi o attivare una notifica.
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent, useRecordId, enqueueSnackbar } from 'twenty-sdk';
|
||||
@@ -801,11 +800,11 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
Because the component returns `null`, Twenty skips rendering a container for it — no empty space appears in the layout. The component still has access to all hooks and the host communication API.
|
||||
Poiché il componente restituisce `null`, Twenty evita di renderizzare un contenitore per esso — non appare alcuno spazio vuoto nel layout. Il componente ha comunque accesso a tutti gli hook e all'API di comunicazione con l'host.
|
||||
|
||||
#### Accessing runtime context
|
||||
#### Accesso al contesto di runtime
|
||||
|
||||
Inside your component, use SDK hooks to access the current user, record, and component instance:
|
||||
All'interno del tuo componente, usa gli hook dell'SDK per accedere all'utente corrente, al record e all'istanza del componente:
|
||||
|
||||
```tsx src/front-components/record-info.tsx
|
||||
import {
|
||||
@@ -836,47 +835,47 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
Available hooks:
|
||||
Hook disponibili:
|
||||
|
||||
| Hook | Returns | Descrizione |
|
||||
| --------------------------------------------- | ------------------ | ---------------------------------------------------------- |
|
||||
| `useUserId()` | `string` or `null` | The current user's ID |
|
||||
| `useRecordId()` | `string` or `null` | The current record's ID (when placed on a record page) |
|
||||
| `useFrontComponentId()` | `string` | This component instance's ID |
|
||||
| `useFrontComponentExecutionContext(selector)` | varia | Access the full execution context with a selector function |
|
||||
| Hook | Restituisce | Descrizione |
|
||||
| --------------------------------------------- | ----------------- | --------------------------------------------------------------------- |
|
||||
| `useUserId()` | `string` o `null` | L'ID dell'utente corrente |
|
||||
| `useRecordId()` | `string` o `null` | L'ID del record corrente (quando posizionato su una pagina di record) |
|
||||
| `useFrontComponentId()` | `string` | L'ID di questa istanza di componente |
|
||||
| `useFrontComponentExecutionContext(selector)` | varia | Accedi all'intero contesto di esecuzione con una funzione selettore |
|
||||
|
||||
#### Host communication API
|
||||
#### API di comunicazione con l'host
|
||||
|
||||
Front components can trigger navigation, modals, and notifications using functions from `twenty-sdk`:
|
||||
I componenti front-end possono attivare navigazione, modali e notifiche utilizzando funzioni da `twenty-sdk`:
|
||||
|
||||
| Funzione | Descrizione |
|
||||
| ----------------------------------------------- | ----------------------------- |
|
||||
| `navigate(to, params?, queryParams?, options?)` | Navigate to a page in the app |
|
||||
| `openSidePanelPage(params)` | Open a side panel |
|
||||
| `closeSidePanel()` | Chiudi il pannello laterale |
|
||||
| `openCommandConfirmationModal(params)` | Show a confirmation dialog |
|
||||
| `enqueueSnackbar(params)` | Show a toast notification |
|
||||
| `unmountFrontComponent()` | Unmount the component |
|
||||
| `updateProgress(progress)` | Update a progress indicator |
|
||||
| Funzione | Descrizione |
|
||||
| ----------------------------------------------- | ------------------------------------- |
|
||||
| `navigate(to, params?, queryParams?, options?)` | Naviga a una pagina dell'app |
|
||||
| `openSidePanelPage(params)` | Apri un pannello laterale |
|
||||
| `closeSidePanel()` | Chiudi il pannello laterale |
|
||||
| `openCommandConfirmationModal(params)` | Mostra una finestra di conferma |
|
||||
| `enqueueSnackbar(params)` | Mostra una notifica toast |
|
||||
| `unmountFrontComponent()` | Smonta il componente |
|
||||
| `updateProgress(progress)` | Aggiorna un indicatore di avanzamento |
|
||||
|
||||
#### Command options
|
||||
#### Opzioni del comando
|
||||
|
||||
Adding a `command` field to `defineFrontComponent` registers the component in the command menu (Cmd+K). If `isPinned` is `true`, it also appears as a quick-action button in the top-right corner of the page.
|
||||
Aggiungere un campo `command` a `defineFrontComponent` registra il componente nel menu comandi (Cmd+K). Se `isPinned` è `true`, compare anche come pulsante di azione rapida nell'angolo in alto a destra della pagina.
|
||||
|
||||
| Campo | Obbligatorio | Descrizione |
|
||||
| --------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `universalIdentifier` | Sì | Stable unique ID for the command |
|
||||
| `etichetta` | Sì | Full label shown in the command menu (Cmd+K) |
|
||||
| `shortLabel` | No | Shorter label displayed on the pinned quick-action button |
|
||||
| `icona` | No | Icon name displayed next to the label (e.g. `'IconBolt'`, `'IconSend'`) |
|
||||
| `isPinned` | No | When `true`, shows the command as a quick-action button in the top-right corner of the page |
|
||||
| `availabilityType` | No | Controls where the command appears: `'GLOBAL'` (always available), `'RECORD_SELECTION'` (only when records are selected), or `'FALLBACK'` (shown when no other commands match) |
|
||||
| `availabilityObjectUniversalIdentifier` | No | Restrict the command to pages of a specific object type (e.g. only on Company records) |
|
||||
| `conditionalAvailabilityExpression` | No | A boolean expression to dynamically control whether the command is visible (see below) |
|
||||
| Campo | Obbligatorio | Descrizione |
|
||||
| --------------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `universalIdentifier` | Sì | ID univoco stabile per il comando |
|
||||
| `etichetta` | Sì | Etichetta completa mostrata nel menu comandi (Cmd+K) |
|
||||
| `shortLabel` | No | Etichetta breve visualizzata sul pulsante di azione rapida fissato |
|
||||
| `icona` | No | Nome dell'icona visualizzato accanto all'etichetta (ad es. `'IconBolt'`, `'IconSend'`) |
|
||||
| `isPinned` | No | Quando `true`, mostra il comando come pulsante di azione rapida nell'angolo in alto a destra della pagina |
|
||||
| `availabilityType` | No | Controlla dove compare il comando: `'GLOBAL'` (sempre disponibile), `'RECORD_SELECTION'` (solo quando sono selezionati dei record) o `'FALLBACK'` (mostrato quando nessun altro comando corrisponde) |
|
||||
| `availabilityObjectUniversalIdentifier` | No | Limita il comando alle pagine di uno specifico tipo di oggetto (ad es. solo sui record Company) |
|
||||
| `conditionalAvailabilityExpression` | No | Un'espressione booleana per controllare dinamicamente se il comando è visibile (vedi sotto) |
|
||||
|
||||
#### Conditional availability expressions
|
||||
#### Espressioni di disponibilità condizionale
|
||||
|
||||
The `conditionalAvailabilityExpression` field lets you control when a command is visible based on the current page context. Import typed variables and operators from `twenty-sdk` to build expressions:
|
||||
Il campo `conditionalAvailabilityExpression` consente di controllare quando un comando è visibile in base al contesto della pagina corrente. Importa variabili tipizzate e operatori da `twenty-sdk` per costruire espressioni:
|
||||
|
||||
```tsx
|
||||
import {
|
||||
@@ -905,45 +904,45 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
**Context variables** — these represent the current state of the page:
|
||||
**Variabili di contesto** — rappresentano lo stato corrente della pagina:
|
||||
|
||||
| Variabile | Tipo | Descrizione |
|
||||
| ------------------------------ | --------- | ---------------------------------------------------------------- |
|
||||
| `pageType` | `string` | Current page type (e.g. `'RecordIndexPage'`, `'RecordShowPage'`) |
|
||||
| `isInSidePanel` | `boolean` | Whether the component is rendered in a side panel |
|
||||
| `numberOfSelectedRecords` | `numero` | Number of currently selected records |
|
||||
| `isSelectAll` | `boolean` | Whether "select all" is active |
|
||||
| `selectedRecords` | `array` | The selected record objects |
|
||||
| `favoriteRecordIds` | `array` | IDs of favorited records |
|
||||
| `objectPermissions` | `oggetto` | Permissions for the current object type |
|
||||
| `targetObjectReadPermissions` | `oggetto` | Read permissions for the target object |
|
||||
| `targetObjectWritePermissions` | `oggetto` | Write permissions for the target object |
|
||||
| `featureFlags` | `oggetto` | Active feature flags |
|
||||
| `objectMetadataItem` | `oggetto` | Metadata of the current object type |
|
||||
| `hasAnySoftDeleteFilterOnView` | `boolean` | Whether the current view has a soft-delete filter |
|
||||
| Variabile | Tipo | Descrizione |
|
||||
| ------------------------------ | --------- | ------------------------------------------------------------------------ |
|
||||
| `pageType` | `string` | Tipo di pagina corrente (ad es. `'RecordIndexPage'`, `'RecordShowPage'`) |
|
||||
| `isInSidePanel` | `boolean` | Indica se il componente è renderizzato in un pannello laterale |
|
||||
| `numberOfSelectedRecords` | `numero` | Numero di record attualmente selezionati |
|
||||
| `isSelectAll` | `boolean` | Indica se "seleziona tutto" è attivo |
|
||||
| `selectedRecords` | `array` | Gli oggetti dei record selezionati |
|
||||
| `favoriteRecordIds` | `array` | ID dei record aggiunti ai preferiti |
|
||||
| `objectPermissions` | `oggetto` | Autorizzazioni per il tipo di oggetto corrente |
|
||||
| `targetObjectReadPermissions` | `oggetto` | Autorizzazioni di lettura per l'oggetto di destinazione |
|
||||
| `targetObjectWritePermissions` | `oggetto` | Autorizzazioni di scrittura per l'oggetto di destinazione |
|
||||
| `featureFlags` | `oggetto` | Flag delle funzionalità attivi |
|
||||
| `objectMetadataItem` | `oggetto` | Metadati del tipo di oggetto corrente |
|
||||
| `hasAnySoftDeleteFilterOnView` | `boolean` | Indica se la vista corrente ha un filtro di soft-delete |
|
||||
|
||||
**Operators** — combine variables into boolean expressions:
|
||||
**Operatori** — combinano variabili in espressioni booleane:
|
||||
|
||||
| Operator | Descrizione |
|
||||
| ----------------------------------- | ----------------------------------------------------------------- |
|
||||
| `isDefined(value)` | `true` if the value is not null/undefined |
|
||||
| `isNonEmptyString(value)` | `true` if the value is a non-empty string |
|
||||
| `includes(array, value)` | `true` if the array contains the value |
|
||||
| `includesEvery(array, prop, value)` | `true` if every item's property includes the value |
|
||||
| `every(array, prop)` | `true` if the property is truthy on every item |
|
||||
| `everyDefined(array, prop)` | `true` if the property is defined on every item |
|
||||
| `everyEquals(array, prop, value)` | `true` if the property equals the value on every item |
|
||||
| `some(array, prop)` | `true` if the property is truthy on at least one item |
|
||||
| `someDefined(array, prop)` | `true` if the property is defined on at least one item |
|
||||
| `someEquals(array, prop, value)` | `true` if the property equals the value on at least one item |
|
||||
| `someNonEmptyString(array, prop)` | `true` if the property is a non-empty string on at least one item |
|
||||
| `none(array, prop)` | `true` if the property is falsy on every item |
|
||||
| `noneDefined(array, prop)` | `true` if the property is undefined on every item |
|
||||
| `noneEquals(array, prop, value)` | `true` if the property does not equal the value on any item |
|
||||
| Operatore | Descrizione |
|
||||
| ----------------------------------- | -------------------------------------------------------------------- |
|
||||
| `isDefined(value)` | `true` se il valore non è null/undefined |
|
||||
| `isNonEmptyString(value)` | `true` se il valore è una stringa non vuota |
|
||||
| `includes(array, value)` | `true` se l'array contiene il valore |
|
||||
| `includesEvery(array, prop, value)` | `true` se la proprietà di ogni elemento include il valore |
|
||||
| `every(array, prop)` | `true` se la proprietà è truthy su ogni elemento |
|
||||
| `everyDefined(array, prop)` | `true` se la proprietà è definita su ogni elemento |
|
||||
| `everyEquals(array, prop, value)` | `true` se la proprietà è uguale al valore su ogni elemento |
|
||||
| `some(array, prop)` | `true` se la proprietà è truthy su almeno un elemento |
|
||||
| `someDefined(array, prop)` | `true` se la proprietà è definita su almeno un elemento |
|
||||
| `someEquals(array, prop, value)` | `true` se la proprietà è uguale al valore su almeno un elemento |
|
||||
| `someNonEmptyString(array, prop)` | `true` se la proprietà è una stringa non vuota su almeno un elemento |
|
||||
| `none(array, prop)` | `true` se la proprietà è falsy su ogni elemento |
|
||||
| `noneDefined(array, prop)` | `true` se la proprietà è undefined su ogni elemento |
|
||||
| `noneEquals(array, prop, value)` | `true` se la proprietà non è uguale al valore su alcun elemento |
|
||||
|
||||
#### Public assets
|
||||
#### Asset pubblici
|
||||
|
||||
Front components can access files from the app's `public/` directory using `getPublicAssetUrl`:
|
||||
I componenti front-end possono accedere ai file dalla directory `public/` dell'app utilizzando `getPublicAssetUrl`:
|
||||
|
||||
```tsx
|
||||
import { defineFrontComponent, getPublicAssetUrl } from 'twenty-sdk';
|
||||
@@ -957,18 +956,18 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
See the [public assets section](#accessing-public-assets-with-getpublicasseturl) for details.
|
||||
Vedi la [sezione sugli asset pubblici](#accessing-public-assets-with-getpublicasseturl) per i dettagli.
|
||||
|
||||
#### Stile
|
||||
|
||||
Front components support multiple styling approaches. You can use:
|
||||
I componenti front-end supportano diversi approcci di styling. Puoi usare:
|
||||
|
||||
* **Inline styles** — `style={{ color: 'red' }}`
|
||||
* **Twenty UI components** — import from `twenty-sdk/ui` (Button, Tag, Status, Chip, Avatar, and more)
|
||||
* **Emotion** — CSS-in-JS with `@emotion/react`
|
||||
* **Styled-components** — `styled.div` patterns
|
||||
* **Tailwind CSS** — utility classes
|
||||
* **Any CSS-in-JS library** compatible with React
|
||||
* **Stili inline** — `style={{ color: 'red' }}`
|
||||
* **Componenti Twenty UI** — importali da `twenty-sdk/ui` (Button, Tag, Status, Chip, Avatar e altro)
|
||||
* **Emotion** — CSS-in-JS con `@emotion/react`
|
||||
* **Styled-components** — pattern `styled.div`
|
||||
* **Tailwind CSS** — classi di utilità
|
||||
* **Qualsiasi libreria CSS-in-JS** compatibile con React
|
||||
|
||||
```tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
@@ -1022,9 +1021,9 @@ Punti chiave:
|
||||
* `description` (opzionale) fornisce contesto aggiuntivo sullo scopo della skill.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineAgent" description="Define AI agents with custom prompts">
|
||||
<Accordion title="defineAgent" description="Definisci agenti IA con prompt personalizzati">
|
||||
|
||||
Agents are AI assistants that live inside your workspace. Use `defineAgent()` to create agents with a custom system prompt:
|
||||
Gli agenti sono assistenti IA che vivono all'interno del tuo spazio di lavoro. Usa `defineAgent()` per creare agenti con un prompt di sistema personalizzato:
|
||||
|
||||
```ts src/agents/example-agent.ts
|
||||
import { defineAgent } from 'twenty-sdk';
|
||||
@@ -1040,17 +1039,17 @@ export default defineAgent({
|
||||
```
|
||||
|
||||
Punti chiave:
|
||||
* `name` is the unique identifier string for the agent (kebab-case recommended).
|
||||
* `label` is the display name shown in the UI.
|
||||
* `prompt` is the system prompt that defines the agent's behavior.
|
||||
* `description` (optional) provides context about what the agent does.
|
||||
* `name` è la stringa identificativa univoca dell'agente (kebab-case consigliato).
|
||||
* `label` è il nome visualizzato nell'UI.
|
||||
* `prompt` è il prompt di sistema che definisce il comportamento dell'agente.
|
||||
* `description` (opzionale) fornisce contesto su ciò che fa l'agente.
|
||||
* `icon` (opzionale) imposta l'icona visualizzata nell'UI.
|
||||
* `modelId` (optional) overrides the default AI model used by the agent.
|
||||
* `modelId` (opzionale) sostituisce il modello di IA predefinito utilizzato dall'agente.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineView" description="Definisci viste salvate per gli oggetti">
|
||||
|
||||
Views are saved configurations for how records of an object are displayed — including which fields are visible, their order, and any filters or groups applied. Use `defineView()` to ship pre-configured views with your app:
|
||||
Le viste sono configurazioni salvate di come vengono visualizzati i record di un oggetto — inclusi quali campi sono visibili, il loro ordine e gli eventuali filtri o raggruppamenti applicati. Usa `defineView()` per fornire viste preconfigurate con la tua app:
|
||||
|
||||
```ts src/views/example-view.ts
|
||||
import { defineView, ViewKey } from 'twenty-sdk';
|
||||
@@ -1077,16 +1076,16 @@ export default defineView({
|
||||
```
|
||||
|
||||
Punti chiave:
|
||||
* `objectUniversalIdentifier` specifies which object this view applies to.
|
||||
* `key` determines the view type (e.g., `ViewKey.INDEX` for the main list view).
|
||||
* `fields` controls which columns appear and their order. Each field references a `fieldMetadataUniversalIdentifier`.
|
||||
* You can also define `filters`, `filterGroups`, `groups`, and `fieldGroups` for more advanced configurations.
|
||||
* `position` controls the ordering when multiple views exist for the same object.
|
||||
* `objectUniversalIdentifier` specifica a quale oggetto si applica questa vista.
|
||||
* `key` determina il tipo di vista (ad es., `ViewKey.INDEX` per la vista elenco principale).
|
||||
* `fields` controlla quali colonne compaiono e il loro ordine. Ogni campo fa riferimento a un `fieldMetadataUniversalIdentifier`.
|
||||
* Puoi anche definire `filters`, `filterGroups`, `groups` e `fieldGroups` per configurazioni più avanzate.
|
||||
* `position` controlla l'ordinamento quando esistono più viste per lo stesso oggetto.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineNavigationMenuItem" description="Definisci i link di navigazione della barra laterale">
|
||||
|
||||
Navigation menu items add custom entries to the workspace sidebar. Use `defineNavigationMenuItem()` to link to views, external URLs, or objects:
|
||||
Le voci del menu di navigazione aggiungono elementi personalizzati alla barra laterale dello spazio di lavoro. Usa `defineNavigationMenuItem()` per collegarti a viste, URL esterni o oggetti:
|
||||
|
||||
```ts src/navigation-menu-items/example-navigation-menu-item.ts
|
||||
import { defineNavigationMenuItem, NavigationMenuItemType } from 'twenty-sdk';
|
||||
@@ -1104,15 +1103,15 @@ export default defineNavigationMenuItem({
|
||||
```
|
||||
|
||||
Punti chiave:
|
||||
* `type` determines what the menu item links to: `NavigationMenuItemType.VIEW` for a saved view, or `NavigationMenuItemType.LINK` for an external URL.
|
||||
* For view links, set `viewUniversalIdentifier`. For external links, set `link`.
|
||||
* `position` controls the ordering in the sidebar.
|
||||
* `icon` and `color` (optional) customize the appearance.
|
||||
* `type` determina a cosa rimanda la voce di menu: `NavigationMenuItemType.VIEW` per una vista salvata o `NavigationMenuItemType.LINK` per un URL esterno.
|
||||
* Per i link a viste, imposta `viewUniversalIdentifier`. Per i link esterni, imposta `link`.
|
||||
* `position` controlla l'ordinamento nella barra laterale.
|
||||
* `icon` e `color` (opzionali) personalizzano l'aspetto.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="definePageLayout" description="Define custom page layouts for record views">
|
||||
<Accordion title="definePageLayout" description="Definisci layout di pagina personalizzati per le viste dei record">
|
||||
|
||||
Page layouts let you customize how a record detail page looks — which tabs appear, what widgets are inside each tab, and how they are arranged. Use `definePageLayout()` to ship custom layouts with your app:
|
||||
I layout di pagina ti consentono di personalizzare l'aspetto di una pagina dei dettagli di un record — quali schede compaiono, quali widget sono all'interno di ciascuna scheda e come sono disposti. Usa `definePageLayout()` per fornire layout personalizzati con la tua app:
|
||||
|
||||
```ts src/page-layouts/example-record-page-layout.ts
|
||||
import { definePageLayout, PageLayoutTabLayoutMode } from 'twenty-sdk';
|
||||
@@ -1149,33 +1148,33 @@ export default definePageLayout({
|
||||
```
|
||||
|
||||
Punti chiave:
|
||||
* `type` is typically `'RECORD_PAGE'` to customize the detail view of a specific object.
|
||||
* `objectUniversalIdentifier` specifies which object this layout applies to.
|
||||
* Each `tab` defines a section of the page with a `title`, `position`, and `layoutMode` (`CANVAS` for free-form layout).
|
||||
* Each `widget` inside a tab can render a front component, a relation list, or other built-in widget types.
|
||||
* `position` on tabs controls their order. Use higher values (e.g., 50) to place custom tabs after built-in ones.
|
||||
* `type` è in genere `'RECORD_PAGE'` per personalizzare la vista dei dettagli di un oggetto specifico.
|
||||
* `objectUniversalIdentifier` specifica a quale oggetto si applica questo layout.
|
||||
* Ogni `tab` definisce una sezione della pagina con un `title`, `position` e `layoutMode` (`CANVAS` per il layout libero).
|
||||
* Ogni `widget` all'interno di una scheda può renderizzare un componente front-end, un elenco di relazioni o altri tipi di widget integrati.
|
||||
* `position` sulle schede controlla il loro ordine. Usa valori più alti (ad es., 50) per posizionare le schede personalizzate dopo quelle integrate.
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Public assets (`public/` folder)
|
||||
## Asset pubblici (cartella `public/`)
|
||||
|
||||
The `public/` folder at the root of your app holds static files — images, icons, fonts, or any other assets your app needs at runtime. These files are automatically included in builds, synced during dev mode, and uploaded to the server.
|
||||
La cartella `public/` alla radice della tua app contiene file statici — immagini, icone, font o qualsiasi altro asset di cui la tua app ha bisogno a runtime. Questi file sono inclusi automaticamente nelle build, sincronizzati durante la modalità di sviluppo e caricati sul server.
|
||||
|
||||
Files placed in `public/` are:
|
||||
I file posizionati in `public/` sono:
|
||||
|
||||
* **Publicly accessible** — once synced to the server, assets are served at a public URL. No authentication is needed to access them.
|
||||
* **Available in front components** — use asset URLs to display images, icons, or any media inside your React components.
|
||||
* **Available in logic functions** — reference asset URLs in emails, API responses, or any server-side logic.
|
||||
* **Used for marketplace metadata** — the `logoUrl` and `screenshots` fields in `defineApplication()` reference files from this folder (e.g., `public/logo.png`). These are displayed in the marketplace when your app is published.
|
||||
* **Auto-synced in dev mode** — when you add, update, or delete a file in `public/`, it is synced to the server automatically. No restart needed.
|
||||
* **Included in builds** — `yarn twenty build` bundles all public assets into the distribution output.
|
||||
* **Pubblicamente accessibili** — una volta sincronizzati sul server, gli asset sono serviti a un URL pubblico. Non è necessaria alcuna autenticazione per accedervi.
|
||||
* **Disponibili nei componenti front-end** — usa gli URL degli asset per visualizzare immagini, icone o qualsiasi media all'interno dei tuoi componenti React.
|
||||
* **Disponibili nelle funzioni logiche** — fai riferimento agli URL degli asset nelle email, nelle risposte API o in qualsiasi logica lato server.
|
||||
* **Usati per i metadati del marketplace** — i campi `logoUrl` e `screenshots` in `defineApplication()` fanno riferimento a file di questa cartella (ad es., `public/logo.png`). Questi vengono visualizzati nel marketplace quando la tua app viene pubblicata.
|
||||
* **Sincronizzati automaticamente in modalità dev** — quando aggiungi, aggiorni o elimini un file in `public/`, viene sincronizzato automaticamente con il server. Nessun riavvio necessario.
|
||||
* **Inclusi nelle build** — `yarn twenty build` raggruppa tutti gli asset pubblici nell'output di distribuzione.
|
||||
|
||||
### Accessing public assets with `getPublicAssetUrl`
|
||||
### Accedere agli asset pubblici con `getPublicAssetUrl`
|
||||
|
||||
Use the `getPublicAssetUrl` helper from `twenty-sdk` to get the full URL of a file in your `public/` directory. It works in both **logic functions** and **front components**.
|
||||
Usa l'helper `getPublicAssetUrl` da `twenty-sdk` per ottenere l'URL completo di un file nella tua directory `public/`. Funziona sia nelle funzioni logiche che nei componenti front-end.
|
||||
|
||||
**In a logic function:**
|
||||
**In una funzione logica:**
|
||||
|
||||
```ts src/logic-functions/send-invoice.ts
|
||||
import { defineLogicFunction, getPublicAssetUrl } from 'twenty-sdk';
|
||||
@@ -1200,7 +1199,7 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
**In a front component:**
|
||||
**In un componente front-end:**
|
||||
|
||||
```tsx src/front-components/company-card.tsx
|
||||
import { defineFrontComponent, getPublicAssetUrl } from 'twenty-sdk';
|
||||
@@ -1212,19 +1211,19 @@ export default defineFrontComponent(() => {
|
||||
});
|
||||
```
|
||||
|
||||
The `path` argument is relative to your app's `public/` folder. Both `getPublicAssetUrl('logo.png')` and `getPublicAssetUrl('public/logo.png')` resolve to the same URL — the `public/` prefix is stripped automatically if present.
|
||||
L'argomento `path` è relativo alla cartella `public/` della tua app. Sia `getPublicAssetUrl('logo.png')` sia `getPublicAssetUrl('public/logo.png')` risolvono allo stesso URL — il prefisso `public/` viene rimosso automaticamente se presente.
|
||||
|
||||
## Using npm packages
|
||||
## Uso dei pacchetti npm
|
||||
|
||||
You can install and use any npm package in your app. Both logic functions and front components are bundled with [esbuild](https://esbuild.github.io/), which inlines all dependencies into the output — no `node_modules` are needed at runtime.
|
||||
Puoi installare e usare qualsiasi pacchetto npm nella tua app. Sia le funzioni logiche sia i componenti front-end vengono impacchettati con [esbuild](https://esbuild.github.io/), che incorpora tutte le dipendenze nell'output — non sono necessari i `node_modules` a runtime.
|
||||
|
||||
### Installing a package
|
||||
### Installazione di un pacchetto
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn add axios
|
||||
```
|
||||
|
||||
Then import it in your code:
|
||||
Quindi importalo nel tuo codice:
|
||||
|
||||
```ts src/logic-functions/fetch-data.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
@@ -1245,7 +1244,7 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
The same works for front components:
|
||||
Lo stesso vale per i componenti front-end:
|
||||
|
||||
```tsx src/front-components/chart.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
@@ -1262,27 +1261,27 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
### How bundling works
|
||||
### Come funziona il bundling
|
||||
|
||||
The build step (`yarn twenty dev` or `yarn twenty build`) uses esbuild to produce a single self-contained file per logic function and per front component. All imported packages are inlined into the bundle.
|
||||
La fase di build (`yarn twenty dev` o `yarn twenty build`) usa esbuild per produrre un singolo file autonomo per ogni funzione logica e per ogni componente front-end. Tutti i pacchetti importati sono incorporati nel bundle.
|
||||
|
||||
**Logic functions** run in a Node.js environment. Node built-in modules (`fs`, `path`, `crypto`, `http`, etc.) are available and do not need to be installed.
|
||||
**Le funzioni logiche** vengono eseguite in un ambiente Node.js. I moduli integrati di Node (`fs`, `path`, `crypto`, `http`, ecc.) sono disponibili e non necessitano di essere installati.
|
||||
|
||||
**Front components** run in a Web Worker. Node built-in modules are **not** available — only browser APIs and npm packages that work in a browser environment.
|
||||
**I componenti front-end** vengono eseguiti in un Web Worker. I moduli integrati di Node non sono disponibili — solo le API del browser e i pacchetti npm che funzionano in un ambiente browser.
|
||||
|
||||
Both environments have `twenty-client-sdk/core` and `twenty-client-sdk/metadata` available as pre-provided modules — these are not bundled but resolved at runtime by the server.
|
||||
Entrambi gli ambienti hanno `twenty-client-sdk/core` e `twenty-client-sdk/metadata` disponibili come moduli preforniti — questi non vengono inclusi nel bundle ma vengono risolti a runtime dal server.
|
||||
|
||||
## Scaffolding entities with `yarn twenty add`
|
||||
## Creazione di entità con lo scaffolding tramite `yarn twenty add`
|
||||
|
||||
Instead of creating entity files by hand, you can use the interactive scaffolder:
|
||||
Invece di creare manualmente i file delle entità, puoi usare lo scaffolder interattivo:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty add
|
||||
```
|
||||
|
||||
This prompts you to pick an entity type and walks you through the required fields. It generates a ready-to-use file with a stable `universalIdentifier` and the correct `defineEntity()` call.
|
||||
Questo ti chiede di scegliere un tipo di entità e ti guida attraverso i campi richiesti. Genera un file pronto all'uso con un `universalIdentifier` stabile e la corretta chiamata a `defineEntity()`.
|
||||
|
||||
You can also pass the entity type directly to skip the first prompt:
|
||||
Puoi anche passare direttamente il tipo di entità per saltare il primo prompt:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty add object
|
||||
@@ -1290,44 +1289,44 @@ yarn twenty add logicFunction
|
||||
yarn twenty add frontComponent
|
||||
```
|
||||
|
||||
### Available entity types
|
||||
### Tipi di entità disponibili
|
||||
|
||||
| Tipo di entità | Comando | Generated file |
|
||||
| -------------------- | ------------------------------------ | ------------------------------------- |
|
||||
| Oggetto | `yarn twenty add object` | `src/objects/<name>.ts` |
|
||||
| Campo | `yarn twenty add field` | `src/fields/<name>.ts` |
|
||||
| Logic function | `yarn twenty add logicFunction` | `src/logic-functions/<name>.ts` |
|
||||
| Front component | `yarn twenty add frontComponent` | `src/front-components/<name>.tsx` |
|
||||
| Ruolo | `yarn twenty add role` | `src/roles/<name>.ts` |
|
||||
| Abilità | `yarn twenty add skill` | `src/skills/<name>.ts` |
|
||||
| Agente | `yarn twenty add agent` | `src/agents/<name>.ts` |
|
||||
| Vista | `yarn twenty add view` | `src/views/<name>.ts` |
|
||||
| Navigation menu item | `yarn twenty add navigationMenuItem` | `src/navigation-menu-items/<name>.ts` |
|
||||
| Page layout | `yarn twenty add pageLayout` | `src/page-layouts/<name>.ts` |
|
||||
| Tipo di entità | Comando | File generato |
|
||||
| ---------------------------- | ------------------------------------ | ------------------------------------- |
|
||||
| Oggetto | `yarn twenty add object` | `src/objects/<name>.ts` |
|
||||
| Campo | `yarn twenty add field` | `src/fields/<name>.ts` |
|
||||
| Funzione logica | `yarn twenty add logicFunction` | `src/logic-functions/<name>.ts` |
|
||||
| Componente front-end | `yarn twenty add frontComponent` | `src/front-components/<name>.tsx` |
|
||||
| Ruolo | `yarn twenty add role` | `src/roles/<name>.ts` |
|
||||
| Abilità | `yarn twenty add skill` | `src/skills/<name>.ts` |
|
||||
| Agente | `yarn twenty add agent` | `src/agents/<name>.ts` |
|
||||
| Vista | `yarn twenty add view` | `src/views/<name>.ts` |
|
||||
| Voce del menu di navigazione | `yarn twenty add navigationMenuItem` | `src/navigation-menu-items/<name>.ts` |
|
||||
| Layout di pagina | `yarn twenty add pageLayout` | `src/page-layouts/<name>.ts` |
|
||||
|
||||
### What the scaffolder generates
|
||||
### Cosa genera lo scaffolder
|
||||
|
||||
Each entity type has its own template. For example, `yarn twenty add object` asks for:
|
||||
Ogni tipo di entità ha il proprio template. Ad esempio, `yarn twenty add object` richiede:
|
||||
|
||||
1. **Name (singular)** — e.g., `invoice`
|
||||
2. **Name (plural)** — e.g., `invoices`
|
||||
3. **Label (singular)** — auto-populated from the name (e.g., `Invoice`)
|
||||
4. **Label (plural)** — auto-populated (e.g., `Invoices`)
|
||||
5. **Create a view and navigation item?** — if you answer yes, the scaffolder also generates a matching view and sidebar link for the new object.
|
||||
1. **Nome (singolare)** — ad es., `invoice`
|
||||
2. **Nome (plurale)** — ad es., `invoices`
|
||||
3. **Etichetta (singolare)** — compilata automaticamente dal nome (ad es., `Invoice`)
|
||||
4. **Etichetta (plurale)** — compilata automaticamente (ad es., `Invoices`)
|
||||
5. **Creare una vista e una voce di navigazione?** — se rispondi sì, lo scaffolder genera anche una vista corrispondente e un link nella barra laterale per il nuovo oggetto.
|
||||
|
||||
Other entity types have simpler prompts — most only ask for a name.
|
||||
Gli altri tipi di entità hanno prompt più semplici — la maggior parte chiede solo un nome.
|
||||
|
||||
The `field` entity type is more detailed: it asks for the field name, label, type (from a list of all available field types like `TEXT`, `NUMBER`, `SELECT`, `RELATION`, etc.), and the target object's `universalIdentifier`.
|
||||
Il tipo di entità `field` è più dettagliato: chiede il nome del campo, l'etichetta, il tipo (da un elenco di tutti i tipi di campo disponibili come `TEXT`, `NUMBER`, `SELECT`, `RELATION`, ecc.) e l'`universalIdentifier` dell'oggetto di destinazione.
|
||||
|
||||
### Custom output path
|
||||
### Percorso di output personalizzato
|
||||
|
||||
Use the `--path` flag to place the generated file in a custom location:
|
||||
Usa il flag `--path` per posizionare il file generato in una posizione personalizzata:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty add logicFunction --path src/custom-folder
|
||||
```
|
||||
|
||||
## Typed API clients (twenty-client-sdk)
|
||||
## Client API tipizzati (twenty-client-sdk)
|
||||
|
||||
Il pacchetto `twenty-client-sdk` fornisce due client GraphQL tipizzati per interagire con l'API di Twenty dalle tue funzioni logiche e dai componenti front-end.
|
||||
|
||||
@@ -1337,9 +1336,9 @@ Il pacchetto `twenty-client-sdk` fornisce due client GraphQL tipizzati per inter
|
||||
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — configurazione dello spazio di lavoro, caricamenti di file | No, fornito pronto all'uso |
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="CoreApiClient" description="Query and mutate workspace data (records, objects)">
|
||||
<Accordion title="CoreApiClient" description="Esegui query e modifica i dati dello spazio di lavoro (record, oggetti)">
|
||||
|
||||
`CoreApiClient` è il client principale per interrogare e modificare i dati dello spazio di lavoro. It is **generated from your workspace schema** during `yarn twenty dev` or `yarn twenty build`, so it is fully typed to match your objects and fields.
|
||||
`CoreApiClient` è il client principale per interrogare e modificare i dati dello spazio di lavoro. Viene **generato dallo schema del tuo spazio di lavoro** durante `yarn twenty dev` o `yarn twenty build`, quindi è completamente tipizzato per corrispondere ai tuoi oggetti e campi.
|
||||
|
||||
```ts
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
@@ -1379,12 +1378,12 @@ const { createCompany } = await client.mutation({
|
||||
Il client utilizza una sintassi a selection-set: passa `true` per includere un campo, usa `__args` per gli argomenti e annida oggetti per le relazioni. Ottieni completamento automatico e controllo dei tipi completi basati sullo schema del tuo spazio di lavoro.
|
||||
|
||||
<Note>
|
||||
**CoreApiClient is generated at dev/build time.** If you use it without running `yarn twenty dev` or `yarn twenty build` first, it throws an error. The generation happens automatically — the CLI introspects your workspace's GraphQL schema and generates a typed client using `@genql/cli`.
|
||||
**CoreApiClient viene generato in fase di dev/build.** Se lo usi senza eseguire prima `yarn twenty dev` o `yarn twenty build`, genera un errore. La generazione avviene automaticamente — la CLI esegue l'introspezione dello schema GraphQL del tuo spazio di lavoro e genera un client tipizzato usando `@genql/cli`.
|
||||
</Note>
|
||||
|
||||
#### Utilizzo di CoreSchema per le annotazioni di tipo
|
||||
|
||||
`CoreSchema` provides TypeScript types matching your workspace objects — useful for typing component state or function parameters:
|
||||
`CoreSchema` fornisce tipi TypeScript corrispondenti agli oggetti del tuo spazio di lavoro — utile per tipizzare lo stato dei componenti o i parametri delle funzioni:
|
||||
|
||||
```ts
|
||||
import { CoreApiClient, CoreSchema } from 'twenty-client-sdk/core';
|
||||
@@ -1406,7 +1405,7 @@ setCompany(result.company);
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="MetadataApiClient" description="Workspace config, applications, and file uploads">
|
||||
<Accordion title="MetadataApiClient" description="Configurazione dello spazio di lavoro, applicazioni e caricamenti di file">
|
||||
|
||||
`MetadataApiClient` è fornito pronto all'uso con l'SDK (nessuna generazione richiesta). Interroga l'endpoint `/metadata` per la configurazione dello spazio di lavoro, le applicazioni e i caricamenti di file.
|
||||
|
||||
@@ -1462,7 +1461,7 @@ console.log(uploadedFile);
|
||||
| ---------------------------------- | -------- | ---------------------------------------------------------------------- |
|
||||
| `fileBuffer` | `Buffer` | Il contenuto grezzo del file |
|
||||
| `filename` | `string` | Il nome del file (utilizzato per l'archiviazione e la visualizzazione) |
|
||||
| `contentType` | `string` | MIME type (defaults to `application/octet-stream` if omitted) |
|
||||
| `contentType` | `string` | Tipo MIME (predefinito su `application/octet-stream` se omesso) |
|
||||
| `fieldMetadataUniversalIdentifier` | `string` | L'`universalIdentifier` del campo di tipo file nel tuo oggetto |
|
||||
|
||||
Punti chiave:
|
||||
@@ -1476,24 +1475,24 @@ Punti chiave:
|
||||
Quando il tuo codice viene eseguito su Twenty (funzioni logiche o componenti front-end), la piattaforma inietta le credenziali come variabili d'ambiente:
|
||||
|
||||
* `TWENTY_API_URL` — URL di base dell'API di Twenty
|
||||
* `TWENTY_APP_ACCESS_TOKEN` — Short-lived key scoped to your application's default function role
|
||||
* `TWENTY_APP_ACCESS_TOKEN` — Chiave a breve durata con ambito al ruolo funzione predefinito della tua applicazione
|
||||
|
||||
Non è **necessario** passarle ai client — vengono lette automaticamente da `process.env`. I permessi della chiave API sono determinati dal ruolo referenziato in `defaultRoleUniversalIdentifier` nel tuo `application-config.ts`.
|
||||
</Note>
|
||||
|
||||
## Testing your app
|
||||
## Testare la tua app
|
||||
|
||||
The SDK provides programmatic APIs that let you build, deploy, install, and uninstall your app from test code. Combined with [Vitest](https://vitest.dev/) and the typed API clients, you can write integration tests that verify your app works end-to-end against a real Twenty server.
|
||||
L'SDK fornisce API programmatiche che ti consentono di compilare, distribuire, installare e disinstallare la tua app dal codice di test. In combinazione con [Vitest](https://vitest.dev/) e i client API tipizzati, puoi scrivere test di integrazione che verificano che la tua app funzioni end-to-end contro un server Twenty reale.
|
||||
|
||||
### Impostazione
|
||||
|
||||
The scaffolded app already includes Vitest. If you set it up manually, install the dependencies:
|
||||
L'app generata tramite scaffolding include già Vitest. Se la configuri manualmente, installa le dipendenze:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn add -D vitest vite-tsconfig-paths
|
||||
```
|
||||
|
||||
Create a `vitest.config.ts` at the root of your app:
|
||||
Crea un `vitest.config.ts` alla radice della tua app:
|
||||
|
||||
```ts vitest.config.ts
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
@@ -1519,7 +1518,7 @@ export default defineConfig({
|
||||
});
|
||||
```
|
||||
|
||||
Create a setup file that verifies the server is reachable before tests run:
|
||||
Crea un file di setup che verifichi che il server sia raggiungibile prima dell'esecuzione dei test:
|
||||
|
||||
```ts src/__tests__/setup-test.ts
|
||||
import * as fs from 'fs';
|
||||
@@ -1559,22 +1558,22 @@ beforeAll(async () => {
|
||||
});
|
||||
```
|
||||
|
||||
### Programmatic SDK APIs
|
||||
### API programmatiche dell'SDK
|
||||
|
||||
The `twenty-sdk/cli` subpath exports functions you can call directly from test code:
|
||||
Il sottopercorso `twenty-sdk/cli` esporta funzioni che puoi chiamare direttamente dal codice di test:
|
||||
|
||||
| Funzione | Descrizione |
|
||||
| -------------- | ------------------------------------------- |
|
||||
| `appBuild` | Build the app and optionally pack a tarball |
|
||||
| `appDeploy` | Upload a tarball to the server |
|
||||
| `appInstall` | Install the app on the active workspace |
|
||||
| `appUninstall` | Uninstall the app from the active workspace |
|
||||
| Funzione | Descrizione |
|
||||
| -------------- | ----------------------------------------------- |
|
||||
| `appBuild` | Compila l'app e, opzionalmente, crea un tarball |
|
||||
| `appDeploy` | Carica un tarball sul server |
|
||||
| `appInstall` | Installa l'app nello spazio di lavoro attivo |
|
||||
| `appUninstall` | Disinstalla l'app dallo spazio di lavoro attivo |
|
||||
|
||||
Each function returns a result object with `success: boolean` and either `data` or `error`.
|
||||
Ogni funzione restituisce un oggetto risultato con `success: boolean` e `data` oppure `error`.
|
||||
|
||||
### Writing an integration test
|
||||
### Scrivere un test di integrazione
|
||||
|
||||
Here is a full example that builds, deploys, and installs the app, then verifies it appears in the workspace:
|
||||
Ecco un esempio completo che compila, distribuisce e installa l'app, quindi verifica che compaia nello spazio di lavoro:
|
||||
|
||||
```ts src/__tests__/app-install.integration-test.ts
|
||||
import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/application-config';
|
||||
@@ -1637,37 +1636,37 @@ describe('App installation', () => {
|
||||
});
|
||||
```
|
||||
|
||||
### Running tests
|
||||
### Esecuzione dei test
|
||||
|
||||
Make sure your local Twenty server is running, then:
|
||||
Assicurati che il tuo server Twenty locale sia in esecuzione, quindi:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn test
|
||||
```
|
||||
|
||||
Or in watch mode during development:
|
||||
Oppure in modalità watch durante lo sviluppo:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn test:watch
|
||||
```
|
||||
|
||||
### Type checking
|
||||
### Controllo dei tipi
|
||||
|
||||
You can also run type checking on your app without running tests:
|
||||
Puoi anche eseguire il controllo dei tipi sulla tua app senza eseguire i test:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty typecheck
|
||||
```
|
||||
|
||||
This runs `tsc --noEmit` and reports any type errors.
|
||||
Questo esegue `tsc --noEmit` e riporta eventuali errori di tipo.
|
||||
|
||||
## Riferimento CLI
|
||||
|
||||
Beyond `dev`, `build`, `add`, and `typecheck`, the CLI provides commands for executing functions, viewing logs, and managing app installations.
|
||||
Oltre a `dev`, `build`, `add` e `typecheck`, la CLI fornisce comandi per eseguire funzioni, visualizzare i log e gestire le installazioni delle app.
|
||||
|
||||
### Executing functions (`yarn twenty exec`)
|
||||
### Esecuzione delle funzioni (`yarn twenty exec`)
|
||||
|
||||
Run a logic function manually without triggering it via HTTP, cron, or database event:
|
||||
Esegui manualmente una funzione logica senza attivarla tramite HTTP, cron o evento del database:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Execute by function name
|
||||
@@ -1684,9 +1683,9 @@ yarn twenty exec --preInstall
|
||||
yarn twenty exec --postInstall
|
||||
```
|
||||
|
||||
### Viewing function logs (`yarn twenty logs`)
|
||||
### Visualizzazione dei log delle funzioni (`yarn twenty logs`)
|
||||
|
||||
Stream execution logs for your app's logic functions:
|
||||
Esegui lo streaming dei log di esecuzione per le funzioni logiche della tua app:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Stream all function logs
|
||||
@@ -1700,12 +1699,12 @@ yarn twenty logs -u e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf
|
||||
```
|
||||
|
||||
<Note>
|
||||
This is different from `yarn twenty server logs`, which shows the Docker container logs. `yarn twenty logs` shows your app's function execution logs from the Twenty server.
|
||||
Questo è diverso da `yarn twenty server logs`, che mostra i log del container Docker. `yarn twenty logs` mostra i log di esecuzione delle funzioni della tua app dal server Twenty.
|
||||
</Note>
|
||||
|
||||
### Uninstalling an app (`yarn twenty uninstall`)
|
||||
### Disinstallazione di un'app (`yarn twenty uninstall`)
|
||||
|
||||
Remove your app from the active workspace:
|
||||
Rimuovi la tua app dallo spazio di lavoro attivo:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty uninstall
|
||||
|
||||
@@ -4,24 +4,24 @@ description: Definiți obiecte, funcții logice, componente front-end și multe
|
||||
---
|
||||
|
||||
<Warning>
|
||||
Apps are currently in alpha. The feature works but is still evolving.
|
||||
Aplicațiile sunt în prezent în testare alfa. Caracteristica funcționează, dar este încă în dezvoltare.
|
||||
</Warning>
|
||||
|
||||
The `twenty-sdk` package provides typed building blocks to create your app. This page covers every entity type and API client available in the SDK.
|
||||
Pachetul `twenty-sdk` oferă blocuri de construcție tipizate pentru a crea aplicația. Această pagină acoperă toate tipurile de entități și clienții API disponibili în SDK.
|
||||
|
||||
## DefineEntity functions
|
||||
## Funcții DefineEntity
|
||||
|
||||
The SDK provides functions to define your app entities. You must use `export default defineEntity({...})` for the SDK to detect your entities. Aceste funcții validează configurația în timpul build-ului și oferă completare automată în IDE și siguranța tipurilor.
|
||||
SDK-ul oferă funcții pentru definirea entităților aplicației. Trebuie să folosiți `export default defineEntity({...})` pentru ca SDK-ul să detecteze entitățile. Aceste funcții validează configurația în timpul build-ului și oferă completare automată în IDE și siguranța tipurilor.
|
||||
|
||||
<Note>
|
||||
**File organization is up to you.**
|
||||
Entity detection is AST-based — the SDK finds `export default defineEntity(...)` calls regardless of where the file lives. Grouping files by type (e.g., `logic-functions/`, `roles/`) is just a convention, not a requirement.
|
||||
**Organizarea fișierelor ține de dvs.**
|
||||
Detectarea entităților este bazată pe AST — SDK-ul găsește apelurile `export default defineEntity(...)` indiferent unde se află fișierul. Gruparea fișierelor după tip (de exemplu, `logic-functions/`, `roles/`) este doar o convenție pentru organizarea codului, nu o cerință.
|
||||
</Note>
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="defineRole" description="Configurați permisiunile rolurilor și accesul la obiecte">
|
||||
|
||||
Roles encapsulate permissions on your workspace's objects and actions.
|
||||
Rolurile încapsulează permisiuni asupra obiectelor și acțiunilor din spațiul dvs. de lucru.
|
||||
|
||||
```ts restricted-company-role.ts
|
||||
import {
|
||||
@@ -69,12 +69,12 @@ export default defineRole({
|
||||
</Accordion>
|
||||
<Accordion title="defineApplication" description="Configurați metadatele aplicației (obligatoriu, una per aplicație)">
|
||||
|
||||
Every app must have exactly one `defineApplication` call that describes:
|
||||
Fiecare aplicație trebuie să aibă exact un apel `defineApplication` care descrie:
|
||||
|
||||
* **Identity**: identifiers, display name, and description.
|
||||
* **Permissions**: which role its functions and front components use.
|
||||
* **(Optional) Variables**: key–value pairs exposed to your functions as environment variables.
|
||||
* **(Optional) Pre-install / post-install functions**: logic functions that run before or after installation.
|
||||
* **Identitate**: identificatori, nume de afișare și descriere.
|
||||
* **Permisiuni**: ce rol folosesc funcțiile și componentele front-end ale acesteia.
|
||||
* **(Opțional) Variabile**: perechi cheie–valoare expuse funcțiilor ca variabile de mediu.
|
||||
* **(Opțional) funcții de pre-instalare / post-instalare**: funcții logice care rulează înainte sau după instalare.
|
||||
|
||||
```ts src/application-config.ts
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
@@ -98,21 +98,21 @@ export default defineApplication({
|
||||
```
|
||||
|
||||
Notițe:
|
||||
* `universalIdentifier` fields are deterministic IDs you own. Generate them once and keep them stable across syncs.
|
||||
* `applicationVariables` become environment variables for your functions and front components (e.g., `DEFAULT_RECIPIENT_NAME` is available as `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
* `defaultRoleUniversalIdentifier` must reference a role defined with `defineRole()` (see above).
|
||||
* Pre-install and post-install functions are detected automatically during the manifest build — you do not need to reference them in `defineApplication()`.
|
||||
* Câmpurile `universalIdentifier` sunt ID-uri deterministe pe care le dețineți. Generați-le o singură dată și mențineți-le stabile între sincronizări.
|
||||
* `applicationVariables` devin variabile de mediu pentru funcțiile și componentele front-end (de exemplu, `DEFAULT_RECIPIENT_NAME` este disponibil ca `process.env.DEFAULT_RECIPIENT_NAME`).
|
||||
* `defaultRoleUniversalIdentifier` trebuie să facă referire la un rol definit cu `defineRole()` (vezi mai sus).
|
||||
* Funcțiile de pre-instalare și post-instalare sunt detectate automat în timpul construirii manifestului — nu trebuie să le referiți în `defineApplication()`.
|
||||
|
||||
#### Metadate pentru marketplace
|
||||
|
||||
If you plan to [publish your app](/l/ro/developers/extend/apps/publishing), these optional fields control how it appears in the marketplace:
|
||||
Dacă intenționați să [publicați aplicația](/l/ro/developers/extend/apps/publishing), aceste câmpuri opționale controlează modul în care apare în marketplace:
|
||||
|
||||
| Câmp | Descriere |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `autor` | Numele autorului sau al companiei |
|
||||
| `categorie` | Categoria aplicației pentru filtrarea în marketplace |
|
||||
| `logoUrl` | Path to your app logo (e.g., `public/logo.png`) |
|
||||
| `screenshots` | Array of screenshot paths (e.g., `public/screenshot-1.png`) |
|
||||
| `logoUrl` | Calea către logo-ul aplicației (de ex., `public/logo.png`) |
|
||||
| `screenshots` | Array de căi către capturi de ecran (de ex., `public/screenshot-1.png`) |
|
||||
| `aboutDescription` | Descriere markdown mai lungă pentru fila "About". Dacă este omis, marketplace-ul folosește `README.md` al pachetului de pe npm |
|
||||
| `websiteUrl` | Link către site-ul dvs. |
|
||||
| `termsUrl` | Link către termenii de serviciu |
|
||||
@@ -121,15 +121,15 @@ If you plan to [publish your app](/l/ro/developers/extend/apps/publishing), thes
|
||||
|
||||
#### Roluri și permisiuni
|
||||
|
||||
The `defaultRoleUniversalIdentifier` in `application-config.ts` designates the default role used by your app's logic functions and front components. See `defineRole` above for details.
|
||||
Câmpul `defaultRoleUniversalIdentifier` din `application-config.ts` desemnează rolul implicit utilizat de funcțiile logice și componentele front-end ale aplicației. Consultați `defineRole` mai sus pentru detalii.
|
||||
|
||||
* The runtime token injected as `TWENTY_APP_ACCESS_TOKEN` is derived from this role.
|
||||
* The typed client is restricted to the permissions granted to that role.
|
||||
* Follow least-privilege: create a dedicated role with only the permissions your functions need.
|
||||
* Tokenul de runtime injectat ca `TWENTY_APP_ACCESS_TOKEN` este derivat din acest rol.
|
||||
* Clientul tipizat este restricționat la permisiunile acordate acelui rol.
|
||||
* Respectați principiul celui mai mic privilegiu: creați un rol dedicat doar cu permisiunile de care au nevoie funcțiile.
|
||||
|
||||
##### Default function role
|
||||
##### Rol implicit pentru funcții
|
||||
|
||||
When you scaffold a new app, the CLI creates a default role file:
|
||||
Când generați o aplicație nouă, CLI creează un fișier de rol implicit:
|
||||
|
||||
```ts src/roles/default-role.ts
|
||||
import { defineRole, PermissionFlag } from 'twenty-sdk';
|
||||
@@ -155,16 +155,16 @@ export default defineRole({
|
||||
});
|
||||
```
|
||||
|
||||
This role's `universalIdentifier` is referenced in `application-config.ts` as `defaultRoleUniversalIdentifier`:
|
||||
`universalIdentifier` al acestui rol este apoi referențiat în `application-config.ts` ca `defaultRoleUniversalIdentifier`.
|
||||
|
||||
* **\*.role.ts** defines what the role can do.
|
||||
* **\*.role.ts** definește ce poate face rolul.
|
||||
* **application-config.ts** indică acel rol, astfel încât funcțiile moștenesc permisiunile lui.
|
||||
|
||||
Notițe:
|
||||
* Porniți de la rolul generat, apoi restrângeți-l progresiv urmând principiul celui mai mic privilegiu.
|
||||
* Replace `objectPermissions` and `fieldPermissions` with the objects and fields your functions actually need.
|
||||
* `permissionFlags` controlează accesul la capabilități la nivelul platformei. Keep them minimal.
|
||||
* See a working example: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
|
||||
* Înlocuiți `objectPermissions` și `fieldPermissions` cu obiectele și câmpurile de care au nevoie efectiv funcțiile.
|
||||
* `permissionFlags` controlează accesul la capabilități la nivelul platformei. Mențineți-le la minimum.
|
||||
* Vedeți un exemplu funcțional: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineObject" description="Definiți obiecte personalizate cu câmpuri">
|
||||
@@ -256,7 +256,7 @@ dar acest lucru nu este recomandat.
|
||||
</Note>
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineField — Standard fields" description="Extindeți obiectele existente cu câmpuri suplimentare">
|
||||
<Accordion title="defineField — Câmpuri standard" description="Extindeți obiectele existente cu câmpuri suplimentare">
|
||||
|
||||
Utilizați `defineField()` pentru a adăuga câmpuri la obiecte pe care nu le dețineți — cum ar fi obiectele standard Twenty (Person, Company etc.). sau obiecte din alte aplicații. Spre deosebire de câmpurile inline din `defineObject()`, câmpurile independente necesită un `objectUniversalIdentifier` pentru a specifica obiectul pe care îl extind:
|
||||
|
||||
@@ -284,7 +284,7 @@ Puncte cheie:
|
||||
* `defineField()` este singura modalitate de a adăuga câmpuri la obiecte pe care nu le-ați creat cu `defineObject()`.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineField — Relation fields" description="Connect objects together with bidirectional relations">
|
||||
<Accordion title="defineField — Câmpuri de relație" description="Conectați obiectele între ele cu relații bidirecționale">
|
||||
|
||||
Relațiile conectează obiectele între ele. În Twenty, relațiile sunt întotdeauna bidirecționale — definiți ambele părți, iar fiecare parte o referențiază pe cealaltă.
|
||||
|
||||
@@ -443,7 +443,7 @@ export default defineObject({
|
||||
});
|
||||
```
|
||||
</Accordion>
|
||||
<Accordion title="defineLogicFunction" description="Define logic functions and their triggers">
|
||||
<Accordion title="defineLogicFunction" description="Definiți funcții logice și declanșatoarele acestora">
|
||||
|
||||
Fiecare fișier de funcție folosește `defineLogicFunction()` pentru a exporta o configurație cu un handler și declanșatoare opționale.
|
||||
|
||||
@@ -487,15 +487,15 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
Available trigger types:
|
||||
* **httpRoute**: Exposes your function on an HTTP path and method **under the `/s/` endpoint**:
|
||||
> e.g. `path: '/post-card/create'` is callable at `https://your-twenty-server.com/s/post-card/create`
|
||||
Tipuri de declanșatoare disponibile:
|
||||
* **httpRoute**: Expune funcția pe o cale și metodă HTTP **sub endpoint-ul `/s/`**:
|
||||
> de ex. `path: '/post-card/create'` este apelabil la `https://your-twenty-server.com/s/post-card/create`
|
||||
* **cron**: Rulează funcția pe un program folosind o expresie CRON.
|
||||
* **databaseEvent**: Rulează la evenimentele ciclului de viață ale obiectelor din spațiul de lucru. Când operațiunea evenimentului este `updated`, câmpurile specifice de urmărit pot fi specificate în array-ul `updatedFields`. Dacă este lăsat nedefinit sau gol, orice actualizare va declanșa funcția.
|
||||
> e.g. `person.updated`, `*.created`, `company.*`
|
||||
> de ex. `person.updated`, `*.created`, `company.*`
|
||||
|
||||
<Note>
|
||||
You can also manually execute a function using the CLI:
|
||||
Puteți, de asemenea, să executați manual o funcție folosind CLI:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty exec -n create-new-post-card -p '{"key": "value"}'
|
||||
@@ -505,7 +505,7 @@ yarn twenty exec -n create-new-post-card -p '{"key": "value"}'
|
||||
yarn twenty exec -y e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf
|
||||
```
|
||||
|
||||
You can watch logs with:
|
||||
Puteți urmări jurnalele cu:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty logs
|
||||
@@ -514,9 +514,9 @@ yarn twenty logs
|
||||
|
||||
#### Payload-ul declanșatorului de rută
|
||||
|
||||
When a route trigger invokes your logic function, it receives a `RoutePayload` object that follows the
|
||||
Când un declanșator de rută invocă funcția logică, aceasta primește un obiect `RoutePayload` care urmează
|
||||
[AWS HTTP API v2 format](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html).
|
||||
Import the `RoutePayload` type from `twenty-sdk`:
|
||||
Importați tipul `RoutePayload` din `twenty-sdk`:
|
||||
|
||||
```ts
|
||||
import { defineLogicFunction, type RoutePayload } from 'twenty-sdk';
|
||||
@@ -533,9 +533,9 @@ Tipul `RoutePayload` are următoarea structură:
|
||||
|
||||
| Proprietate | Tip | Descriere | Exemplu |
|
||||
| ---------------------------- | ------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record<string, string \| undefined>` | Anteturi HTTP (doar cele listate în `forwardedRequestHeaders`) | see section below |
|
||||
| `headers` | `Record<string, string \| undefined>` | Anteturi HTTP (doar cele listate în `forwardedRequestHeaders`) | consultați secțiunea de mai jos |
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Parametri query string (valorile multiple unite cu virgule) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Path parameters extracted from the route pattern | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Parametri de cale extrași din modelul rutei | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Corpul cererii analizat (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `isBase64Encoded` | `boolean` | Indică dacă corpul este codificat în base64 | |
|
||||
| `requestContext.http.method` | `string` | Metoda HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
@@ -545,7 +545,7 @@ Tipul `RoutePayload` are următoarea structură:
|
||||
#### forwardedRequestHeaders
|
||||
|
||||
În mod implicit, anteturile HTTP din cererile de intrare **nu** sunt transmise funcției dvs. de logică din motive de securitate.
|
||||
To access specific headers, list them in the `forwardedRequestHeaders` array:
|
||||
Pentru a accesa anumite anteturi, listează-le explicit în array-ul `forwardedRequestHeaders`:
|
||||
|
||||
```ts
|
||||
export default defineLogicFunction({
|
||||
@@ -561,7 +561,7 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
In your handler, access the forwarded headers like this:
|
||||
În handler, accesați anteturile transmise mai departe astfel:
|
||||
|
||||
```ts
|
||||
const handler = async (event: RoutePayload) => {
|
||||
@@ -574,14 +574,14 @@ const handler = async (event: RoutePayload) => {
|
||||
```
|
||||
|
||||
<Note>
|
||||
Numele anteturilor sunt normalizate la litere mici. Access them using lowercase keys (e.g., `event.headers['content-type']`).
|
||||
Numele anteturilor sunt normalizate la litere mici. Accesați-le folosind chei cu litere mici (de exemplu, `event.headers['content-type']`).
|
||||
</Note>
|
||||
|
||||
#### Exposing a function as a tool
|
||||
#### Expunerea unei funcții ca instrument
|
||||
|
||||
Funcțiile logice pot fi expuse ca **instrumente** pentru agenți de IA și fluxuri de lucru. When marked as a tool, a function becomes discoverable by Twenty's AI features and can be used in workflow automations.
|
||||
Funcțiile logice pot fi expuse ca **instrumente** pentru agenți de IA și fluxuri de lucru. Când este marcată ca instrument, o funcție poate fi descoperită de funcționalitățile de IA ale Twenty și poate fi utilizată în automatizări ale fluxurilor de lucru.
|
||||
|
||||
To mark a logic function as a tool, set `isTool: true`:
|
||||
Pentru a marca o funcție logică drept instrument, setați `isTool: true`:
|
||||
|
||||
```ts src/logic-functions/enrich-company.logic-function.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
@@ -617,8 +617,8 @@ export default defineLogicFunction({
|
||||
|
||||
Puncte cheie:
|
||||
|
||||
* You can combine `isTool` with triggers — a function can be both a tool (callable by AI agents) and triggered by events at the same time.
|
||||
* **`toolInputSchema`** (optional): A JSON Schema object describing the parameters your function accepts. The schema is computed automatically from source code static analysis, but you can set it explicitly:
|
||||
* Puteți combina `isTool` cu declanșatoare — o funcție poate fi atât un instrument (apelabilă de agenții AI), cât și declanșată de evenimente în același timp.
|
||||
* **`toolInputSchema`** (opțional): Un obiect JSON Schema care descrie parametrii pe care îi acceptă funcția dvs. Schema este calculată automat prin analiză statică a codului sursă, dar o puteți seta explicit:
|
||||
|
||||
```ts
|
||||
export default defineLogicFunction({
|
||||
@@ -715,11 +715,11 @@ Puncte cheie:
|
||||
</Accordion>
|
||||
<Accordion title="defineFrontComponent" description="Definiți componente Front pentru interfața de utilizator personalizată">
|
||||
|
||||
Front components are React components that render directly inside Twenty's UI. They run in an **isolated Web Worker** using Remote DOM — your code is sandboxed but renders natively in the page, not in an iframe.
|
||||
Componentele front-end sunt componente React care se afișează direct în interfața Twenty. Rulează într-un **Web Worker** izolat folosind Remote DOM — codul este izolat (sandboxed), dar se redă nativ în pagină, nu într-un iframe.
|
||||
|
||||
#### Basic example
|
||||
#### Exemplu de bază
|
||||
|
||||
The quickest way to see a front component in action is to register it as a **command**. Adding a `command` field with `isPinned: true` makes it appear as a quick-action button in the top-right corner of the page — no page layout needed:
|
||||
Cel mai rapid mod de a vedea o componentă front-end în acțiune este să o înregistrați ca o **comandă**. Adăugarea unui câmp `command` cu `isPinned: true` o face să apară ca un buton de acțiune rapidă în colțul din dreapta sus al paginii — nu este nevoie de layout de pagină:
|
||||
|
||||
```tsx src/front-components/hello-world.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
@@ -749,34 +749,34 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
After syncing with `yarn twenty dev`, the quick action appears in the top-right corner of the page:
|
||||
După sincronizarea cu `yarn twenty dev`, acțiunea rapidă apare în colțul din dreapta sus al paginii:
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img src="/images/docs/developers/extends/apps/quick-action.png" alt="Quick action button in the top-right corner" />
|
||||
<img src="/images/docs/developers/extends/apps/quick-action.png" alt="Buton de acțiune rapidă în colțul din dreapta sus" />
|
||||
</div>
|
||||
|
||||
Click it to render the component inline.
|
||||
Faceți clic pe el pentru a afișa componenta inline.
|
||||
|
||||
{/* TODO: add screenshot of the rendered front component */}
|
||||
|
||||
#### Configuration fields
|
||||
#### Câmpuri de configurare
|
||||
|
||||
| Câmp | Obligatoriu | Descriere |
|
||||
| --------------------- | ----------- | ----------------------------------------------------------------------------------- |
|
||||
| `universalIdentifier` | Da | Stable unique ID for this component |
|
||||
| `component` | Da | A React component function |
|
||||
| `name` | Nu | Display name |
|
||||
| `description` | Nu | Description of what the component does |
|
||||
| `isHeadless` | Nu | Set to `true` if the component has no visible UI (see below) |
|
||||
| `command` | Nu | Register the component as a command (see [command options](#command-options) below) |
|
||||
| Câmp | Obligatoriu | Descriere |
|
||||
| --------------------- | ----------- | ------------------------------------------------------------------------------------------------ |
|
||||
| `universalIdentifier` | Da | ID unic stabil pentru această componentă |
|
||||
| `component` | Da | O funcție de componentă React |
|
||||
| `name` | Nu | Nume afișat |
|
||||
| `description` | Nu | Descriere a ceea ce face componenta |
|
||||
| `isHeadless` | Nu | Setați la `true` dacă componenta nu are UI vizibilă (vezi mai jos) |
|
||||
| `command` | Nu | Înregistrați componenta ca o comandă (consultați [opțiunile comenzii](#command-options) mai jos) |
|
||||
|
||||
#### Placing a front component on a page
|
||||
#### Plasarea unei componente front-end pe o pagină
|
||||
|
||||
Beyond commands, you can embed a front component directly into a record page by adding it as a widget in a **page layout**. See the [definePageLayout](#definepagelayout) section for details.
|
||||
Dincolo de comenzi, puteți încorpora o componentă front-end direct într-o pagină de înregistrare adăugând-o ca widget într-un **layout de pagină**. Consultați secțiunea [definePageLayout](#definepagelayout) pentru detalii.
|
||||
|
||||
#### Headless components (`isHeadless: true`)
|
||||
#### Componente headless (`isHeadless: true`)
|
||||
|
||||
Headless components render no visible UI but still run React logic. This is useful for **effect components** — components that perform side effects when mounted, such as syncing data, starting a timer, listening to events, or triggering a notification.
|
||||
Componentele headless nu redau nicio interfață vizibilă, dar rulează în continuare logica React. Acest lucru este util pentru **componente de efect** — componente care execută efecte secundare la montare, cum ar fi sincronizarea datelor, pornirea unui cronometru, ascultarea evenimentelor sau declanșarea unei notificări.
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent, useRecordId, enqueueSnackbar } from 'twenty-sdk';
|
||||
@@ -801,11 +801,11 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
Because the component returns `null`, Twenty skips rendering a container for it — no empty space appears in the layout. The component still has access to all hooks and the host communication API.
|
||||
Deoarece componenta returnează `null`, Twenty omite redarea unui container pentru ea — nu apare spațiu gol în layout. Componenta are în continuare acces la toate hook-urile și la API-ul de comunicare cu gazda.
|
||||
|
||||
#### Accessing runtime context
|
||||
#### Accesarea contextului de rulare
|
||||
|
||||
Inside your component, use SDK hooks to access the current user, record, and component instance:
|
||||
În interiorul componentei, folosiți hook-urile SDK pentru a accesa utilizatorul curent, înregistrarea curentă și instanța componentei:
|
||||
|
||||
```tsx src/front-components/record-info.tsx
|
||||
import {
|
||||
@@ -836,47 +836,47 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
Available hooks:
|
||||
Hook-uri disponibile:
|
||||
|
||||
| Hook | Returns | Descriere |
|
||||
| --------------------------------------------- | ------------------ | ---------------------------------------------------------- |
|
||||
| `useUserId()` | `string` or `null` | The current user's ID |
|
||||
| `useRecordId()` | `string` or `null` | The current record's ID (when placed on a record page) |
|
||||
| `useFrontComponentId()` | `string` | This component instance's ID |
|
||||
| `useFrontComponentExecutionContext(selector)` | variază | Access the full execution context with a selector function |
|
||||
| Hook | Returnează | Descriere |
|
||||
| --------------------------------------------- | ------------------- | --------------------------------------------------------------------------- |
|
||||
| `useUserId()` | `string` sau `null` | ID-ul utilizatorului curent |
|
||||
| `useRecordId()` | `string` sau `null` | ID-ul înregistrării curente (când este plasată pe o pagină de înregistrare) |
|
||||
| `useFrontComponentId()` | `string` | ID-ul acestei instanțe de componentă |
|
||||
| `useFrontComponentExecutionContext(selector)` | variază | Accesați întregul context de execuție cu o funcție selector |
|
||||
|
||||
#### Host communication API
|
||||
#### API-ul de comunicare cu gazda
|
||||
|
||||
Front components can trigger navigation, modals, and notifications using functions from `twenty-sdk`:
|
||||
Componentele front-end pot declanșa navigare, ferestre modale și notificări folosind funcții din `twenty-sdk`:
|
||||
|
||||
| Funcție | Descriere |
|
||||
| ----------------------------------------------- | ----------------------------- |
|
||||
| `navigate(to, params?, queryParams?, options?)` | Navigate to a page in the app |
|
||||
| `openSidePanelPage(params)` | Open a side panel |
|
||||
| `closeSidePanel()` | Close the side panel |
|
||||
| `openCommandConfirmationModal(params)` | Show a confirmation dialog |
|
||||
| `enqueueSnackbar(params)` | Show a toast notification |
|
||||
| `unmountFrontComponent()` | Unmount the component |
|
||||
| `updateProgress(progress)` | Update a progress indicator |
|
||||
| Funcție | Descriere |
|
||||
| ----------------------------------------------- | ----------------------------------- |
|
||||
| `navigate(to, params?, queryParams?, options?)` | Navigați la o pagină din aplicație |
|
||||
| `openSidePanelPage(params)` | Deschideți un panou lateral |
|
||||
| `closeSidePanel()` | Închideți panoul lateral |
|
||||
| `openCommandConfirmationModal(params)` | Afișați un dialog de confirmare |
|
||||
| `enqueueSnackbar(params)` | Afișați o notificare tip toast |
|
||||
| `unmountFrontComponent()` | Demontați componenta |
|
||||
| `updateProgress(progress)` | Actualizați un indicator de progres |
|
||||
|
||||
#### Command options
|
||||
#### Opțiuni pentru comandă
|
||||
|
||||
Adding a `command` field to `defineFrontComponent` registers the component in the command menu (Cmd+K). If `isPinned` is `true`, it also appears as a quick-action button in the top-right corner of the page.
|
||||
Adăugarea unui câmp `command` la `defineFrontComponent` înregistrează componenta în meniul de comenzi (Cmd+K). Dacă `isPinned` este `true`, apare și ca buton de acțiune rapidă în colțul din dreapta sus al paginii.
|
||||
|
||||
| Câmp | Obligatoriu | Descriere |
|
||||
| --------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `universalIdentifier` | Da | Stable unique ID for the command |
|
||||
| `label` | Da | Full label shown in the command menu (Cmd+K) |
|
||||
| `shortLabel` | Nu | Shorter label displayed on the pinned quick-action button |
|
||||
| `icon` | Nu | Icon name displayed next to the label (e.g. `'IconBolt'`, `'IconSend'`) |
|
||||
| `isPinned` | Nu | When `true`, shows the command as a quick-action button in the top-right corner of the page |
|
||||
| `availabilityType` | Nu | Controls where the command appears: `'GLOBAL'` (always available), `'RECORD_SELECTION'` (only when records are selected), or `'FALLBACK'` (shown when no other commands match) |
|
||||
| `availabilityObjectUniversalIdentifier` | Nu | Restrict the command to pages of a specific object type (e.g. only on Company records) |
|
||||
| `conditionalAvailabilityExpression` | Nu | A boolean expression to dynamically control whether the command is visible (see below) |
|
||||
| Câmp | Obligatoriu | Descriere |
|
||||
| --------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `universalIdentifier` | Da | ID unic stabil pentru comandă |
|
||||
| `label` | Da | Etichetă completă afișată în meniul de comenzi (Cmd+K) |
|
||||
| `shortLabel` | Nu | Etichetă mai scurtă afișată pe butonul de acțiune rapidă fixat |
|
||||
| `icon` | Nu | Numele pictogramei afișat lângă etichetă (de ex. `'IconBolt'`, `'IconSend'`) |
|
||||
| `isPinned` | Nu | Când este `true`, afișează comanda ca buton de acțiune rapidă în colțul din dreapta sus al paginii |
|
||||
| `availabilityType` | Nu | Controlează unde apare comanda: `'GLOBAL'` (mereu disponibilă), `'RECORD_SELECTION'` (doar când sunt selectate înregistrări) sau `'FALLBACK'` (afișată când nicio altă comandă nu se potrivește) |
|
||||
| `availabilityObjectUniversalIdentifier` | Nu | Restricționați comanda la paginile unui anumit tip de obiect (de ex., doar pe înregistrările Company) |
|
||||
| `conditionalAvailabilityExpression` | Nu | O expresie booleană pentru a controla dinamic dacă comanda este vizibilă (vezi mai jos) |
|
||||
|
||||
#### Conditional availability expressions
|
||||
#### Expresii de disponibilitate condițională
|
||||
|
||||
The `conditionalAvailabilityExpression` field lets you control when a command is visible based on the current page context. Import typed variables and operators from `twenty-sdk` to build expressions:
|
||||
Câmpul `conditionalAvailabilityExpression` vă permite să controlați când este vizibilă o comandă în funcție de contextul paginii curente. Importați variabile tipizate și operatori din `twenty-sdk` pentru a construi expresii:
|
||||
|
||||
```tsx
|
||||
import {
|
||||
@@ -905,45 +905,45 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
**Context variables** — these represent the current state of the page:
|
||||
**Variabile de context** — acestea reprezintă starea curentă a paginii:
|
||||
|
||||
| Variabilă | Tip | Descriere |
|
||||
| ------------------------------ | --------- | ---------------------------------------------------------------- |
|
||||
| `pageType` | `string` | Current page type (e.g. `'RecordIndexPage'`, `'RecordShowPage'`) |
|
||||
| `isInSidePanel` | `boolean` | Whether the component is rendered in a side panel |
|
||||
| `numberOfSelectedRecords` | `number` | Number of currently selected records |
|
||||
| `isSelectAll` | `boolean` | Whether "select all" is active |
|
||||
| `selectedRecords` | `array` | The selected record objects |
|
||||
| `favoriteRecordIds` | `array` | IDs of favorited records |
|
||||
| `objectPermissions` | `object` | Permissions for the current object type |
|
||||
| `targetObjectReadPermissions` | `object` | Read permissions for the target object |
|
||||
| `targetObjectWritePermissions` | `object` | Write permissions for the target object |
|
||||
| `featureFlags` | `object` | Active feature flags |
|
||||
| `objectMetadataItem` | `object` | Metadata of the current object type |
|
||||
| `hasAnySoftDeleteFilterOnView` | `boolean` | Whether the current view has a soft-delete filter |
|
||||
| Variabilă | Tip | Descriere |
|
||||
| ------------------------------ | --------- | ---------------------------------------------------------------------- |
|
||||
| `pageType` | `string` | Tipul paginii curente (de ex. `'RecordIndexPage'`, `'RecordShowPage'`) |
|
||||
| `isInSidePanel` | `boolean` | Dacă componenta este redată într-un panou lateral |
|
||||
| `numberOfSelectedRecords` | `number` | Numărul de înregistrări selectate în prezent |
|
||||
| `isSelectAll` | `boolean` | Dacă "select all" este activ |
|
||||
| `selectedRecords` | `array` | Obiectele înregistrărilor selectate |
|
||||
| `favoriteRecordIds` | `array` | ID-urile înregistrărilor marcate ca favorite |
|
||||
| `objectPermissions` | `object` | Permisiuni pentru tipul de obiect curent |
|
||||
| `targetObjectReadPermissions` | `object` | Permisiuni de citire pentru obiectul țintă |
|
||||
| `targetObjectWritePermissions` | `object` | Permisiuni de scriere pentru obiectul țintă |
|
||||
| `featureFlags` | `object` | Steaguri de caracteristici active |
|
||||
| `objectMetadataItem` | `object` | Metadatele tipului de obiect curent |
|
||||
| `hasAnySoftDeleteFilterOnView` | `boolean` | Dacă vizualizarea curentă are un filtru soft-delete |
|
||||
|
||||
**Operators** — combine variables into boolean expressions:
|
||||
**Operatori** — combinați variabilele în expresii booleene:
|
||||
|
||||
| Operator | Descriere |
|
||||
| ----------------------------------- | ----------------------------------------------------------------- |
|
||||
| `isDefined(value)` | `true` if the value is not null/undefined |
|
||||
| `isNonEmptyString(value)` | `true` if the value is a non-empty string |
|
||||
| `includes(array, value)` | `true` if the array contains the value |
|
||||
| `includesEvery(array, prop, value)` | `true` if every item's property includes the value |
|
||||
| `every(array, prop)` | `true` if the property is truthy on every item |
|
||||
| `everyDefined(array, prop)` | `true` if the property is defined on every item |
|
||||
| `everyEquals(array, prop, value)` | `true` if the property equals the value on every item |
|
||||
| `some(array, prop)` | `true` if the property is truthy on at least one item |
|
||||
| `someDefined(array, prop)` | `true` if the property is defined on at least one item |
|
||||
| `someEquals(array, prop, value)` | `true` if the property equals the value on at least one item |
|
||||
| `someNonEmptyString(array, prop)` | `true` if the property is a non-empty string on at least one item |
|
||||
| `none(array, prop)` | `true` if the property is falsy on every item |
|
||||
| `noneDefined(array, prop)` | `true` if the property is undefined on every item |
|
||||
| `noneEquals(array, prop, value)` | `true` if the property does not equal the value on any item |
|
||||
| Operator | Descriere |
|
||||
| ----------------------------------- | ----------------------------------------------------------------------- |
|
||||
| `isDefined(value)` | `true` dacă valoarea nu este null/undefined |
|
||||
| `isNonEmptyString(value)` | `true` dacă valoarea este un șir nevid |
|
||||
| `includes(array, value)` | `true` dacă array-ul conține valoarea |
|
||||
| `includesEvery(array, prop, value)` | `true` dacă proprietatea fiecărui element include valoarea |
|
||||
| `every(array, prop)` | `true` dacă proprietatea este truthy pentru fiecare element |
|
||||
| `everyDefined(array, prop)` | `true` dacă proprietatea este definită pentru fiecare element |
|
||||
| `everyEquals(array, prop, value)` | `true` dacă proprietatea este egală cu valoarea pentru fiecare element |
|
||||
| `some(array, prop)` | `true` dacă proprietatea este truthy pe cel puțin un element |
|
||||
| `someDefined(array, prop)` | `true` dacă proprietatea este definită pe cel puțin un element |
|
||||
| `someEquals(array, prop, value)` | `true` dacă proprietatea este egală cu valoarea pe cel puțin un element |
|
||||
| `someNonEmptyString(array, prop)` | `true` dacă proprietatea este un șir nevid pe cel puțin un element |
|
||||
| `none(array, prop)` | `true` dacă proprietatea este falsy pentru fiecare element |
|
||||
| `noneDefined(array, prop)` | `true` dacă proprietatea este nedefinită pentru fiecare element |
|
||||
| `noneEquals(array, prop, value)` | `true` dacă proprietatea nu este egală cu valoarea pe niciun element |
|
||||
|
||||
#### Public assets
|
||||
#### Resurse publice
|
||||
|
||||
Front components can access files from the app's `public/` directory using `getPublicAssetUrl`:
|
||||
Componentele front-end pot accesa fișiere din directorul `public/` al aplicației folosind `getPublicAssetUrl`:
|
||||
|
||||
```tsx
|
||||
import { defineFrontComponent, getPublicAssetUrl } from 'twenty-sdk';
|
||||
@@ -957,18 +957,18 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
See the [public assets section](#accessing-public-assets-with-getpublicasseturl) for details.
|
||||
Consultați [secțiunea despre resurse publice](#accessing-public-assets-with-getpublicasseturl) pentru detalii.
|
||||
|
||||
#### Stilizare
|
||||
|
||||
Front components support multiple styling approaches. You can use:
|
||||
Componentele front-end acceptă mai multe abordări de stilizare. Puteți folosi:
|
||||
|
||||
* **Inline styles** — `style={{ color: 'red' }}`
|
||||
* **Twenty UI components** — import from `twenty-sdk/ui` (Button, Tag, Status, Chip, Avatar, and more)
|
||||
* **Emotion** — CSS-in-JS with `@emotion/react`
|
||||
* **Styled-components** — `styled.div` patterns
|
||||
* **Tailwind CSS** — utility classes
|
||||
* **Any CSS-in-JS library** compatible with React
|
||||
* **Stiluri inline** — `style={{ color: 'red' }}`
|
||||
* **Componente Twenty UI** — import din `twenty-sdk/ui` (Button, Tag, Status, Chip, Avatar și altele)
|
||||
* **Emotion** — CSS-in-JS cu `@emotion/react`
|
||||
* **Styled-components** — pattern-uri `styled.div`
|
||||
* **Tailwind CSS** — clase utilitare
|
||||
* **Orice bibliotecă CSS-in-JS** compatibilă cu React
|
||||
|
||||
```tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
@@ -1022,9 +1022,9 @@ Puncte cheie:
|
||||
* `description` (opțional) oferă context suplimentar despre scopul abilității.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineAgent" description="Define AI agents with custom prompts">
|
||||
<Accordion title="defineAgent" description="Definiți agenți AI cu prompturi personalizate">
|
||||
|
||||
Agents are AI assistants that live inside your workspace. Use `defineAgent()` to create agents with a custom system prompt:
|
||||
Agenții sunt asistenți AI care există în interiorul spațiului dvs. de lucru. Utilizați `defineAgent()` pentru a crea agenți cu un prompt de sistem personalizat:
|
||||
|
||||
```ts src/agents/example-agent.ts
|
||||
import { defineAgent } from 'twenty-sdk';
|
||||
@@ -1040,17 +1040,17 @@ export default defineAgent({
|
||||
```
|
||||
|
||||
Puncte cheie:
|
||||
* `name` is the unique identifier string for the agent (kebab-case recommended).
|
||||
* `label` is the display name shown in the UI.
|
||||
* `prompt` is the system prompt that defines the agent's behavior.
|
||||
* `description` (optional) provides context about what the agent does.
|
||||
* `name` este un șir identificator unic pentru agent (se recomandă kebab-case).
|
||||
* `label` este numele de afișare din interfața cu utilizatorul (UI).
|
||||
* `prompt` conține promptul de sistem — acesta este textul de instrucțiuni care definește comportamentul agentului.
|
||||
* `description` (opțional) oferă context suplimentar despre scopul agentului.
|
||||
* `icon` (opțional) setează pictograma afișată în UI.
|
||||
* `modelId` (optional) overrides the default AI model used by the agent.
|
||||
* `modelId` (opțional) suprascrie modelul AI implicit utilizat de agent.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineView" description="Definește vizualizări salvate pentru obiecte">
|
||||
|
||||
Views are saved configurations for how records of an object are displayed — including which fields are visible, their order, and any filters or groups applied. Use `defineView()` to ship pre-configured views with your app:
|
||||
Vizualizările sunt configurații salvate despre cum sunt afișate înregistrările unui obiect — inclusiv ce câmpuri sunt vizibile, ordinea lor și orice filtre sau grupuri aplicate. Utilizați `defineView()` pentru a livra vizualizări preconfigurate împreună cu aplicația:
|
||||
|
||||
```ts src/views/example-view.ts
|
||||
import { defineView, ViewKey } from 'twenty-sdk';
|
||||
@@ -1077,16 +1077,16 @@ export default defineView({
|
||||
```
|
||||
|
||||
Puncte cheie:
|
||||
* `objectUniversalIdentifier` specifies which object this view applies to.
|
||||
* `key` determines the view type (e.g., `ViewKey.INDEX` for the main list view).
|
||||
* `fields` controls which columns appear and their order. Each field references a `fieldMetadataUniversalIdentifier`.
|
||||
* You can also define `filters`, `filterGroups`, `groups`, and `fieldGroups` for more advanced configurations.
|
||||
* `position` controls the ordering when multiple views exist for the same object.
|
||||
* `objectUniversalIdentifier` specifică la ce obiect se aplică această vizualizare.
|
||||
* `key` determină tipul vizualizării (de ex., `ViewKey.INDEX` pentru vizualizarea principală de listă).
|
||||
* `fields` controlează ce coloane apar și ordinea acestora. Fiecare câmp face referire la un `fieldMetadataUniversalIdentifier`.
|
||||
* Puteți defini, de asemenea, `filters`, `filterGroups`, `groups` și `fieldGroups` pentru configurații mai avansate.
|
||||
* `position` controlează ordonarea atunci când există mai multe vizualizări pentru același obiect.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="defineNavigationMenuItem" description="Definește linkuri de navigare în bara laterală">
|
||||
|
||||
Navigation menu items add custom entries to the workspace sidebar. Use `defineNavigationMenuItem()` to link to views, external URLs, or objects:
|
||||
Elementele de meniu de navigare adaugă intrări personalizate în bara laterală a spațiului de lucru. Utilizați `defineNavigationMenuItem()` pentru a lega la vizualizări, URL-uri externe sau obiecte:
|
||||
|
||||
```ts src/navigation-menu-items/example-navigation-menu-item.ts
|
||||
import { defineNavigationMenuItem, NavigationMenuItemType } from 'twenty-sdk';
|
||||
@@ -1104,15 +1104,15 @@ export default defineNavigationMenuItem({
|
||||
```
|
||||
|
||||
Puncte cheie:
|
||||
* `type` determines what the menu item links to: `NavigationMenuItemType.VIEW` for a saved view, or `NavigationMenuItemType.LINK` for an external URL.
|
||||
* For view links, set `viewUniversalIdentifier`. For external links, set `link`.
|
||||
* `position` controls the ordering in the sidebar.
|
||||
* `icon` and `color` (optional) customize the appearance.
|
||||
* `type` determină la ce face trimitere elementul de meniu: `NavigationMenuItemType.VIEW` pentru o vizualizare salvată sau `NavigationMenuItemType.LINK` pentru un URL extern.
|
||||
* Pentru link-uri către vizualizări, setați `viewUniversalIdentifier`. Pentru link-uri externe, setați `link`.
|
||||
* `position` controlează ordonarea în bara laterală.
|
||||
* `icon` și `color` (opțional) personalizează aspectul.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="definePageLayout" description="Define custom page layouts for record views">
|
||||
<Accordion title="definePageLayout" description="Definiți machete de pagină personalizate pentru vizualizările de înregistrare">
|
||||
|
||||
Page layouts let you customize how a record detail page looks — which tabs appear, what widgets are inside each tab, and how they are arranged. Use `definePageLayout()` to ship custom layouts with your app:
|
||||
Machetele de pagină vă permit să personalizați aspectul unei pagini de detalii a unei înregistrări — ce file apar, ce widgeturi sunt în fiecare filă și cum sunt aranjate. Utilizați `definePageLayout()` pentru a livra machete personalizate împreună cu aplicația:
|
||||
|
||||
```ts src/page-layouts/example-record-page-layout.ts
|
||||
import { definePageLayout, PageLayoutTabLayoutMode } from 'twenty-sdk';
|
||||
@@ -1149,33 +1149,33 @@ export default definePageLayout({
|
||||
```
|
||||
|
||||
Puncte cheie:
|
||||
* `type` is typically `'RECORD_PAGE'` to customize the detail view of a specific object.
|
||||
* `objectUniversalIdentifier` specifies which object this layout applies to.
|
||||
* Each `tab` defines a section of the page with a `title`, `position`, and `layoutMode` (`CANVAS` for free-form layout).
|
||||
* Each `widget` inside a tab can render a front component, a relation list, or other built-in widget types.
|
||||
* `position` on tabs controls their order. Use higher values (e.g., 50) to place custom tabs after built-in ones.
|
||||
* `type` este de obicei `'RECORD_PAGE'` pentru a personaliza vizualizarea de detaliu a unui obiect specific.
|
||||
* `objectUniversalIdentifier` specifică la ce obiect se aplică această machetă.
|
||||
* Fiecare `tab` definește o secțiune a paginii cu un `title`, `position` și `layoutMode` (`CANVAS` pentru layout liber).
|
||||
* Fiecare `widget` dintr-o filă poate reda o componentă frontend, o listă de relații sau alte tipuri de widgeturi integrate.
|
||||
* `position` pe file le controlează ordinea. Folosiți valori mai mari (de ex., 50) pentru a plasa filele personalizate după cele integrate.
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Public assets (`public/` folder)
|
||||
## Resurse publice (folderul `public/`)
|
||||
|
||||
The `public/` folder at the root of your app holds static files — images, icons, fonts, or any other assets your app needs at runtime. These files are automatically included in builds, synced during dev mode, and uploaded to the server.
|
||||
Folderul `public/` din rădăcina aplicației conține fișiere statice — imagini, pictograme, fonturi sau orice alte resurse de care are nevoie aplicația la rulare. Aceste fișiere sunt incluse automat în build-uri, sincronizate în timpul modului de dezvoltare și încărcate pe server.
|
||||
|
||||
Files placed in `public/` are:
|
||||
Fișierele plasate în `public/` sunt:
|
||||
|
||||
* **Publicly accessible** — once synced to the server, assets are served at a public URL. No authentication is needed to access them.
|
||||
* **Available in front components** — use asset URLs to display images, icons, or any media inside your React components.
|
||||
* **Available in logic functions** — reference asset URLs in emails, API responses, or any server-side logic.
|
||||
* **Used for marketplace metadata** — the `logoUrl` and `screenshots` fields in `defineApplication()` reference files from this folder (e.g., `public/logo.png`). These are displayed in the marketplace when your app is published.
|
||||
* **Auto-synced in dev mode** — when you add, update, or delete a file in `public/`, it is synced to the server automatically. No restart needed.
|
||||
* **Included in builds** — `yarn twenty build` bundles all public assets into the distribution output.
|
||||
* **Accesibile public** — odată sincronizate pe server, resursele sunt servite la un URL public. Nu este necesară autentificarea pentru a le accesa.
|
||||
* **Disponibile în componentele frontend** — folosiți URL-urile resurselor pentru a afișa imagini, pictograme sau orice media în componentele React.
|
||||
* **Disponibile în funcțiile logice** — referiți URL-urile resurselor în e-mailuri, răspunsuri API sau orice logică pe server.
|
||||
* **Utilizate pentru metadatele marketplace-ului** — câmpurile `logoUrl` și `screenshots` din `defineApplication()` fac referire la fișiere din acest folder (de ex., `public/logo.png`). Acestea sunt afișate în marketplace când aplicația este publicată.
|
||||
* **Sincronizate automat în modul de dezvoltare** — când adăugați, actualizați sau ștergeți un fișier în `public/`, acesta este sincronizat automat cu serverul. Nu este nevoie de repornire.
|
||||
* **Incluse în build-uri** — `yarn twenty build` împachetează toate resursele publice în outputul de distribuție.
|
||||
|
||||
### Accessing public assets with `getPublicAssetUrl`
|
||||
### Accesarea resurselor publice cu `getPublicAssetUrl`
|
||||
|
||||
Use the `getPublicAssetUrl` helper from `twenty-sdk` to get the full URL of a file in your `public/` directory. It works in both **logic functions** and **front components**.
|
||||
Utilizați helperul `getPublicAssetUrl` din `twenty-sdk` pentru a obține URL-ul complet al unui fișier din directorul `public/`. Funcționează atât în funcții logice, cât și în componente frontend.
|
||||
|
||||
**In a logic function:**
|
||||
**Într-o funcție logică:**
|
||||
|
||||
```ts src/logic-functions/send-invoice.ts
|
||||
import { defineLogicFunction, getPublicAssetUrl } from 'twenty-sdk';
|
||||
@@ -1200,7 +1200,7 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
**In a front component:**
|
||||
**Într-o componentă frontend:**
|
||||
|
||||
```tsx src/front-components/company-card.tsx
|
||||
import { defineFrontComponent, getPublicAssetUrl } from 'twenty-sdk';
|
||||
@@ -1212,19 +1212,19 @@ export default defineFrontComponent(() => {
|
||||
});
|
||||
```
|
||||
|
||||
The `path` argument is relative to your app's `public/` folder. Both `getPublicAssetUrl('logo.png')` and `getPublicAssetUrl('public/logo.png')` resolve to the same URL — the `public/` prefix is stripped automatically if present.
|
||||
Argumentul `path` este relativ la folderul `public/` al aplicației. Atât `getPublicAssetUrl('logo.png')`, cât și `getPublicAssetUrl('public/logo.png')` se rezolvă la același URL — prefixul `public/` este eliminat automat dacă este prezent.
|
||||
|
||||
## Using npm packages
|
||||
## Utilizarea pachetelor npm
|
||||
|
||||
You can install and use any npm package in your app. Both logic functions and front components are bundled with [esbuild](https://esbuild.github.io/), which inlines all dependencies into the output — no `node_modules` are needed at runtime.
|
||||
Puteți instala și utiliza orice pachet npm în aplicația dvs. Atât funcțiile logice, cât și componentele frontend sunt împachetate cu [esbuild](https://esbuild.github.io/), care integrează toate dependențele în output — nu sunt necesare `node_modules` la rulare.
|
||||
|
||||
### Installing a package
|
||||
### Instalarea unui pachet
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn add axios
|
||||
```
|
||||
|
||||
Then import it in your code:
|
||||
Apoi importați-l în codul dvs.:
|
||||
|
||||
```ts src/logic-functions/fetch-data.ts
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
@@ -1245,7 +1245,7 @@ export default defineLogicFunction({
|
||||
});
|
||||
```
|
||||
|
||||
The same works for front components:
|
||||
Același lucru funcționează și pentru componentele frontend:
|
||||
|
||||
```tsx src/front-components/chart.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
@@ -1262,27 +1262,27 @@ export default defineFrontComponent({
|
||||
});
|
||||
```
|
||||
|
||||
### How bundling works
|
||||
### Cum funcționează împachetarea
|
||||
|
||||
The build step (`yarn twenty dev` or `yarn twenty build`) uses esbuild to produce a single self-contained file per logic function and per front component. All imported packages are inlined into the bundle.
|
||||
Pasul de build (`yarn twenty dev` sau `yarn twenty build`) folosește esbuild pentru a produce un singur fișier autonom per funcție logică și per componentă frontend. Toate pachetele importate sunt integrate în bundle.
|
||||
|
||||
**Logic functions** run in a Node.js environment. Node built-in modules (`fs`, `path`, `crypto`, `http`, etc.) are available and do not need to be installed.
|
||||
**Funcțiile logice** rulează într-un mediu Node.js. Modulele built-in Node (`fs`, `path`, `crypto`, `http` etc.) sunt disponibile și nu trebuie instalate.
|
||||
|
||||
**Front components** run in a Web Worker. Node built-in modules are **not** available — only browser APIs and npm packages that work in a browser environment.
|
||||
**Componentele frontend** rulează într-un Web Worker. Modulele built-in Node nu sunt disponibile — doar API-urile de browser și pachetele npm care funcționează într-un mediu de browser.
|
||||
|
||||
Both environments have `twenty-client-sdk/core` and `twenty-client-sdk/metadata` available as pre-provided modules — these are not bundled but resolved at runtime by the server.
|
||||
Ambele medii au `twenty-client-sdk/core` și `twenty-client-sdk/metadata` disponibile ca module pre-furnizate — acestea nu sunt incluse în bundle, ci sunt rezolvate la rulare de către server.
|
||||
|
||||
## Scaffolding entities with `yarn twenty add`
|
||||
## Generarea scheletului entităților cu `yarn twenty add`
|
||||
|
||||
Instead of creating entity files by hand, you can use the interactive scaffolder:
|
||||
În loc să creați manual fișiere de entități, puteți folosi generatorul interactiv (scaffolder):
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty add
|
||||
```
|
||||
|
||||
This prompts you to pick an entity type and walks you through the required fields. It generates a ready-to-use file with a stable `universalIdentifier` and the correct `defineEntity()` call.
|
||||
Acesta vă solicită să alegeți un tip de entitate și vă ghidează prin câmpurile necesare. Generează un fișier gata de utilizare, cu un `universalIdentifier` stabil și apelul corect `defineEntity()`.
|
||||
|
||||
You can also pass the entity type directly to skip the first prompt:
|
||||
Puteți de asemenea să transmiteți direct tipul de entitate pentru a sări peste primul prompt:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty add object
|
||||
@@ -1290,44 +1290,44 @@ yarn twenty add logicFunction
|
||||
yarn twenty add frontComponent
|
||||
```
|
||||
|
||||
### Available entity types
|
||||
### Tipuri de entități disponibile
|
||||
|
||||
| Tipul entității | Comandă | Generated file |
|
||||
| -------------------- | ------------------------------------ | ------------------------------------- |
|
||||
| Obiect | `yarn twenty add object` | `src/objects/<name>.ts` |
|
||||
| Câmp | `yarn twenty add field` | `src/fields/<name>.ts` |
|
||||
| Logic function | `yarn twenty add logicFunction` | `src/logic-functions/<name>.ts` |
|
||||
| Front component | `yarn twenty add frontComponent` | `src/front-components/<name>.tsx` |
|
||||
| Rol | `yarn twenty add role` | `src/roles/<name>.ts` |
|
||||
| Abilitate | `yarn twenty add skill` | `src/skills/<name>.ts` |
|
||||
| Agent | `yarn twenty add agent` | `src/agents/<name>.ts` |
|
||||
| Vizualizare | `yarn twenty add view` | `src/views/<name>.ts` |
|
||||
| Navigation menu item | `yarn twenty add navigationMenuItem` | `src/navigation-menu-items/<name>.ts` |
|
||||
| Page layout | `yarn twenty add pageLayout` | `src/page-layouts/<name>.ts` |
|
||||
| Tipul entității | Comandă | Fișier generat |
|
||||
| ---------------------------- | ------------------------------------ | ------------------------------------- |
|
||||
| Obiect | `yarn twenty add object` | `src/objects/<name>.ts` |
|
||||
| Câmp | `yarn twenty add field` | `src/fields/<name>.ts` |
|
||||
| Funcție logică | `yarn twenty add logicFunction` | `src/logic-functions/<name>.ts` |
|
||||
| Componentă frontend | `yarn twenty add frontComponent` | `src/front-components/<name>.tsx` |
|
||||
| Rol | `yarn twenty add role` | `src/roles/<name>.ts` |
|
||||
| Abilitate | `yarn twenty add skill` | `src/skills/<name>.ts` |
|
||||
| Agent | `yarn twenty add agent` | `src/agents/<name>.ts` |
|
||||
| Vizualizare | `yarn twenty add view` | `src/views/<name>.ts` |
|
||||
| Element de meniu de navigare | `yarn twenty add navigationMenuItem` | `src/navigation-menu-items/<name>.ts` |
|
||||
| Machetă de pagină | `yarn twenty add pageLayout` | `src/page-layouts/<name>.ts` |
|
||||
|
||||
### What the scaffolder generates
|
||||
### Ce generează scaffolder-ul
|
||||
|
||||
Each entity type has its own template. For example, `yarn twenty add object` asks for:
|
||||
Fiecare tip de entitate are propriul său șablon. De exemplu, `yarn twenty add object` solicită:
|
||||
|
||||
1. **Name (singular)** — e.g., `invoice`
|
||||
2. **Name (plural)** — e.g., `invoices`
|
||||
3. **Label (singular)** — auto-populated from the name (e.g., `Invoice`)
|
||||
4. **Label (plural)** — auto-populated (e.g., `Invoices`)
|
||||
5. **Create a view and navigation item?** — if you answer yes, the scaffolder also generates a matching view and sidebar link for the new object.
|
||||
1. **Nume (singular)** — de ex., `invoice`
|
||||
2. **Nume (plural)** — de ex., `invoices`
|
||||
3. **Etichetă (singular)** — completată automat din nume (de ex., `Invoice`)
|
||||
4. **Etichetă (plural)** — completată automat (de ex., `Invoices`)
|
||||
5. **Creați o vizualizare și un element de navigare?** — dacă răspundeți afirmativ, scaffolder-ul generează, de asemenea, o vizualizare corespunzătoare și un link în bara laterală pentru noul obiect.
|
||||
|
||||
Other entity types have simpler prompts — most only ask for a name.
|
||||
Alte tipuri de entități au prompturi mai simple — majoritatea cer doar un nume.
|
||||
|
||||
The `field` entity type is more detailed: it asks for the field name, label, type (from a list of all available field types like `TEXT`, `NUMBER`, `SELECT`, `RELATION`, etc.), and the target object's `universalIdentifier`.
|
||||
Tipul de entitate `field` este mai detaliat: solicită numele câmpului, eticheta, tipul (dintr-o listă cu toate tipurile de câmp disponibile precum `TEXT`, `NUMBER`, `SELECT`, `RELATION` etc.) și `universalIdentifier` al obiectului țintă.
|
||||
|
||||
### Custom output path
|
||||
### Cale de output personalizată
|
||||
|
||||
Use the `--path` flag to place the generated file in a custom location:
|
||||
Utilizați opțiunea `--path` pentru a plasa fișierul generat într-o locație personalizată:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty add logicFunction --path src/custom-folder
|
||||
```
|
||||
|
||||
## Typed API clients (twenty-client-sdk)
|
||||
## Clienți API tipizați (twenty-client-sdk)
|
||||
|
||||
Pachetul `twenty-client-sdk` oferă doi clienți GraphQL tipați pentru a interacționa cu API-ul Twenty din funcțiile de logică și componentele Front.
|
||||
|
||||
@@ -1337,9 +1337,9 @@ Pachetul `twenty-client-sdk` oferă doi clienți GraphQL tipați pentru a intera
|
||||
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — configurarea spațiului de lucru, încărcări de fișiere | Nu, este livrat preconstruit |
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="CoreApiClient" description="Query and mutate workspace data (records, objects)">
|
||||
<Accordion title="CoreApiClient" description="Interogați și modificați datele spațiului de lucru (înregistrări, obiecte)">
|
||||
|
||||
`CoreApiClient` este clientul principal pentru interogarea și modificarea datelor din spațiul de lucru. It is **generated from your workspace schema** during `yarn twenty dev` or `yarn twenty build`, so it is fully typed to match your objects and fields.
|
||||
`CoreApiClient` este clientul principal pentru interogarea și modificarea datelor din spațiul de lucru. Este generat din schema spațiului de lucru în timpul `yarn twenty dev` sau `yarn twenty build`, astfel încât este complet tipizat pentru a corespunde obiectelor și câmpurilor dvs.
|
||||
|
||||
```ts
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
@@ -1379,12 +1379,12 @@ const { createCompany } = await client.mutation({
|
||||
Clientul folosește o sintaxă de tip selection-set: transmiteți `true` pentru a include un câmp, folosiți `__args` pentru argumente și imbricați obiecte pentru relații. Obțineți autocompletare și verificare a tipurilor complete, pe baza schemei spațiului dvs. de lucru.
|
||||
|
||||
<Note>
|
||||
**CoreApiClient is generated at dev/build time.** If you use it without running `yarn twenty dev` or `yarn twenty build` first, it throws an error. The generation happens automatically — the CLI introspects your workspace's GraphQL schema and generates a typed client using `@genql/cli`.
|
||||
**CoreApiClient este generat în timpul dev/build.** Dacă îl utilizați fără a rula mai întâi `yarn twenty dev` sau `yarn twenty build`, va arunca o eroare. Generarea are loc automat — CLI inspectează schema GraphQL a spațiului dvs. de lucru și generează un client tipizat folosind `@genql/cli`.
|
||||
</Note>
|
||||
|
||||
#### Folosirea CoreSchema pentru adnotări de tip
|
||||
|
||||
`CoreSchema` provides TypeScript types matching your workspace objects — useful for typing component state or function parameters:
|
||||
`CoreSchema` oferă tipuri TypeScript care corespund obiectelor din spațiul dvs. de lucru — utile pentru tiparea stării componentelor sau a parametrilor funcțiilor:
|
||||
|
||||
```ts
|
||||
import { CoreApiClient, CoreSchema } from 'twenty-client-sdk/core';
|
||||
@@ -1406,7 +1406,7 @@ setCompany(result.company);
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="MetadataApiClient" description="Workspace config, applications, and file uploads">
|
||||
<Accordion title="MetadataApiClient" description="Configurația spațiului de lucru, aplicații și încărcări de fișiere">
|
||||
|
||||
`MetadataApiClient` este livrat preconstruit împreună cu SDK-ul (nu este necesară generarea). Interoghează endpointul `/metadata` pentru configurarea spațiului de lucru, aplicații și încărcări de fișiere.
|
||||
|
||||
@@ -1462,7 +1462,7 @@ console.log(uploadedFile);
|
||||
| ---------------------------------- | -------- | ------------------------------------------------------------------ |
|
||||
| `fileBuffer` | `Buffer` | Conținutul brut al fișierului |
|
||||
| `filename` | `string` | Numele fișierului (folosit pentru stocare și afișare) |
|
||||
| `contentType` | `string` | MIME type (defaults to `application/octet-stream` if omitted) |
|
||||
| `contentType` | `string` | Tipul MIME (implicit `application/octet-stream` dacă este omis) |
|
||||
| `fieldMetadataUniversalIdentifier` | `string` | `universalIdentifier` al câmpului de tip fișier de pe obiectul tău |
|
||||
|
||||
Puncte cheie:
|
||||
@@ -1476,24 +1476,24 @@ Puncte cheie:
|
||||
Când codul dvs. rulează pe Twenty (funcții de logică sau componente Front), platforma injectează acreditările ca variabile de mediu:
|
||||
|
||||
* `TWENTY_API_URL` — URL-ul de bază al API-ului Twenty
|
||||
* `TWENTY_APP_ACCESS_TOKEN` — Short-lived key scoped to your application's default function role
|
||||
* `TWENTY_APP_ACCESS_TOKEN` — Cheie cu durată scurtă, limitată la rolul implicit de funcție al aplicației
|
||||
|
||||
Nu trebuie să le transmiteți clienților — aceștia citesc automat din `process.env`. Permisiunile cheii API sunt determinate de rolul referențiat în `defaultRoleUniversalIdentifier` din `application-config.ts`.
|
||||
</Note>
|
||||
|
||||
## Testing your app
|
||||
## Testarea aplicației
|
||||
|
||||
The SDK provides programmatic APIs that let you build, deploy, install, and uninstall your app from test code. Combined with [Vitest](https://vitest.dev/) and the typed API clients, you can write integration tests that verify your app works end-to-end against a real Twenty server.
|
||||
SDK-ul oferă API-uri programatice care vă permit să construiți, să distribuiți, să instalați și să dezinstalați aplicația din codul de test. Combinat cu [Vitest](https://vitest.dev/) și clienții API tipizați, puteți scrie teste de integrare care verifică faptul că aplicația funcționează cap-coadă împotriva unui server Twenty real.
|
||||
|
||||
### Configurare
|
||||
|
||||
The scaffolded app already includes Vitest. If you set it up manually, install the dependencies:
|
||||
Aplicația generată (scaffolded) include deja Vitest. Dacă o configurați manual, instalați dependențele:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn add -D vitest vite-tsconfig-paths
|
||||
```
|
||||
|
||||
Create a `vitest.config.ts` at the root of your app:
|
||||
Creați un `vitest.config.ts` în rădăcina aplicației:
|
||||
|
||||
```ts vitest.config.ts
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
@@ -1519,7 +1519,7 @@ export default defineConfig({
|
||||
});
|
||||
```
|
||||
|
||||
Create a setup file that verifies the server is reachable before tests run:
|
||||
Creați un fișier de configurare care verifică faptul că serverul este accesibil înainte de rularea testelor:
|
||||
|
||||
```ts src/__tests__/setup-test.ts
|
||||
import * as fs from 'fs';
|
||||
@@ -1559,22 +1559,22 @@ beforeAll(async () => {
|
||||
});
|
||||
```
|
||||
|
||||
### Programmatic SDK APIs
|
||||
### API-uri SDK programatice
|
||||
|
||||
The `twenty-sdk/cli` subpath exports functions you can call directly from test code:
|
||||
Subruta `twenty-sdk/cli` exportă funcții pe care le puteți apela direct din codul de test:
|
||||
|
||||
| Funcție | Descriere |
|
||||
| -------------- | ------------------------------------------- |
|
||||
| `appBuild` | Build the app and optionally pack a tarball |
|
||||
| `appDeploy` | Upload a tarball to the server |
|
||||
| `appInstall` | Install the app on the active workspace |
|
||||
| `appUninstall` | Uninstall the app from the active workspace |
|
||||
| Funcție | Descriere |
|
||||
| -------------- | --------------------------------------------------------- |
|
||||
| `appBuild` | Construiți aplicația și, opțional, împachetați un tarball |
|
||||
| `appDeploy` | Încărcați un tarball pe server |
|
||||
| `appInstall` | Instalați aplicația în spațiul de lucru activ |
|
||||
| `appUninstall` | Dezinstalați aplicația din spațiul de lucru activ |
|
||||
|
||||
Each function returns a result object with `success: boolean` and either `data` or `error`.
|
||||
Fiecare funcție returnează un obiect rezultat cu `success: boolean` și fie `data`, fie `error`.
|
||||
|
||||
### Writing an integration test
|
||||
### Scrierea unui test de integrare
|
||||
|
||||
Here is a full example that builds, deploys, and installs the app, then verifies it appears in the workspace:
|
||||
Iată un exemplu complet care construiește, distribuie și instalează aplicația, apoi verifică faptul că aceasta apare în spațiul de lucru:
|
||||
|
||||
```ts src/__tests__/app-install.integration-test.ts
|
||||
import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/application-config';
|
||||
@@ -1637,37 +1637,37 @@ describe('App installation', () => {
|
||||
});
|
||||
```
|
||||
|
||||
### Running tests
|
||||
### Rularea testelor
|
||||
|
||||
Make sure your local Twenty server is running, then:
|
||||
Asigurați-vă că serverul Twenty local rulează, apoi:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn test
|
||||
```
|
||||
|
||||
Or in watch mode during development:
|
||||
Sau în modul watch în timpul dezvoltării:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn test:watch
|
||||
```
|
||||
|
||||
### Type checking
|
||||
### Verificarea tipurilor
|
||||
|
||||
You can also run type checking on your app without running tests:
|
||||
Puteți rula și verificarea tipurilor pe aplicație fără a rula testele:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty typecheck
|
||||
```
|
||||
|
||||
This runs `tsc --noEmit` and reports any type errors.
|
||||
Aceasta rulează `tsc --noEmit` și raportează orice erori de tip.
|
||||
|
||||
## Referință CLI
|
||||
|
||||
Beyond `dev`, `build`, `add`, and `typecheck`, the CLI provides commands for executing functions, viewing logs, and managing app installations.
|
||||
Dincolo de `dev`, `build`, `add` și `typecheck`, CLI oferă comenzi pentru executarea funcțiilor, vizualizarea jurnalelor și gestionarea instalărilor de aplicații.
|
||||
|
||||
### Executing functions (`yarn twenty exec`)
|
||||
### Executarea funcțiilor (`yarn twenty exec`)
|
||||
|
||||
Run a logic function manually without triggering it via HTTP, cron, or database event:
|
||||
Rulați manual o funcție logică fără a o declanșa prin HTTP, cron sau eveniment de bază de date:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Execute by function name
|
||||
@@ -1684,9 +1684,9 @@ yarn twenty exec --preInstall
|
||||
yarn twenty exec --postInstall
|
||||
```
|
||||
|
||||
### Viewing function logs (`yarn twenty logs`)
|
||||
### Vizualizarea jurnalelor funcțiilor (`yarn twenty logs`)
|
||||
|
||||
Stream execution logs for your app's logic functions:
|
||||
Transmiteți în flux jurnalele de execuție pentru funcțiile logice ale aplicației:
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Stream all function logs
|
||||
@@ -1700,12 +1700,12 @@ yarn twenty logs -u e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf
|
||||
```
|
||||
|
||||
<Note>
|
||||
This is different from `yarn twenty server logs`, which shows the Docker container logs. `yarn twenty logs` shows your app's function execution logs from the Twenty server.
|
||||
Acest lucru este diferit de `yarn twenty server logs`, care afișează jurnalele containerului Docker. `yarn twenty logs` afișează jurnalele de execuție ale funcțiilor aplicației de pe serverul Twenty.
|
||||
</Note>
|
||||
|
||||
### Uninstalling an app (`yarn twenty uninstall`)
|
||||
### Dezinstalarea unei aplicații (`yarn twenty uninstall`)
|
||||
|
||||
Remove your app from the active workspace:
|
||||
Eliminați aplicația din spațiul de lucru activ:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty uninstall
|
||||
|
||||
Reference in New Issue
Block a user