diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts
index 87120e6c94..3f98c114fa 100644
--- a/packages/twenty-front/src/generated-metadata/graphql.ts
+++ b/packages/twenty-front/src/generated-metadata/graphql.ts
@@ -4477,9 +4477,15 @@ export type Webhook = {
export type WidgetConfiguration = BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | NumberChartConfiguration | PieChartConfiguration;
export enum WidgetType {
+ CALENDAR = 'CALENDAR',
+ EMAILS = 'EMAILS',
FIELDS = 'FIELDS',
+ FILES = 'FILES',
GRAPH = 'GRAPH',
IFRAME = 'IFRAME',
+ NOTES = 'NOTES',
+ TASKS = 'TASKS',
+ TIMELINE = 'TIMELINE',
VIEW = 'VIEW'
}
diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts
index 17c3725c13..db53d8b620 100644
--- a/packages/twenty-front/src/generated/graphql.ts
+++ b/packages/twenty-front/src/generated/graphql.ts
@@ -4305,9 +4305,15 @@ export type Webhook = {
export type WidgetConfiguration = BarChartConfiguration | GaugeChartConfiguration | IframeConfiguration | LineChartConfiguration | NumberChartConfiguration | PieChartConfiguration;
export enum WidgetType {
+ CALENDAR = 'CALENDAR',
+ EMAILS = 'EMAILS',
FIELDS = 'FIELDS',
+ FILES = 'FILES',
GRAPH = 'GRAPH',
IFRAME = 'IFRAME',
+ NOTES = 'NOTES',
+ TASKS = 'TASKS',
+ TIMELINE = 'TIMELINE',
VIEW = 'VIEW'
}
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx
index 2515e2090c..5977090c39 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx
@@ -13,7 +13,6 @@ import { pageLayoutCurrentBreakpointComponentState } from '@/page-layout/states/
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
import { WidgetPlaceholder } from '@/page-layout/widgets/components/WidgetPlaceholder';
import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer';
-import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
@@ -63,7 +62,11 @@ const StyledVerticalListContainer = styled.div`
gap: ${({ theme }) => theme.spacing(2)};
`;
-export const PageLayoutGridLayout = () => {
+type PageLayoutGridLayoutProps = {
+ tabId: string;
+};
+
+export const PageLayoutGridLayout = ({ tabId }: PageLayoutGridLayoutProps) => {
const isRecordPageEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED,
);
@@ -84,19 +87,11 @@ export const PageLayoutGridLayout = () => {
pageLayoutCurrentLayoutsComponentState,
);
- const activeTabId = useRecoilComponentValue(activeTabIdComponentState);
-
const { currentPageLayout } = useCurrentPageLayout();
- const activeTab = currentPageLayout?.tabs.find(
- (tab) => tab.id === activeTabId,
- );
+ const activeTab = currentPageLayout?.tabs.find((tab) => tab.id === tabId);
- if (
- !isDefined(activeTabId) ||
- !isDefined(currentPageLayout) ||
- !isDefined(activeTab)
- ) {
+ if (!isDefined(currentPageLayout) || !isDefined(activeTab)) {
return null;
}
@@ -107,7 +102,7 @@ export const PageLayoutGridLayout = () => {
const layouts = isLayoutEmpty
? EMPTY_LAYOUT
- : (pageLayoutCurrentLayouts[activeTabId] ?? EMPTY_LAYOUT);
+ : (pageLayoutCurrentLayouts[tabId] ?? EMPTY_LAYOUT);
const Widgets = isLayoutEmpty ? (
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx
index 72273e7fda..d081d833ad 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx
@@ -1,15 +1,21 @@
+import { SummaryCard } from '@/object-record/record-show/components/SummaryCard';
import { PageLayoutGridLayout } from '@/page-layout/components/PageLayoutGridLayout';
import { useCreatePageLayoutTab } from '@/page-layout/hooks/useCreatePageLayoutTab';
import { useCurrentPageLayout } from '@/page-layout/hooks/useCurrentPageLayout';
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId';
+import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
+import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
+import { ShowPageContainer } from '@/ui/layout/page/components/ShowPageContainer';
+import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
+import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import styled from '@emotion/styled';
import { isDefined } from 'twenty-shared/utils';
-const StyledContainer = styled.div`
+const StyledTabsAndDashboardContainer = styled.div`
display: flex;
flex-direction: column;
height: 100%;
@@ -18,6 +24,16 @@ const StyledContainer = styled.div`
background: ${({ theme }) => theme.background.primary};
`;
+const StyledShowPageRightContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ justify-content: start;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+`;
+
const StyledTabList = styled(TabList)`
padding-left: ${({ theme }) => theme.spacing(2)};
`;
@@ -29,10 +45,15 @@ const StyledScrollWrapper = styled(ScrollWrapper)`
export const PageLayoutRendererContent = () => {
const { currentPageLayout } = useCurrentPageLayout();
+ const targetRecordIdentifier = useTargetRecord();
+ const { isInRightDrawer } = useLayoutRenderingContext();
+
const isPageLayoutInEditMode = useRecoilComponentValue(
isPageLayoutInEditModeComponentState,
);
+ const activeTabId = useRecoilComponentValue(activeTabIdComponentState);
+
const { createPageLayoutTab } = useCreatePageLayoutTab(currentPageLayout?.id);
const handleAddTab = isPageLayoutInEditMode ? createPageLayoutTab : undefined;
@@ -41,22 +62,47 @@ export const PageLayoutRendererContent = () => {
return null;
}
+ const tabsToRenderInTabList = currentPageLayout.tabs.filter(
+ (tab) => tab.selfDisplayMode !== 'pinned-left',
+ );
+ const pinnedLeftTab = currentPageLayout.tabs.find(
+ (tab) => tab.selfDisplayMode === 'pinned-left',
+ );
+
return (
-
-
-
-
-
-
+
+ {isDefined(pinnedLeftTab) && (
+
+
+
+
+
+ )}
+
+
+
+
+
+ {isDefined(activeTabId) && (
+
+ )}
+
+
+
+
);
};
diff --git a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutRenderer.stories.tsx b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutRenderer.stories.tsx
index 6e6ecd03c3..0b610998bf 100644
--- a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutRenderer.stories.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutRenderer.stories.tsx
@@ -10,8 +10,10 @@ import { MemoryRouter } from 'react-router-dom';
import { FIND_ONE_PAGE_LAYOUT } from '@/dashboards/graphql/queries/findOnePageLayout';
import { ApolloCoreClientContext } from '@/object-metadata/contexts/ApolloCoreClientContext';
+import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { PageLayoutRenderer } from '@/page-layout/components/PageLayoutRenderer';
import { generateGroupByQuery } from '@/page-layout/widgets/graph/utils/generateGroupByQuery';
+import { LayoutRenderingProvider } from '@/ui/layout/contexts/LayoutRenderingContext';
import {
GraphOrderBy,
GraphType,
@@ -270,7 +272,18 @@ const meta: Meta
= {
-
+
+
+
diff --git a/packages/twenty-front/src/modules/page-layout/constants/DefaultPageLayout.ts b/packages/twenty-front/src/modules/page-layout/constants/DefaultPageLayout.ts
index 9ae322cb43..865a3d4884 100644
--- a/packages/twenty-front/src/modules/page-layout/constants/DefaultPageLayout.ts
+++ b/packages/twenty-front/src/modules/page-layout/constants/DefaultPageLayout.ts
@@ -24,6 +24,7 @@ export const DEFAULT_PAGE_LAYOUT: PageLayout = {
title: 'Fields',
position: 100,
layoutMode: 'vertical-list',
+ selfDisplayMode: 'pinned-left',
pageLayoutId: DEFAULT_PAGE_LAYOUT_ID,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
@@ -67,7 +68,7 @@ export const DEFAULT_PAGE_LAYOUT: PageLayout = {
id: 'default-widget-timeline',
pageLayoutTabId: 'default-tab-timeline',
title: 'Timeline',
- type: WidgetType.VIEW,
+ type: WidgetType.TIMELINE,
objectMetadataId: null,
gridPosition: {
__typename: 'GridPosition',
@@ -100,7 +101,7 @@ export const DEFAULT_PAGE_LAYOUT: PageLayout = {
id: 'default-widget-tasks',
pageLayoutTabId: 'default-tab-tasks',
title: 'Tasks',
- type: WidgetType.VIEW,
+ type: WidgetType.TASKS,
objectMetadataId: null,
gridPosition: {
__typename: 'GridPosition',
@@ -133,7 +134,7 @@ export const DEFAULT_PAGE_LAYOUT: PageLayout = {
id: 'default-widget-notes',
pageLayoutTabId: 'default-tab-notes',
title: 'Notes',
- type: WidgetType.VIEW,
+ type: WidgetType.NOTES,
objectMetadataId: null,
gridPosition: {
__typename: 'GridPosition',
@@ -166,7 +167,7 @@ export const DEFAULT_PAGE_LAYOUT: PageLayout = {
id: 'default-widget-files',
pageLayoutTabId: 'default-tab-files',
title: 'Files',
- type: WidgetType.VIEW,
+ type: WidgetType.FILES,
objectMetadataId: null,
gridPosition: {
__typename: 'GridPosition',
@@ -199,7 +200,7 @@ export const DEFAULT_PAGE_LAYOUT: PageLayout = {
id: 'default-widget-emails',
pageLayoutTabId: 'default-tab-emails',
title: 'Emails',
- type: WidgetType.VIEW,
+ type: WidgetType.EMAILS,
objectMetadataId: null,
gridPosition: {
__typename: 'GridPosition',
@@ -232,7 +233,7 @@ export const DEFAULT_PAGE_LAYOUT: PageLayout = {
id: 'default-widget-calendar',
pageLayoutTabId: 'default-tab-calendar',
title: 'Calendar',
- type: WidgetType.VIEW,
+ type: WidgetType.CALENDAR,
objectMetadataId: null,
gridPosition: {
__typename: 'GridPosition',
diff --git a/packages/twenty-front/src/modules/page-layout/types/PageLayoutTab.ts b/packages/twenty-front/src/modules/page-layout/types/PageLayoutTab.ts
index 31cb1d4ab5..437ea661bd 100644
--- a/packages/twenty-front/src/modules/page-layout/types/PageLayoutTab.ts
+++ b/packages/twenty-front/src/modules/page-layout/types/PageLayoutTab.ts
@@ -13,4 +13,5 @@ export type PageLayoutTab = Omit & {
* Only available behind IS_RECORD_PAGE_LAYOUT_ENABLED for now.
*/
layoutMode?: 'grid' | 'vertical-list';
+ selfDisplayMode?: 'pinned-left';
};
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/calendar/components/CalendarWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/calendar/components/CalendarWidget.tsx
new file mode 100644
index 0000000000..14ac302aa9
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/widgets/calendar/components/CalendarWidget.tsx
@@ -0,0 +1,27 @@
+import { CalendarEventsCard } from '@/activities/calendar/components/CalendarEventsCard';
+import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
+import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
+import styled from '@emotion/styled';
+import { type PageLayoutWidget } from '~/generated/graphql';
+
+const StyledContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+`;
+
+type CalendarWidgetProps = {
+ widget: PageLayoutWidget;
+};
+
+export const CalendarWidget = ({ widget: _widget }: CalendarWidgetProps) => {
+ const { isInRightDrawer } = useLayoutRenderingContext();
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetContentRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetContentRenderer.tsx
index e543059114..16038dd6df 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetContentRenderer.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetContentRenderer.tsx
@@ -1,6 +1,12 @@
+import { CalendarWidget } from '@/page-layout/widgets/calendar/components/CalendarWidget';
+import { EmailWidget } from '@/page-layout/widgets/emails/components/EmailWidget';
import { FieldsWidget } from '@/page-layout/widgets/fields/components/FieldsWidget';
+import { FileWidget } from '@/page-layout/widgets/files/components/FileWidget';
import { GraphWidgetRenderer } from '@/page-layout/widgets/graph/components/GraphWidgetRenderer';
import { IframeWidget } from '@/page-layout/widgets/iframe/components/IframeWidget';
+import { NoteWidget } from '@/page-layout/widgets/notes/components/NoteWidget';
+import { TaskWidget } from '@/page-layout/widgets/tasks/components/TaskWidget';
+import { TimelineWidget } from '@/page-layout/widgets/timeline/components/TimelineWidget';
import { type PageLayoutWidget, WidgetType } from '~/generated/graphql';
type WidgetContentRendererProps = {
@@ -20,6 +26,24 @@ export const WidgetContentRenderer = ({
case WidgetType.FIELDS:
return ;
+ case WidgetType.TIMELINE:
+ return ;
+
+ case WidgetType.TASKS:
+ return ;
+
+ case WidgetType.NOTES:
+ return ;
+
+ case WidgetType.FILES:
+ return ;
+
+ case WidgetType.EMAILS:
+ return ;
+
+ case WidgetType.CALENDAR:
+ return ;
+
default:
return null;
}
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/emails/components/EmailWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/emails/components/EmailWidget.tsx
new file mode 100644
index 0000000000..936131d868
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/widgets/emails/components/EmailWidget.tsx
@@ -0,0 +1,27 @@
+import { EmailsCard } from '@/activities/emails/components/EmailsCard';
+import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
+import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
+import styled from '@emotion/styled';
+import { type PageLayoutWidget } from '~/generated/graphql';
+
+const StyledContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+`;
+
+type EmailWidgetProps = {
+ widget: PageLayoutWidget;
+};
+
+export const EmailWidget = ({ widget: _widget }: EmailWidgetProps) => {
+ const { isInRightDrawer } = useLayoutRenderingContext();
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx
index 75d1cb74dc..3a0c0d1df2 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx
@@ -8,6 +8,7 @@ import { type PageLayoutWidget } from '~/generated/graphql';
const StyledContainer = styled.div`
display: flex;
flex-direction: column;
+ width: 100%;
`;
type FieldsWidgetProps = {
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/files/components/FileWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/files/components/FileWidget.tsx
new file mode 100644
index 0000000000..0940fca7e7
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/widgets/files/components/FileWidget.tsx
@@ -0,0 +1,27 @@
+import { FilesCard } from '@/activities/files/components/FilesCard';
+import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
+import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
+import styled from '@emotion/styled';
+import { type PageLayoutWidget } from '~/generated/graphql';
+
+const StyledContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+`;
+
+type FileWidgetProps = {
+ widget: PageLayoutWidget;
+};
+
+export const FileWidget = ({ widget: _widget }: FileWidgetProps) => {
+ const { isInRightDrawer } = useLayoutRenderingContext();
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/notes/components/NoteWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/notes/components/NoteWidget.tsx
new file mode 100644
index 0000000000..8f821f1154
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/widgets/notes/components/NoteWidget.tsx
@@ -0,0 +1,27 @@
+import { NotesCard } from '@/activities/notes/components/NotesCard';
+import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
+import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
+import styled from '@emotion/styled';
+import { type PageLayoutWidget } from '~/generated/graphql';
+
+const StyledContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+`;
+
+type NoteWidgetProps = {
+ widget: PageLayoutWidget;
+};
+
+export const NoteWidget = ({ widget: _widget }: NoteWidgetProps) => {
+ const { isInRightDrawer } = useLayoutRenderingContext();
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/tasks/components/TaskWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/tasks/components/TaskWidget.tsx
new file mode 100644
index 0000000000..8bc00a81ad
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/widgets/tasks/components/TaskWidget.tsx
@@ -0,0 +1,27 @@
+import { TasksCard } from '@/activities/tasks/components/TasksCard';
+import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
+import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
+import styled from '@emotion/styled';
+import { type PageLayoutWidget } from '~/generated/graphql';
+
+const StyledContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+`;
+
+type TaskWidgetProps = {
+ widget: PageLayoutWidget;
+};
+
+export const TaskWidget = ({ widget: _widget }: TaskWidgetProps) => {
+ const { isInRightDrawer } = useLayoutRenderingContext();
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/timeline/components/TimelineWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/timeline/components/TimelineWidget.tsx
new file mode 100644
index 0000000000..353c0fe757
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/widgets/timeline/components/TimelineWidget.tsx
@@ -0,0 +1,27 @@
+import { TimelineCard } from '@/activities/timeline-activities/components/TimelineCard';
+import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
+import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
+import styled from '@emotion/styled';
+import { type PageLayoutWidget } from '~/generated/graphql';
+
+const StyledContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+`;
+
+type TimelineWidgetProps = {
+ widget: PageLayoutWidget;
+};
+
+export const TimelineWidget = ({ widget: _widget }: TimelineWidgetProps) => {
+ const { isInRightDrawer } = useLayoutRenderingContext();
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx
index 9f6bd71b64..32421b521b 100644
--- a/packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx
@@ -1,5 +1,5 @@
import styled from '@emotion/styled';
-import { type ReactElement } from 'react';
+import { type ReactNode } from 'react';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
@@ -24,7 +24,7 @@ const StyledScrollWrapper = styled(ScrollWrapper)`
`;
export type ShowPageContainerProps = {
- children: ReactElement[] | ReactElement;
+ children: ReactNode;
};
export const ShowPageContainer = ({ children }: ShowPageContainerProps) => {
diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/common/1760628085765-addNewWidgetTypes.ts b/packages/twenty-server/src/database/typeorm/core/migrations/common/1760628085765-addNewWidgetTypes.ts
new file mode 100644
index 0000000000..63b458fa6f
--- /dev/null
+++ b/packages/twenty-server/src/database/typeorm/core/migrations/common/1760628085765-addNewWidgetTypes.ts
@@ -0,0 +1,45 @@
+import { type MigrationInterface, type QueryRunner } from 'typeorm';
+
+export class AddNewWidgetTypes1760628085765 implements MigrationInterface {
+ name = 'AddNewWidgetTypes1760628085765';
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(
+ `ALTER TYPE "core"."pageLayoutWidget_type_enum" RENAME TO "pageLayoutWidget_type_enum_old"`,
+ );
+ await queryRunner.query(
+ `CREATE TYPE "core"."pageLayoutWidget_type_enum" AS ENUM('VIEW', 'IFRAME', 'FIELDS', 'GRAPH', 'TIMELINE', 'TASKS', 'NOTES', 'FILES', 'EMAILS', 'CALENDAR')`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" DROP DEFAULT`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" TYPE "core"."pageLayoutWidget_type_enum" USING "type"::"text"::"core"."pageLayoutWidget_type_enum"`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" SET DEFAULT 'VIEW'`,
+ );
+ await queryRunner.query(
+ `DROP TYPE "core"."pageLayoutWidget_type_enum_old"`,
+ );
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(
+ `CREATE TYPE "core"."pageLayoutWidget_type_enum_old" AS ENUM('FIELDS', 'GRAPH', 'IFRAME', 'VIEW')`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" DROP DEFAULT`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" TYPE "core"."pageLayoutWidget_type_enum_old" USING "type"::"text"::"core"."pageLayoutWidget_type_enum_old"`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE "core"."pageLayoutWidget" ALTER COLUMN "type" SET DEFAULT 'VIEW'`,
+ );
+ await queryRunner.query(`DROP TYPE "core"."pageLayoutWidget_type_enum"`);
+ await queryRunner.query(
+ `ALTER TYPE "core"."pageLayoutWidget_type_enum_old" RENAME TO "pageLayoutWidget_type_enum"`,
+ );
+ }
+}
diff --git a/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts b/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts
index 95fc301213..4460192661 100644
--- a/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts
+++ b/packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts
@@ -1132,7 +1132,18 @@ export const computeMetadataSchemaComponents = (
title: { type: 'string' },
type: {
type: 'string',
- enum: ['VIEW', 'IFRAME', 'FIELDS', 'GRAPH'],
+ enum: [
+ 'VIEW',
+ 'IFRAME',
+ 'FIELDS',
+ 'GRAPH',
+ 'TIMELINE',
+ 'TASKS',
+ 'NOTES',
+ 'FILES',
+ 'EMAILS',
+ 'CALENDAR',
+ ],
default: 'VIEW',
},
objectMetadataId: { type: 'string', format: 'uuid' },
diff --git a/packages/twenty-server/src/engine/core-modules/page-layout/enums/widget-type.enum.ts b/packages/twenty-server/src/engine/core-modules/page-layout/enums/widget-type.enum.ts
index 20493a53ac..311476a945 100644
--- a/packages/twenty-server/src/engine/core-modules/page-layout/enums/widget-type.enum.ts
+++ b/packages/twenty-server/src/engine/core-modules/page-layout/enums/widget-type.enum.ts
@@ -3,4 +3,10 @@ export enum WidgetType {
IFRAME = 'IFRAME',
FIELDS = 'FIELDS',
GRAPH = 'GRAPH',
+ TIMELINE = 'TIMELINE',
+ TASKS = 'TASKS',
+ NOTES = 'NOTES',
+ FILES = 'FILES',
+ EMAILS = 'EMAILS',
+ CALENDAR = 'CALENDAR',
}
diff --git a/packages/twenty-server/test/integration/constants/widget-configuration-test-data.constants.ts b/packages/twenty-server/test/integration/constants/widget-configuration-test-data.constants.ts
index 3d01c60c4f..78062659c2 100644
--- a/packages/twenty-server/test/integration/constants/widget-configuration-test-data.constants.ts
+++ b/packages/twenty-server/test/integration/constants/widget-configuration-test-data.constants.ts
@@ -268,6 +268,12 @@ export function getValidConfigForWidgetType(widgetType: string): any {
}
case 'VIEW':
case 'FIELDS':
+ case 'TIMELINE':
+ case 'TASKS':
+ case 'NOTES':
+ case 'FILES':
+ case 'EMAILS':
+ case 'CALENDAR':
return null;
default:
return null;