i18n - docs translations (#19314)
Created by Github action Co-authored-by: github-actions <github-actions@twenty.com>
This commit is contained in:
committed by
GitHub
parent
4ba2f3b184
commit
0b8421a45a
@@ -81,7 +81,7 @@ import { defineApplication } from 'twenty-sdk';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7',
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
displayName: 'My Twenty App',
|
||||
description: 'My first Twenty app',
|
||||
icon: 'IconWorld',
|
||||
@@ -716,6 +716,13 @@ yarn twenty exec --postInstall
|
||||
|
||||
المكوّنات الأمامية هي مكوّنات React تُعرَض مباشرة داخل واجهة مستخدم Twenty. تعمل ضمن **Web Worker** معزول باستخدام Remote DOM — تكون شيفرتك في صندوق عزل لكنها تُعرَض أصيلًا داخل الصفحة، وليس ضمن iframe.
|
||||
|
||||
#### أين يمكن استخدام مكوّنات الواجهة الأمامية
|
||||
|
||||
يمكن عرض مكوّنات الواجهة الأمامية في موقعين داخل Twenty:
|
||||
|
||||
* **اللوحة الجانبية** — المكوّنات غير عديمة الرأس تفتح في اللوحة الجانبية اليمنى. هذا هو السلوك الافتراضي عندما يتم تشغيل مكوّن واجهة أمامية من قائمة الأوامر.
|
||||
* **الويدجت (لوحات المعلومات وصفحات السجلات)** — يمكن تضمين مكوّنات الواجهة الأمامية كويدجت داخل تخطيطات الصفحات. عند تكوين لوحة معلومات أو تخطيط صفحة سجل، يمكن للمستخدمين إضافة ويدجت لمكوّن واجهة أمامية.
|
||||
|
||||
#### مثال أساسي
|
||||
|
||||
أسرع طريقة لرؤية مكوّن أمامي قيد العمل هي تسجيله كأمر. إضافة حقل `command` مع `isPinned: true` يجعلُه يظهر كزر إجراء سريع في الزاوية العلوية اليمنى من الصفحة — دون الحاجة إلى تخطيط صفحة:
|
||||
@@ -773,9 +780,13 @@ export default defineFrontComponent({
|
||||
|
||||
إضافةً إلى الأوامر، يمكنك تضمين مكوّن أمامي مباشرةً في صفحة سجل عبر إضافته كودجت في **تخطيط صفحة**. راجع قسم [definePageLayout](#definepagelayout) للتفاصيل.
|
||||
|
||||
#### مكوّنات عديمة الواجهة (`isHeadless: true`)
|
||||
#### عديم الرأس مقابل غير عديم الرأس
|
||||
|
||||
المكوّنات عديمة الواجهة لا تُظهر واجهة مرئية لكنها ما تزال تُشغِّل منطق React. يكون هذا مفيدًا لـ **مكوّنات التأثير** — وهي مكوّنات تُجري تأثيرات جانبية عند التثبيت، مثل مزامنة البيانات، بدء مؤقّت، الاستماع إلى الأحداث، أو إطلاق إشعار.
|
||||
تأتي مكوّنات الواجهة الأمامية بوضعَي عرض يتحكّم بهما الخيار `isHeadless`:
|
||||
|
||||
**غير عديم الرأس (افتراضي)** — يعرض المكوّن واجهة مستخدم مرئية. عند تشغيله من قائمة الأوامر يفتح في اللوحة الجانبية. هذا هو السلوك الافتراضي عندما تكون `isHeadless` تساوي `false` أو يتم تجاهلها.
|
||||
|
||||
**عديم الرأس (`isHeadless: true`)** — يتم تركيب المكوّن بشكل غير مرئي في الخلفية. لا يفتح اللوحة الجانبية. تم تصميم المكوّنات عديمة الرأس لإجراءات تنفّذ منطقًا ثم تُزيل تركيبها ذاتيًا — على سبيل المثال، تشغيل مهمة غير متزامنة، أو الانتقال إلى صفحة، أو إظهار نافذة تأكيد منبثقة. تتوافق بشكل طبيعي مع مكوّنات Command في SDK الموصوفة أدناه.
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent, useRecordId, enqueueSnackbar } from 'twenty-sdk';
|
||||
@@ -802,6 +813,89 @@ export default defineFrontComponent({
|
||||
|
||||
نظرًا لأن المكوّن يُرجع `null`، فإن Twenty يتخطّى عرض حاوية له — ولن تظهر مساحة فارغة في التخطيط. لا يزال لدى المكوّن إمكانية الوصول إلى جميع الخطافات وواجهة برمجة الاتصال مع المضيف.
|
||||
|
||||
#### مكوّنات Command في SDK
|
||||
|
||||
توفر حزمة `twenty-sdk` أربعة مكوّنات مساعدة من نوع Command مصممة للمكوّنات عديمة الرأس في الواجهة الأمامية. كل مكوّن ينفّذ إجراءً عند التركيب، ويتعامل مع الأخطاء بعرض إشعار Snackbar، ويزيل تركيب مكوّن الواجهة الأمامية تلقائيًا عند الانتهاء.
|
||||
|
||||
استوردها من `twenty-sdk/command`:
|
||||
|
||||
* **`Command`** — يشغّل رد نداء غير متزامن عبر الخاصية `execute`.
|
||||
* **`CommandLink`** — ينتقل إلى مسار في التطبيق. الخصائص: `to`، `params`، `queryParams`، `options`.
|
||||
* **`CommandModal`** — يفتح نافذة تأكيد منبثقة. إذا أكّد المستخدم، ينفّذ رد النداء `execute`. الخصائص: `title`، `subtitle`، `execute`، `confirmButtonText`، `confirmButtonAccent`.
|
||||
* **`CommandOpenSidePanelPage`** — يفتح صفحة محدّدة في اللوحة الجانبية. الخصائص: `page`، `pageTitle`، `pageIcon`.
|
||||
|
||||
فيما يلي مثال كامل لمكوّن واجهة أمامية عديم الرأس يستخدم `Command` لتشغيل إجراء من قائمة الأوامر:
|
||||
|
||||
```tsx src/front-components/run-action.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const RunAction = () => {
|
||||
const execute = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
createTask: {
|
||||
__args: { data: { title: 'Created by my app' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
||||
name: 'run-action',
|
||||
description: 'Creates a task from the command menu',
|
||||
component: RunAction,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
|
||||
label: 'Run my action',
|
||||
icon: 'IconPlayerPlay',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
ومثال يستخدم `CommandModal` لطلب التأكيد قبل التنفيذ:
|
||||
|
||||
```tsx src/front-components/delete-draft.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { CommandModal } from 'twenty-sdk/command';
|
||||
|
||||
const DeleteDraft = () => {
|
||||
const execute = async () => {
|
||||
// perform the deletion
|
||||
};
|
||||
|
||||
return (
|
||||
<CommandModal
|
||||
title="Delete draft?"
|
||||
subtitle="This action cannot be undone."
|
||||
execute={execute}
|
||||
confirmButtonText="Delete"
|
||||
confirmButtonAccent="danger"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'a7b8c9d0-e1f2-3456-abcd-567890123456',
|
||||
name: 'delete-draft',
|
||||
description: 'Deletes a draft with confirmation',
|
||||
component: DeleteDraft,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'b8c9d0e1-f2a3-4567-bcde-678901234567',
|
||||
label: 'Delete draft',
|
||||
icon: 'IconTrash',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### الوصول إلى سياق وقت التشغيل
|
||||
|
||||
داخل مكوّنك، استخدم خطافات SDK للوصول إلى المستخدم الحالي، والسجل، ومثيل المكوّن:
|
||||
@@ -858,6 +952,50 @@ export default defineFrontComponent({
|
||||
| `unmountFrontComponent()` | إلغاء تركيب المكوّن |
|
||||
| `updateProgress(progress)` | تحديث مؤشّر التقدّم |
|
||||
|
||||
فيما يلي مثال يستخدم واجهة برمجة تطبيقات المضيف لعرض Snackbar وإغلاق اللوحة الجانبية بعد اكتمال الإجراء:
|
||||
|
||||
```tsx src/front-components/archive-record.tsx
|
||||
import { defineFrontComponent, useRecordId } from 'twenty-sdk';
|
||||
import { enqueueSnackbar, closeSidePanel } from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const ArchiveRecord = () => {
|
||||
const recordId = useRecordId();
|
||||
|
||||
const handleArchive = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
updateTask: {
|
||||
__args: { id: recordId, data: { status: 'ARCHIVED' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
await enqueueSnackbar({
|
||||
message: 'Record archived',
|
||||
variant: 'success',
|
||||
});
|
||||
|
||||
await closeSidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<p>Archive this record?</p>
|
||||
<button onClick={handleArchive}>Archive</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'c9d0e1f2-a3b4-5678-cdef-789012345678',
|
||||
name: 'archive-record',
|
||||
description: 'Archives the current record',
|
||||
component: ArchiveRecord,
|
||||
});
|
||||
```
|
||||
|
||||
#### خيارات الأوامر
|
||||
|
||||
إضافة حقل `command` إلى `defineFrontComponent` تُسجِّل المكوّن في قائمة الأوامر (Cmd+K). إذا كانت قيمة `isPinned` هي `true`، فسيظهر أيضًا كزر إجراء سريع في الزاوية العلوية اليمنى من الصفحة.
|
||||
@@ -1712,3 +1850,86 @@ yarn twenty uninstall
|
||||
# Skip the confirmation prompt
|
||||
yarn twenty uninstall --yes
|
||||
```
|
||||
|
||||
## إدارة الريموتات
|
||||
|
||||
**الريموت** هو خادم Twenty يتصل به تطبيقك. أثناء الإعداد، تُنشئ أداة إنشاء الهيكل واحدًا لك تلقائيًا. يمكنك إضافة ريموتات أخرى أو التبديل بينها في أي وقت.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
تُخزَّن بيانات اعتمادك في `~/.twenty/config.json`.
|
||||
|
||||
## التكامل المستمر (CI) باستخدام GitHub Actions
|
||||
|
||||
تولّد أداة إنشاء الهيكل سير عمل GitHub Actions جاهزًا للاستخدام في `.github/workflows/ci.yml`. يشغّل اختبارات التكامل لديك تلقائيًا عند كل دفع إلى `main` وعلى طلبات السحب.
|
||||
|
||||
سير العمل:
|
||||
|
||||
1. يجلب الشيفرة الخاصة بك
|
||||
2. يشغّل خادم Twenty مؤقتًا باستخدام الإجراء `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. يثبّت التبعيات باستخدام `yarn install --immutable`
|
||||
4. يشغّل `yarn test` مع حقن `TWENTY_API_URL` و`TWENTY_API_KEY` من مخرجات الإجراء
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
لا تحتاج إلى تهيئة أي أسرار — إذ يبدأ إجراء `spawn-twenty-docker-image` خادم Twenty عابرًا مباشرة في المشغّل ويُخرِج تفاصيل الاتصال. يتم توفير السر `GITHUB_TOKEN` تلقائيًا من قِبل GitHub.
|
||||
|
||||
لتثبيت إصدار محدّد من Twenty بدلًا من `latest`، غيّر متغير البيئة `TWENTY_VERSION` في أعلى سير العمل.
|
||||
|
||||
@@ -7,7 +7,9 @@ description: أنشئ أول تطبيق Twenty خلال دقائق.
|
||||
التطبيقات حاليًا في مرحلة الألفا. الميزة تعمل لكنها لا تزال قيد التطور.
|
||||
</Warning>
|
||||
|
||||
تتيح لك التطبيقات توسيع Twenty باستخدام كائنات وحقول ووظائف منطقية ومهارات ذكاء اصطناعي ومكونات واجهة مستخدم مخصصة — جميعها تُدار ككود.
|
||||
## ما هي التطبيقات؟
|
||||
|
||||
تتيح لك التطبيقات توسيع Twenty باستخدام كائنات وحقول مخصّصة ووظائف منطقية ومكوّنات الواجهة الأمامية ومهارات الذكاء الاصطناعي وغير ذلك — جميعها تُدار ككود. بدلًا من تكوين كل شيء عبر واجهة المستخدم، تعرّف نموذج بياناتك ومنطقك في TypeScript وتقوم بنشره إلى مساحة عمل واحدة أو أكثر.
|
||||
|
||||
## المتطلبات الأساسية
|
||||
|
||||
@@ -17,7 +19,9 @@ description: أنشئ أول تطبيق Twenty خلال دقائق.
|
||||
* **Yarn 4** — يأتي مع Node.js عبر Corepack. قم بتمكينه عبر تشغيل `corepack enable`
|
||||
* **Docker** — [نزّل من هنا](https://www.docker.com/products/docker-desktop/). مطلوب لتشغيل مثيل محلي من Twenty. غير مطلوب إذا كان لديك خادم Twenty قيد التشغيل بالفعل.
|
||||
|
||||
## الخطوة 1: إنشاء هيكل تطبيقك
|
||||
## قم بإنشاء تطبيقك الأول
|
||||
|
||||
### أنشئ هيكل تطبيقك
|
||||
|
||||
افتح الطرفية وشغّل:
|
||||
|
||||
@@ -29,18 +33,7 @@ npx create-twenty-app@latest my-twenty-app
|
||||
|
||||
سيؤدي ذلك إلى إنشاء مجلد جديد باسم `my-twenty-app` يحتوي على كل ما تحتاجه.
|
||||
|
||||
<Note>
|
||||
أداة إنشاء الهيكل تدعم الأعلام التالية:
|
||||
|
||||
* `--minimal` — إنشاء الهيكل للملفات الأساسية فقط، بدون أمثلة (افتراضي)
|
||||
* `--exhaustive` — إنشاء الهيكل لجميع كيانات الأمثلة
|
||||
* `--name <name>` — تعيين اسم التطبيق (يتخطى المطالبة)
|
||||
* `--display-name <displayName>` — تعيين اسم العرض (يتخطى المطالبة)
|
||||
* `--description <description>` — تعيين الوصف (يتخطى المطالبة)
|
||||
* `--skip-local-instance` — تخطي مطالبة إعداد الخادم المحلي
|
||||
</Note>
|
||||
|
||||
## الخطوة 2: إعداد مثيل محلي من Twenty
|
||||
### إعداد مثيل محلي من Twenty
|
||||
|
||||
ستسأل أداة إنشاء الهيكل:
|
||||
|
||||
@@ -53,7 +46,7 @@ npx create-twenty-app@latest my-twenty-app
|
||||
<img src="/images/docs/developers/extends/apps/start-instance.png" alt="هل يجب بدء المثيل المحلي؟" />
|
||||
</div>
|
||||
|
||||
## الخطوة 3: سجّل الدخول إلى مساحة العمل الخاصة بك
|
||||
### سجّل الدخول إلى مساحة العمل الخاصة بك
|
||||
|
||||
بعد ذلك، ستُفتح نافذة متصفح تعرض صفحة تسجيل الدخول الخاصة بـ Twenty. سجّل الدخول باستخدام حساب العرض التوضيحي المُجهَّز مسبقًا:
|
||||
|
||||
@@ -64,7 +57,7 @@ npx create-twenty-app@latest my-twenty-app
|
||||
<img src="/images/docs/developers/extends/apps/login.png" alt="شاشة تسجيل الدخول إلى Twenty" />
|
||||
</div>
|
||||
|
||||
## الخطوة 4: تفويض التطبيق
|
||||
### قم بتفويض التطبيق
|
||||
|
||||
بعد تسجيل الدخول، ستظهر لك شاشة تفويض. يتيح هذا لتطبيقك التفاعل مع مساحة العمل الخاصة بك.
|
||||
|
||||
@@ -80,7 +73,7 @@ npx create-twenty-app@latest my-twenty-app
|
||||
<img src="/images/docs/developers/extends/apps/scaffolded.png" alt="تم إنشاء هيكل التطبيق بنجاح" />
|
||||
</div>
|
||||
|
||||
## الخطوة 5: ابدأ التطوير
|
||||
### ابدأ التطوير
|
||||
|
||||
انتقل إلى مجلد تطبيقك الجديد وابدأ خادم التطوير:
|
||||
|
||||
@@ -105,7 +98,7 @@ yarn twenty dev --verbose
|
||||
<img src="/images/docs/developers/extends/apps/dev.jpg" alt="مخرجات الطرفية في وضع التطوير" />
|
||||
</div>
|
||||
|
||||
## الخطوة 6: اعرض تطبيقك في Twenty
|
||||
### اعرض تطبيقك في Twenty
|
||||
|
||||
افتح [http://localhost:2020/settings/applications#developer](http://localhost:2020/settings/applications#developer) في متصفحك. انتقل إلى **Settings > Apps** واختر علامة التبويب **Developer**. يُفترض أن ترى تطبيقك مُدرجًا تحت **Your Apps**:
|
||||
|
||||
@@ -133,13 +126,28 @@ yarn twenty dev --verbose
|
||||
|
||||
أنت جاهز تمامًا! حرّر أي ملف في `src/` وسيتم التقاط التغييرات تلقائيًا.
|
||||
|
||||
انتقل إلى [بناء التطبيقات](/l/ar/developers/extend/apps/building) للحصول على دليل مفصّل حول إنشاء الكائنات، ودوال المنطق، ومكونات الواجهة الأمامية، والمهارات، والمزيد.
|
||||
---
|
||||
|
||||
## ما الذي يمكنك بناؤه
|
||||
|
||||
تتكون التطبيقات من **كيانات** — يُعرَّف كل منها كملف TypeScript يحتوي على `export default` واحد:
|
||||
|
||||
| كيان | ماذا يفعل |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| **الكائنات والحقول** | عرّف نماذج بيانات مخصّصة (مثل Post Card، Invoice) مع حقول محددة النوع |
|
||||
| **الوظائف المنطقية** | دوال TypeScript على جانب الخادم يتم تشغيلها عبر مسارات HTTP، وجداول cron، أو أحداث قاعدة البيانات |
|
||||
| **المكوّنات الأمامية** | مكوّنات React تُعرَض داخل واجهة مستخدم Twenty (اللوحة الجانبية، الودجات، قائمة الأوامر) |
|
||||
| **المهارات والوكلاء** | قدرات الذكاء الاصطناعي — تعليمات قابلة لإعادة الاستخدام ومساعدون مستقلون ذاتيًا |
|
||||
| **طرق العرض والتنقّل** | طرق عرض القوائم مُعدّة مسبقًا وعناصر قائمة الشريط الجانبي لكائناتك |
|
||||
| **تخطيطات الصفحات** | صفحات تفاصيل سجلات مخصصة تتضمن علامات تبويب وعناصر واجهة |
|
||||
|
||||
انتقل إلى [بناء التطبيقات](/l/ar/developers/extend/apps/building) للاطلاع على دليل مفصّل لكل نوع من الكيانات.
|
||||
|
||||
---
|
||||
|
||||
## هيكل المشروع
|
||||
|
||||
تولّد أداة إنشاء الهيكل بنية الملفات التالية (مُبيّنة بوضع `--exhaustive` الذي يتضمن أمثلة لكل نوع من الكيانات):
|
||||
تولّد أداة إنشاء الهيكل بنية الملفات التالية:
|
||||
|
||||
```text filename="my-twenty-app/"
|
||||
my-twenty-app/
|
||||
@@ -148,160 +156,50 @@ my-twenty-app/
|
||||
.gitignore
|
||||
.nvmrc
|
||||
.yarnrc.yml
|
||||
.yarn/
|
||||
install-state.gz
|
||||
.oxlintrc.json
|
||||
tsconfig.json
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
LLMS.md
|
||||
README.md
|
||||
.github/
|
||||
└── workflows/
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
src/
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── __tests__/
|
||||
│ ├── setup-test.ts # Test setup (server health check, config)
|
||||
│ └── app-install.integration-test.ts # Example integration test
|
||||
├── roles/
|
||||
│ └── default-role.ts # Default role for logic functions
|
||||
├── objects/
|
||||
│ └── example-object.ts # Example custom object definition
|
||||
├── fields/
|
||||
│ └── example-field.ts # Example standalone field definition
|
||||
├── logic-functions/
|
||||
│ ├── hello-world.ts # Example logic function
|
||||
│ ├── create-hello-world-company.ts # Example logic function using CoreApiClient
|
||||
│ ├── pre-install.ts # Runs before installation
|
||||
│ └── post-install.ts # Runs after installation
|
||||
├── front-components/
|
||||
│ └── hello-world.tsx # Example front component
|
||||
├── page-layouts/
|
||||
│ └── example-record-page-layout.ts # Example page layout with front component
|
||||
├── views/
|
||||
│ └── example-view.ts # Example saved view definition
|
||||
├── navigation-menu-items/
|
||||
│ └── example-navigation-menu-item.ts # Example sidebar navigation link
|
||||
├── skills/
|
||||
│ └── example-skill.ts # Example AI agent skill definition
|
||||
└── agents/
|
||||
└── example-agent.ts # Example AI agent definition
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── default-role.ts # Default role for logic functions
|
||||
├── constants/
|
||||
│ └── universal-identifiers.ts # Auto-generated UUIDs and app metadata
|
||||
└── __tests__/
|
||||
├── setup-test.ts # Test setup (server health check, config)
|
||||
└── app-install.integration-test.ts # Integration test
|
||||
```
|
||||
|
||||
افتراضيًا (`--minimal`)، تُنشأ الملفات الأساسية فقط: `application-config.ts`، `roles/default-role.ts`، `logic-functions/pre-install.ts`، و`logic-functions/post-install.ts`. استخدم `--exhaustive` لتضمين جميع ملفات الأمثلة الموضّحة أعلاه.
|
||||
### البدء من مثال
|
||||
|
||||
للبدء من مثال أكثر اكتمالًا يضم كائنات وحقولًا مخصّصة، ودوال المنطق، ومكوّنات الواجهة الأمامية، وغير ذلك، استخدم الخيار `--example`:
|
||||
|
||||
```bash filename="Terminal"
|
||||
npx create-twenty-app@latest my-twenty-app --example postcard
|
||||
```
|
||||
|
||||
تُستمد الأمثلة من الدليل [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples) على GitHub. يمكنك أيضًا إنشاء هيكل لكيانات فردية داخل مشروع قائم باستخدام `yarn twenty add` (انظر [بناء التطبيقات](/l/ar/developers/extend/apps/building#scaffolding-entities-with-yarn-twenty-add)).
|
||||
|
||||
### الملفات الرئيسية
|
||||
|
||||
| ملف / مجلد | الغرض |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `package.json` | يصرّح باسم تطبيقك وإصداره واعتماداته. يتضمن نصًا برمجيًا باسم `twenty` بحيث يمكنك تشغيل `yarn twenty help` للاطلاع على جميع الأوامر. |
|
||||
| `src/application-config.ts` | **مطلوب.** ملف الإعداد الرئيسي لتطبيقك. |
|
||||
| `src/roles/` | يعرِّف الأدوار التي تتحكم بما يمكن لدوال المنطق الوصول إليه. |
|
||||
| `src/logic-functions/` | دوال على جانب الخادم يتم تشغيلها عبر المسارات، وجداول cron، أو أحداث قاعدة البيانات. |
|
||||
| `src/front-components/` | مكونات React تُعرَض داخل واجهة مستخدم Twenty. |
|
||||
| `src/objects/` | تعريفات كائنات مخصّصة لتوسيع نموذج البيانات لديك. |
|
||||
| `src/fields/` | حقول مخصّصة تُضاف إلى الكائنات الموجودة. |
|
||||
| `src/views/` | تكوينات العروض المحفوظة. |
|
||||
| `src/navigation-menu-items/` | روابط مخصّصة في شريط التنقل الجانبي. |
|
||||
| `src/skills/` | مهارات توسّع قدرات وكلاء الذكاء الاصطناعي في Twenty. |
|
||||
| `src/agents/` | وكلاء ذكاء اصطناعي مع موجهات مخصّصة. |
|
||||
| `src/page-layouts/` | تخطيطات صفحات مخصّصة لعرض السجلات. |
|
||||
| `src/__tests__/` | اختبارات تكامل (إعداد + اختبار مثال). |
|
||||
| `public/` | أصول ثابتة (صور، خطوط) تُقدَّم مع تطبيقك. |
|
||||
| ملف / مجلد | الغرض |
|
||||
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `package.json` | يصرّح باسم تطبيقك وإصداره واعتماداته. يتضمن نصًا برمجيًا باسم `twenty` بحيث يمكنك تشغيل `yarn twenty help` للاطلاع على جميع الأوامر. |
|
||||
| `src/application-config.ts` | **مطلوب.** ملف الإعداد الرئيسي لتطبيقك. |
|
||||
| `src/default-role.ts` | الدور الافتراضي الذي يتحكم بما يمكن لدوال المنطق الوصول إليه. |
|
||||
| `src/constants/universal-identifiers.ts` | معرّفات UUID وبيانات التعريف للتطبيق، والمولَّدة تلقائيًا (اسم العرض، الوصف). |
|
||||
| `src/__tests__/` | اختبارات تكامل (إعداد + اختبار مثال). |
|
||||
| `public/` | أصول ثابتة (صور، خطوط) تُقدَّم مع تطبيقك. |
|
||||
|
||||
## إدارة الريموتات
|
||||
## خادم التطوير المحلي
|
||||
|
||||
**الريموت** هو خادم Twenty يتصل به تطبيقك. أثناء الإعداد، تُنشئ أداة إنشاء الهيكل واحدًا لك تلقائيًا. يمكنك إضافة ريموتات أخرى أو التبديل بينها في أي وقت.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
تُخزَّن بيانات اعتمادك في `~/.twenty/config.json`.
|
||||
|
||||
## خادم التطوير المحلي (`yarn twenty server`)
|
||||
|
||||
يمكن لأداة سطر الأوامر (CLI) إدارة خادم Twenty محلي يعمل داخل Docker. هذا هو الخادم نفسه الذي يبدأ تلقائيًا عند إنشاء هيكل تطبيق باستخدام `create-twenty-app`، لكن يمكنك أيضًا إدارته يدويًا.
|
||||
|
||||
### بدء الخادم
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start
|
||||
```
|
||||
|
||||
سيؤدي ذلك إلى سحب صورة Docker `twentycrm/twenty-app-dev:latest` (إن لم تكن موجودة بالفعل)، وإنشاء حاوية باسم `twenty-app-dev`، وبدء تشغيلها على المنفذ **2020**. تنتظر أداة CLI حتى يجتاز الخادم فحص السلامة قبل الإنهاء.
|
||||
|
||||
يتم إنشاء حجمين في Docker للاحتفاظ بالبيانات بين عمليات إعادة التشغيل:
|
||||
|
||||
* `twenty-app-dev-data` — قاعدة بيانات PostgreSQL
|
||||
* `twenty-app-dev-storage` — تخزين ملفات
|
||||
|
||||
إذا كان المنفذ 2020 مستخدمًا بالفعل، يمكنك البدء على منفذ مختلف:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start --port 3030
|
||||
```
|
||||
|
||||
تقوم أداة CLI تلقائيًا بتهيئة قيم `NODE_PORT` و`SERVER_URL` الداخلية في الحاوية لتطابق المنفذ المختار، بحيث تعمل دوال المنطق وOAuth وكل الشبكات الداخلية الأخرى بشكل صحيح.
|
||||
|
||||
بمجرد البدء، يُسجَّل الخادم تلقائيًا كـ `local` remote في إعدادات CLI لديك.
|
||||
|
||||
### التحقق من حالة الخادم
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server status
|
||||
```
|
||||
|
||||
يعرض ما إذا كان الخادم قيد التشغيل، وعنوان URL الخاص به، وبيانات اعتماد تسجيل الدخول الافتراضية (`tim@apple.dev` / `tim@apple.dev`).
|
||||
|
||||
### عرض سجلات الخادم
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs
|
||||
```
|
||||
|
||||
يبث سجلات الحاوية. استخدم `--lines` للتحكّم بعدد الأسطر الحديثة المراد عرضها:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs --lines 100
|
||||
```
|
||||
|
||||
### إيقاف الخادم
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server stop
|
||||
```
|
||||
|
||||
يوقف الحاوية. تُحفَظ بياناتك في أحجام Docker — وستُستأنف الحالة مع عملية `start` التالية من حيث توقفت.
|
||||
|
||||
### إعادة تعيين الخادم
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server reset
|
||||
```
|
||||
|
||||
يزيل الحاوية **و** يحذف كلا حجمي Docker، ممّا يمحو جميع البيانات. ستنشئ عملية `start` التالية مثيلًا جديدًا من البداية.
|
||||
|
||||
<Note>
|
||||
يتطلّب الخادم أن يكون **Docker** قيد التشغيل. إذا ظهرت لك رسالة خطأ "Docker not running"، فتأكّد من تشغيل Docker Desktop (أو خادوم Docker).
|
||||
</Note>
|
||||
|
||||
### مرجع الأوامر
|
||||
لقد قامت أداة إنشاء الهيكل بالفعل بتشغيل خادم Twenty محليًا لك. لإدارته لاحقًا، استخدم `yarn twenty server`:
|
||||
|
||||
| أمر | الوصف |
|
||||
| -------------------------------------- | --------------------------------------------- |
|
||||
@@ -313,65 +211,11 @@ yarn twenty server reset
|
||||
| `yarn twenty server logs --lines 100` | عرض آخر 100 سطر من السجلات |
|
||||
| `yarn twenty server reset` | حذف جميع البيانات والبدء من جديد |
|
||||
|
||||
## التكامل المستمر (CI) باستخدام GitHub Actions
|
||||
يتم الاحتفاظ بالبيانات عبر عمليات إعادة التشغيل في وحدتي تخزين Docker (`twenty-app-dev-data` لـ PostgreSQL، و`twenty-app-dev-storage` للملفات). استخدم `reset` لمسح كل شيء والبدء من جديد.
|
||||
|
||||
تولّد أداة إنشاء الهيكل سير عمل GitHub Actions جاهزًا للاستخدام في `.github/workflows/ci.yml`. يشغّل اختبارات التكامل لديك تلقائيًا عند كل دفع إلى `main` وعلى طلبات السحب.
|
||||
|
||||
سير العمل:
|
||||
|
||||
1. يجلب الشيفرة الخاصة بك
|
||||
2. يشغّل خادم Twenty مؤقتًا باستخدام الإجراء `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. يثبّت الاعتمادات باستخدام `yarn install --immutable`
|
||||
4. يشغّل `yarn test` مع حقن `TWENTY_API_URL` و`TWENTY_API_KEY` من مخرجات الإجراء
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
لا تحتاج إلى تهيئة أي أسرار — إذ يبدأ إجراء `spawn-twenty-docker-image` خادم Twenty عابرًا مباشرة في المشغّل ويُخرِج تفاصيل الاتصال. يتم توفير السر `GITHUB_TOKEN` تلقائيًا من قِبل GitHub.
|
||||
|
||||
لتثبيت إصدار محدّد من Twenty بدلًا من `latest`، غيّر متغير البيئة `TWENTY_VERSION` في أعلى سير العمل.
|
||||
<Note>
|
||||
يتطلّب الخادم أن يكون **Docker** قيد التشغيل. إذا ظهرت لك رسالة خطأ "Docker not running"، فتأكّد من تشغيل Docker Desktop (أو خادوم Docker).
|
||||
</Note>
|
||||
|
||||
## إعداد يدوي (بدون المهيئ)
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ import { defineApplication } from 'twenty-sdk';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7',
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
displayName: 'My Twenty App',
|
||||
description: 'My first Twenty app',
|
||||
icon: 'IconWorld',
|
||||
@@ -717,6 +717,13 @@ Hlavní body:
|
||||
|
||||
Frontendové komponenty jsou React komponenty, které se vykreslují přímo v uživatelském rozhraní Twenty. Běží v **izolovaném Web Workeru** s využitím Remote DOM — váš kód je sandboxovaný, ale vykresluje se nativně na stránce, nikoli v iframu.
|
||||
|
||||
#### Kde lze použít front komponenty
|
||||
|
||||
Front komponenty se mohou vykreslovat na dvou místech v rámci Twenty:
|
||||
|
||||
* **Postranní panel** — Ne-headless front komponenty se otevírají v pravém postranním panelu. Toto je výchozí chování, když je front komponenta vyvolána z menu příkazů.
|
||||
* **Widgety (nástěnky a stránky záznamů)** — Front komponenty lze vkládat jako widgety do rozložení stránek. Při konfiguraci nástěnky nebo rozložení stránky záznamu mohou uživatelé přidat widget front komponenty.
|
||||
|
||||
#### Základní příklad
|
||||
|
||||
Nejrychlejší způsob, jak vidět frontendovou komponentu v akci, je zaregistrovat ji jako **příkaz**. Přidáním pole `command` s `isPinned: true` se zobrazí jako tlačítko rychlé akce v pravém horním rohu stránky — není potřeba žádné rozvržení stránky:
|
||||
@@ -774,9 +781,13 @@ Kliknutím na něj vykreslíte komponentu přímo ve stránce.
|
||||
|
||||
Mimo příkazy můžete frontendovou komponentu vložit přímo na stránku záznamu přidáním jako widget v **rozvržení stránky**. Podrobnosti viz sekce [definePageLayout](#definepagelayout).
|
||||
|
||||
#### Headless komponenty (`isHeadless: true`)
|
||||
#### Headless vs. ne-headless
|
||||
|
||||
Headless komponenty nevykreslují viditelné UI, ale stále spouštějí logiku Reactu. To je užitečné pro **efektové komponenty** — komponenty, které po připojení provádějí vedlejší efekty, jako je synchronizace dat, spuštění časovače, naslouchání událostem nebo vyvolání oznámení.
|
||||
Front komponenty existují ve dvou režimech vykreslování řízených volbou `isHeadless`:
|
||||
|
||||
**Ne-headless (výchozí)** — Komponenta vykreslí viditelné uživatelské rozhraní. Po vyvolání z menu příkazů se otevře v postranním panelu. Toto je výchozí chování, když je `isHeadless` `false` nebo když tato volba není uvedena.
|
||||
|
||||
**Headless (`isHeadless: true`)** — Komponenta se neviditelně inicializuje na pozadí. Neotevírá postranní panel. Headless komponenty jsou určené pro akce, které provedou logiku a poté se odpojí — například spuštění asynchronního úkolu, navigaci na stránku nebo zobrazení potvrzovacího modálního okna. Přirozeně se hodí ke komponentám SDK Command popsaným níže.
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent, useRecordId, enqueueSnackbar } from 'twenty-sdk';
|
||||
@@ -803,6 +814,89 @@ export default defineFrontComponent({
|
||||
|
||||
Protože komponenta vrací `null`, Twenty přeskočí vykreslení kontejneru — v rozvržení se neobjeví žádné prázdné místo. Komponenta má však stále přístup ke všem hookům a API komunikace s hostitelem.
|
||||
|
||||
#### Komponenty SDK Command
|
||||
|
||||
Balíček `twenty-sdk` poskytuje čtyři pomocné komponenty Command navržené pro headless front komponenty. Každá komponenta při připojení provede akci, chyby zpracuje zobrazením oznámení ve snackbaru a po dokončení automaticky odpojí front komponentu.
|
||||
|
||||
Importujte je z `twenty-sdk/command`:
|
||||
|
||||
* **`Command`** — Spustí asynchronní callback přes prop `execute`.
|
||||
* **`CommandLink`** — Naviguje na cestu v aplikaci. Props: `to`, `params`, `queryParams`, `options`.
|
||||
* **`CommandModal`** — Otevře potvrzovací modální okno. Pokud uživatel potvrdí, provede callback `execute`. Props: `title`, `subtitle`, `execute`, `confirmButtonText`, `confirmButtonAccent`.
|
||||
* **`CommandOpenSidePanelPage`** — Otevře konkrétní stránku postranního panelu. Props: `page`, `pageTitle`, `pageIcon`.
|
||||
|
||||
Zde je kompletní příklad headless front komponenty, která pomocí `Command` spouští akci z menu příkazů:
|
||||
|
||||
```tsx src/front-components/run-action.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const RunAction = () => {
|
||||
const execute = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
createTask: {
|
||||
__args: { data: { title: 'Created by my app' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
||||
name: 'run-action',
|
||||
description: 'Creates a task from the command menu',
|
||||
component: RunAction,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
|
||||
label: 'Run my action',
|
||||
icon: 'IconPlayerPlay',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
A příklad s použitím `CommandModal` k vyžádání potvrzení před provedením:
|
||||
|
||||
```tsx src/front-components/delete-draft.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { CommandModal } from 'twenty-sdk/command';
|
||||
|
||||
const DeleteDraft = () => {
|
||||
const execute = async () => {
|
||||
// perform the deletion
|
||||
};
|
||||
|
||||
return (
|
||||
<CommandModal
|
||||
title="Delete draft?"
|
||||
subtitle="This action cannot be undone."
|
||||
execute={execute}
|
||||
confirmButtonText="Delete"
|
||||
confirmButtonAccent="danger"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'a7b8c9d0-e1f2-3456-abcd-567890123456',
|
||||
name: 'delete-draft',
|
||||
description: 'Deletes a draft with confirmation',
|
||||
component: DeleteDraft,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'b8c9d0e1-f2a3-4567-bcde-678901234567',
|
||||
label: 'Delete draft',
|
||||
icon: 'IconTrash',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### Přístup k běhovému kontextu
|
||||
|
||||
Uvnitř komponenty použijte hooky SDK pro přístup k aktuálnímu uživateli, záznamu a instanci komponenty:
|
||||
@@ -859,6 +953,50 @@ Frontendové komponenty mohou pomocí funkcí z `twenty-sdk` vyvolávat navigaci
|
||||
| `unmountFrontComponent()` | Odmontovat komponentu |
|
||||
| `updateProgress(progress)` | Aktualizovat indikátor průběhu |
|
||||
|
||||
Zde je příklad, který používá hostitelské API k zobrazení snackbaru a zavření postranního panelu po dokončení akce:
|
||||
|
||||
```tsx src/front-components/archive-record.tsx
|
||||
import { defineFrontComponent, useRecordId } from 'twenty-sdk';
|
||||
import { enqueueSnackbar, closeSidePanel } from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const ArchiveRecord = () => {
|
||||
const recordId = useRecordId();
|
||||
|
||||
const handleArchive = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
updateTask: {
|
||||
__args: { id: recordId, data: { status: 'ARCHIVED' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
await enqueueSnackbar({
|
||||
message: 'Record archived',
|
||||
variant: 'success',
|
||||
});
|
||||
|
||||
await closeSidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<p>Archive this record?</p>
|
||||
<button onClick={handleArchive}>Archive</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'c9d0e1f2-a3b4-5678-cdef-789012345678',
|
||||
name: 'archive-record',
|
||||
description: 'Archives the current record',
|
||||
component: ArchiveRecord,
|
||||
});
|
||||
```
|
||||
|
||||
#### Možnosti příkazu
|
||||
|
||||
Přidání pole `command` do `defineFrontComponent` zaregistruje komponentu v příkazovém menu (Cmd+K). Pokud je `isPinned` nastaveno na `true`, zobrazí se také jako tlačítko rychlé akce v pravém horním rohu stránky.
|
||||
@@ -1713,3 +1851,86 @@ yarn twenty uninstall
|
||||
# Skip the confirmation prompt
|
||||
yarn twenty uninstall --yes
|
||||
```
|
||||
|
||||
## Správa vzdálených serverů
|
||||
|
||||
**Remote** je server Twenty, ke kterému se vaše aplikace připojuje. Během nastavení jej generátor kostry automaticky vytvoří. Můžete kdykoli přidat další vzdálené servery nebo mezi nimi přepínat.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Vaše přihlašovací údaje jsou uloženy v `~/.twenty/config.json`.
|
||||
|
||||
## CI s GitHub Actions
|
||||
|
||||
Generátor kostry vytvoří připravený k použití workflow GitHub Actions v `.github/workflows/ci.yml`. Automaticky spouští integrační testy při každém pushi do `main` a u pull requestů.
|
||||
|
||||
Workflow:
|
||||
|
||||
1. Načte váš kód (checkout).
|
||||
2. Spustí dočasný server Twenty pomocí akce `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Nainstaluje závislosti pomocí `yarn install --immutable`
|
||||
4. Spustí `yarn test` s proměnnými `TWENTY_API_URL` a `TWENTY_API_KEY` vloženými z výstupů akce
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Není potřeba konfigurovat žádné secrets — akce `spawn-twenty-docker-image` spustí efemérní server Twenty přímo v runneru a vypíše podrobnosti připojení. Secret `GITHUB_TOKEN` je poskytován GitHubem automaticky.
|
||||
|
||||
Chcete-li připnout konkrétní verzi Twenty místo `latest`, změňte proměnnou prostředí `TWENTY_VERSION` na začátku workflow.
|
||||
|
||||
@@ -7,7 +7,9 @@ description: Vytvořte svou první aplikaci Twenty během několika minut.
|
||||
Aplikace jsou aktuálně v alfa fázi. Funkce funguje, ale stále se vyvíjí.
|
||||
</Warning>
|
||||
|
||||
Aplikace vám umožňují rozšířit Twenty o vlastní objekty, pole, logické funkce, AI schopnosti a komponenty uživatelského rozhraní — vše je spravováno jako kód.
|
||||
## Co jsou aplikace?
|
||||
|
||||
Aplikace vám umožňují rozšířit Twenty o vlastní objekty, pole, logické funkce, frontendové komponenty, AI schopnosti a další — vše je spravováno jako kód. Místo konfigurace všeho přes uživatelské rozhraní definujete v TypeScriptu svůj datový model a logiku a nasadíte je do jednoho nebo více pracovních prostorů.
|
||||
|
||||
## Předpoklady
|
||||
|
||||
@@ -17,7 +19,9 @@ Než začnete, ujistěte se, že máte ve svém počítači nainstalováno násl
|
||||
* **Yarn 4** — Dodává se s Node.js prostřednictvím Corepacku. Povolte jej spuštěním `corepack enable`
|
||||
* **Docker** — [Stáhnout zde](https://www.docker.com/products/docker-desktop/). Nutné pro spuštění lokální instance Twenty. Není potřeba, pokud už máte spuštěný server Twenty.
|
||||
|
||||
## Krok 1: Vytvořte kostru své aplikace
|
||||
## Vytvořte svou první aplikaci
|
||||
|
||||
### Vytvořte kostru své aplikace
|
||||
|
||||
Otevřete terminál a spusťte:
|
||||
|
||||
@@ -29,18 +33,7 @@ Budete vyzváni k zadání názvu a popisu své aplikace. Stisknutím **Enter**
|
||||
|
||||
Tím se vytvoří nová složka s názvem `my-twenty-app` se vším potřebným.
|
||||
|
||||
<Note>
|
||||
Generátor kostry podporuje tyto přepínače:
|
||||
|
||||
* `--minimal` — vygeneruje pouze nezbytné soubory, bez příkladů (výchozí)
|
||||
* `--exhaustive` — vygeneruje všechny ukázkové entity
|
||||
* `--name <name>` — nastaví název aplikace (přeskočí výzvu)
|
||||
* `--display-name <displayName>` — nastaví zobrazovaný název (přeskočí výzvu)
|
||||
* `--description <description>` — nastaví popis (přeskočí výzvu)
|
||||
* `--skip-local-instance` — přeskočí výzvu k nastavení lokálního serveru
|
||||
</Note>
|
||||
|
||||
## Krok 2: Nastavte lokální instanci Twenty
|
||||
### Nastavte lokální instanci Twenty
|
||||
|
||||
Generátor kostry se zeptá:
|
||||
|
||||
@@ -53,7 +46,7 @@ Generátor kostry se zeptá:
|
||||
<img src="/images/docs/developers/extends/apps/start-instance.png" alt="Spustit lokální instanci?" />
|
||||
</div>
|
||||
|
||||
## Krok 3: Přihlaste se do svého pracovního prostoru
|
||||
### Přihlaste se do svého pracovního prostoru
|
||||
|
||||
Poté se otevře okno prohlížeče se stránkou přihlášení do Twenty. Přihlaste se předpřipraveným demo účtem:
|
||||
|
||||
@@ -64,7 +57,7 @@ Poté se otevře okno prohlížeče se stránkou přihlášení do Twenty. Přih
|
||||
<img src="/images/docs/developers/extends/apps/login.png" alt="Přihlašovací obrazovka Twenty" />
|
||||
</div>
|
||||
|
||||
## Krok 4: Autorizujte aplikaci
|
||||
### Autorizujte aplikaci
|
||||
|
||||
Po přihlášení uvidíte autorizační obrazovku. Tím umožníte vaší aplikaci pracovat s vaším pracovním prostorem.
|
||||
|
||||
@@ -80,7 +73,7 @@ Po autorizaci váš terminál potvrdí, že je vše nastaveno.
|
||||
<img src="/images/docs/developers/extends/apps/scaffolded.png" alt="Aplikace byla úspěšně vygenerována" />
|
||||
</div>
|
||||
|
||||
## Krok 5: Začněte vyvíjet
|
||||
### Začněte vyvíjet
|
||||
|
||||
Přejděte do nové složky aplikace a spusťte vývojový server:
|
||||
|
||||
@@ -105,7 +98,7 @@ Vývojový režim je k dispozici pouze na instancích Twenty běžících v rež
|
||||
<img src="/images/docs/developers/extends/apps/dev.jpg" alt="Výstup terminálu ve vývojovém režimu" />
|
||||
</div>
|
||||
|
||||
## Krok 6: Zobrazte svou aplikaci v Twenty
|
||||
### Zobrazte svou aplikaci v Twenty
|
||||
|
||||
Otevřete ve svém prohlížeči [http://localhost:2020/settings/applications#developer](http://localhost:2020/settings/applications#developer). Přejděte do **Settings > Apps** a vyberte kartu **Developer**. Vaše aplikace by měla být uvedena v části **Your Apps**:
|
||||
|
||||
@@ -133,13 +126,28 @@ Přepněte na kartu **Content**, abyste viděli vše, co vaše aplikace poskytuj
|
||||
|
||||
Vše je připraveno! Upravte libovolný soubor v `src/` a změny se automaticky projeví.
|
||||
|
||||
Přejděte na [Tvorba aplikací](/l/cs/developers/extend/apps/building) pro podrobný průvodce vytvářením objektů, logických funkcí, frontendových komponent, dovedností a dalšího.
|
||||
---
|
||||
|
||||
## Co můžete vytvořit
|
||||
|
||||
Aplikace se skládají z **entit** — každá je definována jako soubor TypeScriptu s jediným `export default`:
|
||||
|
||||
| Entita | K čemu slouží |
|
||||
| -------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Objekty a pole** | Definujte vlastní datové modely (např. Post Card, Invoice) s typovanými poli |
|
||||
| **Logické funkce** | Serverové funkce v TypeScriptu spouštěné HTTP trasami, plánovačem cron nebo událostmi databáze |
|
||||
| **Frontendové komponenty** | Komponenty Reactu, které se vykreslují v uživatelském rozhraní Twenty (postranní panel, widgety, příkazová nabídka) |
|
||||
| **Dovednosti a agenti** | AI schopnosti — znovu použitelné pokyny a autonomní asistenti |
|
||||
| **Pohledy a navigace** | Předkonfigurované seznamové pohledy a položky postranní nabídky pro vaše objekty |
|
||||
| **Rozvržení stránek** | Vlastní stránky detailu záznamu s kartami a widgety |
|
||||
|
||||
Přejděte na [Tvorba aplikací](/l/cs/developers/extend/apps/building) pro podrobný průvodce každým typem entity.
|
||||
|
||||
---
|
||||
|
||||
## Struktura projektu
|
||||
|
||||
Generátor kostry vytvoří následující strukturu souborů (zobrazeno v režimu `--exhaustive`, který zahrnuje příklady pro každý typ entity):
|
||||
Nástroj pro vytvoření kostry vygeneruje následující strukturu souborů:
|
||||
|
||||
```text filename="my-twenty-app/"
|
||||
my-twenty-app/
|
||||
@@ -148,160 +156,50 @@ my-twenty-app/
|
||||
.gitignore
|
||||
.nvmrc
|
||||
.yarnrc.yml
|
||||
.yarn/
|
||||
install-state.gz
|
||||
.oxlintrc.json
|
||||
tsconfig.json
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
LLMS.md
|
||||
README.md
|
||||
.github/
|
||||
└── workflows/
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
src/
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── __tests__/
|
||||
│ ├── setup-test.ts # Test setup (server health check, config)
|
||||
│ └── app-install.integration-test.ts # Example integration test
|
||||
├── roles/
|
||||
│ └── default-role.ts # Default role for logic functions
|
||||
├── objects/
|
||||
│ └── example-object.ts # Example custom object definition
|
||||
├── fields/
|
||||
│ └── example-field.ts # Example standalone field definition
|
||||
├── logic-functions/
|
||||
│ ├── hello-world.ts # Example logic function
|
||||
│ ├── create-hello-world-company.ts # Example logic function using CoreApiClient
|
||||
│ ├── pre-install.ts # Runs before installation
|
||||
│ └── post-install.ts # Runs after installation
|
||||
├── front-components/
|
||||
│ └── hello-world.tsx # Example front component
|
||||
├── page-layouts/
|
||||
│ └── example-record-page-layout.ts # Example page layout with front component
|
||||
├── views/
|
||||
│ └── example-view.ts # Example saved view definition
|
||||
├── navigation-menu-items/
|
||||
│ └── example-navigation-menu-item.ts # Example sidebar navigation link
|
||||
├── skills/
|
||||
│ └── example-skill.ts # Example AI agent skill definition
|
||||
└── agents/
|
||||
└── example-agent.ts # Example AI agent definition
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── default-role.ts # Default role for logic functions
|
||||
├── constants/
|
||||
│ └── universal-identifiers.ts # Auto-generated UUIDs and app metadata
|
||||
└── __tests__/
|
||||
├── setup-test.ts # Test setup (server health check, config)
|
||||
└── app-install.integration-test.ts # Integration test
|
||||
```
|
||||
|
||||
Ve výchozím nastavení (`--minimal`) se vytvoří pouze základní soubory: `application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` a `logic-functions/post-install.ts`. Pro zahrnutí všech ukázkových souborů výše použijte `--exhaustive`.
|
||||
### Začít s příkladem
|
||||
|
||||
Chcete-li začít z úplnějšího příkladu s vlastními objekty, poli, logickými funkcemi, frontendovými komponentami a dalšími, použijte příznak `--example`:
|
||||
|
||||
```bash filename="Terminal"
|
||||
npx create-twenty-app@latest my-twenty-app --example postcard
|
||||
```
|
||||
|
||||
Příklady pocházejí z adresáře [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples) na GitHubu. Můžete také vytvořit kostru jednotlivých entit v existujícím projektu pomocí `yarn twenty add` (viz [Tvorba aplikací](/l/cs/developers/extend/apps/building#scaffolding-entities-with-yarn-twenty-add)).
|
||||
|
||||
### Klíčové soubory
|
||||
|
||||
| Soubor / Složka | Účel |
|
||||
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Definuje název, verzi a závislosti vaší aplikace. Obsahuje skript `twenty`, takže můžete spustit `yarn twenty help` a zobrazit všechny příkazy. |
|
||||
| `src/application-config.ts` | **Povinné.** Hlavní konfigurační soubor vaší aplikace. |
|
||||
| `src/roles/` | Definuje role, které určují, k čemu mají vaše logické funkce přístup. |
|
||||
| `src/logic-functions/` | Serverové funkce spouštěné trasami, plánovačem cron nebo událostmi databáze. |
|
||||
| `src/front-components/` | Komponenty Reactu, které se vykreslují uvnitř uživatelského rozhraní Twenty. |
|
||||
| `src/objects/` | Vlastní definice objektů pro rozšíření vašeho datového modelu. |
|
||||
| `src/fields/` | Vlastní pole přidaná k existujícím objektům. |
|
||||
| `src/views/` | Konfigurace uložených zobrazení. |
|
||||
| `src/navigation-menu-items/` | Vlastní odkazy v postranní navigaci. |
|
||||
| `src/skills/` | Dovednosti, které rozšiřují možnosti AI agentů Twenty. |
|
||||
| `src/agents/` | AI agenti s vlastními prompty. |
|
||||
| `src/page-layouts/` | Vlastní rozvržení stránek pro zobrazení záznamů. |
|
||||
| `src/__tests__/` | Integrační testy (nastavení + ukázkový test). |
|
||||
| `public/` | Statická aktiva (obrázky, písma) poskytovaná s vaší aplikací. |
|
||||
| Soubor / Složka | Účel |
|
||||
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Definuje název, verzi a závislosti vaší aplikace. Obsahuje skript `twenty`, takže můžete spustit `yarn twenty help` a zobrazit všechny příkazy. |
|
||||
| `src/application-config.ts` | **Povinné.** Hlavní konfigurační soubor vaší aplikace. |
|
||||
| `src/default-role.ts` | Výchozí role, která určuje, k čemu mají vaše logické funkce přístup. |
|
||||
| `src/constants/universal-identifiers.ts` | Automaticky generovaná UUID a metadata aplikace (zobrazovaný název, popis). |
|
||||
| `src/__tests__/` | Integrační testy (nastavení + ukázkový test). |
|
||||
| `public/` | Statická aktiva (obrázky, písma) poskytovaná s vaší aplikací. |
|
||||
|
||||
## Správa vzdálených serverů
|
||||
## Lokální vývojový server
|
||||
|
||||
**Remote** je server Twenty, ke kterému se vaše aplikace připojuje. Během nastavení jej generátor kostry automaticky vytvoří. Můžete kdykoli přidat další vzdálené servery nebo mezi nimi přepínat.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Vaše přihlašovací údaje jsou uloženy v `~/.twenty/config.json`.
|
||||
|
||||
## Lokální vývojový server (`yarn twenty server`)
|
||||
|
||||
CLI může spravovat lokální server Twenty běžící v Dockeru. Jde o stejný server, který se spustí automaticky při vytvoření kostry aplikace pomocí `create-twenty-app`, ale můžete jej spravovat i ručně.
|
||||
|
||||
### Spuštění serveru
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start
|
||||
```
|
||||
|
||||
Stáhne image Dockeru `twentycrm/twenty-app-dev:latest` (pokud již není k dispozici), vytvoří kontejner s názvem `twenty-app-dev` a spustí jej na portu **2020**. CLI čeká, dokud server neprojde kontrolou stavu, než vrátí řízení.
|
||||
|
||||
Vytvoří se dva svazky Dockeru pro zachování dat mezi restartováními:
|
||||
|
||||
* `twenty-app-dev-data` — databáze PostgreSQL
|
||||
* `twenty-app-dev-storage` — úložiště souborů
|
||||
|
||||
Pokud je port 2020 již používán, můžete spustit na jiném portu:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start --port 3030
|
||||
```
|
||||
|
||||
CLI automaticky nakonfiguruje interní `NODE_PORT` a `SERVER_URL` kontejneru tak, aby odpovídaly zvolenému portu, takže logické funkce, OAuth a veškerá ostatní vnitřní síťová komunikace fungují správně.
|
||||
|
||||
Po spuštění je server automaticky zaregistrován jako `local` remote ve vaší konfiguraci CLI.
|
||||
|
||||
### Kontrola stavu serveru
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server status
|
||||
```
|
||||
|
||||
Zobrazí, zda server běží, jeho URL a výchozí přihlašovací údaje (`tim@apple.dev` / `tim@apple.dev`).
|
||||
|
||||
### Zobrazení protokolů serveru
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs
|
||||
```
|
||||
|
||||
Streamuje protokoly kontejneru. Pomocí `--lines` ovládnete, kolik posledních řádků se má zobrazit:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs --lines 100
|
||||
```
|
||||
|
||||
### Zastavení serveru
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server stop
|
||||
```
|
||||
|
||||
Zastaví kontejner. Vaše data jsou zachována ve svazcích Dockeru — další `start` naváže tam, kde jste skončili.
|
||||
|
||||
### Resetování serveru
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server reset
|
||||
```
|
||||
|
||||
Odstraní kontejner **a** smaže oba svazky Dockeru, čímž vymaže všechna data. Další `start` vytvoří čistou instanci.
|
||||
|
||||
<Note>
|
||||
Server vyžaduje, aby **Docker** běžel. Pokud vidíte chybu "Docker not running", ujistěte se, že je spuštěný Docker Desktop (nebo démon Dockeru).
|
||||
</Note>
|
||||
|
||||
### Přehled příkazů
|
||||
Nástroj pro vytvoření kostry vám již spustil lokální server Twenty. Pro jeho správu později použijte `yarn twenty server`:
|
||||
|
||||
| Příkaz | Popis |
|
||||
| -------------------------------------- | ------------------------------------------------------ |
|
||||
@@ -313,65 +211,11 @@ Odstraní kontejner **a** smaže oba svazky Dockeru, čímž vymaže všechna da
|
||||
| `yarn twenty server logs --lines 100` | Zobrazí posledních 100 řádků logu |
|
||||
| `yarn twenty server reset` | Smaže všechna data a začne znovu |
|
||||
|
||||
## CI s GitHub Actions
|
||||
Data přetrvávají při restartech ve dvou svazcích Dockeru (`twenty-app-dev-data` pro PostgreSQL, `twenty-app-dev-storage` pro soubory). Pomocí `reset` vymažte vše a začněte znovu.
|
||||
|
||||
Generátor kostry vytvoří připravený k použití workflow GitHub Actions v `.github/workflows/ci.yml`. Automaticky spouští integrační testy při každém pushi do `main` a u pull requestů.
|
||||
|
||||
Workflow:
|
||||
|
||||
1. Načte váš kód (checkout).
|
||||
2. Spustí dočasný server Twenty pomocí akce `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Nainstaluje závislosti pomocí `yarn install --immutable`
|
||||
4. Spustí `yarn test` s proměnnými `TWENTY_API_URL` a `TWENTY_API_KEY` vloženými z výstupů akce
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Není potřeba konfigurovat žádné secrets — akce `spawn-twenty-docker-image` spustí efemérní server Twenty přímo v runneru a vypíše podrobnosti připojení. Secret `GITHUB_TOKEN` je poskytován GitHubem automaticky.
|
||||
|
||||
Chcete-li připnout konkrétní verzi Twenty místo `latest`, změňte proměnnou prostředí `TWENTY_VERSION` na začátku workflow.
|
||||
<Note>
|
||||
Server vyžaduje, aby **Docker** běžel. Pokud vidíte chybu "Docker not running", ujistěte se, že je spuštěný Docker Desktop (nebo démon Dockeru).
|
||||
</Note>
|
||||
|
||||
## Ruční nastavení (bez scaffolderu)
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ import { defineApplication } from 'twenty-sdk';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7',
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
displayName: 'My Twenty App',
|
||||
description: 'My first Twenty app',
|
||||
icon: 'IconWorld',
|
||||
@@ -716,6 +716,13 @@ Hauptpunkte:
|
||||
|
||||
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.
|
||||
|
||||
#### Wo Front-Komponenten verwendet werden können
|
||||
|
||||
Front-Komponenten können an zwei Stellen innerhalb von Twenty gerendert werden:
|
||||
|
||||
* **Seitenpanel** — Nicht-Headless-Front-Komponenten werden im rechten Seitenpanel geöffnet. Dies ist das Standardverhalten, wenn eine Front-Komponente über das Befehlsmenü ausgelöst wird.
|
||||
* **Widgets (Dashboards und Datensatzseiten)** — Front-Komponenten können als Widgets in Seitenlayouts eingebettet werden. Beim Konfigurieren eines Dashboards oder eines Datensatzseiten-Layouts können Benutzer ein Front-Komponenten-Widget hinzufügen.
|
||||
|
||||
#### Einfaches Beispiel
|
||||
|
||||
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:
|
||||
@@ -773,9 +780,13 @@ Klicken Sie darauf, um die Komponente inline zu rendern.
|
||||
|
||||
Ü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-Komponenten (`isHeadless: true`)
|
||||
#### Headless vs. Nicht-Headless
|
||||
|
||||
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.
|
||||
Front-Komponenten gibt es in zwei Rendering-Modi, die durch die Option `isHeadless` gesteuert werden:
|
||||
|
||||
**Nicht-Headless (Standard)** — Die Komponente rendert eine sichtbare UI. Wird sie über das Befehlsmenü ausgelöst, öffnet sie sich im Seitenpanel. Dies ist das Standardverhalten, wenn `isHeadless` `false` ist oder weggelassen wird.
|
||||
|
||||
**Headless (`isHeadless: true`)** — Die Komponente wird unsichtbar im Hintergrund gemountet. Sie öffnet das Seitenpanel nicht. Headless-Komponenten sind für Aktionen konzipiert, die Logik ausführen und sich anschließend selbst unmounten — zum Beispiel das Ausführen einer asynchronen Aufgabe, das Navigieren zu einer Seite oder das Anzeigen eines Bestätigungsdialogs. Sie lassen sich gut mit den unten beschriebenen SDK-Command-Komponenten kombinieren.
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent, useRecordId, enqueueSnackbar } from 'twenty-sdk';
|
||||
@@ -802,6 +813,89 @@ export default defineFrontComponent({
|
||||
|
||||
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.
|
||||
|
||||
#### SDK-Command-Komponenten
|
||||
|
||||
Das Paket `twenty-sdk` stellt vier Command-Hilfskomponenten bereit, die für Headless-Front-Komponenten ausgelegt sind. Jede Komponente führt beim Mounten eine Aktion aus, behandelt Fehler durch Anzeige einer Snackbar-Benachrichtigung und unmountet die Front-Komponente nach Abschluss automatisch.
|
||||
|
||||
Importieren Sie sie aus `twenty-sdk/command`:
|
||||
|
||||
* **`Command`** — Führt einen asynchronen Callback über das Prop `execute` aus.
|
||||
* **`CommandLink`** — Navigiert zu einem App-Pfad. Props: `to`, `params`, `queryParams`, `options`.
|
||||
* **`CommandModal`** — Öffnet einen Bestätigungsdialog. Bestätigt der Benutzer, wird der Callback `execute` ausgeführt. Props: `title`, `subtitle`, `execute`, `confirmButtonText`, `confirmButtonAccent`.
|
||||
* **`CommandOpenSidePanelPage`** — Öffnet eine bestimmte Seite im Seitenpanel. Props: `page`, `pageTitle`, `pageIcon`.
|
||||
|
||||
Hier ist ein vollständiges Beispiel einer Headless-Front-Komponente, die `Command` verwendet, um eine Aktion aus dem Befehlsmenü auszuführen:
|
||||
|
||||
```tsx src/front-components/run-action.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const RunAction = () => {
|
||||
const execute = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
createTask: {
|
||||
__args: { data: { title: 'Created by my app' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
||||
name: 'run-action',
|
||||
description: 'Creates a task from the command menu',
|
||||
component: RunAction,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
|
||||
label: 'Run my action',
|
||||
icon: 'IconPlayerPlay',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Und ein Beispiel, das `CommandModal` verwendet, um vor der Ausführung um Bestätigung zu bitten:
|
||||
|
||||
```tsx src/front-components/delete-draft.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { CommandModal } from 'twenty-sdk/command';
|
||||
|
||||
const DeleteDraft = () => {
|
||||
const execute = async () => {
|
||||
// perform the deletion
|
||||
};
|
||||
|
||||
return (
|
||||
<CommandModal
|
||||
title="Delete draft?"
|
||||
subtitle="This action cannot be undone."
|
||||
execute={execute}
|
||||
confirmButtonText="Delete"
|
||||
confirmButtonAccent="danger"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'a7b8c9d0-e1f2-3456-abcd-567890123456',
|
||||
name: 'delete-draft',
|
||||
description: 'Deletes a draft with confirmation',
|
||||
component: DeleteDraft,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'b8c9d0e1-f2a3-4567-bcde-678901234567',
|
||||
label: 'Delete draft',
|
||||
icon: 'IconTrash',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### Zugriff auf den Laufzeitkontext
|
||||
|
||||
Verwenden Sie innerhalb Ihrer Komponente SDK-Hooks, um auf den aktuellen Benutzer, den Datensatz und die Komponenteninstanz zuzugreifen:
|
||||
@@ -858,6 +952,50 @@ Frontend-Komponenten können Navigation, Modals und Benachrichtigungen mittels F
|
||||
| `unmountFrontComponent()` | Die Komponente entfernen |
|
||||
| `updateProgress(progress)` | Einen Fortschrittsindikator aktualisieren |
|
||||
|
||||
Hier ist ein Beispiel, das die Host-API verwendet, um nach Abschluss einer Aktion eine Snackbar anzuzeigen und das Seitenpanel zu schließen:
|
||||
|
||||
```tsx src/front-components/archive-record.tsx
|
||||
import { defineFrontComponent, useRecordId } from 'twenty-sdk';
|
||||
import { enqueueSnackbar, closeSidePanel } from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const ArchiveRecord = () => {
|
||||
const recordId = useRecordId();
|
||||
|
||||
const handleArchive = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
updateTask: {
|
||||
__args: { id: recordId, data: { status: 'ARCHIVED' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
await enqueueSnackbar({
|
||||
message: 'Record archived',
|
||||
variant: 'success',
|
||||
});
|
||||
|
||||
await closeSidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<p>Archive this record?</p>
|
||||
<button onClick={handleArchive}>Archive</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'c9d0e1f2-a3b4-5678-cdef-789012345678',
|
||||
name: 'archive-record',
|
||||
description: 'Archives the current record',
|
||||
component: ArchiveRecord,
|
||||
});
|
||||
```
|
||||
|
||||
#### Befehlsoptionen
|
||||
|
||||
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.
|
||||
@@ -1712,3 +1850,86 @@ yarn twenty uninstall
|
||||
# Skip the confirmation prompt
|
||||
yarn twenty uninstall --yes
|
||||
```
|
||||
|
||||
## Remotes verwalten
|
||||
|
||||
Ein **Remote** ist ein Twenty-Server, mit dem sich Ihre App verbindet. Während der Einrichtung erstellt das Scaffolding-Tool automatisch eines für Sie. Sie können jederzeit weitere Remotes hinzufügen oder zwischen ihnen wechseln.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Ihre Anmeldedaten werden in `~/.twenty/config.json` gespeichert.
|
||||
|
||||
## CI mit GitHub Actions
|
||||
|
||||
Das Scaffolding-Tool erzeugt einen einsatzbereiten GitHub-Actions-Workflow in `.github/workflows/ci.yml`. Er führt Ihre Integrationstests automatisch bei jedem Push auf `main` und bei Pull Requests aus.
|
||||
|
||||
Der Workflow:
|
||||
|
||||
1. Checkt Ihren Code aus
|
||||
2. Startet einen temporären Twenty-Server mit der Aktion `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Installiert Abhängigkeiten mit `yarn install --immutable`
|
||||
4. Führt `yarn test` aus, wobei `TWENTY_API_URL` und `TWENTY_API_KEY` aus den Aktionsausgaben injiziert werden.
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Sie müssen keine Secrets konfigurieren — die Aktion `spawn-twenty-docker-image` startet einen flüchtigen Twenty-Server direkt im Runner und gibt die Verbindungsdetails aus. Das Secret `GITHUB_TOKEN` wird automatisch von GitHub bereitgestellt.
|
||||
|
||||
Um eine bestimmte Twenty-Version statt `latest` festzulegen, ändern Sie die Umgebungsvariable `TWENTY_VERSION` oben im Workflow.
|
||||
|
||||
@@ -7,7 +7,9 @@ description: Erstellen Sie in wenigen Minuten Ihre erste Twenty-App.
|
||||
Apps befinden sich derzeit in der Alpha-Phase. Die Funktion ist funktionsfähig, entwickelt sich jedoch noch weiter.
|
||||
</Warning>
|
||||
|
||||
Apps ermöglichen es Ihnen, Twenty mit benutzerdefinierten Objekten, Feldern, Logikfunktionen, KI-Fähigkeiten und UI-Komponenten zu erweitern — alles als Code verwaltet.
|
||||
## Was sind Apps?
|
||||
|
||||
Apps ermöglichen es Ihnen, Twenty mit benutzerdefinierten Objekten, Feldern, Logikfunktionen, Frontend-Komponenten, KI-Fähigkeiten und mehr zu erweitern — alles als Code verwaltet. Anstatt alles über die UI zu konfigurieren, definieren Sie Ihr Datenmodell und Ihre Logik in TypeScript und stellen es in einem oder mehreren Workspaces bereit.
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
@@ -17,7 +19,9 @@ Bevor Sie beginnen, stellen Sie sicher, dass Folgendes auf Ihrem Rechner install
|
||||
* **Yarn 4** — Wird mit Node.js über Corepack mitgeliefert. Aktivieren Sie es, indem Sie `corepack enable` ausführen
|
||||
* **Docker** — [Hier herunterladen](https://www.docker.com/products/docker-desktop/). Erforderlich, um eine lokale Twenty-Instanz auszuführen. Nicht erforderlich, wenn bereits ein Twenty-Server läuft.
|
||||
|
||||
## Schritt 1: App-Gerüst erstellen
|
||||
## Create your first app
|
||||
|
||||
### Scaffold your app
|
||||
|
||||
Öffnen Sie ein Terminal und führen Sie Folgendes aus:
|
||||
|
||||
@@ -29,18 +33,7 @@ Sie werden aufgefordert, einen Namen und eine Beschreibung für Ihre App einzuge
|
||||
|
||||
Dadurch wird ein neuer Ordner namens `my-twenty-app` mit allem erstellt, was Sie benötigen.
|
||||
|
||||
<Note>
|
||||
Das Scaffolding-Tool unterstützt diese Flags:
|
||||
|
||||
* `--minimal` — erstellt nur die wesentlichen Dateien, keine Beispiele (Standard)
|
||||
* `--exhaustive` — erstellt alle Beispiel-Entitäten
|
||||
* `--name <name>` — legt den App-Namen fest (überspringt die Abfrage)
|
||||
* `--display-name <displayName>` — legt den Anzeigenamen fest (überspringt die Abfrage)
|
||||
* `--description <description>` — legt die Beschreibung fest (überspringt die Abfrage)
|
||||
* `--skip-local-instance` — überspringt die Eingabeaufforderung zur Einrichtung des lokalen Servers
|
||||
</Note>
|
||||
|
||||
## Schritt 2: Lokale Twenty-Instanz einrichten
|
||||
### Set up a local Twenty instance
|
||||
|
||||
Das Scaffolding-Tool fragt:
|
||||
|
||||
@@ -53,7 +46,7 @@ Das Scaffolding-Tool fragt:
|
||||
<img src="/images/docs/developers/extends/apps/start-instance.png" alt="Soll die lokale Instanz gestartet werden?" />
|
||||
</div>
|
||||
|
||||
## Schritt 3: Bei Ihrem Arbeitsbereich anmelden
|
||||
### Sign in to your workspace
|
||||
|
||||
Anschließend öffnet sich ein Browserfenster mit der Twenty-Anmeldeseite. Melden Sie sich mit dem vorab eingerichteten Demo-Konto an:
|
||||
|
||||
@@ -64,7 +57,7 @@ Anschließend öffnet sich ein Browserfenster mit der Twenty-Anmeldeseite. Melde
|
||||
<img src="/images/docs/developers/extends/apps/login.png" alt="Twenty-Anmeldebildschirm" />
|
||||
</div>
|
||||
|
||||
## Schritt 4: Die App autorisieren
|
||||
### Authorize the app
|
||||
|
||||
Nach der Anmeldung sehen Sie einen Autorisierungsbildschirm. Dadurch kann Ihre App mit Ihrem Arbeitsbereich interagieren.
|
||||
|
||||
@@ -80,7 +73,7 @@ Nach der Autorisierung bestätigt Ihr Terminal, dass alles eingerichtet ist.
|
||||
<img src="/images/docs/developers/extends/apps/scaffolded.png" alt="App-Gerüst erfolgreich erstellt" />
|
||||
</div>
|
||||
|
||||
## Schritt 5: Mit der Entwicklung beginnen
|
||||
### Start developing
|
||||
|
||||
Wechseln Sie in Ihren neuen App-Ordner und starten Sie den Entwicklungsserver:
|
||||
|
||||
@@ -105,7 +98,7 @@ Der Dev-Modus ist nur auf Twenty-Instanzen verfügbar, die im Entwicklungsmodus
|
||||
<img src="/images/docs/developers/extends/apps/dev.jpg" alt="Terminalausgabe im Dev-Modus" />
|
||||
</div>
|
||||
|
||||
## Schritt 6: Ihre App in Twenty ansehen
|
||||
### See your app in Twenty
|
||||
|
||||
Öffnen Sie [http://localhost:2020/settings/applications#developer](http://localhost:2020/settings/applications#developer) in Ihrem Browser. Navigieren Sie zu **Settings > Apps** und wählen Sie die Registerkarte **Developer**. Unter **Your Apps** sollte Ihre App aufgeführt sein:
|
||||
|
||||
@@ -133,13 +126,28 @@ Wechseln Sie zur Registerkarte **Content**, um alles zu sehen, was Ihre App bere
|
||||
|
||||
Alles erledigt! Bearbeiten Sie eine beliebige Datei in `src/`, und die Änderungen werden automatisch übernommen.
|
||||
|
||||
Wechseln Sie zu [Apps erstellen](/l/de/developers/extend/apps/building) für eine ausführliche Anleitung zum Erstellen von Objekten, Logikfunktionen, Frontend-Komponenten, Skills und mehr.
|
||||
---
|
||||
|
||||
## Was Sie erstellen können
|
||||
|
||||
Apps are composed of **entities** — each defined as a TypeScript file with a single `export default`:
|
||||
|
||||
| Entity | What it does |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------- |
|
||||
| **Objects & Fields** | Define custom data models (like Post Card, Invoice) with typed fields |
|
||||
| **Logikfunktionen** | Server-side TypeScript functions triggered by HTTP routes, cron schedules, or database events |
|
||||
| **Frontend-Komponenten** | React components that render inside Twenty's UI (side panel, widgets, command menu) |
|
||||
| **Skills & Agents** | AI capabilities — reusable instructions and autonomous assistants |
|
||||
| **Views & Navigation** | Pre-configured list views and sidebar menu items for your objects |
|
||||
| **Seitenlayouts** | Custom record detail pages with tabs and widgets |
|
||||
|
||||
Head over to [Building Apps](/l/de/developers/extend/apps/building) for a detailed guide on each entity type.
|
||||
|
||||
---
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
Das Scaffolding-Tool erzeugt die folgende Verzeichnisstruktur (gezeigt im Modus `--exhaustive`, der Beispiele für jeden Entitätstyp enthält):
|
||||
The scaffolder generates the following file structure:
|
||||
|
||||
```text filename="my-twenty-app/"
|
||||
my-twenty-app/
|
||||
@@ -148,160 +156,50 @@ my-twenty-app/
|
||||
.gitignore
|
||||
.nvmrc
|
||||
.yarnrc.yml
|
||||
.yarn/
|
||||
install-state.gz
|
||||
.oxlintrc.json
|
||||
tsconfig.json
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
LLMS.md
|
||||
README.md
|
||||
.github/
|
||||
└── workflows/
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
src/
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── __tests__/
|
||||
│ ├── setup-test.ts # Test setup (server health check, config)
|
||||
│ └── app-install.integration-test.ts # Example integration test
|
||||
├── roles/
|
||||
│ └── default-role.ts # Default role for logic functions
|
||||
├── objects/
|
||||
│ └── example-object.ts # Example custom object definition
|
||||
├── fields/
|
||||
│ └── example-field.ts # Example standalone field definition
|
||||
├── logic-functions/
|
||||
│ ├── hello-world.ts # Example logic function
|
||||
│ ├── create-hello-world-company.ts # Example logic function using CoreApiClient
|
||||
│ ├── pre-install.ts # Runs before installation
|
||||
│ └── post-install.ts # Runs after installation
|
||||
├── front-components/
|
||||
│ └── hello-world.tsx # Example front component
|
||||
├── page-layouts/
|
||||
│ └── example-record-page-layout.ts # Example page layout with front component
|
||||
├── views/
|
||||
│ └── example-view.ts # Example saved view definition
|
||||
├── navigation-menu-items/
|
||||
│ └── example-navigation-menu-item.ts # Example sidebar navigation link
|
||||
├── skills/
|
||||
│ └── example-skill.ts # Example AI agent skill definition
|
||||
└── agents/
|
||||
└── example-agent.ts # Example AI agent definition
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── default-role.ts # Default role for logic functions
|
||||
├── constants/
|
||||
│ └── universal-identifiers.ts # Auto-generated UUIDs and app metadata
|
||||
└── __tests__/
|
||||
├── setup-test.ts # Test setup (server health check, config)
|
||||
└── app-install.integration-test.ts # Integration test
|
||||
```
|
||||
|
||||
Standardmäßig (`--minimal`) werden nur die Kerndateien erstellt: `application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` und `logic-functions/post-install.ts`. Verwenden Sie `--exhaustive`, um alle oben gezeigten Beispieldateien einzuschließen.
|
||||
### Starting from an example
|
||||
|
||||
To start from a more complete example with custom objects, fields, logic functions, front components, and more, use the `--example` flag:
|
||||
|
||||
```bash filename="Terminal"
|
||||
npx create-twenty-app@latest my-twenty-app --example postcard
|
||||
```
|
||||
|
||||
Examples are sourced from the [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples) directory on GitHub. You can also scaffold individual entities into an existing project with `yarn twenty add` (see [Building Apps](/l/de/developers/extend/apps/building#scaffolding-entities-with-yarn-twenty-add)).
|
||||
|
||||
### Wichtige Dateien
|
||||
|
||||
| Datei / Ordner | Zweck |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `package.json` | Deklariert den App-Namen, die Version und Abhängigkeiten. Enthält ein `twenty`-Skript, sodass Sie `yarn twenty help` ausführen können, um alle Befehle anzuzeigen. |
|
||||
| `src/application-config.ts` | **Erforderlich.** Die Hauptkonfigurationsdatei für Ihre App. |
|
||||
| `src/roles/` | Definiert Rollen, die steuern, worauf Ihre Logikfunktionen zugreifen können. |
|
||||
| `src/logic-functions/` | Serverseitige Funktionen, die durch Routen, Cron-Zeitpläne oder Datenbankereignisse ausgelöst werden. |
|
||||
| `src/front-components/` | React-Komponenten, die innerhalb der Twenty-UI gerendert werden. |
|
||||
| `src/objects/` | Benutzerdefinierte Objektdefinitionen zur Erweiterung Ihres Datenmodells. |
|
||||
| `src/fields/` | Benutzerdefinierte Felder, die vorhandenen Objekten hinzugefügt werden. |
|
||||
| `src/views/` | Konfigurationen gespeicherter Ansichten. |
|
||||
| `src/navigation-menu-items/` | Benutzerdefinierte Links in der Seitenleisten-Navigation. |
|
||||
| `src/skills/` | Skills, die die KI-Agenten von Twenty erweitern. |
|
||||
| `src/agents/` | KI-Agenten mit benutzerdefinierten Prompts. |
|
||||
| `src/page-layouts/` | Benutzerdefinierte Seitenlayouts für Datensatzansichten. |
|
||||
| `src/__tests__/` | Integrationstests (Setup + Beispieltest). |
|
||||
| `public/` | Statische Assets (Bilder, Schriftarten), die mit Ihrer App ausgeliefert werden. |
|
||||
| Datei / Ordner | Zweck |
|
||||
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `package.json` | Deklariert den App-Namen, die Version und Abhängigkeiten. Enthält ein `twenty`-Skript, sodass Sie `yarn twenty help` ausführen können, um alle Befehle anzuzeigen. |
|
||||
| `src/application-config.ts` | **Erforderlich.** Die Hauptkonfigurationsdatei für Ihre App. |
|
||||
| `src/default-role.ts` | Default role that controls what your logic functions can access. |
|
||||
| `src/constants/universal-identifiers.ts` | Auto-generated UUIDs and app metadata (display name, description). |
|
||||
| `src/__tests__/` | Integrationstests (Setup + Beispieltest). |
|
||||
| `public/` | Statische Assets (Bilder, Schriftarten), die mit Ihrer App ausgeliefert werden. |
|
||||
|
||||
## Remotes verwalten
|
||||
## Local development server
|
||||
|
||||
Ein **Remote** ist ein Twenty-Server, mit dem sich Ihre App verbindet. Während der Einrichtung erstellt das Scaffolding-Tool automatisch eines für Sie. Sie können jederzeit weitere Remotes hinzufügen oder zwischen ihnen wechseln.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Ihre Anmeldedaten werden in `~/.twenty/config.json` gespeichert.
|
||||
|
||||
## Lokaler Entwicklungsserver (`yarn twenty server`)
|
||||
|
||||
Die CLI kann einen lokalen, in Docker laufenden Twenty-Server verwalten. Dies ist derselbe Server, der automatisch gestartet wird, wenn Sie mit `create-twenty-app` eine App aufsetzen, aber Sie können ihn auch manuell verwalten.
|
||||
|
||||
### Server starten
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start
|
||||
```
|
||||
|
||||
Dadurch wird das Docker-Image `twentycrm/twenty-app-dev:latest` heruntergeladen (falls nicht bereits vorhanden), ein Container namens `twenty-app-dev` erstellt und auf Port **2020** gestartet. Die CLI wartet, bis der Server seinen Health-Check bestanden hat, bevor sie zurückkehrt.
|
||||
|
||||
Es werden zwei Docker-Volumes erstellt, um Daten zwischen Neustarts beizubehalten:
|
||||
|
||||
* `twenty-app-dev-data` — PostgreSQL-Datenbank
|
||||
* `twenty-app-dev-storage` — Dateispeicher
|
||||
|
||||
Wenn Port 2020 bereits verwendet wird, können Sie auf einem anderen Port starten:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start --port 3030
|
||||
```
|
||||
|
||||
Die CLI konfiguriert automatisch die internen Werte `NODE_PORT` und `SERVER_URL` des Containers passend zum gewählten Port, sodass Logikfunktionen, OAuth und alle anderen internen Netzwerkfunktionen korrekt arbeiten.
|
||||
|
||||
Nach dem Start wird der Server automatisch als `local`-Remote in Ihrer CLI-Konfiguration registriert.
|
||||
|
||||
### Serverstatus prüfen
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server status
|
||||
```
|
||||
|
||||
Zeigt an, ob der Server läuft, seine URL und die Standard-Anmeldedaten (`tim@apple.dev` / `tim@apple.dev`).
|
||||
|
||||
### Serverprotokolle anzeigen
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs
|
||||
```
|
||||
|
||||
Streamt die Containerprotokolle. Verwenden Sie `--lines`, um zu steuern, wie viele der letzten Zeilen angezeigt werden:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs --lines 100
|
||||
```
|
||||
|
||||
### Server stoppen
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server stop
|
||||
```
|
||||
|
||||
Stoppt den Container. Ihre Daten bleiben in den Docker-Volumes erhalten — der nächste `start` macht dort weiter, wo Sie aufgehört haben.
|
||||
|
||||
### Server zurücksetzen
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server reset
|
||||
```
|
||||
|
||||
Entfernt den Container **und** löscht beide Docker-Volumes, wobei alle Daten gelöscht werden. Der nächste `start` erstellt eine frische Instanz.
|
||||
|
||||
<Note>
|
||||
Der Server erfordert, dass **Docker** läuft. Wenn der Fehler "Docker not running" angezeigt wird, stellen Sie sicher, dass Docker Desktop (oder der Docker-Daemon) gestartet ist.
|
||||
</Note>
|
||||
|
||||
### Befehlsreferenz
|
||||
The scaffolder already started a local Twenty server for you. To manage it later, use `yarn twenty server`:
|
||||
|
||||
| Befehl | Beschreibung |
|
||||
| -------------------------------------- | ----------------------------------------------------------- |
|
||||
@@ -313,65 +211,11 @@ Entfernt den Container **und** löscht beide Docker-Volumes, wobei alle Daten ge
|
||||
| `yarn twenty server logs --lines 100` | Die letzten 100 Protokollzeilen anzeigen |
|
||||
| `yarn twenty server reset` | Alle Daten löschen und neu starten |
|
||||
|
||||
## CI mit GitHub Actions
|
||||
Data is persisted across restarts in two Docker volumes (`twenty-app-dev-data` for PostgreSQL, `twenty-app-dev-storage` for files). Use `reset` to wipe everything and start fresh.
|
||||
|
||||
Das Scaffolding-Tool erzeugt einen einsatzbereiten GitHub-Actions-Workflow in `.github/workflows/ci.yml`. Er führt Ihre Integrationstests automatisch bei jedem Push auf `main` und bei Pull Requests aus.
|
||||
|
||||
Der Workflow:
|
||||
|
||||
1. Checkt Ihren Code aus
|
||||
2. Startet einen temporären Twenty-Server mit der Aktion `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Installiert Abhängigkeiten mit `yarn install --immutable`
|
||||
4. Führt `yarn test` aus, wobei `TWENTY_API_URL` und `TWENTY_API_KEY` aus den Aktionsausgaben injiziert werden.
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Sie müssen keine Secrets konfigurieren — die Aktion `spawn-twenty-docker-image` startet einen flüchtigen Twenty-Server direkt im Runner und gibt die Verbindungsdetails aus. Das Secret `GITHUB_TOKEN` wird automatisch von GitHub bereitgestellt.
|
||||
|
||||
Um eine bestimmte Twenty-Version statt `latest` festzulegen, ändern Sie die Umgebungsvariable `TWENTY_VERSION` oben im Workflow.
|
||||
<Note>
|
||||
Der Server erfordert, dass **Docker** läuft. Wenn der Fehler "Docker not running" angezeigt wird, stellen Sie sicher, dass Docker Desktop (oder der Docker-Daemon) gestartet ist.
|
||||
</Note>
|
||||
|
||||
## Manuelle Einrichtung (ohne Scaffolder)
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ import { defineApplication } from 'twenty-sdk';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7',
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
displayName: 'My Twenty App',
|
||||
description: 'My first Twenty app',
|
||||
icon: 'IconWorld',
|
||||
@@ -716,6 +716,13 @@ Punti chiave:
|
||||
|
||||
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.
|
||||
|
||||
#### Dove possono essere utilizzati i componenti front.
|
||||
|
||||
I componenti front possono essere renderizzati in due posizioni all'interno di Twenty:
|
||||
|
||||
* **Pannello laterale** — I componenti front non headless si aprono nel pannello laterale destro. Questo è il comportamento predefinito quando un componente front viene avviato dal menu comandi.
|
||||
* **Widget (dashboard e pagine dei record)** — I componenti front possono essere incorporati come widget all'interno dei layout di pagina. Quando si configura una dashboard o il layout di una pagina record, gli utenti possono aggiungere un widget del componente front.
|
||||
|
||||
#### Esempio di base
|
||||
|
||||
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:
|
||||
@@ -773,9 +780,13 @@ Fai clic per renderizzare il componente in linea.
|
||||
|
||||
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.
|
||||
|
||||
#### Componenti headless (`isHeadless: true`)
|
||||
#### Headless vs non headless
|
||||
|
||||
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.
|
||||
I componenti front prevedono due modalità di rendering controllate dall'opzione `isHeadless`:
|
||||
|
||||
**Non headless (predefinito)** — Il componente renderizza un'interfaccia utente visibile. Quando viene avviato dal menu comandi, si apre nel pannello laterale. Questo è il comportamento predefinito quando `isHeadless` è `false` o omesso.
|
||||
|
||||
**Headless (`isHeadless: true`)** — Il componente viene montato in modo invisibile in background. Non apre il pannello laterale. I componenti headless sono pensati per azioni che eseguono una logica e poi si smontano — ad esempio, eseguire un'attività asincrona, navigare a una pagina o mostrare una finestra modale di conferma. Si abbinano naturalmente ai componenti Command dell'SDK descritti di seguito.
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent, useRecordId, enqueueSnackbar } from 'twenty-sdk';
|
||||
@@ -802,6 +813,89 @@ export default defineFrontComponent({
|
||||
|
||||
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.
|
||||
|
||||
#### Componenti Command dell'SDK
|
||||
|
||||
Il pacchetto `twenty-sdk` fornisce quattro componenti di supporto Command progettati per i componenti front headless. Ogni componente esegue un'azione al montaggio, gestisce gli errori mostrando una notifica snackbar e smonta automaticamente il componente front al termine.
|
||||
|
||||
Importali da `twenty-sdk/command`:
|
||||
|
||||
* **`Command`** — Esegue una callback asincrona tramite la prop `execute`.
|
||||
* **`CommandLink`** — Naviga verso un percorso dell'app. Props: `to`, `params`, `queryParams`, `options`.
|
||||
* **`CommandModal`** — Apre una finestra modale di conferma. Se l'utente conferma, esegue la callback `execute`. Props: `title`, `subtitle`, `execute`, `confirmButtonText`, `confirmButtonAccent`.
|
||||
* **`CommandOpenSidePanelPage`** — Apre una specifica pagina del pannello laterale. Props: `page`, `pageTitle`, `pageIcon`.
|
||||
|
||||
Ecco un esempio completo di componente front headless che usa `Command` per eseguire un'azione dal menu comandi:
|
||||
|
||||
```tsx src/front-components/run-action.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const RunAction = () => {
|
||||
const execute = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
createTask: {
|
||||
__args: { data: { title: 'Created by my app' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
||||
name: 'run-action',
|
||||
description: 'Creates a task from the command menu',
|
||||
component: RunAction,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
|
||||
label: 'Run my action',
|
||||
icon: 'IconPlayerPlay',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
E un esempio che usa `CommandModal` per chiedere conferma prima di eseguire:
|
||||
|
||||
```tsx src/front-components/delete-draft.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { CommandModal } from 'twenty-sdk/command';
|
||||
|
||||
const DeleteDraft = () => {
|
||||
const execute = async () => {
|
||||
// perform the deletion
|
||||
};
|
||||
|
||||
return (
|
||||
<CommandModal
|
||||
title="Delete draft?"
|
||||
subtitle="This action cannot be undone."
|
||||
execute={execute}
|
||||
confirmButtonText="Delete"
|
||||
confirmButtonAccent="danger"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'a7b8c9d0-e1f2-3456-abcd-567890123456',
|
||||
name: 'delete-draft',
|
||||
description: 'Deletes a draft with confirmation',
|
||||
component: DeleteDraft,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'b8c9d0e1-f2a3-4567-bcde-678901234567',
|
||||
label: 'Delete draft',
|
||||
icon: 'IconTrash',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### Accesso al contesto di runtime
|
||||
|
||||
All'interno del tuo componente, usa gli hook dell'SDK per accedere all'utente corrente, al record e all'istanza del componente:
|
||||
@@ -858,6 +952,50 @@ I componenti front-end possono attivare navigazione, modali e notifiche utilizza
|
||||
| `unmountFrontComponent()` | Smonta il componente |
|
||||
| `updateProgress(progress)` | Aggiorna un indicatore di avanzamento |
|
||||
|
||||
Ecco un esempio che usa l'API host per mostrare una snackbar e chiudere il pannello laterale dopo il completamento di un'azione:
|
||||
|
||||
```tsx src/front-components/archive-record.tsx
|
||||
import { defineFrontComponent, useRecordId } from 'twenty-sdk';
|
||||
import { enqueueSnackbar, closeSidePanel } from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const ArchiveRecord = () => {
|
||||
const recordId = useRecordId();
|
||||
|
||||
const handleArchive = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
updateTask: {
|
||||
__args: { id: recordId, data: { status: 'ARCHIVED' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
await enqueueSnackbar({
|
||||
message: 'Record archived',
|
||||
variant: 'success',
|
||||
});
|
||||
|
||||
await closeSidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<p>Archive this record?</p>
|
||||
<button onClick={handleArchive}>Archive</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'c9d0e1f2-a3b4-5678-cdef-789012345678',
|
||||
name: 'archive-record',
|
||||
description: 'Archives the current record',
|
||||
component: ArchiveRecord,
|
||||
});
|
||||
```
|
||||
|
||||
#### Opzioni del comando
|
||||
|
||||
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.
|
||||
@@ -1712,3 +1850,86 @@ yarn twenty uninstall
|
||||
# Skip the confirmation prompt
|
||||
yarn twenty uninstall --yes
|
||||
```
|
||||
|
||||
## Gestione dei remoti
|
||||
|
||||
Un **remoto** è un server Twenty a cui la tua app si connette. Durante la configurazione, lo strumento di scaffolding ne crea uno automaticamente per te. Puoi aggiungere altri remoti o passare da uno all'altro in qualsiasi momento.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Le tue credenziali sono archiviate in `~/.twenty/config.json`.
|
||||
|
||||
## CI con GitHub Actions
|
||||
|
||||
Lo strumento di scaffolding genera un workflow GitHub Actions pronto all'uso in `.github/workflows/ci.yml`. Esegue automaticamente i test di integrazione a ogni push su `main` e sulle pull request.
|
||||
|
||||
Il workflow:
|
||||
|
||||
1. Esegue il checkout del tuo codice
|
||||
2. Avvia un server Twenty temporaneo utilizzando l'azione `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Installa le dipendenze con `yarn install --immutable`
|
||||
4. Esegue `yarn test` con `TWENTY_API_URL` e `TWENTY_API_KEY` iniettati dagli output dell'azione
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Non è necessario configurare alcun secret — l'azione `spawn-twenty-docker-image` avvia un server Twenty effimero direttamente nel runner e fornisce i dettagli di connessione. Il secret `GITHUB_TOKEN` è fornito automaticamente da GitHub.
|
||||
|
||||
Per fissare una versione specifica di Twenty invece di `latest`, modifica la variabile d'ambiente `TWENTY_VERSION` all'inizio del workflow.
|
||||
|
||||
@@ -7,7 +7,9 @@ description: Crea la tua prima app Twenty in pochi minuti.
|
||||
Le app sono attualmente in fase alfa. La funzionalità funziona ma è ancora in evoluzione.
|
||||
</Warning>
|
||||
|
||||
Le app ti permettono di estendere Twenty con oggetti, campi, funzioni logiche, competenze IA e componenti UI personalizzati — il tutto gestito come codice.
|
||||
## Cosa sono le app?
|
||||
|
||||
Le app ti consentono di estendere Twenty con oggetti, campi, funzioni logiche, componenti front-end, competenze IA e altro ancora — il tutto gestito come codice. Invece di configurare tutto tramite l'interfaccia utente, definisci in TypeScript il modello dati e la logica e li distribuisci in uno o più spazi di lavoro.
|
||||
|
||||
## Prerequisiti
|
||||
|
||||
@@ -17,7 +19,9 @@ Prima di iniziare, assicurati che quanto segue sia installato sul tuo computer:
|
||||
* **Yarn 4** — Incluso con Node.js tramite Corepack. Abilitalo eseguendo `corepack enable`
|
||||
* **Docker** — [Scarica qui](https://www.docker.com/products/docker-desktop/). Necessario per eseguire un'istanza locale di Twenty. Non necessario se hai già un server Twenty in esecuzione.
|
||||
|
||||
## Passaggio 1: Crea lo scheletro della tua app
|
||||
## Create your first app
|
||||
|
||||
### Scaffold your app
|
||||
|
||||
Apri un terminale ed esegui:
|
||||
|
||||
@@ -29,18 +33,7 @@ Ti verrà chiesto di inserire un nome e una descrizione per la tua app. Premi **
|
||||
|
||||
Questo crea una nuova cartella chiamata `my-twenty-app` con tutto il necessario.
|
||||
|
||||
<Note>
|
||||
Lo strumento di scaffolding supporta questi flag:
|
||||
|
||||
* `--minimal` — genera solo i file essenziali, senza esempi (predefinito)
|
||||
* `--exhaustive` — genera tutte le entità di esempio
|
||||
* `--name <name>` — imposta il nome dell'app (salta la richiesta)
|
||||
* `--display-name <displayName>` — imposta il nome visualizzato (salta la richiesta)
|
||||
* `--description <description>` — imposta la descrizione (salta la richiesta)
|
||||
* `--skip-local-instance` — salta la richiesta di configurazione del server locale
|
||||
</Note>
|
||||
|
||||
## Passaggio 2: Configura un'istanza locale di Twenty
|
||||
### Set up a local Twenty instance
|
||||
|
||||
Lo strumento di scaffolding chiederà:
|
||||
|
||||
@@ -53,7 +46,7 @@ Lo strumento di scaffolding chiederà:
|
||||
<img src="/images/docs/developers/extends/apps/start-instance.png" alt="Avviare l'istanza locale?" />
|
||||
</div>
|
||||
|
||||
## Passaggio 3: Accedi al tuo spazio di lavoro
|
||||
### Sign in to your workspace
|
||||
|
||||
Successivamente si aprirà una finestra del browser con la pagina di accesso di Twenty. Accedi con l'account demo preconfigurato:
|
||||
|
||||
@@ -64,7 +57,7 @@ Successivamente si aprirà una finestra del browser con la pagina di accesso di
|
||||
<img src="/images/docs/developers/extends/apps/login.png" alt="Schermata di accesso di Twenty" />
|
||||
</div>
|
||||
|
||||
## Passaggio 4: Autorizza l'app
|
||||
### Authorize the app
|
||||
|
||||
Dopo l'accesso, vedrai una schermata di autorizzazione. Questo consente alla tua app di interagire con il tuo spazio di lavoro.
|
||||
|
||||
@@ -80,7 +73,7 @@ Una volta autorizzato, il terminale confermerà che tutto è configurato.
|
||||
<img src="/images/docs/developers/extends/apps/scaffolded.png" alt="App creata con successo" />
|
||||
</div>
|
||||
|
||||
## Passaggio 5: Inizia a sviluppare
|
||||
### Start developing
|
||||
|
||||
Entra nella nuova cartella della tua app e avvia il server di sviluppo:
|
||||
|
||||
@@ -105,7 +98,7 @@ La modalità di sviluppo è disponibile solo sulle istanze di Twenty in esecuzio
|
||||
<img src="/images/docs/developers/extends/apps/dev.jpg" alt="Output del terminale in modalità sviluppo" />
|
||||
</div>
|
||||
|
||||
## Passaggio 6: Visualizza la tua app in Twenty
|
||||
### See your app in Twenty
|
||||
|
||||
Apri [http://localhost:2020/settings/applications#developer](http://localhost:2020/settings/applications#developer) nel browser. Vai su **Settings > Apps** e seleziona la scheda **Developer**. Dovresti vedere la tua app elencata in **Your Apps**:
|
||||
|
||||
@@ -133,13 +126,28 @@ Passa alla scheda **Content** per vedere tutto ciò che la tua app fornisce —
|
||||
|
||||
È tutto pronto! Modifica qualsiasi file in `src/` e le modifiche verranno rilevate automaticamente.
|
||||
|
||||
Vai a [Creare app](/l/it/developers/extend/apps/building) per una guida dettagliata sulla creazione di oggetti, funzioni logiche, componenti front-end, skill e altro.
|
||||
---
|
||||
|
||||
## Cosa puoi creare
|
||||
|
||||
Apps are composed of **entities** — each defined as a TypeScript file with a single `export default`:
|
||||
|
||||
| Entity | What it does |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------- |
|
||||
| **Objects & Fields** | Define custom data models (like Post Card, Invoice) with typed fields |
|
||||
| **Funzioni logiche** | Server-side TypeScript functions triggered by HTTP routes, cron schedules, or database events |
|
||||
| **Componenti front-end** | React components that render inside Twenty's UI (side panel, widgets, command menu) |
|
||||
| **Skills & Agents** | AI capabilities — reusable instructions and autonomous assistants |
|
||||
| **Views & Navigation** | Pre-configured list views and sidebar menu items for your objects |
|
||||
| **Layout di pagina** | Custom record detail pages with tabs and widgets |
|
||||
|
||||
Head over to [Building Apps](/l/it/developers/extend/apps/building) for a detailed guide on each entity type.
|
||||
|
||||
---
|
||||
|
||||
## Struttura del progetto
|
||||
|
||||
Lo strumento di scaffolding genera la seguente struttura di file (mostrata con la modalità `--exhaustive`, che include esempi per ogni tipo di entità):
|
||||
The scaffolder generates the following file structure:
|
||||
|
||||
```text filename="my-twenty-app/"
|
||||
my-twenty-app/
|
||||
@@ -148,160 +156,50 @@ my-twenty-app/
|
||||
.gitignore
|
||||
.nvmrc
|
||||
.yarnrc.yml
|
||||
.yarn/
|
||||
install-state.gz
|
||||
.oxlintrc.json
|
||||
tsconfig.json
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
LLMS.md
|
||||
README.md
|
||||
.github/
|
||||
└── workflows/
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
src/
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── __tests__/
|
||||
│ ├── setup-test.ts # Test setup (server health check, config)
|
||||
│ └── app-install.integration-test.ts # Example integration test
|
||||
├── roles/
|
||||
│ └── default-role.ts # Default role for logic functions
|
||||
├── objects/
|
||||
│ └── example-object.ts # Example custom object definition
|
||||
├── fields/
|
||||
│ └── example-field.ts # Example standalone field definition
|
||||
├── logic-functions/
|
||||
│ ├── hello-world.ts # Example logic function
|
||||
│ ├── create-hello-world-company.ts # Example logic function using CoreApiClient
|
||||
│ ├── pre-install.ts # Runs before installation
|
||||
│ └── post-install.ts # Runs after installation
|
||||
├── front-components/
|
||||
│ └── hello-world.tsx # Example front component
|
||||
├── page-layouts/
|
||||
│ └── example-record-page-layout.ts # Example page layout with front component
|
||||
├── views/
|
||||
│ └── example-view.ts # Example saved view definition
|
||||
├── navigation-menu-items/
|
||||
│ └── example-navigation-menu-item.ts # Example sidebar navigation link
|
||||
├── skills/
|
||||
│ └── example-skill.ts # Example AI agent skill definition
|
||||
└── agents/
|
||||
└── example-agent.ts # Example AI agent definition
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── default-role.ts # Default role for logic functions
|
||||
├── constants/
|
||||
│ └── universal-identifiers.ts # Auto-generated UUIDs and app metadata
|
||||
└── __tests__/
|
||||
├── setup-test.ts # Test setup (server health check, config)
|
||||
└── app-install.integration-test.ts # Integration test
|
||||
```
|
||||
|
||||
Per impostazione predefinita (`--minimal`), vengono creati solo i file principali: `application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` e `logic-functions/post-install.ts`. Usa `--exhaustive` per includere tutti i file di esempio mostrati sopra.
|
||||
### Starting from an example
|
||||
|
||||
To start from a more complete example with custom objects, fields, logic functions, front components, and more, use the `--example` flag:
|
||||
|
||||
```bash filename="Terminal"
|
||||
npx create-twenty-app@latest my-twenty-app --example postcard
|
||||
```
|
||||
|
||||
Examples are sourced from the [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples) directory on GitHub. You can also scaffold individual entities into an existing project with `yarn twenty add` (see [Building Apps](/l/it/developers/extend/apps/building#scaffolding-entities-with-yarn-twenty-add)).
|
||||
|
||||
### File principali
|
||||
|
||||
| File / Cartella | Scopo |
|
||||
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Dichiara il nome, la versione e le dipendenze della tua app. Include uno script `twenty` così puoi eseguire `yarn twenty help` per vedere tutti i comandi. |
|
||||
| `src/application-config.ts` | **Obbligatorio.** Il file di configurazione principale della tua app. |
|
||||
| `src/roles/` | Definisce i ruoli che controllano a cosa possono accedere le tue funzioni logiche. |
|
||||
| `src/logic-functions/` | Funzioni lato server attivate da route, pianificazioni cron o eventi del database. |
|
||||
| `src/front-components/` | Componenti React che vengono renderizzati all'interno della UI di Twenty. |
|
||||
| `src/objects/` | Definizioni di oggetti personalizzati per estendere il tuo modello dati. |
|
||||
| `src/fields/` | Campi personalizzati aggiunti a oggetti esistenti. |
|
||||
| `src/views/` | Configurazioni di viste salvate. |
|
||||
| `src/navigation-menu-items/` | Link personalizzati nella navigazione laterale. |
|
||||
| `src/skills/` | Abilità che estendono gli agenti IA di Twenty. |
|
||||
| `src/agents/` | Agenti IA con prompt personalizzati. |
|
||||
| `src/page-layouts/` | Layout di pagina personalizzati per le viste dei record. |
|
||||
| `src/__tests__/` | Test di integrazione (setup + test di esempio). |
|
||||
| `public/` | Asset statici (immagini, font) serviti insieme alla tua app. |
|
||||
| File / Cartella | Scopo |
|
||||
| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Dichiara il nome, la versione e le dipendenze della tua app. Include uno script `twenty` così puoi eseguire `yarn twenty help` per vedere tutti i comandi. |
|
||||
| `src/application-config.ts` | **Obbligatorio.** Il file di configurazione principale della tua app. |
|
||||
| `src/default-role.ts` | Default role that controls what your logic functions can access. |
|
||||
| `src/constants/universal-identifiers.ts` | Auto-generated UUIDs and app metadata (display name, description). |
|
||||
| `src/__tests__/` | Test di integrazione (setup + test di esempio). |
|
||||
| `public/` | Asset statici (immagini, font) serviti insieme alla tua app. |
|
||||
|
||||
## Gestione dei remoti
|
||||
## Local development server
|
||||
|
||||
Un **remoto** è un server Twenty a cui la tua app si connette. Durante la configurazione, lo strumento di scaffolding ne crea uno automaticamente per te. Puoi aggiungere altri remoti o passare da uno all'altro in qualsiasi momento.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Le tue credenziali sono archiviate in `~/.twenty/config.json`.
|
||||
|
||||
## Server di sviluppo locale (`yarn twenty server`)
|
||||
|
||||
La CLI può gestire un server Twenty locale in esecuzione in Docker. Questo è lo stesso server avviato automaticamente quando crei lo scheletro di un'app con `create-twenty-app`, ma puoi anche gestirlo manualmente.
|
||||
|
||||
### Avvio del server
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start
|
||||
```
|
||||
|
||||
Questo scarica l'immagine Docker `twentycrm/twenty-app-dev:latest` (se non è già presente), crea un container chiamato `twenty-app-dev` e lo avvia sulla porta **2020**. La CLI attende che il server superi il controllo di integrità prima di restituire il controllo.
|
||||
|
||||
Vengono creati due volumi Docker per mantenere i dati tra i riavvii:
|
||||
|
||||
* `twenty-app-dev-data` — database PostgreSQL
|
||||
* `twenty-app-dev-storage` — archiviazione file
|
||||
|
||||
Se la porta 2020 è già in uso, puoi avviare su una porta diversa:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start --port 3030
|
||||
```
|
||||
|
||||
La CLI configura automaticamente le variabili interne del container `NODE_PORT` e `SERVER_URL` per corrispondere alla porta scelta, in modo che funzioni logiche, OAuth e tutto il resto del networking interno funzionino correttamente.
|
||||
|
||||
Una volta avviato, il server viene registrato automaticamente come remoto `local` nella configurazione della CLI.
|
||||
|
||||
### Verifica dello stato del server
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server status
|
||||
```
|
||||
|
||||
Mostra se il server è in esecuzione, il suo URL e le credenziali di accesso predefinite (`tim@apple.dev` / `tim@apple.dev`).
|
||||
|
||||
### Visualizzazione dei log del server
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs
|
||||
```
|
||||
|
||||
Trasmette in streaming i log del container. Usa `--lines` per controllare quante righe recenti mostrare:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs --lines 100
|
||||
```
|
||||
|
||||
### Arresto del server
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server stop
|
||||
```
|
||||
|
||||
Arresta il container. I tuoi dati vengono conservati nei volumi Docker — il prossimo `start` riprenderà da dove avevi lasciato.
|
||||
|
||||
### Reimpostazione del server
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server reset
|
||||
```
|
||||
|
||||
Rimuove il container **e** elimina entrambi i volumi Docker, cancellando tutti i dati. Il prossimo `start` crea un'istanza nuova.
|
||||
|
||||
<Note>
|
||||
Il server richiede che **Docker** sia in esecuzione. Se vedi l'errore "Docker not running", assicurati che Docker Desktop (o il demone Docker) sia avviato.
|
||||
</Note>
|
||||
|
||||
### Riferimento ai comandi
|
||||
The scaffolder already started a local Twenty server for you. To manage it later, use `yarn twenty server`:
|
||||
|
||||
| Comando | Descrizione |
|
||||
| -------------------------------------- | --------------------------------------------------------- |
|
||||
@@ -313,65 +211,11 @@ Rimuove il container **e** elimina entrambi i volumi Docker, cancellando tutti i
|
||||
| `yarn twenty server logs --lines 100` | Mostra le ultime 100 righe di log |
|
||||
| `yarn twenty server reset` | Elimina tutti i dati e riparti da zero |
|
||||
|
||||
## CI con GitHub Actions
|
||||
Data is persisted across restarts in two Docker volumes (`twenty-app-dev-data` for PostgreSQL, `twenty-app-dev-storage` for files). Use `reset` to wipe everything and start fresh.
|
||||
|
||||
Lo strumento di scaffolding genera un workflow GitHub Actions pronto all'uso in `.github/workflows/ci.yml`. Esegue automaticamente i test di integrazione a ogni push su `main` e sulle pull request.
|
||||
|
||||
Il workflow:
|
||||
|
||||
1. Esegue il checkout del tuo codice
|
||||
2. Avvia un server Twenty temporaneo utilizzando l'azione `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Installa le dipendenze con `yarn install --immutable`
|
||||
4. Esegue `yarn test` con `TWENTY_API_URL` e `TWENTY_API_KEY` iniettati dagli output dell'azione
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Non è necessario configurare alcun secret — l'azione `spawn-twenty-docker-image` avvia un server Twenty effimero direttamente nel runner e fornisce i dettagli di connessione. Il secret `GITHUB_TOKEN` è fornito automaticamente da GitHub.
|
||||
|
||||
Per fissare una versione specifica di Twenty invece di `latest`, modifica la variabile d'ambiente `TWENTY_VERSION` all'inizio del workflow.
|
||||
<Note>
|
||||
Il server richiede che **Docker** sia in esecuzione. Se vedi l'errore "Docker not running", assicurati che Docker Desktop (o il demone Docker) sia avviato.
|
||||
</Note>
|
||||
|
||||
## Configurazione manuale (senza lo scaffolder)
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ import { defineApplication } from 'twenty-sdk';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7',
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
displayName: 'My Twenty App',
|
||||
description: 'My first Twenty app',
|
||||
icon: 'IconWorld',
|
||||
@@ -716,6 +716,13 @@ Pontos-chave:
|
||||
|
||||
Componentes de front-end são componentes React que renderizam diretamente dentro da UI do Twenty. Eles são executados em um Web Worker isolado usando Remote DOM — seu código é sandboxed, mas renderiza nativamente na página, não em um iframe.
|
||||
|
||||
#### Onde os componentes de front-end podem ser usados
|
||||
|
||||
Os componentes de front-end podem ser renderizados em dois locais dentro do Twenty:
|
||||
|
||||
* **Painel lateral** — Componentes de front-end não headless abrem no painel lateral direito. Este é o comportamento padrão quando um componente de front-end é acionado pelo menu de comandos.
|
||||
* **Widgets (painéis e páginas de registro)** — Componentes de front-end podem ser incorporados como widgets nos layouts de página. Ao configurar um painel ou o layout de uma página de registro, os usuários podem adicionar um widget de componente de front-end.
|
||||
|
||||
#### Exemplo básico
|
||||
|
||||
A maneira mais rápida de ver um componente de front-end em ação é registrá-lo como um **comando**. Adicionar um campo `command` com `isPinned: true` faz com que ele apareça como um botão de ação rápida no canto superior direito da página — não é necessário layout de página:
|
||||
@@ -773,9 +780,13 @@ Clique nele para renderizar o componente inline.
|
||||
|
||||
Além de comandos, você pode incorporar um componente de front-end diretamente em uma página de registro adicionando-o como um widget em um **layout de página**. Veja a seção [definePageLayout](#definepagelayout) para obter detalhes.
|
||||
|
||||
#### Componentes sem interface (`isHeadless: true`)
|
||||
#### Headless vs não headless
|
||||
|
||||
Componentes sem interface não renderizam nenhuma UI visível, mas ainda executam a lógica do React. Isso é útil para **componentes de efeito** — componentes que executam efeitos colaterais quando montados, como sincronizar dados, iniciar um temporizador, ouvir eventos ou disparar uma notificação.
|
||||
Os componentes de front-end têm dois modos de renderização controlados pela opção `isHeadless`:
|
||||
|
||||
**Não headless (padrão)** — O componente renderiza uma interface visível. Quando acionado pelo menu de comandos, ele é aberto no painel lateral. Este é o comportamento padrão quando `isHeadless` é `false` ou omitido.
|
||||
|
||||
**Headless (`isHeadless: true`)** — The component mounts invisibly in the background. Ele não abre o painel lateral. Componentes headless são projetados para ações que executam lógica e, em seguida, se desmontam — por exemplo, executar uma tarefa assíncrona, navegar para uma página ou exibir um modal de confirmação. Eles se combinam naturalmente com os componentes Command do SDK descritos abaixo.
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent, useRecordId, enqueueSnackbar } from 'twenty-sdk';
|
||||
@@ -802,6 +813,89 @@ export default defineFrontComponent({
|
||||
|
||||
Como o componente retorna `null`, o Twenty ignora renderizar um contêiner para ele — nenhum espaço vazio aparece no layout. O componente ainda tem acesso a todos os hooks e à API de comunicação do host.
|
||||
|
||||
#### Componentes Command do SDK
|
||||
|
||||
O pacote `twenty-sdk` fornece quatro componentes auxiliares Command projetados para componentes de front-end headless. Cada componente executa uma ação ao montar, trata erros exibindo uma notificação de snackbar e desmonta automaticamente o componente de front-end ao concluir.
|
||||
|
||||
Importe-os de `twenty-sdk/command`:
|
||||
|
||||
* **`Command`** — Executa um callback assíncrono via a prop `execute`.
|
||||
* **`CommandLink`** — Navega para um caminho do app. Props: `to`, `params`, `queryParams`, `options`.
|
||||
* **`CommandModal`** — Abre um modal de confirmação. Se o usuário confirmar, executa o callback `execute`. Props: `title`, `subtitle`, `execute`, `confirmButtonText`, `confirmButtonAccent`.
|
||||
* **`CommandOpenSidePanelPage`** — Abre uma página específica do painel lateral. Props: `page`, `pageTitle`, `pageIcon`.
|
||||
|
||||
Aqui está um exemplo completo de um componente de front-end headless usando `Command` para executar uma ação a partir do menu de comandos:
|
||||
|
||||
```tsx src/front-components/run-action.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const RunAction = () => {
|
||||
const execute = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
createTask: {
|
||||
__args: { data: { title: 'Created by my app' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
||||
name: 'run-action',
|
||||
description: 'Creates a task from the command menu',
|
||||
component: RunAction,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
|
||||
label: 'Run my action',
|
||||
icon: 'IconPlayerPlay',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
E um exemplo usando `CommandModal` para solicitar confirmação antes de executar:
|
||||
|
||||
```tsx src/front-components/delete-draft.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { CommandModal } from 'twenty-sdk/command';
|
||||
|
||||
const DeleteDraft = () => {
|
||||
const execute = async () => {
|
||||
// perform the deletion
|
||||
};
|
||||
|
||||
return (
|
||||
<CommandModal
|
||||
title="Delete draft?"
|
||||
subtitle="This action cannot be undone."
|
||||
execute={execute}
|
||||
confirmButtonText="Delete"
|
||||
confirmButtonAccent="danger"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'a7b8c9d0-e1f2-3456-abcd-567890123456',
|
||||
name: 'delete-draft',
|
||||
description: 'Deletes a draft with confirmation',
|
||||
component: DeleteDraft,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'b8c9d0e1-f2a3-4567-bcde-678901234567',
|
||||
label: 'Delete draft',
|
||||
icon: 'IconTrash',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### Acessando o contexto de execução
|
||||
|
||||
Dentro do seu componente, use hooks do SDK para acessar o usuário atual, o registro e a instância do componente:
|
||||
@@ -858,6 +952,50 @@ Componentes de front-end podem acionar navegação, modais e notificações usan
|
||||
| `unmountFrontComponent()` | Desmontar o componente |
|
||||
| `updateProgress(progress)` | Atualizar um indicador de progresso |
|
||||
|
||||
Aqui está um exemplo que usa a API do host para exibir um snackbar e fechar o painel lateral após a conclusão de uma ação:
|
||||
|
||||
```tsx src/front-components/archive-record.tsx
|
||||
import { defineFrontComponent, useRecordId } from 'twenty-sdk';
|
||||
import { enqueueSnackbar, closeSidePanel } from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const ArchiveRecord = () => {
|
||||
const recordId = useRecordId();
|
||||
|
||||
const handleArchive = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
updateTask: {
|
||||
__args: { id: recordId, data: { status: 'ARCHIVED' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
await enqueueSnackbar({
|
||||
message: 'Record archived',
|
||||
variant: 'success',
|
||||
});
|
||||
|
||||
await closeSidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<p>Archive this record?</p>
|
||||
<button onClick={handleArchive}>Archive</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'c9d0e1f2-a3b4-5678-cdef-789012345678',
|
||||
name: 'archive-record',
|
||||
description: 'Archives the current record',
|
||||
component: ArchiveRecord,
|
||||
});
|
||||
```
|
||||
|
||||
#### Opções de comando
|
||||
|
||||
Adicionar um campo `command` a `defineFrontComponent` registra o componente no menu de comandos (Cmd+K). Se `isPinned` for `true`, ele também aparece como um botão de ação rápida no canto superior direito da página.
|
||||
@@ -1712,3 +1850,86 @@ yarn twenty uninstall
|
||||
# Skip the confirmation prompt
|
||||
yarn twenty uninstall --yes
|
||||
```
|
||||
|
||||
## Gerenciando remotos
|
||||
|
||||
Um **remoto** é um servidor Twenty ao qual seu aplicativo se conecta. Durante a configuração, o gerador de scaffold cria um para você automaticamente. Você pode adicionar mais remotos ou alternar entre eles a qualquer momento.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Suas credenciais são armazenadas em `~/.twenty/config.json`.
|
||||
|
||||
## CI com GitHub Actions
|
||||
|
||||
O gerador de scaffold cria um workflow do GitHub Actions pronto para uso em `.github/workflows/ci.yml`. Ele executa seus testes de integração automaticamente a cada push para `main` e em pull requests.
|
||||
|
||||
O workflow:
|
||||
|
||||
1. Faz checkout do seu código
|
||||
2. Inicializa um servidor Twenty temporário usando a ação `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Instala as dependências com `yarn install --immutable`
|
||||
4. Executa `yarn test` com `TWENTY_API_URL` e `TWENTY_API_KEY` injetados a partir das saídas da ação
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Você não precisa configurar nenhum segredo — a ação `spawn-twenty-docker-image` inicia um servidor Twenty efêmero diretamente no runner e fornece os detalhes de conexão. O segredo `GITHUB_TOKEN` é fornecido automaticamente pelo GitHub.
|
||||
|
||||
Para fixar uma versão específica do Twenty em vez de `latest`, altere a variável de ambiente `TWENTY_VERSION` no topo do workflow.
|
||||
|
||||
@@ -7,7 +7,9 @@ description: Crie seu primeiro app do Twenty em minutos.
|
||||
Os aplicativos estão atualmente em testes alfa. O recurso é funcional, mas ainda está evoluindo.
|
||||
</Warning>
|
||||
|
||||
Os apps permitem que você estenda o Twenty com objetos, campos, funções de lógica, habilidades de IA e componentes de UI personalizados — tudo gerenciado como código.
|
||||
## O que são aplicativos?
|
||||
|
||||
Os aplicativos permitem que você estenda o Twenty com objetos e campos personalizados, funções lógicas, componentes de front-end, habilidades de IA e mais — tudo gerenciado como código. Em vez de configurar tudo pela UI, você define seu modelo de dados e a lógica em TypeScript e implanta em um ou mais workspaces.
|
||||
|
||||
## Pré-requisitos
|
||||
|
||||
@@ -17,7 +19,9 @@ Antes de começar, verifique se o seguinte está instalado na sua máquina:
|
||||
* **Yarn 4** — Vem com o Node.js via Corepack. Ative-o executando `corepack enable`
|
||||
* **Docker** — [Baixe aqui](https://www.docker.com/products/docker-desktop/). Necessário para executar uma instância local do Twenty. Não é necessário se você já tiver um servidor Twenty em execução.
|
||||
|
||||
## Passo 1: Gere o scaffold do seu aplicativo
|
||||
## Create your first app
|
||||
|
||||
### Scaffold your app
|
||||
|
||||
Abra um terminal e execute:
|
||||
|
||||
@@ -29,18 +33,7 @@ Será solicitado que você informe um nome e uma descrição para o seu aplicati
|
||||
|
||||
Isso cria uma nova pasta chamada `my-twenty-app` com tudo de que você precisa.
|
||||
|
||||
<Note>
|
||||
O gerador de scaffold oferece suporte a estas flags:
|
||||
|
||||
* `--minimal` — gera apenas os arquivos essenciais, sem exemplos (padrão)
|
||||
* `--exhaustive` — gera todas as entidades de exemplo
|
||||
* `--name <name>` — define o nome do aplicativo (pula o prompt)
|
||||
* `--display-name <displayName>` — define o nome de exibição (pula o prompt)
|
||||
* `--description <description>` — define a descrição (pula o prompt)
|
||||
* `--skip-local-instance` — ignora o prompt de configuração do servidor local
|
||||
</Note>
|
||||
|
||||
## Passo 2: Configure uma instância local do Twenty
|
||||
### Set up a local Twenty instance
|
||||
|
||||
O gerador de scaffold perguntará:
|
||||
|
||||
@@ -53,7 +46,7 @@ O gerador de scaffold perguntará:
|
||||
<img src="/images/docs/developers/extends/apps/start-instance.png" alt="Deve iniciar instância local?" />
|
||||
</div>
|
||||
|
||||
## Passo 3: Faça login no seu espaço de trabalho
|
||||
### Sign in to your workspace
|
||||
|
||||
Em seguida, uma janela do navegador será aberta com a página de login do Twenty. Faça login com a conta de demonstração pré-configurada:
|
||||
|
||||
@@ -64,7 +57,7 @@ Em seguida, uma janela do navegador será aberta com a página de login do Twent
|
||||
<img src="/images/docs/developers/extends/apps/login.png" alt="Tela de login do Twenty" />
|
||||
</div>
|
||||
|
||||
## Passo 4: Autorize o aplicativo
|
||||
### Authorize the app
|
||||
|
||||
Após fazer login, você verá uma tela de autorização. Isso permite que seu aplicativo interaja com seu espaço de trabalho.
|
||||
|
||||
@@ -80,7 +73,7 @@ Depois de autorizado, seu terminal confirmará que tudo está configurado.
|
||||
<img src="/images/docs/developers/extends/apps/scaffolded.png" alt="Scaffold do aplicativo criado com sucesso" />
|
||||
</div>
|
||||
|
||||
## Passo 5: Comece a desenvolver
|
||||
### Start developing
|
||||
|
||||
Entre na nova pasta do seu aplicativo e inicie o servidor de desenvolvimento:
|
||||
|
||||
@@ -105,7 +98,7 @@ O modo de desenvolvimento só está disponível em instâncias do Twenty em modo
|
||||
<img src="/images/docs/developers/extends/apps/dev.jpg" alt="Saída do terminal no modo de desenvolvimento" />
|
||||
</div>
|
||||
|
||||
## Passo 6: Veja seu aplicativo no Twenty
|
||||
### See your app in Twenty
|
||||
|
||||
Abra [http://localhost:2020/settings/applications#developer](http://localhost:2020/settings/applications#developer) no seu navegador. Navegue até **Settings > Apps** e selecione a aba **Developer**. Você deverá ver seu aplicativo listado em **Your Apps**:
|
||||
|
||||
@@ -133,13 +126,28 @@ Altere para a aba **Content** para ver tudo o que seu aplicativo oferece — obj
|
||||
|
||||
Tudo pronto! Edite qualquer arquivo em `src/` e as alterações serão detectadas automaticamente.
|
||||
|
||||
Acesse [Criando aplicativos](/l/pt/developers/extend/apps/building) para um guia detalhado sobre criação de objetos, funções de lógica, componentes de front-end, habilidades e mais.
|
||||
---
|
||||
|
||||
## O que você pode criar
|
||||
|
||||
Apps are composed of **entities** — each defined as a TypeScript file with a single `export default`:
|
||||
|
||||
| Entity | What it does |
|
||||
| ---------------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| **Objects & Fields** | Define custom data models (like Post Card, Invoice) with typed fields |
|
||||
| **Funções lógicas** | Server-side TypeScript functions triggered by HTTP routes, cron schedules, or database events |
|
||||
| **Componentes de front-end** | React components that render inside Twenty's UI (side panel, widgets, command menu) |
|
||||
| **Skills & Agents** | AI capabilities — reusable instructions and autonomous assistants |
|
||||
| **Views & Navigation** | Pre-configured list views and sidebar menu items for your objects |
|
||||
| **Layouts de página** | Custom record detail pages with tabs and widgets |
|
||||
|
||||
Head over to [Building Apps](/l/pt/developers/extend/apps/building) for a detailed guide on each entity type.
|
||||
|
||||
---
|
||||
|
||||
## Estrutura do projeto
|
||||
|
||||
O gerador de scaffold cria a seguinte estrutura de arquivos (mostrada com o modo `--exhaustive`, que inclui exemplos para cada tipo de entidade):
|
||||
The scaffolder generates the following file structure:
|
||||
|
||||
```text filename="my-twenty-app/"
|
||||
my-twenty-app/
|
||||
@@ -148,160 +156,50 @@ my-twenty-app/
|
||||
.gitignore
|
||||
.nvmrc
|
||||
.yarnrc.yml
|
||||
.yarn/
|
||||
install-state.gz
|
||||
.oxlintrc.json
|
||||
tsconfig.json
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
LLMS.md
|
||||
README.md
|
||||
.github/
|
||||
└── workflows/
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
src/
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── __tests__/
|
||||
│ ├── setup-test.ts # Test setup (server health check, config)
|
||||
│ └── app-install.integration-test.ts # Example integration test
|
||||
├── roles/
|
||||
│ └── default-role.ts # Default role for logic functions
|
||||
├── objects/
|
||||
│ └── example-object.ts # Example custom object definition
|
||||
├── fields/
|
||||
│ └── example-field.ts # Example standalone field definition
|
||||
├── logic-functions/
|
||||
│ ├── hello-world.ts # Example logic function
|
||||
│ ├── create-hello-world-company.ts # Example logic function using CoreApiClient
|
||||
│ ├── pre-install.ts # Runs before installation
|
||||
│ └── post-install.ts # Runs after installation
|
||||
├── front-components/
|
||||
│ └── hello-world.tsx # Example front component
|
||||
├── page-layouts/
|
||||
│ └── example-record-page-layout.ts # Example page layout with front component
|
||||
├── views/
|
||||
│ └── example-view.ts # Example saved view definition
|
||||
├── navigation-menu-items/
|
||||
│ └── example-navigation-menu-item.ts # Example sidebar navigation link
|
||||
├── skills/
|
||||
│ └── example-skill.ts # Example AI agent skill definition
|
||||
└── agents/
|
||||
└── example-agent.ts # Example AI agent definition
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── default-role.ts # Default role for logic functions
|
||||
├── constants/
|
||||
│ └── universal-identifiers.ts # Auto-generated UUIDs and app metadata
|
||||
└── __tests__/
|
||||
├── setup-test.ts # Test setup (server health check, config)
|
||||
└── app-install.integration-test.ts # Integration test
|
||||
```
|
||||
|
||||
Por padrão (`--minimal`), apenas os arquivos principais são criados: `application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` e `logic-functions/post-install.ts`. Use `--exhaustive` para incluir todos os arquivos de exemplo mostrados acima.
|
||||
### Starting from an example
|
||||
|
||||
To start from a more complete example with custom objects, fields, logic functions, front components, and more, use the `--example` flag:
|
||||
|
||||
```bash filename="Terminal"
|
||||
npx create-twenty-app@latest my-twenty-app --example postcard
|
||||
```
|
||||
|
||||
Examples are sourced from the [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples) directory on GitHub. You can also scaffold individual entities into an existing project with `yarn twenty add` (see [Building Apps](/l/pt/developers/extend/apps/building#scaffolding-entities-with-yarn-twenty-add)).
|
||||
|
||||
### Arquivos principais
|
||||
|
||||
| Arquivo / Pasta | Finalidade |
|
||||
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Declara o nome, a versão e as dependências do seu aplicativo. Inclui um script `twenty` para que você possa executar `yarn twenty help` e ver todos os comandos. |
|
||||
| `src/application-config.ts` | **Obrigatório.** O principal arquivo de configuração do seu aplicativo. |
|
||||
| `src/roles/` | Define papéis que controlam o que suas funções de lógica podem acessar. |
|
||||
| `src/logic-functions/` | Funções do lado do servidor acionadas por rotas, agendamentos do cron ou eventos de banco de dados. |
|
||||
| `src/front-components/` | Componentes React que renderizam dentro da interface do Twenty. |
|
||||
| `src/objects/` | Definições de objetos personalizados para estender seu modelo de dados. |
|
||||
| `src/fields/` | Campos personalizados adicionados a objetos existentes. |
|
||||
| `src/views/` | Configurações de visualizações salvas. |
|
||||
| `src/navigation-menu-items/` | Links personalizados na navegação da barra lateral. |
|
||||
| `src/skills/` | Habilidades que estendem os agentes de IA do Twenty. |
|
||||
| `src/agents/` | Agentes de IA com prompts personalizados. |
|
||||
| `src/page-layouts/` | Layouts de página personalizados para visualizações de registros. |
|
||||
| `src/__tests__/` | Testes de integração (configuração + teste de exemplo). |
|
||||
| `public/` | Recursos estáticos (imagens, fontes) servidos com seu aplicativo. |
|
||||
| Arquivo / Pasta | Finalidade |
|
||||
| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Declara o nome, a versão e as dependências do seu aplicativo. Inclui um script `twenty` para que você possa executar `yarn twenty help` e ver todos os comandos. |
|
||||
| `src/application-config.ts` | **Obrigatório.** O principal arquivo de configuração do seu aplicativo. |
|
||||
| `src/default-role.ts` | Default role that controls what your logic functions can access. |
|
||||
| `src/constants/universal-identifiers.ts` | Auto-generated UUIDs and app metadata (display name, description). |
|
||||
| `src/__tests__/` | Testes de integração (configuração + teste de exemplo). |
|
||||
| `public/` | Recursos estáticos (imagens, fontes) servidos com seu aplicativo. |
|
||||
|
||||
## Gerenciando remotos
|
||||
## Local development server
|
||||
|
||||
Um **remoto** é um servidor Twenty ao qual seu aplicativo se conecta. Durante a configuração, o gerador de scaffold cria um para você automaticamente. Você pode adicionar mais remotos ou alternar entre eles a qualquer momento.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Suas credenciais são armazenadas em `~/.twenty/config.json`.
|
||||
|
||||
## Servidor de desenvolvimento local (`yarn twenty server`)
|
||||
|
||||
A CLI pode gerenciar um servidor Twenty local em execução no Docker. Este é o mesmo servidor iniciado automaticamente quando você cria o scaffold de um aplicativo com `create-twenty-app`, mas você também pode gerenciá-lo manualmente.
|
||||
|
||||
### Iniciando o servidor
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start
|
||||
```
|
||||
|
||||
Isso baixa a imagem Docker `twentycrm/twenty-app-dev:latest` (se ainda não estiver presente), cria um contêiner chamado `twenty-app-dev` e o inicia na porta **2020**. A CLI aguarda até que o servidor passe na verificação de integridade antes de retornar.
|
||||
|
||||
Dois volumes do Docker são criados para persistir os dados entre reinicializações:
|
||||
|
||||
* `twenty-app-dev-data` — banco de dados PostgreSQL
|
||||
* `twenty-app-dev-storage` — armazenamento de arquivos
|
||||
|
||||
Se a porta 2020 já estiver em uso, você pode iniciar em uma porta diferente:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start --port 3030
|
||||
```
|
||||
|
||||
A CLI configura automaticamente as variáveis internas do contêiner `NODE_PORT` e `SERVER_URL` para corresponderem à porta escolhida, para que as funções de lógica, o OAuth e toda a comunicação interna de rede funcionem corretamente.
|
||||
|
||||
Depois de iniciado, o servidor é registrado automaticamente como o remoto `local` na configuração da sua CLI.
|
||||
|
||||
### Verificando o status do servidor
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server status
|
||||
```
|
||||
|
||||
Exibe se o servidor está em execução, sua URL e as credenciais de login padrão (`tim@apple.dev` / `tim@apple.dev`).
|
||||
|
||||
### Visualizando os logs do servidor
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs
|
||||
```
|
||||
|
||||
Transmite os logs do contêiner. Use `--lines` para controlar quantas linhas recentes mostrar:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs --lines 100
|
||||
```
|
||||
|
||||
### Parando o servidor
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server stop
|
||||
```
|
||||
|
||||
Interrompe o contêiner. Seus dados são preservados nos volumes do Docker — o próximo `start` continua de onde você parou.
|
||||
|
||||
### Redefinindo o servidor
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server reset
|
||||
```
|
||||
|
||||
Remove o contêiner **e** exclui os dois volumes do Docker, apagando todos os dados. O próximo `start` cria uma instância nova.
|
||||
|
||||
<Note>
|
||||
O servidor requer que o **Docker** esteja em execução. Se você vir um erro "Docker not running", certifique-se de que o Docker Desktop (ou o daemon do Docker) esteja iniciado.
|
||||
</Note>
|
||||
|
||||
### Referência de comandos
|
||||
The scaffolder already started a local Twenty server for you. To manage it later, use `yarn twenty server`:
|
||||
|
||||
| Comando | Descrição |
|
||||
| -------------------------------------- | ------------------------------------------------------ |
|
||||
@@ -313,65 +211,11 @@ Remove o contêiner **e** exclui os dois volumes do Docker, apagando todos os da
|
||||
| `yarn twenty server logs --lines 100` | Mostra as últimas 100 linhas de log |
|
||||
| `yarn twenty server reset` | Exclui todos os dados e inicia do zero |
|
||||
|
||||
## CI com GitHub Actions
|
||||
Data is persisted across restarts in two Docker volumes (`twenty-app-dev-data` for PostgreSQL, `twenty-app-dev-storage` for files). Use `reset` to wipe everything and start fresh.
|
||||
|
||||
O gerador de scaffold cria um workflow do GitHub Actions pronto para uso em `.github/workflows/ci.yml`. Ele executa seus testes de integração automaticamente a cada push para `main` e em pull requests.
|
||||
|
||||
O workflow:
|
||||
|
||||
1. Faz checkout do seu código
|
||||
2. Inicializa um servidor Twenty temporário usando a ação `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Instala as dependências com `yarn install --immutable`
|
||||
4. Executa `yarn test` com `TWENTY_API_URL` e `TWENTY_API_KEY` injetados a partir das saídas da ação
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Você não precisa configurar nenhum segredo — a ação `spawn-twenty-docker-image` inicia um servidor Twenty efêmero diretamente no runner e fornece os detalhes de conexão. O segredo `GITHUB_TOKEN` é fornecido automaticamente pelo GitHub.
|
||||
|
||||
Para fixar uma versão específica do Twenty em vez de `latest`, altere a variável de ambiente `TWENTY_VERSION` no topo do workflow.
|
||||
<Note>
|
||||
O servidor requer que o **Docker** esteja em execução. Se você vir um erro "Docker not running", certifique-se de que o Docker Desktop (ou o daemon do Docker) esteja iniciado.
|
||||
</Note>
|
||||
|
||||
## Configuração manual (sem o gerador)
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ import { defineApplication } from 'twenty-sdk';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7',
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
displayName: 'My Twenty App',
|
||||
description: 'My first Twenty app',
|
||||
icon: 'IconWorld',
|
||||
@@ -717,6 +717,13 @@ Puncte cheie:
|
||||
|
||||
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.
|
||||
|
||||
#### Unde pot fi utilizate componentele frontale
|
||||
|
||||
Componentele frontale pot fi afișate în două locații în cadrul Twenty:
|
||||
|
||||
* **Panou lateral** — Componentele frontale care nu sunt headless se deschid în panoul lateral din dreapta. Acesta este comportamentul implicit atunci când o componentă frontală este declanșată din meniul de comenzi.
|
||||
* **Widgeturi (tablouri de bord și pagini de înregistrare)** — Componentele frontale pot fi încorporate ca widgeturi în machetele de pagină. La configurarea unui tablou de bord sau a machetei unei pagini de înregistrare, utilizatorii pot adăuga un widget de componentă frontală.
|
||||
|
||||
#### Exemplu de bază
|
||||
|
||||
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ă:
|
||||
@@ -774,9 +781,13 @@ Faceți clic pe el pentru a afișa componenta inline.
|
||||
|
||||
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.
|
||||
|
||||
#### Componente headless (`isHeadless: true`)
|
||||
#### Headless vs non-headless
|
||||
|
||||
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.
|
||||
Componentele frontale au două moduri de randare controlate de opțiunea `isHeadless`:
|
||||
|
||||
**Non-headless (implicit)** — Componenta afișează o interfață vizibilă. Când este declanșat din meniul de comenzi, se deschide în panoul lateral. Acesta este comportamentul implicit când `isHeadless` este `false` sau omis.
|
||||
|
||||
**Headless (`isHeadless: true`)** — Componenta se montează invizibil în fundal. Nu deschide panoul lateral. Componentele headless sunt concepute pentru acțiuni care execută logică și apoi se demontează — de exemplu, rularea unei sarcini asincrone, navigarea la o pagină sau afișarea unui modal de confirmare. Se potrivesc în mod natural cu componentele Command din SDK descrise mai jos.
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent, useRecordId, enqueueSnackbar } from 'twenty-sdk';
|
||||
@@ -803,6 +814,89 @@ export default defineFrontComponent({
|
||||
|
||||
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.
|
||||
|
||||
#### Componentele Command din SDK
|
||||
|
||||
Pachetul `twenty-sdk` oferă patru componente ajutătoare Command, concepute pentru componente front-end headless. Fiecare componentă execută o acțiune la montare, gestionează erorile afișând o notificare snackbar și demontează automat componenta de interfață la final.
|
||||
|
||||
Importă-le din `twenty-sdk/command`:
|
||||
|
||||
* **`Command`** — Rulează un callback asincron prin prop-ul `execute`.
|
||||
* **`CommandLink`** — Navighează către o rută a aplicației. Props: `to`, `params`, `queryParams`, `options`.
|
||||
* **`CommandModal`** — Deschide un modal de confirmare. Dacă utilizatorul confirmă, execută callback-ul `execute`. Props: `title`, `subtitle`, `execute`, `confirmButtonText`, `confirmButtonAccent`.
|
||||
* **`CommandOpenSidePanelPage`** — Deschide o anumită pagină din panoul lateral. Props: `page`, `pageTitle`, `pageIcon`.
|
||||
|
||||
Iată un exemplu complet de componentă front-end headless care folosește `Command` pentru a rula o acțiune din meniul de comenzi:
|
||||
|
||||
```tsx src/front-components/run-action.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const RunAction = () => {
|
||||
const execute = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
createTask: {
|
||||
__args: { data: { title: 'Created by my app' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
||||
name: 'run-action',
|
||||
description: 'Creates a task from the command menu',
|
||||
component: RunAction,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
|
||||
label: 'Run my action',
|
||||
icon: 'IconPlayerPlay',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Și un exemplu care folosește `CommandModal` pentru a cere confirmarea înainte de execuție:
|
||||
|
||||
```tsx src/front-components/delete-draft.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { CommandModal } from 'twenty-sdk/command';
|
||||
|
||||
const DeleteDraft = () => {
|
||||
const execute = async () => {
|
||||
// perform the deletion
|
||||
};
|
||||
|
||||
return (
|
||||
<CommandModal
|
||||
title="Delete draft?"
|
||||
subtitle="This action cannot be undone."
|
||||
execute={execute}
|
||||
confirmButtonText="Delete"
|
||||
confirmButtonAccent="danger"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'a7b8c9d0-e1f2-3456-abcd-567890123456',
|
||||
name: 'delete-draft',
|
||||
description: 'Deletes a draft with confirmation',
|
||||
component: DeleteDraft,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'b8c9d0e1-f2a3-4567-bcde-678901234567',
|
||||
label: 'Delete draft',
|
||||
icon: 'IconTrash',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### Accesarea contextului de rulare
|
||||
|
||||
În interiorul componentei, folosiți hook-urile SDK pentru a accesa utilizatorul curent, înregistrarea curentă și instanța componentei:
|
||||
@@ -859,6 +953,50 @@ Componentele front-end pot declanșa navigare, ferestre modale și notificări f
|
||||
| `unmountFrontComponent()` | Demontați componenta |
|
||||
| `updateProgress(progress)` | Actualizați un indicator de progres |
|
||||
|
||||
Iată un exemplu care folosește API-ul gazdă pentru a afișa un snackbar și a închide panoul lateral după finalizarea unei acțiuni:
|
||||
|
||||
```tsx src/front-components/archive-record.tsx
|
||||
import { defineFrontComponent, useRecordId } from 'twenty-sdk';
|
||||
import { enqueueSnackbar, closeSidePanel } from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const ArchiveRecord = () => {
|
||||
const recordId = useRecordId();
|
||||
|
||||
const handleArchive = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
updateTask: {
|
||||
__args: { id: recordId, data: { status: 'ARCHIVED' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
await enqueueSnackbar({
|
||||
message: 'Record archived',
|
||||
variant: 'success',
|
||||
});
|
||||
|
||||
await closeSidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<p>Archive this record?</p>
|
||||
<button onClick={handleArchive}>Archive</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'c9d0e1f2-a3b4-5678-cdef-789012345678',
|
||||
name: 'archive-record',
|
||||
description: 'Archives the current record',
|
||||
component: ArchiveRecord,
|
||||
});
|
||||
```
|
||||
|
||||
#### Opțiuni pentru comandă
|
||||
|
||||
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.
|
||||
@@ -1713,3 +1851,86 @@ yarn twenty uninstall
|
||||
# Skip the confirmation prompt
|
||||
yarn twenty uninstall --yes
|
||||
```
|
||||
|
||||
## Gestionarea remote-urilor
|
||||
|
||||
Un „remote” este un server Twenty la care se conectează aplicația. În timpul configurării, generatorul de schelet creează automat unul pentru dvs. Puteți adăuga mai multe remote-uri sau comuta între ele oricând.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Acreditările dvs. sunt stocate în `~/.twenty/config.json`.
|
||||
|
||||
## CI cu GitHub Actions
|
||||
|
||||
Scaffolderul generează un workflow GitHub Actions gata de utilizare în `.github/workflows/ci.yml`. Rulează automat testele de integrare la fiecare push pe `main` și la pull request-uri.
|
||||
|
||||
Workflow-ul:
|
||||
|
||||
1. Preia codul
|
||||
2. Pornește un server Twenty temporar folosind acțiunea `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Instalează dependențele cu `yarn install --immutable`
|
||||
4. Rulează `yarn test` cu `TWENTY_API_URL` și `TWENTY_API_KEY` injectate din rezultatele acțiunii
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Nu trebuie să configurați niciun secret — acțiunea `spawn-twenty-docker-image` pornește un server Twenty efemer direct în runner și oferă detaliile de conectare. Secretul `GITHUB_TOKEN` este furnizat automat de GitHub.
|
||||
|
||||
Pentru a fixa o versiune Twenty specifică în loc de `latest`, modificați variabila de mediu `TWENTY_VERSION` din partea de sus a workflow-ului.
|
||||
|
||||
@@ -7,7 +7,9 @@ description: Creați prima dvs. aplicație Twenty în câteva minute.
|
||||
Aplicațiile sunt în prezent în testare alfa. Caracteristica funcționează, dar este încă în dezvoltare.
|
||||
</Warning>
|
||||
|
||||
Aplicațiile vă permit să extindeți Twenty cu obiecte personalizate, câmpuri, funcții logice, abilități IA și componente UI — toate gestionate ca cod.
|
||||
## Ce sunt aplicațiile?
|
||||
|
||||
Aplicațiile vă permit să extindeți Twenty cu obiecte personalizate, câmpuri, funcții logice, componente front-end, abilități IA și altele — toate gestionate ca cod. În loc să configurați totul prin interfața de utilizator (UI), vă definiți modelul de date și logica în TypeScript și le implementați în unul sau mai multe spații de lucru.
|
||||
|
||||
## Cerințe
|
||||
|
||||
@@ -17,7 +19,9 @@ Aplicațiile vă permit să extindeți Twenty cu obiecte personalizate, câmpuri
|
||||
* **Yarn 4** — Vine împreună cu Node.js prin Corepack. Activați-l rulând `corepack enable`
|
||||
* **Docker** — [Descărcați aici](https://www.docker.com/products/docker-desktop/). Necesar pentru a rula o instanță Twenty locală. Nu este necesar dacă aveți deja un server Twenty care rulează.
|
||||
|
||||
## Pasul 1: Creați scheletul aplicației
|
||||
## Create your first app
|
||||
|
||||
### Scaffold your app
|
||||
|
||||
Deschideți un terminal și rulați:
|
||||
|
||||
@@ -29,18 +33,7 @@ Vi se va cere să introduceți un nume și o descriere pentru aplicația dvs. Ap
|
||||
|
||||
Aceasta creează un folder nou numit `my-twenty-app` cu tot ce aveți nevoie.
|
||||
|
||||
<Note>
|
||||
Generatorul de schelet acceptă următoarele opțiuni:
|
||||
|
||||
* `--minimal` — generează doar fișierele esențiale, fără exemple (implicit)
|
||||
* `--exhaustive` — generează toate entitățile de exemplu
|
||||
* `--name <name>` — setează numele aplicației (omite solicitarea)
|
||||
* `--display-name <displayName>` — setează numele afișat (omite solicitarea)
|
||||
* `--description <description>` — setează descrierea (omite solicitarea)
|
||||
* `--skip-local-instance` — omite solicitarea de configurare a serverului local
|
||||
</Note>
|
||||
|
||||
## Pasul 2: Configurați o instanță Twenty locală
|
||||
### Set up a local Twenty instance
|
||||
|
||||
Generatorul de schelet va întreba:
|
||||
|
||||
@@ -53,7 +46,7 @@ Generatorul de schelet va întreba:
|
||||
<img src="/images/docs/developers/extends/apps/start-instance.png" alt="Porniți instanța locală?" />
|
||||
</div>
|
||||
|
||||
## Pasul 3: Autentificați-vă în spațiul dvs. de lucru
|
||||
### Sign in to your workspace
|
||||
|
||||
În continuare, se va deschide o fereastră de browser cu pagina de autentificare Twenty. Autentificați-vă cu contul demo preconfigurat:
|
||||
|
||||
@@ -64,7 +57,7 @@ Generatorul de schelet va întreba:
|
||||
<img src="/images/docs/developers/extends/apps/login.png" alt="Ecranul de autentificare Twenty" />
|
||||
</div>
|
||||
|
||||
## Pasul 4: Autorizați aplicația
|
||||
### Authorize the app
|
||||
|
||||
După autentificare, veți vedea un ecran de autorizare. Acest lucru permite aplicației dvs. să interacționeze cu spațiul dvs. de lucru.
|
||||
|
||||
@@ -80,7 +73,7 @@ După autorizare, terminalul va confirma că totul este configurat.
|
||||
<img src="/images/docs/developers/extends/apps/scaffolded.png" alt="Aplicația a fost creată cu succes" />
|
||||
</div>
|
||||
|
||||
## Pasul 5: Începeți dezvoltarea
|
||||
### Start developing
|
||||
|
||||
Intrați în noul folder al aplicației și porniți serverul de dezvoltare:
|
||||
|
||||
@@ -105,7 +98,7 @@ Modul de dezvoltare este disponibil doar pe instanțele Twenty care rulează în
|
||||
<img src="/images/docs/developers/extends/apps/dev.jpg" alt="Ieșirea terminalului în modul de dezvoltare" />
|
||||
</div>
|
||||
|
||||
## Pasul 6: Vedeți aplicația în Twenty
|
||||
### See your app in Twenty
|
||||
|
||||
Deschideți [http://localhost:2020/settings/applications#developer](http://localhost:2020/settings/applications#developer) în browser. Navigați la **Settings > Apps** și selectați fila **Developer**. Ar trebui să vedeți aplicația listată la **Your Apps**:
|
||||
|
||||
@@ -133,13 +126,28 @@ Comutați la fila **Content** pentru a vedea tot ceea ce oferă aplicația — o
|
||||
|
||||
Totul este gata! Editați orice fișier din `src/`, iar modificările vor fi preluate automat.
|
||||
|
||||
Accesați [Construirea aplicațiilor](/l/ro/developers/extend/apps/building) pentru un ghid detaliat despre crearea de obiecte, funcții logice, componente front-end, abilități și altele.
|
||||
---
|
||||
|
||||
## Ce puteți construi
|
||||
|
||||
Apps are composed of **entities** — each defined as a TypeScript file with a single `export default`:
|
||||
|
||||
| Entity | What it does |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------- |
|
||||
| **Objects & Fields** | Define custom data models (like Post Card, Invoice) with typed fields |
|
||||
| **Funcții logice** | Server-side TypeScript functions triggered by HTTP routes, cron schedules, or database events |
|
||||
| **Componente front-end** | React components that render inside Twenty's UI (side panel, widgets, command menu) |
|
||||
| **Skills & Agents** | AI capabilities — reusable instructions and autonomous assistants |
|
||||
| **Views & Navigation** | Pre-configured list views and sidebar menu items for your objects |
|
||||
| **Layouturi de pagină** | Custom record detail pages with tabs and widgets |
|
||||
|
||||
Head over to [Building Apps](/l/ro/developers/extend/apps/building) for a detailed guide on each entity type.
|
||||
|
||||
---
|
||||
|
||||
## Structura proiectului
|
||||
|
||||
Generatorul de schelet generează următoarea structură de fișiere (afișată cu modul `--exhaustive`, care include exemple pentru fiecare tip de entitate):
|
||||
The scaffolder generates the following file structure:
|
||||
|
||||
```text filename="my-twenty-app/"
|
||||
my-twenty-app/
|
||||
@@ -148,160 +156,50 @@ my-twenty-app/
|
||||
.gitignore
|
||||
.nvmrc
|
||||
.yarnrc.yml
|
||||
.yarn/
|
||||
install-state.gz
|
||||
.oxlintrc.json
|
||||
tsconfig.json
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
LLMS.md
|
||||
README.md
|
||||
.github/
|
||||
└── workflows/
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
src/
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── __tests__/
|
||||
│ ├── setup-test.ts # Test setup (server health check, config)
|
||||
│ └── app-install.integration-test.ts # Example integration test
|
||||
├── roles/
|
||||
│ └── default-role.ts # Default role for logic functions
|
||||
├── objects/
|
||||
│ └── example-object.ts # Example custom object definition
|
||||
├── fields/
|
||||
│ └── example-field.ts # Example standalone field definition
|
||||
├── logic-functions/
|
||||
│ ├── hello-world.ts # Example logic function
|
||||
│ ├── create-hello-world-company.ts # Example logic function using CoreApiClient
|
||||
│ ├── pre-install.ts # Runs before installation
|
||||
│ └── post-install.ts # Runs after installation
|
||||
├── front-components/
|
||||
│ └── hello-world.tsx # Example front component
|
||||
├── page-layouts/
|
||||
│ └── example-record-page-layout.ts # Example page layout with front component
|
||||
├── views/
|
||||
│ └── example-view.ts # Example saved view definition
|
||||
├── navigation-menu-items/
|
||||
│ └── example-navigation-menu-item.ts # Example sidebar navigation link
|
||||
├── skills/
|
||||
│ └── example-skill.ts # Example AI agent skill definition
|
||||
└── agents/
|
||||
└── example-agent.ts # Example AI agent definition
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── default-role.ts # Default role for logic functions
|
||||
├── constants/
|
||||
│ └── universal-identifiers.ts # Auto-generated UUIDs and app metadata
|
||||
└── __tests__/
|
||||
├── setup-test.ts # Test setup (server health check, config)
|
||||
└── app-install.integration-test.ts # Integration test
|
||||
```
|
||||
|
||||
În mod implicit (`--minimal`), sunt create doar fișierele de bază: `application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` și `logic-functions/post-install.ts`. Folosiți `--exhaustive` pentru a include toate fișierele de exemplu prezentate mai sus.
|
||||
### Starting from an example
|
||||
|
||||
To start from a more complete example with custom objects, fields, logic functions, front components, and more, use the `--example` flag:
|
||||
|
||||
```bash filename="Terminal"
|
||||
npx create-twenty-app@latest my-twenty-app --example postcard
|
||||
```
|
||||
|
||||
Examples are sourced from the [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples) directory on GitHub. You can also scaffold individual entities into an existing project with `yarn twenty add` (see [Building Apps](/l/ro/developers/extend/apps/building#scaffolding-entities-with-yarn-twenty-add)).
|
||||
|
||||
### Fișiere cheie
|
||||
|
||||
| Fișier / Folder | Scop |
|
||||
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Declară numele aplicației, versiunea și dependențele. Include un script `twenty` astfel încât să puteți rula `yarn twenty help` pentru a vedea toate comenzile. |
|
||||
| `src/application-config.ts` | **Necesar.** Fișierul principal de configurare pentru aplicație. |
|
||||
| `src/roles/` | Definește roluri care controlează la ce pot avea acces funcțiile logice. |
|
||||
| `src/logic-functions/` | Funcții pe server declanșate de rute, programări cron sau evenimente din baza de date. |
|
||||
| `src/front-components/` | Componente React care se afișează în interfața Twenty. |
|
||||
| `src/objects/` | Definiții de obiecte personalizate pentru a extinde modelul de date. |
|
||||
| `src/fields/` | Câmpuri personalizate adăugate obiectelor existente. |
|
||||
| `src/views/` | Configurații pentru vizualizări salvate. |
|
||||
| `src/navigation-menu-items/` | Linkuri personalizate în bara laterală de navigare. |
|
||||
| `src/skills/` | Abilități care extind capabilitățile agenților AI ai Twenty. |
|
||||
| `src/agents/` | Agenți AI cu prompturi personalizate. |
|
||||
| `src/page-layouts/` | Machete de pagină personalizate pentru vizualizările de înregistrare. |
|
||||
| `src/__tests__/` | Teste de integrare (configurare + test exemplu). |
|
||||
| `public/` | Resurse statice (imagini, fonturi) servite împreună cu aplicația. |
|
||||
| Fișier / Folder | Scop |
|
||||
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Declară numele aplicației, versiunea și dependențele. Include un script `twenty` astfel încât să puteți rula `yarn twenty help` pentru a vedea toate comenzile. |
|
||||
| `src/application-config.ts` | **Necesar.** Fișierul principal de configurare pentru aplicație. |
|
||||
| `src/default-role.ts` | Default role that controls what your logic functions can access. |
|
||||
| `src/constants/universal-identifiers.ts` | Auto-generated UUIDs and app metadata (display name, description). |
|
||||
| `src/__tests__/` | Teste de integrare (configurare + test exemplu). |
|
||||
| `public/` | Resurse statice (imagini, fonturi) servite împreună cu aplicația. |
|
||||
|
||||
## Gestionarea remote-urilor
|
||||
## Local development server
|
||||
|
||||
Un „remote” este un server Twenty la care se conectează aplicația. În timpul configurării, generatorul de schelet creează automat unul pentru dvs. Puteți adăuga mai multe remote-uri sau comuta între ele oricând.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Acreditările dvs. sunt stocate în `~/.twenty/config.json`.
|
||||
|
||||
## Server local de dezvoltare (`yarn twenty server`)
|
||||
|
||||
CLI-ul poate gestiona un server Twenty local care rulează în Docker. Acesta este același server pornit automat când creați scheletul unei aplicații cu `create-twenty-app`, dar îl puteți gestiona și manual.
|
||||
|
||||
### Pornirea serverului
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start
|
||||
```
|
||||
|
||||
Aceasta descarcă imaginea Docker `twentycrm/twenty-app-dev:latest` (dacă nu este deja prezentă), creează un container numit `twenty-app-dev` și îl pornește pe portul **2020**. CLI-ul așteaptă până când serverul trece verificarea de integritate înainte de a reveni.
|
||||
|
||||
Sunt create două volume Docker pentru a păstra datele între reporniri:
|
||||
|
||||
* `twenty-app-dev-data` — bază de date PostgreSQL
|
||||
* `twenty-app-dev-storage` — stocare fișiere
|
||||
|
||||
Dacă portul 2020 este deja utilizat, puteți porni pe un alt port:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start --port 3030
|
||||
```
|
||||
|
||||
CLI-ul configurează automat `NODE_PORT` și `SERVER_URL` interne ale containerului pentru a se potrivi cu portul ales, astfel încât funcțiile logice, OAuth și toată rețeaua internă să funcționeze corect.
|
||||
|
||||
După pornire, serverul este înregistrat automat ca remote `local` în configurația CLI.
|
||||
|
||||
### Verificarea stării serverului
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server status
|
||||
```
|
||||
|
||||
Afișează dacă serverul rulează, URL-ul său și acreditările implicite de autentificare (`tim@apple.dev` / `tim@apple.dev`).
|
||||
|
||||
### Vizualizarea jurnalelor serverului
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs
|
||||
```
|
||||
|
||||
Transmite în flux jurnalele containerului. Folosiți `--lines` pentru a controla câte linii recente să fie afișate:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs --lines 100
|
||||
```
|
||||
|
||||
### Oprirea serverului
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server stop
|
||||
```
|
||||
|
||||
Oprește containerul. Datele dvs. sunt păstrate în volumele Docker — următoarea comandă `start` reia de unde ați rămas.
|
||||
|
||||
### Resetarea serverului
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server reset
|
||||
```
|
||||
|
||||
Elimină containerul **și** șterge ambele volume Docker, ștergând toate datele. Următoarea comandă `start` creează o instanță nouă.
|
||||
|
||||
<Note>
|
||||
Serverul necesită ca **Docker** să ruleze. Dacă vedeți eroarea "Docker not running", asigurați-vă că Docker Desktop (sau demonul Docker) este pornit.
|
||||
</Note>
|
||||
|
||||
### Referință pentru comenzi
|
||||
The scaffolder already started a local Twenty server for you. To manage it later, use `yarn twenty server`:
|
||||
|
||||
| Comandă | Descriere |
|
||||
| -------------------------------------- | ------------------------------------------------------------- |
|
||||
@@ -313,65 +211,11 @@ Elimină containerul **și** șterge ambele volume Docker, ștergând toate date
|
||||
| `yarn twenty server logs --lines 100` | Afișează ultimele 100 de linii de jurnal |
|
||||
| `yarn twenty server reset` | Șterge toate datele și pornește de la zero |
|
||||
|
||||
## CI cu GitHub Actions
|
||||
Data is persisted across restarts in two Docker volumes (`twenty-app-dev-data` for PostgreSQL, `twenty-app-dev-storage` for files). Use `reset` to wipe everything and start fresh.
|
||||
|
||||
Scaffolderul generează un workflow GitHub Actions gata de utilizare în `.github/workflows/ci.yml`. Rulează automat testele de integrare la fiecare push pe `main` și la pull request-uri.
|
||||
|
||||
Workflow-ul:
|
||||
|
||||
1. Preia codul
|
||||
2. Pornește un server Twenty temporar folosind acțiunea `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Instalează dependențele cu `yarn install --immutable`
|
||||
4. Rulează `yarn test` cu `TWENTY_API_URL` și `TWENTY_API_KEY` injectate din rezultatele acțiunii
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Nu trebuie să configurați niciun secret — acțiunea `spawn-twenty-docker-image` pornește un server Twenty efemer direct în runner și oferă detaliile de conectare. Secretul `GITHUB_TOKEN` este furnizat automat de GitHub.
|
||||
|
||||
Pentru a fixa o versiune Twenty specifică în loc de `latest`, modificați variabila de mediu `TWENTY_VERSION` din partea de sus a workflow-ului.
|
||||
<Note>
|
||||
Serverul necesită ca **Docker** să ruleze. Dacă vedeți eroarea "Docker not running", asigurați-vă că Docker Desktop (sau demonul Docker) este pornit.
|
||||
</Note>
|
||||
|
||||
## Configurare manuală (fără generator)
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ import { defineApplication } from 'twenty-sdk';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7',
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
displayName: 'My Twenty App',
|
||||
description: 'My first Twenty app',
|
||||
icon: 'IconWorld',
|
||||
@@ -716,6 +716,13 @@ yarn twenty exec --postInstall
|
||||
|
||||
Фронтенд-компоненты — это компоненты React, которые отображаются непосредственно внутри интерфейса Twenty. Они выполняются в изолированном Web Worker с использованием Remote DOM — ваш код изолирован (sandboxed), но рендерится нативно на странице, а не в iframe.
|
||||
|
||||
#### Где можно использовать фронт-компоненты
|
||||
|
||||
Фронт-компоненты могут отображаться в двух местах внутри Twenty:
|
||||
|
||||
* **Боковая панель** — фронт-компоненты с интерфейсом открываются в правой боковой панели. Это поведение по умолчанию, когда фронт-компонент запускается из меню команд.
|
||||
* **Виджеты (дашборды и страницы записей)** — фронт-компоненты можно встраивать как виджеты в макеты страниц. При настройке дашборда или макета страницы записи пользователи могут добавить виджет фронт-компонента.
|
||||
|
||||
#### Простой пример
|
||||
|
||||
Самый быстрый способ увидеть фронтенд-компонент в действии — зарегистрировать его как **команду**. Добавление поля `command` с `isPinned: true` делает его кнопкой быстрого действия в правом верхнем углу страницы — макет страницы не требуется:
|
||||
@@ -773,9 +780,13 @@ export default defineFrontComponent({
|
||||
|
||||
Помимо команд, вы можете встроить фронт-компонент непосредственно на страницу записи, добавив его как виджет в **макет страницы**. См. раздел [definePageLayout](#definepagelayout) для подробностей.
|
||||
|
||||
#### Headless-компоненты (`isHeadless: true`)
|
||||
#### Headless и non-headless
|
||||
|
||||
Headless-компоненты не отображают видимый UI, но при этом выполняют логику React. Это полезно для **компонентов-эффектов** — компонентов, которые выполняют побочные эффекты при монтировании, например синхронизацию данных, запуск таймера, прослушивание событий или показ уведомления.
|
||||
Фронт-компоненты поддерживают два режима отображения, управляемых опцией `isHeadless`:
|
||||
|
||||
**Non-headless (по умолчанию)** — компонент отображает видимый интерфейс. При запуске из меню команд он открывается в боковой панели. Это поведение по умолчанию, когда `isHeadless` имеет значение `false` или опущен.
|
||||
|
||||
**Headless (`isHeadless: true`)** — компонент монтируется невидимо в фоновом режиме. Он не открывает боковую панель. Компоненты headless предназначены для действий, которые выполняют логику и затем размонтируются — например, запуск асинхронной задачи, переход на страницу или показ модального окна подтверждения. Они естественно сочетаются с компонентами SDK Command, описанными ниже.
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent, useRecordId, enqueueSnackbar } from 'twenty-sdk';
|
||||
@@ -802,6 +813,89 @@ export default defineFrontComponent({
|
||||
|
||||
Поскольку компонент возвращает `null`, Twenty пропускает рендеринг контейнера для него — в макете не появляется пустое место. Компонент по-прежнему имеет доступ ко всем хукам и API взаимодействия с хостом.
|
||||
|
||||
#### Компоненты SDK Command
|
||||
|
||||
Пакет `twenty-sdk` предоставляет четыре вспомогательных компонента Command, предназначенных для headless фронт-компонентов. Каждый компонент выполняет действие при монтировании, обрабатывает ошибки, показывая уведомление snackbar, и автоматически размонтирует фронт-компонент по завершении.
|
||||
|
||||
Импортируйте их из `twenty-sdk/command`:
|
||||
|
||||
* **`Command`** — запускает асинхронный колбэк через проп `execute`.
|
||||
* **`CommandLink`** — переходит по пути внутри приложения. Пропы: `to`, `params`, `queryParams`, `options`.
|
||||
* **`CommandModal`** — открывает модальное окно подтверждения. Если пользователь подтвердит, выполняет колбэк `execute`. Пропы: `title`, `subtitle`, `execute`, `confirmButtonText`, `confirmButtonAccent`.
|
||||
* **`CommandOpenSidePanelPage`** — открывает конкретную страницу боковой панели. Пропы: `page`, `pageTitle`, `pageIcon`.
|
||||
|
||||
Полный пример headless фронт-компонента, использующего `Command` для запуска действия из меню команд:
|
||||
|
||||
```tsx src/front-components/run-action.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const RunAction = () => {
|
||||
const execute = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
createTask: {
|
||||
__args: { data: { title: 'Created by my app' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
||||
name: 'run-action',
|
||||
description: 'Creates a task from the command menu',
|
||||
component: RunAction,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
|
||||
label: 'Run my action',
|
||||
icon: 'IconPlayerPlay',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
А также пример с использованием `CommandModal` для запроса подтверждения перед выполнением:
|
||||
|
||||
```tsx src/front-components/delete-draft.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { CommandModal } from 'twenty-sdk/command';
|
||||
|
||||
const DeleteDraft = () => {
|
||||
const execute = async () => {
|
||||
// perform the deletion
|
||||
};
|
||||
|
||||
return (
|
||||
<CommandModal
|
||||
title="Delete draft?"
|
||||
subtitle="This action cannot be undone."
|
||||
execute={execute}
|
||||
confirmButtonText="Delete"
|
||||
confirmButtonAccent="danger"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'a7b8c9d0-e1f2-3456-abcd-567890123456',
|
||||
name: 'delete-draft',
|
||||
description: 'Deletes a draft with confirmation',
|
||||
component: DeleteDraft,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'b8c9d0e1-f2a3-4567-bcde-678901234567',
|
||||
label: 'Delete draft',
|
||||
icon: 'IconTrash',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### Доступ к контексту времени выполнения
|
||||
|
||||
Внутри вашего компонента используйте хуки SDK для доступа к текущему пользователю, записи и экземпляру компонента:
|
||||
@@ -858,6 +952,50 @@ export default defineFrontComponent({
|
||||
| `unmountFrontComponent()` | Размонтировать компонент |
|
||||
| `updateProgress(progress)` | Обновить индикатор прогресса |
|
||||
|
||||
Пример, который использует API хоста для показа snackbar и закрытия боковой панели после завершения действия:
|
||||
|
||||
```tsx src/front-components/archive-record.tsx
|
||||
import { defineFrontComponent, useRecordId } from 'twenty-sdk';
|
||||
import { enqueueSnackbar, closeSidePanel } from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const ArchiveRecord = () => {
|
||||
const recordId = useRecordId();
|
||||
|
||||
const handleArchive = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
updateTask: {
|
||||
__args: { id: recordId, data: { status: 'ARCHIVED' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
await enqueueSnackbar({
|
||||
message: 'Record archived',
|
||||
variant: 'success',
|
||||
});
|
||||
|
||||
await closeSidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<p>Archive this record?</p>
|
||||
<button onClick={handleArchive}>Archive</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'c9d0e1f2-a3b4-5678-cdef-789012345678',
|
||||
name: 'archive-record',
|
||||
description: 'Archives the current record',
|
||||
component: ArchiveRecord,
|
||||
});
|
||||
```
|
||||
|
||||
#### Параметры команды
|
||||
|
||||
Добавление поля `command` в `defineFrontComponent` регистрирует компонент в меню команд (Cmd+K). Если `isPinned` имеет значение `true`, команда также отображается как кнопка быстрого действия в правом верхнем углу страницы.
|
||||
@@ -1712,3 +1850,86 @@ yarn twenty uninstall
|
||||
# Skip the confirmation prompt
|
||||
yarn twenty uninstall --yes
|
||||
```
|
||||
|
||||
## Управление удалёнными серверами
|
||||
|
||||
**Remote** — это сервер Twenty, к которому подключается ваше приложение. Во время настройки скэффолдер автоматически создаст его для вас. Вы можете в любой момент добавлять новые удалённые серверы или переключаться между ними.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Ваши учётные данные хранятся в `~/.twenty/config.json`.
|
||||
|
||||
## CI с GitHub Actions
|
||||
|
||||
Скэффолдер генерирует готовый к использованию workflow GitHub Actions в `.github/workflows/ci.yml`. Он автоматически запускает ваши интеграционные тесты при каждом пуше в `main` и в pull request'ах.
|
||||
|
||||
Рабочий процесс:
|
||||
|
||||
1. Извлекает ваш код
|
||||
2. Поднимает временный сервер Twenty с помощью экшена `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Устанавливает зависимости с помощью `yarn install --immutable`
|
||||
4. Запускает `yarn test` с `TWENTY_API_URL` и `TWENTY_API_KEY`, переданными из выходных данных экшена
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Вам не нужно настраивать секреты — экшен `spawn-twenty-docker-image` запускает эфемерный сервер Twenty прямо в раннере и выводит данные для подключения. Секрет `GITHUB_TOKEN` предоставляется GitHub автоматически.
|
||||
|
||||
Чтобы закрепить конкретную версию Twenty вместо `latest`, измените переменную окружения `TWENTY_VERSION` в начале workflow.
|
||||
|
||||
@@ -7,7 +7,9 @@ description: Создайте своё первое приложение Twenty
|
||||
Приложения сейчас проходят альфа-тестирование. Функция работает, но продолжает развиваться.
|
||||
</Warning>
|
||||
|
||||
Приложения позволяют расширять Twenty с помощью пользовательских объектов, полей, логических функций, навыков ИИ и UI-компонентов — всё это управляется как код.
|
||||
## Что такое приложения?
|
||||
|
||||
Приложения позволяют расширять Twenty с помощью пользовательских объектов, полей, логических функций, фронтенд-компонентов, навыков ИИ и многого другого — всё это управляется как код. Вместо настройки всего через интерфейс вы определяете модель данных и логику на TypeScript и развёртываете их в одном или нескольких рабочих пространствах.
|
||||
|
||||
## Требования
|
||||
|
||||
@@ -17,7 +19,9 @@ description: Создайте своё первое приложение Twenty
|
||||
* **Yarn 4** — Поставляется вместе с Node.js через Corepack. Включите его, выполнив `corepack enable`
|
||||
* **Docker** — [Скачать здесь](https://www.docker.com/products/docker-desktop/). Требуется для запуска локального экземпляра Twenty. Не требуется, если у вас уже запущен сервер Twenty.
|
||||
|
||||
## Шаг 1: Сгенерируйте каркас приложения
|
||||
## Create your first app
|
||||
|
||||
### Scaffold your app
|
||||
|
||||
Откройте терминал и выполните:
|
||||
|
||||
@@ -29,18 +33,7 @@ npx create-twenty-app@latest my-twenty-app
|
||||
|
||||
Будет создана новая папка `my-twenty-app` со всем необходимым.
|
||||
|
||||
<Note>
|
||||
Генератор поддерживает следующие флаги:
|
||||
|
||||
* `--minimal` — сгенерировать только основные файлы, без примеров (по умолчанию)
|
||||
* `--exhaustive` — сгенерировать все примеры сущностей
|
||||
* `--name <name>` — задать имя приложения (пропускает запрос)
|
||||
* `--display-name <displayName>` — задать отображаемое имя (пропускает запрос)
|
||||
* `--description <description>` — задать описание (пропускает запрос)
|
||||
* `--skip-local-instance` — пропустить запрос на настройку локального сервера
|
||||
</Note>
|
||||
|
||||
## Шаг 2: Настройте локальный экземпляр Twenty
|
||||
### Set up a local Twenty instance
|
||||
|
||||
Скэффолдер спросит:
|
||||
|
||||
@@ -53,7 +46,7 @@ npx create-twenty-app@latest my-twenty-app
|
||||
<img src="/images/docs/developers/extends/apps/start-instance.png" alt="Запустить локальный экземпляр?" />
|
||||
</div>
|
||||
|
||||
## Шаг 3: Войдите в своё рабочее пространство
|
||||
### Sign in to your workspace
|
||||
|
||||
Затем откроется окно браузера со страницей входа в Twenty. Войдите, используя предварительно созданную демонстрационную учётную запись:
|
||||
|
||||
@@ -64,7 +57,7 @@ npx create-twenty-app@latest my-twenty-app
|
||||
<img src="/images/docs/developers/extends/apps/login.png" alt="Экран входа в Twenty" />
|
||||
</div>
|
||||
|
||||
## Шаг 4: Авторизуйте приложение
|
||||
### Authorize the app
|
||||
|
||||
После входа вы увидите экран авторизации. Это позволит вашему приложению взаимодействовать с вашим рабочим пространством.
|
||||
|
||||
@@ -80,7 +73,7 @@ npx create-twenty-app@latest my-twenty-app
|
||||
<img src="/images/docs/developers/extends/apps/scaffolded.png" alt="Каркас приложения успешно создан" />
|
||||
</div>
|
||||
|
||||
## Шаг 5: Начните разработку
|
||||
### Start developing
|
||||
|
||||
Перейдите в папку вашего нового приложения и запустите сервер разработки:
|
||||
|
||||
@@ -105,7 +98,7 @@ yarn twenty dev --verbose
|
||||
<img src="/images/docs/developers/extends/apps/dev.jpg" alt="Вывод терминала в режиме разработки" />
|
||||
</div>
|
||||
|
||||
## Шаг 6: Посмотрите своё приложение в Twenty
|
||||
### See your app in Twenty
|
||||
|
||||
Откройте [http://localhost:2020/settings/applications#developer](http://localhost:2020/settings/applications#developer) в браузере. Перейдите в **Settings > Apps** и выберите вкладку **Developer**. Вы должны увидеть своё приложение в разделе **Your Apps**:
|
||||
|
||||
@@ -133,13 +126,28 @@ yarn twenty dev --verbose
|
||||
|
||||
Готово! Отредактируйте любой файл в `src/`, и изменения будут подхвачены автоматически.
|
||||
|
||||
Перейдите к разделу [Создание приложений](/l/ru/developers/extend/apps/building) за подробным руководством по созданию объектов, логических функций, фронтенд-компонентов, навыков и многого другого.
|
||||
---
|
||||
|
||||
## Что вы можете создать
|
||||
|
||||
Apps are composed of **entities** — each defined as a TypeScript file with a single `export default`:
|
||||
|
||||
| Entity | What it does |
|
||||
| ----------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| **Objects & Fields** | Define custom data models (like Post Card, Invoice) with typed fields |
|
||||
| **Логические функции** | Server-side TypeScript functions triggered by HTTP routes, cron schedules, or database events |
|
||||
| **Фронтенд-компоненты** | React components that render inside Twenty's UI (side panel, widgets, command menu) |
|
||||
| **Skills & Agents** | AI capabilities — reusable instructions and autonomous assistants |
|
||||
| **Views & Navigation** | Pre-configured list views and sidebar menu items for your objects |
|
||||
| **Макеты страниц** | Custom record detail pages with tabs and widgets |
|
||||
|
||||
Head over to [Building Apps](/l/ru/developers/extend/apps/building) for a detailed guide on each entity type.
|
||||
|
||||
---
|
||||
|
||||
## Структура проекта
|
||||
|
||||
Скэффолдер генерирует следующую структуру файлов (показано в режиме `--exhaustive`, который включает примеры для каждого типа сущностей):
|
||||
The scaffolder generates the following file structure:
|
||||
|
||||
```text filename="my-twenty-app/"
|
||||
my-twenty-app/
|
||||
@@ -148,160 +156,50 @@ my-twenty-app/
|
||||
.gitignore
|
||||
.nvmrc
|
||||
.yarnrc.yml
|
||||
.yarn/
|
||||
install-state.gz
|
||||
.oxlintrc.json
|
||||
tsconfig.json
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
LLMS.md
|
||||
README.md
|
||||
.github/
|
||||
└── workflows/
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
src/
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── __tests__/
|
||||
│ ├── setup-test.ts # Test setup (server health check, config)
|
||||
│ └── app-install.integration-test.ts # Example integration test
|
||||
├── roles/
|
||||
│ └── default-role.ts # Default role for logic functions
|
||||
├── objects/
|
||||
│ └── example-object.ts # Example custom object definition
|
||||
├── fields/
|
||||
│ └── example-field.ts # Example standalone field definition
|
||||
├── logic-functions/
|
||||
│ ├── hello-world.ts # Example logic function
|
||||
│ ├── create-hello-world-company.ts # Example logic function using CoreApiClient
|
||||
│ ├── pre-install.ts # Runs before installation
|
||||
│ └── post-install.ts # Runs after installation
|
||||
├── front-components/
|
||||
│ └── hello-world.tsx # Example front component
|
||||
├── page-layouts/
|
||||
│ └── example-record-page-layout.ts # Example page layout with front component
|
||||
├── views/
|
||||
│ └── example-view.ts # Example saved view definition
|
||||
├── navigation-menu-items/
|
||||
│ └── example-navigation-menu-item.ts # Example sidebar navigation link
|
||||
├── skills/
|
||||
│ └── example-skill.ts # Example AI agent skill definition
|
||||
└── agents/
|
||||
└── example-agent.ts # Example AI agent definition
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── default-role.ts # Default role for logic functions
|
||||
├── constants/
|
||||
│ └── universal-identifiers.ts # Auto-generated UUIDs and app metadata
|
||||
└── __tests__/
|
||||
├── setup-test.ts # Test setup (server health check, config)
|
||||
└── app-install.integration-test.ts # Integration test
|
||||
```
|
||||
|
||||
По умолчанию (`--minimal`) создаются только основные файлы: `application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` и `logic-functions/post-install.ts`. Используйте `--exhaustive`, чтобы включить все показанные выше файлы-примеры.
|
||||
### Starting from an example
|
||||
|
||||
To start from a more complete example with custom objects, fields, logic functions, front components, and more, use the `--example` flag:
|
||||
|
||||
```bash filename="Terminal"
|
||||
npx create-twenty-app@latest my-twenty-app --example postcard
|
||||
```
|
||||
|
||||
Examples are sourced from the [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples) directory on GitHub. You can also scaffold individual entities into an existing project with `yarn twenty add` (see [Building Apps](/l/ru/developers/extend/apps/building#scaffolding-entities-with-yarn-twenty-add)).
|
||||
|
||||
### Ключевые файлы
|
||||
|
||||
| Файл / Папка | Назначение |
|
||||
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Содержит имя, версию и зависимости вашего приложения. Содержит скрипт `twenty`, чтобы вы могли выполнить `yarn twenty help` и увидеть все команды. |
|
||||
| `src/application-config.ts` | **Обязательно.** Основной файл конфигурации для вашего приложения. |
|
||||
| `src/roles/` | Определяет роли, которые контролируют доступ логических функций. |
|
||||
| `src/logic-functions/` | Серверные функции, запускаемые маршрутами, расписаниями cron или событиями базы данных. |
|
||||
| `src/front-components/` | Компоненты React, которые отображаются внутри интерфейса Twenty. |
|
||||
| `src/objects/` | Пользовательские определения объектов для расширения вашей модели данных. |
|
||||
| `src/fields/` | Пользовательские поля, добавляемые к существующим объектам. |
|
||||
| `src/views/` | Конфигурации сохранённых представлений. |
|
||||
| `src/navigation-menu-items/` | Пользовательские ссылки в боковой навигации. |
|
||||
| `src/skills/` | Навыки, расширяющие возможности ИИ-агентов Twenty. |
|
||||
| `src/agents/` | ИИ-агенты с пользовательскими промптами. |
|
||||
| `src/page-layouts/` | Пользовательские макеты страниц для представлений записей. |
|
||||
| `src/__tests__/` | Интеграционные тесты (настройка + пример теста). |
|
||||
| `public/` | Статические ресурсы (изображения, шрифты), обслуживаемые вместе с вашим приложением. |
|
||||
| Файл / Папка | Назначение |
|
||||
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Содержит имя, версию и зависимости вашего приложения. Содержит скрипт `twenty`, чтобы вы могли выполнить `yarn twenty help` и увидеть все команды. |
|
||||
| `src/application-config.ts` | **Обязательно.** Основной файл конфигурации для вашего приложения. |
|
||||
| `src/default-role.ts` | Default role that controls what your logic functions can access. |
|
||||
| `src/constants/universal-identifiers.ts` | Auto-generated UUIDs and app metadata (display name, description). |
|
||||
| `src/__tests__/` | Интеграционные тесты (настройка + пример теста). |
|
||||
| `public/` | Статические ресурсы (изображения, шрифты), обслуживаемые вместе с вашим приложением. |
|
||||
|
||||
## Управление удалёнными серверами
|
||||
## Local development server
|
||||
|
||||
Remote — это сервер Twenty, к которому подключается ваше приложение. Во время настройки скэффолдер автоматически создаст его для вас. Вы можете в любой момент добавлять новые remotes или переключаться между ними.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Ваши учётные данные хранятся в `~/.twenty/config.json`.
|
||||
|
||||
## Локальный сервер разработки (`yarn twenty server`)
|
||||
|
||||
CLI может управлять локальным сервером Twenty, запущенным в Docker. Это тот же сервер, который автоматически запускается при создании каркаса приложения с помощью `create-twenty-app`, но им можно управлять и вручную.
|
||||
|
||||
### Запуск сервера
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start
|
||||
```
|
||||
|
||||
Эта команда скачивает Docker-образ `twentycrm/twenty-app-dev:latest` (если его ещё нет), создаёт контейнер с именем `twenty-app-dev` и запускает его на порту **2020**. CLI ждёт, пока сервер пройдёт проверку работоспособности, прежде чем вернуть управление.
|
||||
|
||||
Создаются два тома Docker для сохранения данных между перезапусками:
|
||||
|
||||
* `twenty-app-dev-data` — база данных PostgreSQL
|
||||
* `twenty-app-dev-storage` — файловое хранилище
|
||||
|
||||
Если порт 2020 уже используется, вы можете запустить на другом порту:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start --port 3030
|
||||
```
|
||||
|
||||
CLI автоматически настраивает внутренние `NODE_PORT` и `SERVER_URL` контейнера в соответствии с выбранным портом, чтобы логические функции, OAuth и прочие внутренние сетевые взаимодействия работали корректно.
|
||||
|
||||
После запуска сервер автоматически регистрируется как remote `local` в конфигурации вашего CLI.
|
||||
|
||||
### Проверка состояния сервера
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server status
|
||||
```
|
||||
|
||||
Показывает, запущен ли сервер, его URL и учётные данные по умолчанию (`tim@apple.dev` / `tim@apple.dev`).
|
||||
|
||||
### Просмотр журналов сервера
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs
|
||||
```
|
||||
|
||||
Выводит журналы контейнера в потоковом режиме. Используйте `--lines`, чтобы задать, сколько последних строк показывать:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs --lines 100
|
||||
```
|
||||
|
||||
### Остановка сервера
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server stop
|
||||
```
|
||||
|
||||
Останавливает контейнер. Ваши данные сохраняются в томах Docker — следующий `start` продолжит с того места, где вы остановились.
|
||||
|
||||
### Сброс сервера
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server reset
|
||||
```
|
||||
|
||||
Удаляет контейнер и оба тома Docker, полностью стирая все данные. Следующий `start` создаст новый чистый экземпляр.
|
||||
|
||||
<Note>
|
||||
Для работы сервера необходимо, чтобы **Docker** был запущен. Если вы видите ошибку "Docker not running", убедитесь, что запущен Docker Desktop (или демон Docker).
|
||||
</Note>
|
||||
|
||||
### Справочник команд
|
||||
The scaffolder already started a local Twenty server for you. To manage it later, use `yarn twenty server`:
|
||||
|
||||
| Команда | Описание |
|
||||
| -------------------------------------- | -------------------------------------------------------------- |
|
||||
@@ -313,65 +211,11 @@ yarn twenty server reset
|
||||
| `yarn twenty server logs --lines 100` | Показать последние 100 строк журнала |
|
||||
| `yarn twenty server reset` | Удалить все данные и начать с чистого листа |
|
||||
|
||||
## CI с GitHub Actions
|
||||
Data is persisted across restarts in two Docker volumes (`twenty-app-dev-data` for PostgreSQL, `twenty-app-dev-storage` for files). Use `reset` to wipe everything and start fresh.
|
||||
|
||||
Скэффолдер генерирует готовый к использованию workflow GitHub Actions в `.github/workflows/ci.yml`. Он автоматически запускает ваши интеграционные тесты при каждом пуше в `main` и в pull request'ах.
|
||||
|
||||
Рабочий процесс:
|
||||
|
||||
1. Извлекает ваш код
|
||||
2. Поднимает временный сервер Twenty с помощью экшена `twentyhq/twenty/.github/actions/spawn-twenty-docker-image`
|
||||
3. Устанавливает зависимости с помощью `yarn install --immutable`
|
||||
4. Запускает `yarn test` с `TWENTY_API_URL` и `TWENTY_API_KEY`, переданными из выходных данных экшена
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Вам не нужно настраивать секреты — экшен `spawn-twenty-docker-image` запускает эфемерный сервер Twenty прямо в раннере и выводит данные для подключения. Секрет `GITHUB_TOKEN` предоставляется GitHub автоматически.
|
||||
|
||||
Чтобы закрепить конкретную версию Twenty вместо `latest`, измените переменную окружения `TWENTY_VERSION` в начале workflow.
|
||||
<Note>
|
||||
Для работы сервера необходимо, чтобы **Docker** был запущен. Если вы видите ошибку "Docker not running", убедитесь, что запущен Docker Desktop (или демон Docker).
|
||||
</Note>
|
||||
|
||||
## Ручная настройка (без генератора)
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ import { defineApplication } from 'twenty-sdk';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7',
|
||||
universalIdentifier: '39783023-bcac-41e3-b0d2-ff1944d8465d',
|
||||
displayName: 'My Twenty App',
|
||||
description: 'My first Twenty app',
|
||||
icon: 'IconWorld',
|
||||
@@ -717,6 +717,13 @@ yarn twenty exec --postInstall
|
||||
|
||||
Ön uç bileşenler, Twenty'nin UI'si içinde doğrudan görüntülenen React bileşenleridir. Remote DOM kullanan izole bir Web Worker içinde çalışırlar — kodunuz izole bir ortamda (sandbox) çalışır ancak bir iframe içinde değil, sayfada yerel olarak işlenir.
|
||||
|
||||
#### Ön bileşenlerin kullanılabileceği yerler
|
||||
|
||||
Ön bileşenler, Twenty içinde iki konumda işlenebilir:
|
||||
|
||||
* **Yan panel** — Headless olmayan ön bileşenler, sağ taraftaki yan panelde açılır. Bir ön bileşen komut menüsünden tetiklendiğinde varsayılan davranış budur.
|
||||
* **Widget'lar (panolar ve kayıt sayfaları)** — Ön bileşenler, sayfa düzenlerine widget olarak gömülebilir. Bir pano veya kayıt sayfası düzeni yapılandırılırken kullanıcılar bir ön bileşen widget'ı ekleyebilir.
|
||||
|
||||
#### Basit örnek
|
||||
|
||||
Bir ön uç bileşenini çalışırken görmenin en hızlı yolu, onu bir komut olarak kaydetmektir. `isPinned: true` ile bir `command` alanı eklemek, sayfanın sağ üst köşesinde hızlı işlem düğmesi olarak görünmesini sağlar — herhangi bir sayfa düzenine gerek yoktur:
|
||||
@@ -774,9 +781,13 @@ Bileşeni satır içi işlemek için üzerine tıklayın.
|
||||
|
||||
Komutların ötesinde, bir ön uç bileşenini bir **sayfa düzeninde** widget olarak ekleyerek doğrudan bir kayıt sayfasına gömebilirsiniz. Ayrıntılar için [definePageLayout](#definepagelayout) bölümüne bakın.
|
||||
|
||||
#### Headless bileşenler (`isHeadless: true`)
|
||||
#### Headless ve headless olmayan
|
||||
|
||||
Headless bileşenler görünür bir kullanıcı arayüzü oluşturmaz ancak yine de React mantığını çalıştırır. Bu, **etki bileşenleri** için kullanışlıdır — bağlandıklarında veri senkronizasyonu yapmak, bir zamanlayıcı başlatmak, olayları dinlemek veya bir bildirimi tetiklemek gibi yan etkiler gerçekleştiren bileşenler.
|
||||
Ön bileşenler, `isHeadless` seçeneğiyle kontrol edilen iki işleme kipiyle gelir:
|
||||
|
||||
**Headless olmayan (varsayılan)** — Bileşen görünür bir kullanıcı arayüzü (UI) oluşturur. Komut menüsünden tetiklendiğinde yan panelde açılır. `isHeadless` `false` olduğunda veya belirtilmediğinde bu varsayılan davranıştır.
|
||||
|
||||
**Headless (`isHeadless: true`)** — Bileşen arka planda görünmez şekilde bağlanır. Yan paneli açmaz. Headless bileşenler, mantığı çalıştırıp ardından kendilerini kaldıran eylemler için tasarlanmıştır — örneğin, bir async görevi çalıştırma, bir sayfaya gitme veya bir onay modalı gösterme. Aşağıda açıklanan SDK Command bileşenleriyle doğal olarak eşleşirler.
|
||||
|
||||
```tsx src/front-components/sync-tracker.tsx
|
||||
import { defineFrontComponent, useRecordId, enqueueSnackbar } from 'twenty-sdk';
|
||||
@@ -803,6 +814,89 @@ export default defineFrontComponent({
|
||||
|
||||
Bileşen `null` döndürdüğü için, Twenty bunun için bir kapsayıcı oluşturmayı atlar — düzende boş alan görünmez. Bileşen yine de tüm hook'lara ve host iletişim API'sine erişime sahiptir.
|
||||
|
||||
#### SDK Command bileşenleri
|
||||
|
||||
`twenty-sdk` paketi, headless ön bileşenler için tasarlanmış dört Command yardımcı bileşeni sağlar. Her bileşen bağlandığında bir eylem yürütür, hataları bir snackbar bildirimi göstererek ele alır ve tamamlandığında ön bileşeni otomatik olarak kaldırır.
|
||||
|
||||
Bunları `twenty-sdk/command` içinden içe aktarın:
|
||||
|
||||
* **`Command`** — `execute` prop'u aracılığıyla async bir geri çağrıyı çalıştırır.
|
||||
* **`CommandLink`** — Bir uygulama yoluna gider. Props: `to`, `params`, `queryParams`, `options`.
|
||||
* **`CommandModal`** — Bir onay modalı açar. Kullanıcı onaylarsa `execute` geri çağrısını yürütür. Props: `title`, `subtitle`, `execute`, `confirmButtonText`, `confirmButtonAccent`.
|
||||
* **`CommandOpenSidePanelPage`** — Belirli bir yan panel sayfasını açar. Props: `page`, `pageTitle`, `pageIcon`.
|
||||
|
||||
`Command` kullanarak komut menüsünden bir eylem çalıştıran headless bir ön bileşenin tam örneği:
|
||||
|
||||
```tsx src/front-components/run-action.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { Command } from 'twenty-sdk/command';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const RunAction = () => {
|
||||
const execute = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
createTask: {
|
||||
__args: { data: { title: 'Created by my app' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return <Command execute={execute} />;
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
||||
name: 'run-action',
|
||||
description: 'Creates a task from the command menu',
|
||||
component: RunAction,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
|
||||
label: 'Run my action',
|
||||
icon: 'IconPlayerPlay',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Ve yürütmeden önce onay istemek için `CommandModal` kullanan bir örnek:
|
||||
|
||||
```tsx src/front-components/delete-draft.tsx
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
import { CommandModal } from 'twenty-sdk/command';
|
||||
|
||||
const DeleteDraft = () => {
|
||||
const execute = async () => {
|
||||
// perform the deletion
|
||||
};
|
||||
|
||||
return (
|
||||
<CommandModal
|
||||
title="Delete draft?"
|
||||
subtitle="This action cannot be undone."
|
||||
execute={execute}
|
||||
confirmButtonText="Delete"
|
||||
confirmButtonAccent="danger"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'a7b8c9d0-e1f2-3456-abcd-567890123456',
|
||||
name: 'delete-draft',
|
||||
description: 'Deletes a draft with confirmation',
|
||||
component: DeleteDraft,
|
||||
isHeadless: true,
|
||||
command: {
|
||||
universalIdentifier: 'b8c9d0e1-f2a3-4567-bcde-678901234567',
|
||||
label: 'Delete draft',
|
||||
icon: 'IconTrash',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### Çalışma zamanı bağlamına erişme
|
||||
|
||||
Bileşeninizin içinde, geçerli kullanıcıya, kayda ve bileşen örneğine erişmek için SDK hook'larını kullanın:
|
||||
@@ -859,6 +953,50 @@ Kullanılabilir hook'lar:
|
||||
| `unmountFrontComponent()` | Bileşeni kaldır (unmount) |
|
||||
| `updateProgress(progress)` | Bir ilerleme göstergesini güncelle |
|
||||
|
||||
Bir eylem tamamlandıktan sonra bir snackbar göstermek ve yan paneli kapatmak için host API'sini kullanan bir örnek:
|
||||
|
||||
```tsx src/front-components/archive-record.tsx
|
||||
import { defineFrontComponent, useRecordId } from 'twenty-sdk';
|
||||
import { enqueueSnackbar, closeSidePanel } from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
const ArchiveRecord = () => {
|
||||
const recordId = useRecordId();
|
||||
|
||||
const handleArchive = async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
await client.mutation({
|
||||
updateTask: {
|
||||
__args: { id: recordId, data: { status: 'ARCHIVED' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
await enqueueSnackbar({
|
||||
message: 'Record archived',
|
||||
variant: 'success',
|
||||
});
|
||||
|
||||
await closeSidePanel();
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<p>Archive this record?</p>
|
||||
<button onClick={handleArchive}>Archive</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineFrontComponent({
|
||||
universalIdentifier: 'c9d0e1f2-a3b4-5678-cdef-789012345678',
|
||||
name: 'archive-record',
|
||||
description: 'Archives the current record',
|
||||
component: ArchiveRecord,
|
||||
});
|
||||
```
|
||||
|
||||
#### Komut seçenekleri
|
||||
|
||||
`defineFrontComponent` içine bir `command` alanı eklemek, bileşeni komut menüsüne (Cmd+K) kaydeder. `isPinned` `true` ise, sayfanın sağ üst köşesinde bir hızlı işlem düğmesi olarak da görünür.
|
||||
@@ -1713,3 +1851,86 @@ yarn twenty uninstall
|
||||
# Skip the confirmation prompt
|
||||
yarn twenty uninstall --yes
|
||||
```
|
||||
|
||||
## Uzakları yönetme
|
||||
|
||||
Bir **uzak**, uygulamanızın bağlandığı Twenty sunucusudur. Kurulum sırasında iskelet oluşturucu sizin için otomatik olarak bir tane oluşturur. Dilediğiniz zaman daha fazla uzak ekleyebilir veya aralarında geçiş yapabilirsiniz.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Kimlik bilgileriniz `~/.twenty/config.json` içinde saklanır.
|
||||
|
||||
## GitHub Actions ile CI
|
||||
|
||||
İskelet oluşturucu, `.github/workflows/ci.yml` konumunda kullanıma hazır bir GitHub Actions iş akışı üretir. Entegrasyon testlerinizi `main` dalına yapılan her itmede ve çekme isteklerinde otomatik olarak çalıştırır.
|
||||
|
||||
İş akışı:
|
||||
|
||||
1. Kodunuzu çalışma alanına alır
|
||||
2. `twentyhq/twenty/.github/actions/spawn-twenty-docker-image` eylemini kullanarak geçici bir Twenty sunucusu başlatır
|
||||
3. `yarn install --immutable` ile bağımlılıkları kurar
|
||||
4. Eylem çıktılarından enjekte edilen `TWENTY_API_URL` ve `TWENTY_API_KEY` ile `yarn test` çalıştırır
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Herhangi bir gizli değişken yapılandırmanız gerekmez — `spawn-twenty-docker-image` eylemi, koşucu içinde doğrudan geçici bir Twenty sunucusu başlatır ve bağlantı ayrıntılarını çıktı olarak verir. `GITHUB_TOKEN` gizli değişkeni GitHub tarafından otomatik olarak sağlanır.
|
||||
|
||||
`latest` yerine belirli bir Twenty sürümünü sabitlemek için iş akışının başındaki `TWENTY_VERSION` ortam değişkenini değiştirin.
|
||||
|
||||
@@ -7,7 +7,9 @@ description: İlk Twenty uygulamanızı dakikalar içinde oluşturun.
|
||||
Uygulamalar şu anda alfa aşamasında. Özellik işlevsel ancak hâlâ gelişmekte.
|
||||
</Warning>
|
||||
|
||||
Uygulamalar, Twenty'yi özel nesneler, alanlar, mantık işlevleri, Yapay Zeka yetenekleri ve UI bileşenleriyle genişletmenizi sağlar — tümü kod olarak yönetilir.
|
||||
## Uygulamalar nedir?
|
||||
|
||||
Uygulamalar, Twenty'yi özel nesneler, alanlar, mantıksal işlevler, ön uç bileşenleri, yapay zekâ yetenekleri ve daha fazlasıyla genişletmenizi sağlar — tümü kod olarak yönetilir. Her şeyi UI üzerinden yapılandırmak yerine, veri modelinizi ve mantığınızı TypeScript'te tanımlar ve bunu bir veya daha fazla çalışma alanına dağıtırsınız.
|
||||
|
||||
## Ön Gereksinimler
|
||||
|
||||
@@ -17,7 +19,9 @@ Başlamadan önce, makinenizde aşağıdakilerin kurulu olduğundan emin olun:
|
||||
* **Yarn 4** — Corepack aracılığıyla Node.js ile birlikte gelir. `corepack enable` komutunu çalıştırarak etkinleştirin
|
||||
* **Docker** — [Buradan indirin](https://www.docker.com/products/docker-desktop/). Yerel bir Twenty örneğini çalıştırmak için gereklidir. Zaten çalışan bir Twenty sunucunuz varsa gerekmez.
|
||||
|
||||
## Adım 1: Uygulamanızın iskeletini oluşturun
|
||||
## Create your first app
|
||||
|
||||
### Scaffold your app
|
||||
|
||||
Bir terminal açın ve şunu çalıştırın:
|
||||
|
||||
@@ -29,18 +33,7 @@ Uygulamanız için bir ad ve açıklama girmeniz istenecektir. Varsayılanları
|
||||
|
||||
Bu, `my-twenty-app` adlı, ihtiyacınız olan her şeyi içeren yeni bir klasör oluşturur.
|
||||
|
||||
<Note>
|
||||
İskelet oluşturucu şu bayrakları destekler:
|
||||
|
||||
* `--minimal` — yalnızca temel dosyaların iskeletini oluşturur, örnek yok (varsayılan)
|
||||
* `--exhaustive` — tüm örnek varlıkların iskeletini oluşturur
|
||||
* `--name <name>` — uygulama adını ayarlar (istemi atlar)
|
||||
* `--display-name <displayName>` — görünen adı ayarlar (istemi atlar)
|
||||
* `--description <description>` — açıklamayı ayarlar (istemi atlar)
|
||||
* `--skip-local-instance` — yerel sunucu kurulum istemini atlar
|
||||
</Note>
|
||||
|
||||
## Adım 2: Yerel bir Twenty örneği kurun
|
||||
### Set up a local Twenty instance
|
||||
|
||||
İskelet oluşturucu şunu soracaktır:
|
||||
|
||||
@@ -53,7 +46,7 @@ Bu, `my-twenty-app` adlı, ihtiyacınız olan her şeyi içeren yeni bir klasör
|
||||
<img src="/images/docs/developers/extends/apps/start-instance.png" alt="Yerel örnek başlatılsın mı?" />
|
||||
</div>
|
||||
|
||||
## Adım 3: Çalışma alanınıza giriş yapın
|
||||
### Sign in to your workspace
|
||||
|
||||
Ardından, Twenty oturum açma sayfasıyla bir tarayıcı penceresi açılacaktır. Önceden eklenmiş demo hesabıyla oturum açın:
|
||||
|
||||
@@ -64,7 +57,7 @@ Ardından, Twenty oturum açma sayfasıyla bir tarayıcı penceresi açılacakt
|
||||
<img src="/images/docs/developers/extends/apps/login.png" alt="Twenty oturum açma ekranı" />
|
||||
</div>
|
||||
|
||||
## Adım 4: Uygulamayı yetkilendirin
|
||||
### Authorize the app
|
||||
|
||||
Oturum açtıktan sonra bir yetkilendirme ekranı göreceksiniz. Bu, uygulamanızın çalışma alanınızla etkileşim kurmasını sağlar.
|
||||
|
||||
@@ -80,7 +73,7 @@ Yetkilendirildikten sonra terminaliniz her şeyin kurulduğunu onaylayacaktır.
|
||||
<img src="/images/docs/developers/extends/apps/scaffolded.png" alt="Uygulama iskeleti başarıyla oluşturuldu" />
|
||||
</div>
|
||||
|
||||
## Adım 5: Geliştirmeye başlayın
|
||||
### Start developing
|
||||
|
||||
Yeni uygulama klasörünüze gidin ve geliştirme sunucusunu başlatın:
|
||||
|
||||
@@ -105,7 +98,7 @@ Geliştirme modu yalnızca geliştirme ortamında (`NODE_ENV=development`) çal
|
||||
<img src="/images/docs/developers/extends/apps/dev.jpg" alt="Geliştirme modu terminal çıktısı" />
|
||||
</div>
|
||||
|
||||
## Adım 6: Uygulamanızı Twenty'de görün
|
||||
### See your app in Twenty
|
||||
|
||||
Tarayıcınızda [http://localhost:2020/settings/applications#developer](http://localhost:2020/settings/applications#developer) adresini açın. **Settings > Apps** bölümüne gidin ve **Developer** sekmesini seçin. **Your Apps** altında uygulamanızın listelendiğini görmelisiniz:
|
||||
|
||||
@@ -133,13 +126,28 @@ Uygulamanızın sağladığı her şeyi — nesneler, alanlar, mantık işlevler
|
||||
|
||||
Her şey hazır! `src/` içindeki herhangi bir dosyayı düzenleyin; değişiklikler otomatik olarak alınacaktır.
|
||||
|
||||
Nesneler, mantık işlevleri, ön bileşenler, beceriler ve daha fazlasını oluşturma hakkında ayrıntılı bir kılavuz için [Uygulama Oluşturma](/l/tr/developers/extend/apps/building) bölümüne göz atın.
|
||||
---
|
||||
|
||||
## Oluşturabilecekleriniz
|
||||
|
||||
Apps are composed of **entities** — each defined as a TypeScript file with a single `export default`:
|
||||
|
||||
| Entity | What it does |
|
||||
| ---------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| **Objects & Fields** | Define custom data models (like Post Card, Invoice) with typed fields |
|
||||
| **Mantıksal işlevler** | Server-side TypeScript functions triggered by HTTP routes, cron schedules, or database events |
|
||||
| **Ön uç bileşenleri** | React components that render inside Twenty's UI (side panel, widgets, command menu) |
|
||||
| **Skills & Agents** | AI capabilities — reusable instructions and autonomous assistants |
|
||||
| **Views & Navigation** | Pre-configured list views and sidebar menu items for your objects |
|
||||
| **Sayfa düzenleri** | Custom record detail pages with tabs and widgets |
|
||||
|
||||
Head over to [Building Apps](/l/tr/developers/extend/apps/building) for a detailed guide on each entity type.
|
||||
|
||||
---
|
||||
|
||||
## Proje yapısı
|
||||
|
||||
İskelet oluşturucu aşağıdaki dosya yapısını üretir (`--exhaustive` modunda gösterilmiştir; her varlık türü için örnekler içerir):
|
||||
The scaffolder generates the following file structure:
|
||||
|
||||
```text filename="my-twenty-app/"
|
||||
my-twenty-app/
|
||||
@@ -148,160 +156,50 @@ my-twenty-app/
|
||||
.gitignore
|
||||
.nvmrc
|
||||
.yarnrc.yml
|
||||
.yarn/
|
||||
install-state.gz
|
||||
.oxlintrc.json
|
||||
tsconfig.json
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
tsconfig.spec.json # TypeScript config for tests
|
||||
vitest.config.ts # Vitest test runner configuration
|
||||
LLMS.md
|
||||
README.md
|
||||
.github/
|
||||
└── workflows/
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
└── ci.yml # GitHub Actions CI workflow
|
||||
public/ # Public assets (images, fonts, etc.)
|
||||
src/
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── __tests__/
|
||||
│ ├── setup-test.ts # Test setup (server health check, config)
|
||||
│ └── app-install.integration-test.ts # Example integration test
|
||||
├── roles/
|
||||
│ └── default-role.ts # Default role for logic functions
|
||||
├── objects/
|
||||
│ └── example-object.ts # Example custom object definition
|
||||
├── fields/
|
||||
│ └── example-field.ts # Example standalone field definition
|
||||
├── logic-functions/
|
||||
│ ├── hello-world.ts # Example logic function
|
||||
│ ├── create-hello-world-company.ts # Example logic function using CoreApiClient
|
||||
│ ├── pre-install.ts # Runs before installation
|
||||
│ └── post-install.ts # Runs after installation
|
||||
├── front-components/
|
||||
│ └── hello-world.tsx # Example front component
|
||||
├── page-layouts/
|
||||
│ └── example-record-page-layout.ts # Example page layout with front component
|
||||
├── views/
|
||||
│ └── example-view.ts # Example saved view definition
|
||||
├── navigation-menu-items/
|
||||
│ └── example-navigation-menu-item.ts # Example sidebar navigation link
|
||||
├── skills/
|
||||
│ └── example-skill.ts # Example AI agent skill definition
|
||||
└── agents/
|
||||
└── example-agent.ts # Example AI agent definition
|
||||
├── application-config.ts # Required — main application configuration
|
||||
├── default-role.ts # Default role for logic functions
|
||||
├── constants/
|
||||
│ └── universal-identifiers.ts # Auto-generated UUIDs and app metadata
|
||||
└── __tests__/
|
||||
├── setup-test.ts # Test setup (server health check, config)
|
||||
└── app-install.integration-test.ts # Integration test
|
||||
```
|
||||
|
||||
Varsayılan olarak (`--minimal`), yalnızca çekirdek dosyalar oluşturulur: `application-config.ts`, `roles/default-role.ts`, `logic-functions/pre-install.ts` ve `logic-functions/post-install.ts`. Yukarıda gösterilen tüm örnek dosyaları dahil etmek için `--exhaustive` kullanın.
|
||||
### Starting from an example
|
||||
|
||||
To start from a more complete example with custom objects, fields, logic functions, front components, and more, use the `--example` flag:
|
||||
|
||||
```bash filename="Terminal"
|
||||
npx create-twenty-app@latest my-twenty-app --example postcard
|
||||
```
|
||||
|
||||
Examples are sourced from the [twenty-apps/examples](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/examples) directory on GitHub. You can also scaffold individual entities into an existing project with `yarn twenty add` (see [Building Apps](/l/tr/developers/extend/apps/building#scaffolding-entities-with-yarn-twenty-add)).
|
||||
|
||||
### Temel dosyalar
|
||||
|
||||
| Dosya / Klasör | Amaç |
|
||||
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Uygulamanızın adını, sürümünü ve bağımlılıklarını bildirir. Tüm komutları görmek için `yarn twenty help` çalıştırabilmeniz amacıyla bir `twenty` betiği içerir. |
|
||||
| `src/application-config.ts` | **Gerekli.** Uygulamanızın ana yapılandırma dosyası. |
|
||||
| `src/roles/` | Mantık işlevlerinizin neye erişebileceğini kontrol eden rolleri tanımlar. |
|
||||
| `src/logic-functions/` | Rotalar, cron zamanlamaları veya veritabanı olayları tarafından tetiklenen sunucu tarafı işlevler. |
|
||||
| `src/front-components/` | Twenty'nin UI'si içinde görüntülenen React bileşenleri. |
|
||||
| `src/objects/` | Veri modelinizi genişletmek için özel nesne tanımları. |
|
||||
| `src/fields/` | Mevcut nesnelere eklenen özel alanlar. |
|
||||
| `src/views/` | Kaydedilmiş görünüm yapılandırmaları. |
|
||||
| `src/navigation-menu-items/` | Kenar çubuğu gezintisinde özel bağlantılar. |
|
||||
| `src/skills/` | Twenty'nin yapay zeka ajanlarının yeteneklerini genişleten beceriler. |
|
||||
| `src/agents/` | Özel istemlere sahip yapay zekâ ajanları. |
|
||||
| `src/page-layouts/` | Kayıt görünümleri için özel sayfa düzenleri. |
|
||||
| `src/__tests__/` | Entegrasyon testleri (kurulum + örnek test). |
|
||||
| `public/` | Uygulamanızla birlikte sunulan statik varlıklar (görüntüler, yazı tipleri). |
|
||||
| Dosya / Klasör | Amaç |
|
||||
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `package.json` | Uygulamanızın adını, sürümünü ve bağımlılıklarını bildirir. Tüm komutları görmek için `yarn twenty help` çalıştırabilmeniz amacıyla bir `twenty` betiği içerir. |
|
||||
| `src/application-config.ts` | **Gerekli.** Uygulamanızın ana yapılandırma dosyası. |
|
||||
| `src/default-role.ts` | Default role that controls what your logic functions can access. |
|
||||
| `src/constants/universal-identifiers.ts` | Auto-generated UUIDs and app metadata (display name, description). |
|
||||
| `src/__tests__/` | Entegrasyon testleri (kurulum + örnek test). |
|
||||
| `public/` | Uygulamanızla birlikte sunulan statik varlıklar (görüntüler, yazı tipleri). |
|
||||
|
||||
## Uzakları yönetme
|
||||
## Local development server
|
||||
|
||||
Bir **uzak**, uygulamanızın bağlandığı Twenty sunucusudur. Kurulum sırasında iskelet oluşturucu sizin için otomatik olarak bir tane oluşturur. Dilediğiniz zaman daha fazla uzak ekleyebilir veya aralarında geçiş yapabilirsiniz.
|
||||
|
||||
```bash filename="Terminal"
|
||||
# Add a new remote (opens a browser for OAuth login)
|
||||
yarn twenty remote add
|
||||
|
||||
# Connect to a local Twenty server (auto-detects port 2020 or 3000)
|
||||
yarn twenty remote add --local
|
||||
|
||||
# Add a remote non-interactively (useful for CI)
|
||||
yarn twenty remote add --api-url https://your-twenty-server.com --api-key $TWENTY_API_KEY --as my-remote
|
||||
|
||||
# List all configured remotes
|
||||
yarn twenty remote list
|
||||
|
||||
# Switch the active remote
|
||||
yarn twenty remote switch <name>
|
||||
```
|
||||
|
||||
Kimlik bilgileriniz `~/.twenty/config.json` içinde saklanır.
|
||||
|
||||
## Yerel geliştirme sunucusu (`yarn twenty server`)
|
||||
|
||||
CLI, Docker'da çalışan yerel bir Twenty sunucusunu yönetebilir. Bu, `create-twenty-app` ile bir uygulamanın iskeletini oluşturduğunuzda otomatik olarak başlatılan sunucunun aynısıdır; ancak bunu el ile de yönetebilirsiniz.
|
||||
|
||||
### Sunucuyu Başlatma
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start
|
||||
```
|
||||
|
||||
Bu, `twentycrm/twenty-app-dev:latest` Docker imajını (zaten mevcut değilse) çeker, `twenty-app-dev` adlı bir konteyner oluşturur ve **2020** portunda başlatır. CLI, dönmeden önce sunucunun sağlık kontrolünü geçmesini bekler.
|
||||
|
||||
Yeniden başlatmalar arasında verileri kalıcı kılmak için iki Docker birimi oluşturulur:
|
||||
|
||||
* `twenty-app-dev-data` — PostgreSQL veritabanı
|
||||
* `twenty-app-dev-storage` — dosya depolama
|
||||
|
||||
2020 portu zaten kullanımda ise farklı bir portta başlatabilirsiniz:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server start --port 3030
|
||||
```
|
||||
|
||||
CLI, seçilen porta uyacak şekilde konteynerin dahili `NODE_PORT` ve `SERVER_URL` ayarlarını otomatik olarak yapılandırır; böylece mantık işlevleri, OAuth ve diğer tüm dahili ağ işlemleri doğru şekilde çalışır.
|
||||
|
||||
Başlatıldığında, sunucu CLI yapılandırmanızda `local` uzak olarak otomatik olarak kaydedilir.
|
||||
|
||||
### Sunucu durumunu kontrol etme
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server status
|
||||
```
|
||||
|
||||
Sunucunun çalışıp çalışmadığını, URL'sini ve varsayılan oturum açma kimlik bilgilerini (`tim@apple.dev` / `tim@apple.dev`) gösterir.
|
||||
|
||||
### Sunucu günlüklerini görüntüleme
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs
|
||||
```
|
||||
|
||||
Konteyner günlüklerini akış olarak iletir. Kaç satırın gösterileceğini denetlemek için `--lines` kullanın:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server logs --lines 100
|
||||
```
|
||||
|
||||
### Sunucuyu durdurma
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server stop
|
||||
```
|
||||
|
||||
Konteyneri durdurur. Verileriniz Docker birimlerinde korunur — bir sonraki `start`, kaldığınız yerden devam eder.
|
||||
|
||||
### Sunucuyu sıfırlama
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty server reset
|
||||
```
|
||||
|
||||
Konteyneri kaldırır ve her iki Docker birimini de silerek tüm verileri temizler. Sonraki `start`, yeni bir örnek oluşturur.
|
||||
|
||||
<Note>
|
||||
Sunucunun çalışması için **Docker**'ın çalışıyor olması gerekir. "Docker not running" hatası görürseniz Docker Desktop'ın (veya Docker daemon'ının) başlatıldığından emin olun.
|
||||
</Note>
|
||||
|
||||
### Komut başvurusu
|
||||
The scaffolder already started a local Twenty server for you. To manage it later, use `yarn twenty server`:
|
||||
|
||||
| Komut | Açıklama |
|
||||
| -------------------------------------- | ------------------------------------------------------ |
|
||||
@@ -313,65 +211,11 @@ Konteyneri kaldırır ve her iki Docker birimini de silerek tüm verileri temizl
|
||||
| `yarn twenty server logs --lines 100` | Son 100 günlük satırını gösterir |
|
||||
| `yarn twenty server reset` | Tüm verileri siler ve sıfırdan başlatır |
|
||||
|
||||
## GitHub Actions ile CI
|
||||
Data is persisted across restarts in two Docker volumes (`twenty-app-dev-data` for PostgreSQL, `twenty-app-dev-storage` for files). Use `reset` to wipe everything and start fresh.
|
||||
|
||||
İskelet oluşturucu, `.github/workflows/ci.yml` konumunda kullanıma hazır bir GitHub Actions iş akışı üretir. Entegrasyon testlerinizi `main` dalına yapılan her itmede ve çekme isteklerinde otomatik olarak çalıştırır.
|
||||
|
||||
İş akışı:
|
||||
|
||||
1. Kodunuzu depodan çıkarır
|
||||
2. `twentyhq/twenty/.github/actions/spawn-twenty-docker-image` eylemini kullanarak geçici bir Twenty sunucusu başlatır
|
||||
3. `yarn install --immutable` ile bağımlılıkları kurar
|
||||
4. Eylem çıktılarından enjekte edilen `TWENTY_API_URL` ve `TWENTY_API_KEY` ile `yarn test` çalıştırır
|
||||
|
||||
```yaml .github/workflows/ci.yml
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
TWENTY_VERSION: latest
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Spawn Twenty instance
|
||||
id: twenty
|
||||
uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main
|
||||
with:
|
||||
twenty-version: ${{ env.TWENTY_VERSION }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Run integration tests
|
||||
run: yarn test
|
||||
env:
|
||||
TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }}
|
||||
TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }}
|
||||
```
|
||||
|
||||
Herhangi bir gizli değişken yapılandırmanız gerekmez — `spawn-twenty-docker-image` eylemi, koşucu içinde doğrudan geçici bir Twenty sunucusu başlatır ve bağlantı ayrıntılarını çıktı olarak verir. `GITHUB_TOKEN` gizli değişkeni GitHub tarafından otomatik olarak sağlanır.
|
||||
|
||||
`latest` yerine belirli bir Twenty sürümünü sabitlemek için iş akışının başındaki `TWENTY_VERSION` ortam değişkenini değiştirin.
|
||||
<Note>
|
||||
Sunucunun çalışması için **Docker**'ın çalışıyor olması gerekir. "Docker not running" hatası görürseniz Docker Desktop'ın (veya Docker daemon'ının) başlatıldığından emin olun.
|
||||
</Note>
|
||||
|
||||
## Manuel kurulum (iskelet oluşturucu olmadan)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user