Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74e3dba98f | ||
|
|
d225d132f9 | ||
|
|
020000b3c5 | ||
|
|
0a94f93f0c |
@@ -18,13 +18,13 @@ Ambos os caminhos começam na mesma etapa de **build**.
|
||||
|
||||
## Compilando seu app
|
||||
|
||||
Execute o comando build para compilar seu app e gerar um `manifest.json` pronto para distribuição:
|
||||
Run the build command to compile your app and generate a distribution-ready `manifest.json`:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
Isso compila seu código-fonte em TypeScript, transpila funções de lógica e componentes de front-end e grava tudo em `.twenty/output/`. Adicione `--tarball` para também gerar um pacote `.tgz` para distribuição manual ou para o comando de deploy.
|
||||
This compiles TypeScript sources, transpiles logic functions and front components, and writes everything to `.twenty/output/`. Add `--tarball` to also produce a `.tgz` package for manual distribution or the deploy command.
|
||||
|
||||
## Implantando em um servidor (tarball)
|
||||
|
||||
@@ -61,7 +61,7 @@ Aplicativos em tarball não são listados no marketplace público, então outros
|
||||
O link de compartilhamento usa a URL base do servidor (sem qualquer subdomínio de espaço de trabalho), para funcionar em qualquer espaço de trabalho no servidor.
|
||||
|
||||
<Warning>
|
||||
Compartilhar apps privados é um recurso do plano Enterprise. Vá para [Configurações > Painel de Administração > Enterprise](/settings/admin-panel#enterprise) para ativá-lo.
|
||||
Sharing private apps is an Enterprise feature. Go to [Settings > Admin Panel > Enterprise](/settings/admin-panel#enterprise) to enable it.
|
||||
</Warning>
|
||||
|
||||
### Gerenciamento de versões
|
||||
@@ -69,7 +69,7 @@ Compartilhar apps privados é um recurso do plano Enterprise. Vá para [Configur
|
||||
Para lançar uma atualização:
|
||||
|
||||
1. Atualize o campo `version` no seu `package.json`
|
||||
2. Execute `yarn twenty deploy` (ou `yarn twenty deploy --remote production`)
|
||||
2. Run `yarn twenty deploy` (or `yarn twenty deploy --remote production`)
|
||||
3. Os espaços de trabalho que têm o aplicativo instalado verão a atualização disponível em suas configurações
|
||||
|
||||
{/* TODO: add screenshot of the Upgrade button */}
|
||||
@@ -81,7 +81,7 @@ Publicar no npm torna seu aplicativo descobrível no Marketplace da Twenty. Qual
|
||||
### Requisitos
|
||||
|
||||
* Uma conta no [npm](https://www.npmjs.com)
|
||||
* A palavra-chave `twenty-app` no array `keywords` do seu `package.json` (já incluída quando você cria o projeto com `create-twenty-app`)
|
||||
* The `twenty-app` keyword in your `package.json` `keywords` array (already included when you scaffold with `create-twenty-app`)
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
@@ -93,7 +93,7 @@ Publicar no npm torna seu aplicativo descobrível no Marketplace da Twenty. Qual
|
||||
|
||||
### Metadados do Marketplace
|
||||
|
||||
A configuração `defineApplication()` oferece suporte a campos opcionais que controlam como seu app aparece no marketplace. Use `logoUrl` e `screenshots` para referenciar imagens da pasta `public/`:
|
||||
The `defineApplication()` config supports optional fields that control how your app appears in the marketplace. Use `logoUrl` and `screenshots` to reference images from the `public/` folder:
|
||||
|
||||
```ts src/application-config.ts
|
||||
export default defineApplication({
|
||||
@@ -109,9 +109,9 @@ export default defineApplication({
|
||||
});
|
||||
```
|
||||
|
||||
Veja o [acordeão de defineApplication](/l/pt/developers/extend/apps/building#defineentity-functions) na página Building Apps para a lista completa de campos do marketplace (`author`, `category`, `aboutDescription`, `websiteUrl`, `termsUrl`, etc.).
|
||||
See the [defineApplication accordion](/l/pt/developers/extend/apps/building#defineentity-functions) in the Building Apps page for the full list of marketplace fields (`author`, `category`, `aboutDescription`, `websiteUrl`, `termsUrl`, etc.).
|
||||
|
||||
### Publicar
|
||||
### Publish
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish
|
||||
@@ -127,7 +127,7 @@ yarn twenty publish --tag beta
|
||||
|
||||
O servidor Twenty sincroniza seu catálogo do marketplace a partir do registro do npm **a cada hora**.
|
||||
|
||||
Você pode acionar a sincronização imediatamente em vez de esperar:
|
||||
You can trigger the sync immediately instead of waiting:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync
|
||||
@@ -135,7 +135,7 @@ yarn twenty catalog-sync
|
||||
# yarn twenty catalog-sync --remote production
|
||||
```
|
||||
|
||||
Os metadados exibidos no marketplace vêm da sua configuração `defineApplication()` — campos como `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl` e `termsUrl`.
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` config — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
|
||||
<Note>
|
||||
Se o seu aplicativo não definir um `aboutDescription` em `defineApplication()`, o marketplace usará automaticamente o `README.md` do seu pacote no npm como conteúdo da página Sobre. Isso significa que você pode manter um único README tanto para o npm quanto para o marketplace da Twenty. Se quiser uma descrição diferente no marketplace, defina explicitamente `aboutDescription`.
|
||||
@@ -143,7 +143,7 @@ Se o seu aplicativo não definir um `aboutDescription` em `defineApplication()`,
|
||||
|
||||
### Publicação via CI
|
||||
|
||||
Use este workflow do GitHub Actions para publicar automaticamente a cada release (usa [OIDC](https://docs.npmjs.com/trusted-publishers)):
|
||||
Use this GitHub Actions workflow to publish automatically on every release (uses [OIDC](https://docs.npmjs.com/trusted-publishers)):
|
||||
|
||||
```yaml filename=".github/workflows/publish.yml"
|
||||
name: Publish
|
||||
@@ -178,13 +178,13 @@ Para outros sistemas de CI (GitLab CI, CircleCI etc.), aplicam-se os mesmos trê
|
||||
|
||||
## Instalando aplicativos
|
||||
|
||||
Depois que um app é publicado (npm) ou implantado (tarball), os espaços de trabalho podem instalá-lo pela interface do usuário.
|
||||
Once an app is published (npm) or deployed (tarball), workspaces can install it through the UI.
|
||||
|
||||
Vá para a página **Configurações > Aplicações** no Twenty, onde é possível navegar e instalar tanto apps do marketplace quanto apps implantados por tarball.
|
||||
Go to the **Settings > Applications** page in Twenty, where both marketplace and tarball-deployed apps can be browsed and installed.
|
||||
|
||||
{/* TODO: add screenshot of the UI when the app is registered */}
|
||||
|
||||
Você também pode instalar apps pela linha de comando:
|
||||
You can also install apps from the command line:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty install
|
||||
|
||||
@@ -18,13 +18,13 @@ description: Распространяйте своё приложение Twenty
|
||||
|
||||
## Сборка вашего приложения
|
||||
|
||||
Выполните команду сборки, чтобы скомпилировать приложение и сгенерировать готовый к распространению `manifest.json`:
|
||||
Run the build command to compile your app and generate a distribution-ready `manifest.json`:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
Это компилирует исходные файлы TypeScript, транспилирует функции логики и фронтенд-компоненты и записывает всё в `.twenty/output/`. Добавьте `--tarball`, чтобы также создать пакет `.tgz` для ручного распространения или для команды deploy.
|
||||
This compiles TypeScript sources, transpiles logic functions and front components, and writes everything to `.twenty/output/`. Add `--tarball` to also produce a `.tgz` package for manual distribution or the deploy command.
|
||||
|
||||
## Развертывание на сервер (tarball)
|
||||
|
||||
@@ -61,7 +61,7 @@ yarn twenty deploy
|
||||
Ссылка общего доступа использует базовый URL сервера (без какого-либо поддомена рабочего пространства), поэтому она работает для любого рабочего пространства на сервере.
|
||||
|
||||
<Warning>
|
||||
Возможность делиться частными приложениями — функция Enterprise. Перейдите в [Настройки > Панель администратора > Enterprise](/settings/admin-panel#enterprise), чтобы включить её.
|
||||
Sharing private apps is an Enterprise feature. Go to [Settings > Admin Panel > Enterprise](/settings/admin-panel#enterprise) to enable it.
|
||||
</Warning>
|
||||
|
||||
### Управление версиями
|
||||
@@ -69,7 +69,7 @@ yarn twenty deploy
|
||||
Чтобы выпустить обновление:
|
||||
|
||||
1. Обновите значение поля `version` в файле `package.json`
|
||||
2. Выполните `yarn twenty deploy` (или `yarn twenty deploy --remote production`)
|
||||
2. Run `yarn twenty deploy` (or `yarn twenty deploy --remote production`)
|
||||
3. Рабочие пространства, в которых установлено приложение, увидят доступное обновление в своих настройках
|
||||
|
||||
{/* TODO: add screenshot of the Upgrade button */}
|
||||
@@ -81,7 +81,7 @@ yarn twenty deploy
|
||||
### Требования
|
||||
|
||||
* Учётная запись [npm](https://www.npmjs.com)
|
||||
* Ключевое слово `twenty-app` в массиве `keywords` вашего `package.json` (уже добавлено при создании проекта с помощью `create-twenty-app`)
|
||||
* The `twenty-app` keyword in your `package.json` `keywords` array (already included when you scaffold with `create-twenty-app`)
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
@@ -93,7 +93,7 @@ yarn twenty deploy
|
||||
|
||||
### Метаданные маркетплейса
|
||||
|
||||
Конфигурация `defineApplication()` поддерживает необязательные поля, которые определяют, как ваше приложение отображается в маркетплейсе. Используйте `logoUrl` и `screenshots`, чтобы ссылаться на изображения из папки `public/`:
|
||||
The `defineApplication()` config supports optional fields that control how your app appears in the marketplace. Use `logoUrl` and `screenshots` to reference images from the `public/` folder:
|
||||
|
||||
```ts src/application-config.ts
|
||||
export default defineApplication({
|
||||
@@ -109,9 +109,9 @@ export default defineApplication({
|
||||
});
|
||||
```
|
||||
|
||||
См. [аккордеон defineApplication](/l/ru/developers/extend/apps/building#defineentity-functions) на странице «Создание приложений» для полного списка полей маркетплейса (`author`, `category`, `aboutDescription`, `websiteUrl`, `termsUrl` и т. д.).
|
||||
See the [defineApplication accordion](/l/ru/developers/extend/apps/building#defineentity-functions) in the Building Apps page for the full list of marketplace fields (`author`, `category`, `aboutDescription`, `websiteUrl`, `termsUrl`, etc.).
|
||||
|
||||
### Публикация
|
||||
### Publish
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish
|
||||
@@ -127,7 +127,7 @@ yarn twenty publish --tag beta
|
||||
|
||||
Сервер Twenty синхронизирует каталог маркетплейса из реестра npm **каждый час**.
|
||||
|
||||
Вы можете запустить синхронизацию немедленно, вместо ожидания:
|
||||
You can trigger the sync immediately instead of waiting:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync
|
||||
@@ -135,7 +135,7 @@ yarn twenty catalog-sync
|
||||
# yarn twenty catalog-sync --remote production
|
||||
```
|
||||
|
||||
Метаданные, отображаемые в маркетплейсе, берутся из конфигурации `defineApplication()` — из таких полей, как `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl` и `termsUrl`.
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` config — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
|
||||
<Note>
|
||||
Если ваше приложение не определяет `aboutDescription` в `defineApplication()`, маркетплейс автоматически использует `README.md` вашего пакета из npm в качестве содержимого страницы «О приложении». Это означает, что вы можете поддерживать единый README как для npm, так и для маркетплейса Twenty. Если вы хотите другое описание в маркетплейсе, явно задайте `aboutDescription`.
|
||||
@@ -143,7 +143,7 @@ yarn twenty catalog-sync
|
||||
|
||||
### Публикация через CI
|
||||
|
||||
Используйте этот workflow GitHub Actions, чтобы публиковать автоматически при каждом релизе (использует [OIDC](https://docs.npmjs.com/trusted-publishers)):
|
||||
Use this GitHub Actions workflow to publish automatically on every release (uses [OIDC](https://docs.npmjs.com/trusted-publishers)):
|
||||
|
||||
```yaml filename=".github/workflows/publish.yml"
|
||||
name: Publish
|
||||
@@ -178,13 +178,13 @@ jobs:
|
||||
|
||||
## Установка приложений
|
||||
|
||||
После публикации приложения (npm) или его развертывания (tarball) рабочие пространства могут установить его через интерфейс.
|
||||
Once an app is published (npm) or deployed (tarball), workspaces can install it through the UI.
|
||||
|
||||
Перейдите на страницу **Настройки > Приложения** в Twenty, где можно просматривать и устанавливать как приложения из маркетплейса, так и развернутые через tarball.
|
||||
Go to the **Settings > Applications** page in Twenty, where both marketplace and tarball-deployed apps can be browsed and installed.
|
||||
|
||||
{/* TODO: add screenshot of the UI when the app is registered */}
|
||||
|
||||
Вы также можете устанавливать приложения из командной строки:
|
||||
You can also install apps from the command line:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty install
|
||||
|
||||
@@ -18,13 +18,13 @@ Her iki yol da aynı **build** adımından başlar.
|
||||
|
||||
## Uygulamanızı derleme
|
||||
|
||||
Uygulamanızı derlemek ve dağıtıma hazır bir `manifest.json` oluşturmak için build komutunu çalıştırın:
|
||||
Run the build command to compile your app and generate a distribution-ready `manifest.json`:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty build
|
||||
```
|
||||
|
||||
Bu işlem TypeScript kaynaklarını derler, mantık işlevlerini ve ön uç bileşenlerini transpile eder ve her şeyi `.twenty/output/` konumuna yazar. El ile dağıtım veya deploy komutu için bir `.tgz` paketini de üretmek amacıyla `--tarball` ekleyin.
|
||||
This compiles TypeScript sources, transpiles logic functions and front components, and writes everything to `.twenty/output/`. Add `--tarball` to also produce a `.tgz` package for manual distribution or the deploy command.
|
||||
|
||||
## Sunucuya dağıtım (tarball)
|
||||
|
||||
@@ -61,7 +61,7 @@ Tarball uygulamaları genel pazar yerinde listelenmez; bu nedenle aynı sunucuda
|
||||
Paylaşım bağlantısı, sunucunun temel URL’sini (herhangi bir çalışma alanı alt alan adı olmadan) kullanır; böylece sunucudaki herhangi bir çalışma alanı için çalışır.
|
||||
|
||||
<Warning>
|
||||
Özel uygulamaları paylaşma bir Kurumsal özelliktir. [Ayarlar > Yönetim Paneli > Kurumsal](/settings/admin-panel#enterprise) bölümüne giderek etkinleştirin.
|
||||
Sharing private apps is an Enterprise feature. Go to [Settings > Admin Panel > Enterprise](/settings/admin-panel#enterprise) to enable it.
|
||||
</Warning>
|
||||
|
||||
### Sürüm yönetimi
|
||||
@@ -69,7 +69,7 @@ Paylaşım bağlantısı, sunucunun temel URL’sini (herhangi bir çalışma al
|
||||
Bir güncelleme yayımlamak için:
|
||||
|
||||
1. `package.json` içindeki `version` alanını artırın
|
||||
2. `yarn twenty deploy` (veya `yarn twenty deploy --remote production`) komutunu çalıştırın
|
||||
2. Run `yarn twenty deploy` (or `yarn twenty deploy --remote production`)
|
||||
3. Uygulamayı kurmuş olan çalışma alanları, ayarlarında mevcut güncellemeyi görecektir
|
||||
|
||||
{/* TODO: add screenshot of the Upgrade button */}
|
||||
@@ -81,7 +81,7 @@ npm’ye yayımlamak, uygulamanızın Twenty pazaryerinde keşfedilebilir olmas
|
||||
### Gereksinimler
|
||||
|
||||
* Bir [npm](https://www.npmjs.com) hesabı
|
||||
* `package.json` içindeki `keywords` dizinizdeki `twenty-app` anahtar sözcüğü (`create-twenty-app` ile iskelet oluşturduğunuzda zaten eklenir)
|
||||
* The `twenty-app` keyword in your `package.json` `keywords` array (already included when you scaffold with `create-twenty-app`)
|
||||
|
||||
```json filename="package.json"
|
||||
{
|
||||
@@ -93,7 +93,7 @@ npm’ye yayımlamak, uygulamanızın Twenty pazaryerinde keşfedilebilir olmas
|
||||
|
||||
### Pazaryeri meta verileri
|
||||
|
||||
`defineApplication()` yapılandırması, uygulamanızın pazar yerinde nasıl görüneceğini kontrol eden isteğe bağlı alanları destekler. `public/` klasöründeki görsellere başvurmak için `logoUrl` ve `screenshots` kullanın:
|
||||
The `defineApplication()` config supports optional fields that control how your app appears in the marketplace. Use `logoUrl` and `screenshots` to reference images from the `public/` folder:
|
||||
|
||||
```ts src/application-config.ts
|
||||
export default defineApplication({
|
||||
@@ -109,9 +109,9 @@ export default defineApplication({
|
||||
});
|
||||
```
|
||||
|
||||
Pazar yeri alanlarının tam listesi için Uygulama Oluşturma sayfasındaki [defineApplication akordeonu](/l/tr/developers/extend/apps/building#defineentity-functions)'na bakın (`author`, `category`, `aboutDescription`, `websiteUrl`, `termsUrl`, vb.).
|
||||
See the [defineApplication accordion](/l/tr/developers/extend/apps/building#defineentity-functions) in the Building Apps page for the full list of marketplace fields (`author`, `category`, `aboutDescription`, `websiteUrl`, `termsUrl`, etc.).
|
||||
|
||||
### Yayımla
|
||||
### Publish
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty publish
|
||||
@@ -125,9 +125,9 @@ yarn twenty publish --tag beta
|
||||
|
||||
### Pazar yerinde keşif nasıl çalışır
|
||||
|
||||
Twenty sunucusu pazar yeri kataloğunu npm kayıt defterinden **her saat** eşitler.
|
||||
The Twenty server syncs its marketplace catalog from the npm registry **every hour**.
|
||||
|
||||
Beklemek yerine eşitlemeyi hemen tetikleyebilirsiniz:
|
||||
You can trigger the sync immediately instead of waiting:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty catalog-sync
|
||||
@@ -135,7 +135,7 @@ yarn twenty catalog-sync
|
||||
# yarn twenty catalog-sync --remote production
|
||||
```
|
||||
|
||||
Pazar yerinde gösterilen meta veriler, `defineApplication()` yapılandırmanızdan gelir — `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl` ve `termsUrl` gibi alanlar.
|
||||
The metadata shown in the marketplace comes from your `defineApplication()` config — fields like `displayName`, `description`, `author`, `category`, `logoUrl`, `screenshots`, `aboutDescription`, `websiteUrl`, and `termsUrl`.
|
||||
|
||||
<Note>
|
||||
Uygulamanız `defineApplication()` içinde bir `aboutDescription` tanımlamıyorsa, pazaryeri, hakkında sayfasının içeriği olarak paketinizin npm'deki `README.md` dosyasını otomatik olarak kullanır. Bu, hem npm hem de Twenty pazaryeri için tek bir README dosyası kullanabileceğiniz anlamına gelir. Pazaryerinde farklı bir açıklama istiyorsanız, `aboutDescription` değerini açıkça ayarlayın.
|
||||
@@ -143,7 +143,7 @@ Uygulamanız `defineApplication()` içinde bir `aboutDescription` tanımlamıyor
|
||||
|
||||
### CI üzerinden yayımlama
|
||||
|
||||
Her sürümde otomatik olarak yayımlamak için bu GitHub Actions iş akışını kullanın ([OIDC](https://docs.npmjs.com/trusted-publishers) kullanır):
|
||||
Use this GitHub Actions workflow to publish automatically on every release (uses [OIDC](https://docs.npmjs.com/trusted-publishers)):
|
||||
|
||||
```yaml filename=".github/workflows/publish.yml"
|
||||
name: Publish
|
||||
@@ -178,13 +178,13 @@ Diğer CI sistemleri (GitLab CI, CircleCI, vb.) için de aynı üç komut geçer
|
||||
|
||||
## Uygulamaları yükleme
|
||||
|
||||
Bir uygulama yayımlandığında (npm) veya dağıtıldığında (tarball), çalışma alanları onu kullanıcı arayüzü (UI) üzerinden yükleyebilir.
|
||||
Once an app is published (npm) or deployed (tarball), workspaces can install it through the UI.
|
||||
|
||||
Twenty içinde **Ayarlar > Uygulamalar** sayfasına gidin; burada hem pazar yerindeki hem de tarball ile dağıtılmış uygulamalar görüntülenip yüklenebilir.
|
||||
Go to the **Settings > Applications** page in Twenty, where both marketplace and tarball-deployed apps can be browsed and installed.
|
||||
|
||||
{/* TODO: add screenshot of the UI when the app is registered */}
|
||||
|
||||
Uygulamaları komut satırından da yükleyebilirsiniz:
|
||||
You can also install apps from the command line:
|
||||
|
||||
```bash filename="Terminal"
|
||||
yarn twenty install
|
||||
|
||||
@@ -146,15 +146,14 @@ export class ApolloFactory implements ApolloManager {
|
||||
attempts: {
|
||||
max: 2,
|
||||
retryIf: (error) => {
|
||||
// oxlint-disable-next-line no-console
|
||||
console.log('retryIf error from retryLink', error);
|
||||
if (this.isAuthenticationError(error)) {
|
||||
return false;
|
||||
}
|
||||
if (this.isPayloadTooLargeError(error)) {
|
||||
return false;
|
||||
}
|
||||
if (this.isGatewayError(error)) {
|
||||
return false;
|
||||
}
|
||||
return Boolean(error);
|
||||
},
|
||||
},
|
||||
@@ -389,15 +388,6 @@ export class ApolloFactory implements ApolloManager {
|
||||
return ServerError.is(error) && error.statusCode === 413;
|
||||
}
|
||||
|
||||
private isGatewayError(error: ErrorLike): boolean {
|
||||
return (
|
||||
ServerError.is(error) &&
|
||||
(error.statusCode === 502 ||
|
||||
error.statusCode === 503 ||
|
||||
error.statusCode === 504)
|
||||
);
|
||||
}
|
||||
|
||||
updateWorkspaceMember(workspaceMember: CurrentWorkspaceMember | null) {
|
||||
this.currentWorkspaceMember = workspaceMember;
|
||||
}
|
||||
|
||||
@@ -47,12 +47,6 @@ export const SentryInitEffect = () => {
|
||||
onunhandledrejection: false, // handled in PromiseRejectionEffect
|
||||
}),
|
||||
],
|
||||
ignoreErrors: [
|
||||
// Transient browser network errors from reverse proxy 502/503/504
|
||||
'NetworkError when attempting to fetch resource',
|
||||
'Failed to fetch',
|
||||
'Load failed',
|
||||
],
|
||||
tracePropagationTargets: [
|
||||
'localhost:3001',
|
||||
REACT_APP_SERVER_BASE_URL,
|
||||
|
||||
+1
@@ -6,6 +6,7 @@ export const FIND_MANY_FRONT_COMPONENTS = gql`
|
||||
id
|
||||
name
|
||||
applicationId
|
||||
isHeadless
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
||||
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
||||
import { addWidgetToTab } from '@/page-layout/utils/addWidgetToTab';
|
||||
import { createDefaultFrontComponentWidgetForVerticalList } from '@/page-layout/utils/createDefaultFrontComponentWidgetForVerticalList';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export const useCreateRecordPageFrontComponentWidget = ({
|
||||
pageLayoutId,
|
||||
tabListInstanceId,
|
||||
}: {
|
||||
pageLayoutId: string;
|
||||
tabListInstanceId: string;
|
||||
}) => {
|
||||
const activeTabId = useAtomComponentStateValue(
|
||||
activeTabIdComponentState,
|
||||
tabListInstanceId,
|
||||
);
|
||||
|
||||
const pageLayoutDraft = useAtomComponentStateValue(
|
||||
pageLayoutDraftComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const pageLayoutDraftState = useAtomComponentStateCallbackState(
|
||||
pageLayoutDraftComponentState,
|
||||
pageLayoutId,
|
||||
);
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const createRecordPageFrontComponentWidget = useCallback(
|
||||
(title: string, frontComponentId: string): PageLayoutWidget | undefined => {
|
||||
if (!isDefined(activeTabId)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const activeTab = pageLayoutDraft.tabs.find(
|
||||
(tab) => tab.id === activeTabId,
|
||||
);
|
||||
const existingWidgets = activeTab?.widgets ?? [];
|
||||
|
||||
const positionIndex = existingWidgets.length;
|
||||
const widgetId = uuidv4();
|
||||
|
||||
const newWidget = createDefaultFrontComponentWidgetForVerticalList({
|
||||
id: widgetId,
|
||||
pageLayoutTabId: activeTabId,
|
||||
title,
|
||||
frontComponentId,
|
||||
positionIndex,
|
||||
});
|
||||
|
||||
store.set(pageLayoutDraftState, (prev) => ({
|
||||
...prev,
|
||||
tabs: addWidgetToTab(prev.tabs, activeTabId, newWidget),
|
||||
}));
|
||||
|
||||
return newWidget;
|
||||
},
|
||||
[activeTabId, pageLayoutDraft.tabs, pageLayoutDraftState, store],
|
||||
);
|
||||
|
||||
return { createRecordPageFrontComponentWidget };
|
||||
};
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
||||
import {
|
||||
PageLayoutTabLayoutMode,
|
||||
WidgetConfigurationType,
|
||||
WidgetType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const createDefaultFrontComponentWidgetForVerticalList = ({
|
||||
id,
|
||||
pageLayoutTabId,
|
||||
title,
|
||||
frontComponentId,
|
||||
positionIndex,
|
||||
}: {
|
||||
id: string;
|
||||
pageLayoutTabId: string;
|
||||
title: string;
|
||||
frontComponentId: string;
|
||||
positionIndex: number;
|
||||
}): PageLayoutWidget => {
|
||||
return {
|
||||
__typename: 'PageLayoutWidget',
|
||||
id,
|
||||
pageLayoutTabId,
|
||||
title,
|
||||
type: WidgetType.FRONT_COMPONENT,
|
||||
configuration: {
|
||||
__typename: 'FrontComponentConfiguration',
|
||||
configurationType: WidgetConfigurationType.FRONT_COMPONENT,
|
||||
frontComponentId,
|
||||
},
|
||||
gridPosition: {
|
||||
__typename: 'GridPosition',
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 1,
|
||||
columnSpan: 12,
|
||||
},
|
||||
position: {
|
||||
__typename: 'PageLayoutWidgetVerticalListPosition',
|
||||
layoutMode: PageLayoutTabLayoutMode.VERTICAL_LIST,
|
||||
index: positionIndex,
|
||||
},
|
||||
objectMetadataId: null,
|
||||
isOverridden: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
};
|
||||
};
|
||||
+14
-3
@@ -3,13 +3,18 @@ import { Suspense, lazy } from 'react';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { usePageLayoutContentContext } from '@/page-layout/contexts/PageLayoutContentContext';
|
||||
import { useIsPageLayoutInEditMode } from '@/page-layout/hooks/useIsPageLayoutInEditMode';
|
||||
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
||||
import { PageLayoutWidgetNoDataDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay';
|
||||
import { isWidgetConfigurationOfType } from '@/side-panel/pages/page-layout/utils/isWidgetConfigurationOfType';
|
||||
import { PageLayoutTabLayoutMode } from '~/generated-metadata/graphql';
|
||||
|
||||
const StyledContainer = styled.div<{ isInEditMode: boolean }>`
|
||||
height: 100%;
|
||||
const StyledContainer = styled.div<{
|
||||
isInEditMode: boolean;
|
||||
isVerticalList: boolean;
|
||||
}>`
|
||||
height: ${({ isVerticalList }) => (isVerticalList ? '300px' : '100%')};
|
||||
overflow: auto;
|
||||
pointer-events: ${({ isInEditMode }) => (isInEditMode ? 'none' : 'auto')};
|
||||
width: 100%;
|
||||
@@ -29,6 +34,9 @@ export const FrontComponentWidgetRenderer = ({
|
||||
widget,
|
||||
}: FrontComponentWidgetRendererProps) => {
|
||||
const isPageLayoutInEditMode = useIsPageLayoutInEditMode();
|
||||
const { layoutMode } = usePageLayoutContentContext();
|
||||
|
||||
const isVerticalList = layoutMode === PageLayoutTabLayoutMode.VERTICAL_LIST;
|
||||
|
||||
const configuration = widget.configuration;
|
||||
|
||||
@@ -42,7 +50,10 @@ export const FrontComponentWidgetRenderer = ({
|
||||
const frontComponentId = configuration.frontComponentId;
|
||||
|
||||
return (
|
||||
<StyledContainer isInEditMode={isPageLayoutInEditMode}>
|
||||
<StyledContainer
|
||||
isInEditMode={isPageLayoutInEditMode}
|
||||
isVerticalList={isVerticalList}
|
||||
>
|
||||
<Suspense fallback={null}>
|
||||
<FrontComponentRenderer frontComponentId={frontComponentId} />
|
||||
</Suspense>
|
||||
|
||||
+41
-5
@@ -5,10 +5,12 @@ import { useCreatePageLayoutGraphWidget } from '@/page-layout/hooks/useCreatePag
|
||||
import { useCreatePageLayoutIframeWidget } from '@/page-layout/hooks/useCreatePageLayoutIframeWidget';
|
||||
import { useCreatePageLayoutRecordTableWidget } from '@/page-layout/hooks/useCreatePageLayoutRecordTableWidget';
|
||||
import { useCreatePageLayoutStandaloneRichTextWidget } from '@/page-layout/hooks/useCreatePageLayoutStandaloneRichTextWidget';
|
||||
import { useCreateRecordPageFrontComponentWidget } from '@/page-layout/hooks/useCreateRecordPageFrontComponentWidget';
|
||||
import { useOpportunityDefaultChartConfig } from '@/page-layout/hooks/useOpportunityDefaultChartConfig';
|
||||
import { useRemovePageLayoutWidgetAndPreservePosition } from '@/page-layout/hooks/useRemovePageLayoutWidgetAndPreservePosition';
|
||||
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
||||
import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState';
|
||||
import { getTabLayoutMode } from '@/page-layout/utils/getTabLayoutMode';
|
||||
import { getTabListInstanceIdFromPageLayoutAndRecord } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutAndRecord';
|
||||
import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup';
|
||||
import { SidePanelList } from '@/side-panel/components/SidePanelList';
|
||||
@@ -18,6 +20,7 @@ import { usePageLayoutIdFromContextStore } from '@/side-panel/pages/page-layout/
|
||||
import { getFrontComponentWidgetTypeSelectItemId } from '@/side-panel/pages/page-layout/utils/getFrontComponentWidgetTypeSelectItemId';
|
||||
import { isExistingWidgetMissingOrDifferentType } from '@/side-panel/pages/page-layout/utils/isExistingWidgetMissingOrDifferentType';
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
@@ -35,6 +38,7 @@ import {
|
||||
import {
|
||||
FeatureFlagKey,
|
||||
type FrontComponent,
|
||||
PageLayoutTabLayoutMode,
|
||||
WidgetType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
@@ -80,6 +84,27 @@ export const SidePanelPageLayoutWidgetTypeSelect = () => {
|
||||
tabListInstanceId,
|
||||
});
|
||||
|
||||
const { createRecordPageFrontComponentWidget } =
|
||||
useCreateRecordPageFrontComponentWidget({
|
||||
pageLayoutId,
|
||||
tabListInstanceId,
|
||||
});
|
||||
|
||||
const activeTabId = useAtomComponentStateValue(
|
||||
activeTabIdComponentState,
|
||||
tabListInstanceId,
|
||||
);
|
||||
|
||||
const activeTab = pageLayoutDraft.tabs.find((tab) => tab.id === activeTabId);
|
||||
|
||||
const activeTabLayoutMode = getTabLayoutMode({
|
||||
tab: activeTab,
|
||||
pageLayoutType: pageLayoutDraft.type,
|
||||
});
|
||||
|
||||
const isVerticalList =
|
||||
activeTabLayoutMode === PageLayoutTabLayoutMode.VERTICAL_LIST;
|
||||
|
||||
const { createPageLayoutRecordTableWidget } =
|
||||
useCreatePageLayoutRecordTableWidget(pageLayoutId);
|
||||
|
||||
@@ -94,7 +119,9 @@ export const SidePanelPageLayoutWidgetTypeSelect = () => {
|
||||
frontComponents: FrontComponent[];
|
||||
}>(FIND_MANY_FRONT_COMPONENTS);
|
||||
|
||||
const frontComponents = frontComponentsData?.frontComponents ?? [];
|
||||
const frontComponents = (frontComponentsData?.frontComponents ?? []).filter(
|
||||
(frontComponent) => !frontComponent.isHeadless,
|
||||
);
|
||||
|
||||
const frontComponentsWithSelectItemId = frontComponents.map(
|
||||
(frontComponent) => ({
|
||||
@@ -212,10 +239,19 @@ export const SidePanelPageLayoutWidgetTypeSelect = () => {
|
||||
removePageLayoutWidgetAndPreservePosition(pageLayoutEditingWidgetId);
|
||||
}
|
||||
|
||||
const newWidget = createPageLayoutFrontComponentWidget(
|
||||
frontComponent.name,
|
||||
frontComponent.id,
|
||||
);
|
||||
const newWidget = isVerticalList
|
||||
? createRecordPageFrontComponentWidget(
|
||||
frontComponent.name,
|
||||
frontComponent.id,
|
||||
)
|
||||
: createPageLayoutFrontComponentWidget(
|
||||
frontComponent.name,
|
||||
frontComponent.id,
|
||||
);
|
||||
|
||||
if (!isDefined(newWidget)) {
|
||||
return;
|
||||
}
|
||||
setPageLayoutEditingWidgetId(newWidget.id);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user