> ## Documentation Index
> Fetch the complete documentation index at: https://docs.get-clara.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Ön uç bileşenleri

> Build React components that render inside Twenty's UI with sandboxed isolation.

Ö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 uç bileşenlerinin kullanılabileceği yerler

Ön uç bileşenler, Twenty içinde iki konumda işlenebilir:

* **Yan panel** — Headless olmayan ön uç bileşenler, sağ taraftaki yan panelde açılır. Bir ön uç bileşeni komut menüsünden tetiklendiğinde varsayılan davranış budur.
* **Widget'lar (panolar ve kayıt sayfaları)** — Ön uç 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 uç 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:

```tsx src/front-components/hello-world.tsx theme={null}
import { defineFrontComponent } from 'twenty-sdk/define';

const HelloWorld = () => {
  return (
    <div style={{ padding: '20px', fontFamily: 'sans-serif' }}>
      <h1>Hello from my app!</h1>
      <p>This component renders inside Twenty.</p>
    </div>
  );
};

export default defineFrontComponent({
  universalIdentifier: '74c526eb-cb68-4cf7-b05c-0dd8c288d948',
  name: 'hello-world',
  description: 'A simple front component',
  component: HelloWorld,
  command: {
    universalIdentifier: 'd4e5f6a7-b8c9-0123-defa-456789012345',
    shortLabel: 'Hello',
    label: 'Hello World',
    icon: 'IconBolt',
    isPinned: true,
    availabilityType: 'GLOBAL',
  },
});
```

`yarn twenty dev` ile senkronize ettikten sonra (veya tek seferlik bir `yarn twenty dev --once` çalıştırdıktan sonra), hızlı işlem sayfanın sağ üst köşesinde görünür:

<div style={{textAlign: 'center'}}>
  <img src="https://mintcdn.com/clara-1b8b12e1/qLc_oPoqnIeP4kYN/images/docs/developers/extends/apps/quick-action.png?fit=max&auto=format&n=qLc_oPoqnIeP4kYN&q=85&s=e718e660bb389e74285aeefd2837d787" alt="Sağ üst köşedeki hızlı işlem düğmesi" width="3024" height="1502" data-path="images/docs/developers/extends/apps/quick-action.png" />
</div>

Bileşeni satır içi işlemek için üzerine tıklayın.

## Yapılandırma alanları

