Compare commits

..
10 changed files with 221 additions and 69 deletions
@@ -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 URLsini (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 URLsini (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 @@ npmye 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 @@ npmye 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,
@@ -6,6 +6,7 @@ export const FIND_MANY_FRONT_COMPONENTS = gql`
id
name
applicationId
isHeadless
}
}
`;
@@ -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 };
};
@@ -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,
};
};
@@ -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>
@@ -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);
}