| Alan                  | Zorunlu | Açıklama                                                                                   |
| --------------------- | ------- | ------------------------------------------------------------------------------------------ |
| `universalIdentifier` | Evet    | Bu bileşen için kalıcı benzersiz kimlik                                                    |
| `component`           | Evet    | Bir React bileşen fonksiyonu                                                               |
| `name`                | Hayır   | Görünen Ad                                                                                 |
| `description`         | Hayır   | Bileşenin ne yaptığına dair açıklama                                                       |
| `isHeadless`          | Hayır   | Bileşenin görünür bir kullanıcı arayüzü yoksa `true` olarak ayarlayın (aşağıya bakın)      |
| `command`             | Hayır   | Bileşeni bir komut olarak kaydedin (aşağıda [komut seçeneklerine](#command-options) bakın) |

## Bir ön uç bileşenini bir sayfaya yerleştirme

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](/l/tr/developers/extend/apps/skills-and-agents#definepagelayout) bölümüne bakın.

## Headless ve headless olmayan

Ön uç 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 theme={null}
import { defineFrontComponent } from 'twenty-sdk/define';
import { useRecordId, enqueueSnackbar } from 'twenty-sdk/front-component';
import { useEffect } from 'react';

const SyncTracker = () => {
  const recordId = useRecordId();

  useEffect(() => {
    enqueueSnackbar({ message: `Tracking record ${recordId}`, variant: 'info' });
  }, [recordId]);

  return null;
};

export default defineFrontComponent({
  universalIdentifier: '...',
  name: 'sync-tracker',
  description: 'Tracks record views silently',
  isHeadless: true,
  component: SyncTracker,
});
```

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 theme={null}
import { defineFrontComponent } from 'twenty-sdk/define';
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 theme={null}
import { defineFrontComponent } from 'twenty-sdk/define';
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:

```tsx src/front-components/record-info.tsx theme={null}
import { defineFrontComponent } from 'twenty-sdk/define';
import {
  useUserId,
  useRecordId,
  useFrontComponentId,
} from 'twenty-sdk/front-component';

const RecordInfo = () => {
  const userId = useUserId();
  const recordId = useRecordId();
  const componentId = useFrontComponentId();

  return (
    <div>
      <p>User: {userId}</p>
      <p>Record: {recordId ?? 'No record context'}</p>
      <p>Component: {componentId}</p>
    </div>
  );
};

export default defineFrontComponent({
  universalIdentifier: 'b2c3d4e5-f6a7-8901-bcde-f23456789012',
  name: 'record-info',
  component: RecordInfo,
});
```

Kullanılabilir hook'lar:

| Hook                                          | Döndürür             | Açıklama                                                      |
| --------------------------------------------- | -------------------- | ------------------------------------------------------------- |
| `useUserId()`                                 | `string` veya `null` | Geçerli kullanıcının ID'si                                    |
| `useRecordId()`                               | `string` veya `null` | Geçerli kaydın ID'si (bir kayıt sayfasına yerleştirildiğinde) |
| `useFrontComponentId()`                       | `string`             | Bu bileşen örneğinin ID'si                                    |
| `useFrontComponentExecutionContext(selector)` | değişir              | Bir seçici işlevle tam yürütme bağlamına erişin               |

## Host iletişim API'si

Ön uç bileşenleri, `twenty-sdk`'deki işlevleri kullanarak gezinmeyi, modalları ve bildirimleri tetikleyebilir:

| Fonksiyon                                       | Açıklama                           |
| ----------------------------------------------- | ---------------------------------- |
| `navigate(to, params?, queryParams?, options?)` | Uygulamada bir sayfaya git         |
| `openSidePanelPage(params)`                     | Bir yan panel aç                   |
| `closeSidePanel()`                              | Yan paneli kapat                   |
| `openCommandConfirmationModal(params)`          | Bir onay iletişim kutusu göster    |
| `enqueueSnackbar(params)`                       | Bir toast bildirimi göster         |
| `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 theme={null}
import { defineFrontComponent } from 'twenty-sdk/define';
import { useRecordId } from 'twenty-sdk/front-component';
import { enqueueSnackbar, closeSidePanel } from 'twenty-sdk/front-component';
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.

| Alan                                    | Zorunlu | Açıklama                                                                                                                                                                                              |
| --------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `universalIdentifier`                   | Evet    | Komut için kalıcı benzersiz kimlik                                                                                                                                                                    |
| `label`                                 | Evet    | Komut menüsünde (Cmd+K) gösterilen tam etiket                                                                                                                                                         |
| `shortLabel`                            | Hayır   | Sabitlenmiş hızlı işlem düğmesinde görüntülenen daha kısa etiket                                                                                                                                      |
| `icon`                                  | Hayır   | Etiketin yanında görüntülenen simge adı (örn. `'IconBolt'`, `'IconSend'`)                                                                                                                             |
| `isPinned`                              | Hayır   | `true` olduğunda, komutu sayfanın sağ üst köşesinde bir hızlı işlem düğmesi olarak gösterir                                                                                                           |
| `availabilityType`                      | Hayır   | Komutun nerede görüneceğini kontrol eder: `'GLOBAL'` (her zaman kullanılabilir), `'RECORD_SELECTION'` (yalnızca kayıtlar seçiliyken) veya `'FALLBACK'` (başka hiçbir komut eşleşmediğinde gösterilir) |
| `availabilityObjectUniversalIdentifier` | Hayır   | Komutu belirli bir nesne türünün sayfalarıyla sınırlandırın (örn. yalnızca Company kayıtlarında)                                                                                                      |
| `conditionalAvailabilityExpression`     | Hayır   | Komutun görünür olup olmadığını dinamik olarak kontrol eden bir boolean ifade (aşağıya bakın)                                                                                                         |

## Koşullu kullanılabilirlik ifadeleri

`conditionalAvailabilityExpression` alanı, geçerli sayfa bağlamına göre bir komutun ne zaman görünür olacağını kontrol etmenizi sağlar. İfadeler oluşturmak için `twenty-sdk`'den türlendirilmiş değişkenleri ve operatörleri içe aktarın:

```tsx theme={null}
import { defineFrontComponent } from 'twenty-sdk/define';
import {
  pageType,
  numberOfSelectedRecords,
  objectPermissions,
  everyEquals,
  isDefined,
} from 'twenty-sdk/front-component';

export default defineFrontComponent({
  universalIdentifier: '...',
  name: 'bulk-action',
  component: BulkAction,
  command: {
    universalIdentifier: '...',
    label: 'Bulk Update',
    availabilityType: 'RECORD_SELECTION',
    conditionalAvailabilityExpression: everyEquals(
      objectPermissions,
      'canUpdateObjectRecords',
      true,
    ),
  },
});
```

**Bağlam değişkenleri** — bunlar sayfanın mevcut durumunu temsil eder:

| Değişken                       | Tür       | Açıklama                                                          |
| ------------------------------ | --------- | ----------------------------------------------------------------- |
| `pageType`                     | `string`  | Geçerli sayfa türü (örn. `'RecordIndexPage'`, `'RecordShowPage'`) |
| `isInSidePanel`                | `boolean` | Bileşenin bir yan panelde oluşturulup oluşturulmadığı             |
| `numberOfSelectedRecords`      | `number`  | Şu anda seçili kayıt sayısı                                       |
| `isSelectAll`                  | `boolean` | "tümünü seç" seçeneğinin etkin olup olmadığı                      |
| `selectedRecords`              | `array`   | Seçili kayıt nesneleri                                            |
| `favoriteRecordIds`            | `array`   | Favorilere eklenen kayıtların ID'leri                             |
| `objectPermissions`            | `object`  | Geçerli nesne türü için izinler                                   |
| `targetObjectReadPermissions`  | `object`  | Hedef nesne için okuma izinleri                                   |
| `targetObjectWritePermissions` | `object`  | Hedef nesne için yazma izinleri                                   |
| `featureFlags`                 | `object`  | Etkin özellik bayrakları                                          |
| `objectMetadataItem`           | `object`  | Geçerli nesne türünün üst verileri                                |
| `hasAnySoftDeleteFilterOnView` | `boolean` | Geçerli görünümde soft-delete filtresi olup olmadığı              |

**Operatörler** — değişkenleri boolean ifadelere dönüştürmek için birleştirin:

| Operatör                            | Açıklama                                                  |
| ----------------------------------- | --------------------------------------------------------- |
| `isDefined(value)`                  | Değer null/undefined değilse `true`                       |
| `isNonEmptyString(value)`           | Değer boş olmayan bir string ise `true`                   |
| `includes(array, value)`            | Dizi değeri içeriyorsa `true`                             |
| `includesEvery(array, prop, value)` | Her bir öğenin özelliği değeri içeriyorsa `true`          |
| `every(array, prop)`                | Özellik her öğede truthy ise `true`                       |
| `everyDefined(array, prop)`         | Özellik her öğede tanımlıysa `true`                       |
| `everyEquals(array, prop, value)`   | Özellik her öğede değere eşitse `true`                    |
| `some(array, prop)`                 | Özellik en az bir öğede truthy ise `true`                 |
| `someDefined(array, prop)`          | Özellik en az bir öğede tanımlıysa `true`                 |
| `someEquals(array, prop, value)`    | Özellik en az bir öğede değere eşitse `true`              |
| `someNonEmptyString(array, prop)`   | Özellik en az bir öğede boş olmayan bir string ise `true` |
| `none(array, prop)`                 | Özellik her öğede falsy ise `true`                        |
| `noneDefined(array, prop)`          | Özellik her öğede tanımsızsa `true`                       |
| `noneEquals(array, prop, value)`    | Özellik hiçbir öğede değere eşit değilse `true`           |

## Genel varlıklar

Ön uç bileşenleri, `getPublicAssetUrl` kullanarak uygulamanın `public/` dizinindeki dosyalara erişebilir:

```tsx theme={null}
import { defineFrontComponent, getPublicAssetUrl } from 'twenty-sdk/define';

const Logo = () => <img src={getPublicAssetUrl('logo.png')} alt="Logo" />;

export default defineFrontComponent({
  universalIdentifier: '...',
  name: 'logo',
  component: Logo,
});
```

Ayrıntılar için [genel varlıklar bölümüne](/l/tr/developers/extend/apps/cli-and-testing#public-assets-public-folder) bakın.

## Stil

Ön uç bileşenleri birden fazla biçimlendirme yaklaşımını destekler. Şunları kullanabilirsiniz:

* **Satır içi stiller** — `style={{ color: 'red' }}`
* **Twenty UI bileşenleri** — `twenty-sdk/ui` içinden içe aktarın (Button, Tag, Status, Chip, Avatar ve daha fazlası)
* **Emotion** — `@emotion/react` ile CSS-in-JS
* **Styled-components** — `styled.div` kalıpları
* **Tailwind CSS** — yardımcı sınıflar
* **React ile uyumlu herhangi bir CSS-in-JS kitaplığı**

```tsx theme={null}
import { defineFrontComponent } from 'twenty-sdk/define';
import { Button, Tag, Status } from 'twenty-sdk/ui';

const StyledWidget = () => {
  return (
    <div style={{ padding: '16px', display: 'flex', gap: '8px' }}>
      <Button title="Click me" onClick={() => alert('Clicked!')} />
      <Tag text="Active" color="green" />
      <Status color="green" text="Online" />
    </div>
  );
};

export default defineFrontComponent({
  universalIdentifier: 'e5f6a7b8-c9d0-1234-efab-567890123456',
  name: 'styled-widget',
  component: StyledWidget,
});
```
