diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql
index 25b663bcb8..9976c91dcb 100644
--- a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql
+++ b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql
@@ -1750,12 +1750,10 @@ enum FeatureFlagKey {
IS_UNIQUE_INDEXES_ENABLED
IS_JSON_FILTER_ENABLED
IS_MARKETPLACE_SETTING_TAB_VISIBLE
- IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED
IS_PUBLIC_DOMAIN_ENABLED
IS_EMAILING_DOMAIN_ENABLED
IS_EMAIL_GROUP_ENABLED
IS_JUNCTION_RELATIONS_ENABLED
- IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED
IS_REST_METADATA_API_NEW_FORMAT_DIRECT
}
diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.ts b/packages/twenty-client-sdk/src/metadata/generated/schema.ts
index 31647dd03d..8b50d21c0e 100644
--- a/packages/twenty-client-sdk/src/metadata/generated/schema.ts
+++ b/packages/twenty-client-sdk/src/metadata/generated/schema.ts
@@ -1391,7 +1391,7 @@ export interface FeatureFlag {
__typename: 'FeatureFlag'
}
-export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT'
+export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT'
export interface WorkspaceUrls {
customUrl?: Scalars['String']
@@ -8762,12 +8762,10 @@ export const enumFeatureFlagKey = {
IS_UNIQUE_INDEXES_ENABLED: 'IS_UNIQUE_INDEXES_ENABLED' as const,
IS_JSON_FILTER_ENABLED: 'IS_JSON_FILTER_ENABLED' as const,
IS_MARKETPLACE_SETTING_TAB_VISIBLE: 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' as const,
- IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' as const,
IS_PUBLIC_DOMAIN_ENABLED: 'IS_PUBLIC_DOMAIN_ENABLED' as const,
IS_EMAILING_DOMAIN_ENABLED: 'IS_EMAILING_DOMAIN_ENABLED' as const,
IS_EMAIL_GROUP_ENABLED: 'IS_EMAIL_GROUP_ENABLED' as const,
IS_JUNCTION_RELATIONS_ENABLED: 'IS_JUNCTION_RELATIONS_ENABLED' as const,
- IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' as const,
IS_REST_METADATA_API_NEW_FORMAT_DIRECT: 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' as const
}
diff --git a/packages/twenty-front/src/generated-admin/graphql.ts b/packages/twenty-front/src/generated-admin/graphql.ts
index 24e6ddca53..b750e9c075 100644
--- a/packages/twenty-front/src/generated-admin/graphql.ts
+++ b/packages/twenty-front/src/generated-admin/graphql.ts
@@ -276,8 +276,6 @@ export enum FeatureFlagKey {
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',
IS_MARKETPLACE_SETTING_TAB_VISIBLE = 'IS_MARKETPLACE_SETTING_TAB_VISIBLE',
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
- IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
- IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED',
IS_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT',
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED'
}
diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts
index 6aa6f0d343..9c18146be8 100644
--- a/packages/twenty-front/src/generated-metadata/graphql.ts
+++ b/packages/twenty-front/src/generated-metadata/graphql.ts
@@ -1647,8 +1647,6 @@ export enum FeatureFlagKey {
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',
IS_MARKETPLACE_SETTING_TAB_VISIBLE = 'IS_MARKETPLACE_SETTING_TAB_VISIBLE',
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
- IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
- IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED',
IS_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT',
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED'
}
diff --git a/packages/twenty-front/src/modules/layout-customization/hooks/useSaveLayoutCustomization.ts b/packages/twenty-front/src/modules/layout-customization/hooks/useSaveLayoutCustomization.ts
index 82c4e684ec..5f5cbd73d8 100644
--- a/packages/twenty-front/src/modules/layout-customization/hooks/useSaveLayoutCustomization.ts
+++ b/packages/twenty-front/src/modules/layout-customization/hooks/useSaveLayoutCustomization.ts
@@ -18,15 +18,12 @@ import { type PageLayout } from '@/page-layout/types/PageLayout';
import { convertPageLayoutDraftToUpdateInput } from '@/page-layout/utils/convertPageLayoutDraftToUpdateInput';
import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLayoutToTabLayouts';
import { isDefaultPageLayoutId } from '@/page-layout/utils/isDefaultPageLayoutId';
-import { reInjectDynamicRelationWidgetsFromDraft } from '@/page-layout/utils/reInjectDynamicRelationWidgetsFromDraft';
import { transformPageLayout } from '@/page-layout/utils/transformPageLayout';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useLingui } from '@lingui/react/macro';
import { useStore } from 'jotai';
import { useCallback, useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
-import { FeatureFlagKey, PageLayoutType } from '~/generated-metadata/graphql';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
import { logError } from '~/utils/logError';
@@ -48,10 +45,6 @@ export const useSaveLayoutCustomization = () => {
const { exitLayoutCustomizationMode } = useExitLayoutCustomizationMode();
const { savePageLayoutWidgetsData } = useSavePageLayoutWidgetsData();
- const featureFlags = useFeatureFlagsMap();
- const isRecordPageLayoutEditingEnabled =
- featureFlags[FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED];
-
const save = useCallback(async () => {
setIsSaving(true);
try {
@@ -119,10 +112,7 @@ export const useSaveLayoutCustomization = () => {
await createPendingRecordTableWidgetViews(pageLayoutId);
if (isPageLayoutStructureDirty) {
- const updateInput = convertPageLayoutDraftToUpdateInput(draft, {
- shouldFilterDynamicRelationWidgets:
- !isRecordPageLayoutEditingEnabled,
- });
+ const updateInput = convertPageLayoutDraftToUpdateInput(draft);
const result = await updatePageLayoutWithTabsAndWidgets(
pageLayoutId,
updateInput,
@@ -136,26 +126,17 @@ export const useSaveLayoutCustomization = () => {
const persistedLayout: PageLayout =
transformPageLayout(updatedPageLayout);
- const pageLayoutToPersist =
- !isRecordPageLayoutEditingEnabled &&
- persistedLayout.type === PageLayoutType.RECORD_PAGE
- ? reInjectDynamicRelationWidgetsFromDraft(
- persistedLayout,
- draft,
- )
- : persistedLayout;
-
store.set(
pageLayoutPersistedComponentState.atomFamily({
instanceId: pageLayoutId,
}),
- pageLayoutToPersist,
+ persistedLayout,
);
store.set(
pageLayoutCurrentLayoutsComponentState.atomFamily({
instanceId: pageLayoutId,
}),
- convertPageLayoutToTabLayouts(pageLayoutToPersist),
+ convertPageLayoutToTabLayouts(persistedLayout),
);
}
} else {
@@ -194,7 +175,6 @@ export const useSaveLayoutCustomization = () => {
savePageLayoutWidgetsData,
exitLayoutCustomizationMode,
enqueueErrorSnackBar,
- isRecordPageLayoutEditingEnabled,
store,
t,
]);
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx
index aa6a5f89d8..41666a0f6c 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx
@@ -9,10 +9,8 @@ import { usePageLayoutTabWithVisibleWidgetsOrThrow } from '@/page-layout/hooks/u
import { useReorderPageLayoutWidgets } from '@/page-layout/hooks/useReorderPageLayoutWidgets';
import { StandaloneWidgetPlaceholder } from '@/page-layout/widgets/components/StandaloneWidgetPlaceholder';
import { RecordPageAddWidgetSection } from '@/page-layout/widgets/components/RecordPageAddWidgetSection';
-import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { styled } from '@linaria/react';
import {
- FeatureFlagKey,
PageLayoutTabLayoutMode,
PageLayoutType,
} from '~/generated-metadata/graphql';
@@ -38,10 +36,6 @@ export const PageLayoutContent = () => {
const isRecordPageLayout =
currentPageLayout.type === PageLayoutType.RECORD_PAGE;
- const isRecordPageGlobalEditionEnabled = useIsFeatureEnabled(
- FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED,
- );
-
const isCanvasLayout = layoutMode === PageLayoutTabLayoutMode.CANVAS;
const isVerticalList = layoutMode === PageLayoutTabLayoutMode.VERTICAL_LIST;
@@ -62,19 +56,13 @@ export const PageLayoutContent = () => {
}
if (isVerticalList) {
- if (
- isPageLayoutInEditMode &&
- isRecordPageLayout &&
- isRecordPageGlobalEditionEnabled
- ) {
+ if (isPageLayoutInEditMode && isRecordPageLayout) {
return (
: undefined
- }
+ trailingElement={}
/>
);
}
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx
index 4f389ef2b2..83b4bee807 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx
@@ -1,5 +1,4 @@
import { useBasePageLayout } from '@/page-layout/hooks/useBasePageLayout';
-import { usePageLayoutWithRelationWidgets } from '@/page-layout/hooks/usePageLayoutWithRelationWidgets';
import { useSetIsPageLayoutInEditMode } from '@/page-layout/hooks/useSetIsPageLayoutInEditMode';
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
@@ -8,27 +7,24 @@ import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayo
import { type PageLayout } from '@/page-layout/types/PageLayout';
import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLayoutToTabLayouts';
import { isPageLayoutEmpty } from '@/page-layout/utils/isPageLayoutEmpty';
-import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState';
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
-import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useStore } from 'jotai';
import { useCallback, useEffect } from 'react';
import { isDefined } from 'twenty-shared/utils';
-import { FeatureFlagKey, PageLayoutType } from '~/generated-metadata/graphql';
+import { PageLayoutType } from '~/generated-metadata/graphql';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
type PageLayoutInitializationQueryEffectProps = {
pageLayoutId: string;
};
-const PageLayoutInitializationEffect = ({
+// oxlint-disable-next-line twenty/effect-components
+export const PageLayoutInitializationQueryEffect = ({
pageLayoutId,
- pageLayout,
-}: {
- pageLayoutId: string;
- pageLayout: PageLayout | undefined;
-}) => {
+}: PageLayoutInitializationQueryEffectProps) => {
+ const pageLayout = useBasePageLayout(pageLayoutId);
+
const [pageLayoutIsInitialized, setPageLayoutIsInitialized] =
useAtomComponentState(pageLayoutIsInitializedComponentState);
@@ -99,53 +95,3 @@ const PageLayoutInitializationEffect = ({
return null;
};
-
-const PageLayoutInitializationWithRelationWidgets = ({
- pageLayoutId,
- basePageLayout,
-}: {
- pageLayoutId: string;
- basePageLayout: PageLayout | undefined;
-}) => {
- const pageLayout = usePageLayoutWithRelationWidgets(basePageLayout);
-
- return (
-
- );
-};
-
-// oxlint-disable-next-line twenty/effect-components
-export const PageLayoutInitializationQueryEffect = ({
- pageLayoutId,
-}: PageLayoutInitializationQueryEffectProps) => {
- const { layoutType } = useLayoutRenderingContext();
-
- const featureFlags = useFeatureFlagsMap();
- const isRecordPageLayoutEditingEnabled =
- featureFlags[FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED];
-
- const basePageLayout = useBasePageLayout(pageLayoutId);
-
- const needsRelationWidgets =
- layoutType === PageLayoutType.RECORD_PAGE &&
- !isRecordPageLayoutEditingEnabled;
-
- if (needsRelationWidgets) {
- return (
-
- );
- }
-
- return (
-
- );
-};
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRelationWidgetsSyncEffect.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRelationWidgetsSyncEffect.tsx
deleted file mode 100644
index a2ef1bf740..0000000000
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRelationWidgetsSyncEffect.tsx
+++ /dev/null
@@ -1,193 +0,0 @@
-import { isLayoutCustomizationModeEnabledState } from '@/layout-customization/states/isLayoutCustomizationModeEnabledState';
-import { useFieldListFieldMetadataItems } from '@/object-record/record-field-list/hooks/useFieldListFieldMetadataItems';
-import { useBasePageLayout } from '@/page-layout/hooks/useBasePageLayout';
-import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
-import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
-import { pageLayoutIsInitializedComponentState } from '@/page-layout/states/pageLayoutIsInitializedComponentState';
-import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState';
-import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout';
-import { type PageLayout } from '@/page-layout/types/PageLayout';
-import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLayoutToTabLayouts';
-import { injectRelationWidgetsIntoLayout } from '@/page-layout/utils/injectRelationWidgetsIntoLayout';
-import { isDynamicRelationWidget } from '@/page-layout/utils/isDynamicRelationWidget';
-import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
-import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
-import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
-import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
-import { useStore } from 'jotai';
-import { useCallback, useEffect } from 'react';
-import { isDefined } from 'twenty-shared/utils';
-import { PageLayoutType, WidgetType } from '~/generated-metadata/graphql';
-import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
-
-type PageLayoutRelationWidgetsSyncEffectProps = {
- pageLayoutId: string;
-};
-
-export const PageLayoutRelationWidgetsSyncEffect = ({
- pageLayoutId,
-}: PageLayoutRelationWidgetsSyncEffectProps) => {
- const { targetRecordIdentifier, layoutType } = useLayoutRenderingContext();
-
- const pageLayoutIsInitialized = useAtomComponentStateValue(
- pageLayoutIsInitializedComponentState,
- );
-
- const basePageLayout = useBasePageLayout(pageLayoutId);
-
- const { boxedRelationFieldMetadataItems } = useFieldListFieldMetadataItems({
- objectNameSingular: targetRecordIdentifier?.targetObjectNameSingular ?? '',
- });
-
- const pageLayoutPersistedComponentCallbackState =
- useAtomComponentStateCallbackState(pageLayoutPersistedComponentState);
-
- const pageLayoutDraftComponentCallbackState =
- useAtomComponentStateCallbackState(pageLayoutDraftComponentState);
-
- const pageLayoutCurrentLayoutsComponentCallbackState =
- useAtomComponentStateCallbackState(pageLayoutCurrentLayoutsComponentState);
-
- const store = useStore();
- const isLayoutCustomizationModeEnabled = useAtomStateValue(
- isLayoutCustomizationModeEnabledState,
- );
-
- const getDraftWithSyncedDynamicRelationWidgets = useCallback(
- (
- currentDraft: DraftPageLayout,
- layoutWithRelationWidgets: PageLayout,
- ): DraftPageLayout => {
- return {
- ...currentDraft,
- tabs: currentDraft.tabs.map((draftTab) => {
- const persistedTab = layoutWithRelationWidgets.tabs.find(
- (tab) => tab.id === draftTab.id,
- );
-
- if (!isDefined(persistedTab)) {
- return draftTab;
- }
-
- const dynamicRelationWidgets = persistedTab.widgets.filter(
- isDynamicRelationWidget,
- );
-
- const nonDynamicWidgets = draftTab.widgets.filter(
- (widget) => !isDynamicRelationWidget(widget),
- );
-
- if (dynamicRelationWidgets.length === 0) {
- return {
- ...draftTab,
- widgets: nonDynamicWidgets,
- };
- }
-
- const firstFieldsWidgetIndex = nonDynamicWidgets.findIndex(
- (widget) => widget.type === WidgetType.FIELDS,
- );
-
- if (firstFieldsWidgetIndex === -1) {
- return {
- ...draftTab,
- widgets: [...nonDynamicWidgets, ...dynamicRelationWidgets],
- };
- }
-
- const widgetsBeforeFields = nonDynamicWidgets.slice(
- 0,
- firstFieldsWidgetIndex + 1,
- );
- const widgetsAfterFields = nonDynamicWidgets.slice(
- firstFieldsWidgetIndex + 1,
- );
-
- return {
- ...draftTab,
- widgets: [
- ...widgetsBeforeFields,
- ...dynamicRelationWidgets,
- ...widgetsAfterFields,
- ],
- };
- }),
- };
- },
- [],
- );
-
- const syncPageLayoutWithRelationWidgets = useCallback(
- (layout: PageLayout) => {
- const currentPersisted = store.get(
- pageLayoutPersistedComponentCallbackState,
- );
-
- if (!isDeeplyEqual(layout, currentPersisted)) {
- store.set(pageLayoutPersistedComponentCallbackState, layout);
-
- const currentDraft = store.get(pageLayoutDraftComponentCallbackState);
-
- const nextDraft = isLayoutCustomizationModeEnabled
- ? getDraftWithSyncedDynamicRelationWidgets(currentDraft, layout)
- : {
- id: layout.id,
- name: layout.name,
- type: layout.type,
- objectMetadataId: layout.objectMetadataId,
- tabs: layout.tabs,
- defaultTabToFocusOnMobileAndSidePanelId:
- layout.defaultTabToFocusOnMobileAndSidePanelId,
- };
-
- if (!isDeeplyEqual(nextDraft, currentDraft)) {
- store.set(pageLayoutDraftComponentCallbackState, nextDraft);
- }
-
- const tabLayouts = convertPageLayoutToTabLayouts({
- ...layout,
- tabs: nextDraft.tabs,
- });
- store.set(pageLayoutCurrentLayoutsComponentCallbackState, tabLayouts);
- }
- },
- [
- getDraftWithSyncedDynamicRelationWidgets,
- isLayoutCustomizationModeEnabled,
- pageLayoutCurrentLayoutsComponentCallbackState,
- pageLayoutDraftComponentCallbackState,
- pageLayoutPersistedComponentCallbackState,
- store,
- ],
- );
-
- useEffect(() => {
- if (!pageLayoutIsInitialized) {
- return;
- }
-
- if (!isDefined(basePageLayout)) {
- return;
- }
-
- const isRecordPage = layoutType === PageLayoutType.RECORD_PAGE;
- if (!isRecordPage) {
- return;
- }
-
- const layoutWithRelationWidgets = injectRelationWidgetsIntoLayout(
- basePageLayout,
- boxedRelationFieldMetadataItems,
- );
-
- syncPageLayoutWithRelationWidgets(layoutWithRelationWidgets);
- }, [
- basePageLayout,
- boxedRelationFieldMetadataItems,
- pageLayoutIsInitialized,
- layoutType,
- syncPageLayoutWithRelationWidgets,
- ]);
-
- return null;
-};
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRenderer.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRenderer.tsx
index 1773606f76..f55f8f2eab 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRenderer.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRenderer.tsx
@@ -1,16 +1,13 @@
import { PageLayoutEditModeProvider } from '@/page-layout/components/PageLayoutEditModeProvider';
import { PageLayoutInitializationQueryEffect } from '@/page-layout/components/PageLayoutInitializationQueryEffect';
import { PageLayoutRecordPageCustomizationSessionRegistrationEffect } from '@/page-layout/components/PageLayoutRecordPageCustomizationSessionRegistrationEffect';
-import { PageLayoutRelationWidgetsSyncEffect } from '@/page-layout/components/PageLayoutRelationWidgetsSyncEffect';
import { PageLayoutRendererContent } from '@/page-layout/components/PageLayoutRendererContent';
import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext';
import { getTabListInstanceIdFromPageLayoutAndRecord } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutAndRecord';
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
import { TabListComponentInstanceContext } from '@/ui/layout/tab-list/states/contexts/TabListComponentInstanceContext';
-import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
-import { FeatureFlagKey, PageLayoutType } from '~/generated-metadata/graphql';
type PageLayoutRendererProps = {
pageLayoutId: string;
@@ -21,10 +18,6 @@ export const PageLayoutRenderer = ({
}: PageLayoutRendererProps) => {
const { targetRecordIdentifier, layoutType } = useLayoutRenderingContext();
- const featureFlags = useFeatureFlagsMap();
- const isRecordPageLayoutEditingEnabled =
- featureFlags[FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED];
-
const tabListInstanceId = getTabListInstanceIdFromPageLayoutAndRecord({
pageLayoutId,
layoutType,
@@ -48,12 +41,6 @@ export const PageLayoutRenderer = ({
>
- {!isRecordPageLayoutEditingEnabled &&
- layoutType === PageLayoutType.RECORD_PAGE && (
-
- )}
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutSingleTabRenderer.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutSingleTabRenderer.tsx
index a258a44974..f472a147ea 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutSingleTabRenderer.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutSingleTabRenderer.tsx
@@ -3,7 +3,6 @@ import { PageLayoutContent } from '@/page-layout/components/PageLayoutContent';
import { PageLayoutEditModeProvider } from '@/page-layout/components/PageLayoutEditModeProvider';
import { PageLayoutInitializationQueryEffect } from '@/page-layout/components/PageLayoutInitializationQueryEffect';
import { PageLayoutRecordPageCustomizationSessionRegistrationEffect } from '@/page-layout/components/PageLayoutRecordPageCustomizationSessionRegistrationEffect';
-import { PageLayoutRelationWidgetsSyncEffect } from '@/page-layout/components/PageLayoutRelationWidgetsSyncEffect';
import { PageLayoutContentProvider } from '@/page-layout/contexts/PageLayoutContentContext';
import { useCurrentPageLayoutOrThrow } from '@/page-layout/hooks/useCurrentPageLayoutOrThrow';
import { usePageLayoutTabWithVisibleWidgetsOrThrow } from '@/page-layout/hooks/usePageLayoutTabWithVisibleWidgetsOrThrow';
@@ -16,8 +15,6 @@ import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingC
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
import { TabListComponentInstanceContext } from '@/ui/layout/tab-list/states/contexts/TabListComponentInstanceContext';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
-import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
-import { FeatureFlagKey } from '~/generated-metadata/graphql';
type PageLayoutSingleTabRendererProps = {
pageLayoutId: string;
@@ -79,10 +76,6 @@ export const PageLayoutSingleTabRenderer = ({
}: PageLayoutSingleTabRendererProps) => {
const { targetRecordIdentifier, layoutType } = useLayoutRenderingContext();
- const featureFlags = useFeatureFlagsMap();
- const isRecordPageLayoutEditingEnabled =
- featureFlags[FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED];
-
const tabListInstanceId = getTabListInstanceIdFromPageLayoutAndRecord({
pageLayoutId,
layoutType,
@@ -106,9 +99,6 @@ export const PageLayoutSingleTabRenderer = ({
>
- {!isRecordPageLayoutEditingEnabled && (
-
- )}
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx
index 0f96733c0f..7205b5595e 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx
@@ -46,14 +46,10 @@ import { TabListFromUrlOptionalEffect } from '@/ui/layout/tab-list/components/Ta
import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
-import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { SidePanelPages } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { themeCssVariables } from 'twenty-ui/theme-constants';
-import {
- FeatureFlagKey,
- type PageLayoutType,
-} from '~/generated-metadata/graphql';
+import { type PageLayoutType } from '~/generated-metadata/graphql';
const StyledContainer = styled.div`
box-sizing: border-box;
@@ -112,10 +108,6 @@ export const PageLayoutTabList = ({
const { getIcon } = useIcons();
const { t } = useLingui();
- const isRecordPageGlobalEditionEnabled = useIsFeatureEnabled(
- FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED,
- );
-
const tabsWithIcons: SingleTabProps[] = tabs.map((tab) => ({
id: tab.id,
title: tab.title,
@@ -266,10 +258,7 @@ export const PageLayoutTabList = ({
(tabId: string) => {
const shouldOpenSettings =
isPageLayoutInEditMode &&
- shouldEnableTabEditingFeatures(
- pageLayoutType,
- isRecordPageGlobalEditionEnabled,
- );
+ shouldEnableTabEditingFeatures(pageLayoutType);
if (shouldOpenSettings && activeTabId === tabId) {
openTabSettings(tabId);
@@ -284,7 +273,6 @@ export const PageLayoutTabList = ({
},
[
isPageLayoutInEditMode,
- isRecordPageGlobalEditionEnabled,
pageLayoutType,
activeTabId,
isTabSettingsOpen,
@@ -297,10 +285,7 @@ export const PageLayoutTabList = ({
(tabId: string) => {
const shouldOpenSettings =
isPageLayoutInEditMode &&
- shouldEnableTabEditingFeatures(
- pageLayoutType,
- isRecordPageGlobalEditionEnabled,
- );
+ shouldEnableTabEditingFeatures(pageLayoutType);
if (shouldOpenSettings && activeTabId === tabId) {
openTabSettings(tabId);
@@ -316,7 +301,6 @@ export const PageLayoutTabList = ({
},
[
isPageLayoutInEditMode,
- isRecordPageGlobalEditionEnabled,
pageLayoutType,
activeTabId,
isTabSettingsOpen,
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx
index 488f5a4f44..05ddbd3eb9 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx
@@ -26,14 +26,10 @@ import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
-import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useContext } from 'react';
import { SidePanelPages } from 'twenty-shared/types';
import { ThemeContext } from 'twenty-ui/theme-constants';
-import {
- FeatureFlagKey,
- type PageLayoutType,
-} from '~/generated-metadata/graphql';
+import { type PageLayoutType } from '~/generated-metadata/graphql';
const StyledOverflowDropdownListDraggableWrapper = styled.div`
cursor: grab;
@@ -79,16 +75,8 @@ export const PageLayoutTabListReorderableOverflowDropdown = ({
const isPageLayoutInEditMode = useIsPageLayoutInEditMode();
- const isRecordPageGlobalEditionEnabled = useIsFeatureEnabled(
- FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED,
- );
-
const shouldShowEditButton =
- isPageLayoutInEditMode &&
- shouldEnableTabEditingFeatures(
- pageLayoutType,
- isRecordPageGlobalEditionEnabled,
- );
+ isPageLayoutInEditMode && shouldEnableTabEditingFeatures(pageLayoutType);
const isPageLayoutTabDragging = useAtomComponentStateValue(
isPageLayoutTabDraggingComponentState,
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabsRenderer.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabsRenderer.tsx
index ae18ac4506..f32d3dea3d 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabsRenderer.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabsRenderer.tsx
@@ -21,11 +21,9 @@ import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTab
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
-import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { styled } from '@linaria/react';
import { isDefined } from 'twenty-shared/utils';
import { useIsMobile } from 'twenty-ui/utilities';
-import { FeatureFlagKey } from '~/generated-metadata/graphql';
const StyledContainer = styled.div<{ hasPinnedTab: boolean }>`
display: grid;
grid-template-columns: ${({ hasPinnedTab }) =>
@@ -73,10 +71,6 @@ export const PageLayoutTabsRenderer = () => {
const isMobile = useIsMobile();
- const isRecordPageGlobalEditionEnabled = useIsFeatureEnabled(
- FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED,
- );
-
const metadataStore = useAtomFamilyStateValue(
metadataStoreState,
'objectMetadataItems',
@@ -90,10 +84,7 @@ export const PageLayoutTabsRenderer = () => {
const canEnableTabEditing =
isPageLayoutInEditMode &&
- shouldEnableTabEditingFeatures(
- currentPageLayout.type,
- isRecordPageGlobalEditionEnabled,
- );
+ shouldEnableTabEditingFeatures(currentPageLayout.type);
const tabsWithVisibleWidgets = getTabsWithVisibleWidgets({
tabs: currentPageLayout.tabs,
diff --git a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutWithRelationWidgets.test.tsx b/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutWithRelationWidgets.test.tsx
deleted file mode 100644
index c09a99cc4c..0000000000
--- a/packages/twenty-front/src/modules/page-layout/hooks/__tests__/usePageLayoutWithRelationWidgets.test.tsx
+++ /dev/null
@@ -1,333 +0,0 @@
-import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
-import { useFieldListFieldMetadataItems } from '@/object-record/record-field-list/hooks/useFieldListFieldMetadataItems';
-import { usePageLayoutWithRelationWidgets } from '@/page-layout/hooks/usePageLayoutWithRelationWidgets';
-import { type PageLayout } from '@/page-layout/types/PageLayout';
-import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
-import { renderHook } from '@testing-library/react';
-import {
- AggregateOperations,
- BarChartLayout,
- GraphOrderBy,
- PageLayoutTabLayoutMode,
- PageLayoutType,
- WidgetConfigurationType,
- WidgetType,
-} from '~/generated-metadata/graphql';
-
-jest.mock('@/ui/layout/contexts/LayoutRenderingContext');
-jest.mock(
- '@/object-record/record-field-list/hooks/useFieldListFieldMetadataItems',
-);
-
-describe('usePageLayoutWithRelationWidgets', () => {
- const mockBasePageLayout: PageLayout = {
- __typename: 'PageLayout',
- id: 'test-layout',
- name: 'Test Layout',
- type: PageLayoutType.RECORD_PAGE,
- objectMetadataId: 'obj-1',
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- deletedAt: null,
- tabs: [
- {
- __typename: 'PageLayoutTab',
- applicationId: '',
- id: 'tab-1',
- title: 'Fields',
- isActive: true,
- icon: 'IconList',
- position: 100,
- layoutMode: PageLayoutTabLayoutMode.VERTICAL_LIST,
- pageLayoutId: 'test-layout',
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- deletedAt: null,
- widgets: [
- {
- __typename: 'PageLayoutWidget',
- id: 'widget-fields',
- applicationId: '',
- pageLayoutTabId: 'tab-1',
- title: 'Fields',
- isActive: true,
- type: WidgetType.FIELDS,
- objectMetadataId: null,
- gridPosition: {
- __typename: 'GridPosition',
- row: 0,
- column: 0,
- rowSpan: 1,
- columnSpan: 12,
- },
- configuration: {
- __typename: 'FieldsConfiguration',
- configurationType: WidgetConfigurationType.FIELDS,
- viewId: null,
- },
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- deletedAt: null,
- },
- {
- __typename: 'PageLayoutWidget',
- id: 'widget-notes',
- applicationId: '',
- pageLayoutTabId: 'tab-1',
- title: 'Notes',
- isActive: true,
- type: WidgetType.NOTES,
- objectMetadataId: null,
- gridPosition: {
- __typename: 'GridPosition',
- row: 1,
- column: 0,
- rowSpan: 1,
- columnSpan: 12,
- },
- configuration: {
- __typename: 'NotesConfiguration',
- configurationType: WidgetConfigurationType.NOTES,
- },
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- deletedAt: null,
- },
- {
- __typename: 'PageLayoutWidget',
- id: 'widget-other',
- applicationId: '',
- pageLayoutTabId: 'tab-1',
- title: 'Other',
- isActive: true,
- type: WidgetType.GRAPH,
- objectMetadataId: null,
- gridPosition: {
- __typename: 'GridPosition',
- row: 2,
- column: 0,
- rowSpan: 1,
- columnSpan: 12,
- },
- configuration: {
- __typename: 'BarChartConfiguration',
- configurationType: WidgetConfigurationType.BAR_CHART,
- layout: BarChartLayout.VERTICAL,
- aggregateOperation: AggregateOperations.COUNT,
- aggregateFieldMetadataId: 'id',
- primaryAxisGroupByFieldMetadataId: 'createdAt',
- primaryAxisOrderBy: GraphOrderBy.FIELD_ASC,
- displayDataLabel: false,
- },
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- deletedAt: null,
- },
- ],
- },
- ],
- };
-
- const mockRelationFields: FieldMetadataItem[] = [
- {
- id: 'field-1',
- universalIdentifier: 'field-1',
- label: 'Related Companies',
- name: 'relatedCompanies',
- type: 'RELATION',
- isNullable: true,
- isActive: true,
- isSystem: false,
- isCustom: false,
- defaultValue: null,
- options: null,
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- fromRelationMetadata: null,
- toRelationMetadata: null,
- relationDefinition: null,
- settings: null,
- } as FieldMetadataItem,
- {
- id: 'field-2',
- universalIdentifier: 'field-2',
- label: 'Related People',
- name: 'relatedPeople',
- type: 'RELATION',
- isNullable: true,
- isActive: true,
- isSystem: false,
- isCustom: false,
- defaultValue: null,
- options: null,
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- fromRelationMetadata: null,
- toRelationMetadata: null,
- relationDefinition: null,
- settings: null,
- } as FieldMetadataItem,
- ];
-
- beforeEach(() => {
- (useLayoutRenderingContext as jest.Mock).mockReturnValue({
- targetRecordIdentifier: {
- targetObjectNameSingular: 'company',
- },
- layoutType: PageLayoutType.RECORD_PAGE,
- });
-
- (useFieldListFieldMetadataItems as jest.Mock).mockReturnValue({
- boxedRelationFieldMetadataItems: mockRelationFields,
- });
- });
-
- it('should inject relation widgets after the first FIELDS widget', () => {
- const { result } = renderHook(() =>
- usePageLayoutWithRelationWidgets(mockBasePageLayout),
- );
-
- const firstTab = result.current?.tabs[0];
- expect(firstTab).toBeDefined();
-
- const widgets = firstTab?.widgets || [];
- expect(widgets.length).toBe(5); // 1 FIELDS + 2 relation + 1 NOTES + 1 OTHER
-
- // First widget should be FIELDS
- expect(widgets[0].type).toBe(WidgetType.FIELDS);
- expect(widgets[0].id).toBe('widget-fields');
-
- // Next two should be relation widgets
- expect(widgets[1].type).toBe(WidgetType.FIELD);
- expect(widgets[1].title).toBe('Related Companies');
- expect(widgets[2].type).toBe(WidgetType.FIELD);
- expect(widgets[2].title).toBe('Related People');
-
- // Then NOTES widget
- expect(widgets[3].type).toBe(WidgetType.NOTES);
- expect(widgets[3].id).toBe('widget-notes');
-
- // Finally OTHER widget
- expect(widgets[4].type).toBe(WidgetType.GRAPH);
- expect(widgets[4].id).toBe('widget-other');
- });
-
- it('should handle layout with no FIELDS widget by appending to end', () => {
- const layoutWithoutFields: PageLayout = {
- ...mockBasePageLayout,
- tabs: [
- {
- ...mockBasePageLayout.tabs[0],
- widgets: [
- {
- __typename: 'PageLayoutWidget',
- id: 'widget-other',
- applicationId: '',
- pageLayoutTabId: 'tab-1',
- title: 'Other',
- isActive: true,
- type: WidgetType.GRAPH,
- objectMetadataId: null,
- gridPosition: {
- __typename: 'GridPosition',
- row: 0,
- column: 0,
- rowSpan: 1,
- columnSpan: 12,
- },
- configuration: {
- __typename: 'BarChartConfiguration',
- configurationType: WidgetConfigurationType.BAR_CHART,
- layout: BarChartLayout.VERTICAL,
- aggregateOperation: AggregateOperations.COUNT,
- aggregateFieldMetadataId: 'id',
- primaryAxisGroupByFieldMetadataId: 'createdAt',
- primaryAxisOrderBy: GraphOrderBy.FIELD_ASC,
- displayDataLabel: false,
- },
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- deletedAt: null,
- },
- ],
- },
- ],
- };
-
- const { result } = renderHook(() =>
- usePageLayoutWithRelationWidgets(layoutWithoutFields),
- );
-
- const firstTab = result.current?.tabs[0];
- const widgets = firstTab?.widgets || [];
-
- expect(widgets.length).toBe(3); // 1 OTHER + 2 relation
- expect(widgets[0].type).toBe(WidgetType.GRAPH);
- expect(widgets[1].type).toBe(WidgetType.FIELD);
- expect(widgets[2].type).toBe(WidgetType.FIELD);
- });
-
- it('should return unchanged layout when no relation fields exist', () => {
- (useFieldListFieldMetadataItems as jest.Mock).mockReturnValue({
- boxedRelationFieldMetadataItems: [],
- });
-
- const { result } = renderHook(() =>
- usePageLayoutWithRelationWidgets(mockBasePageLayout),
- );
-
- expect(result.current).toEqual(mockBasePageLayout);
- });
-
- it('should return undefined when basePageLayout is undefined', () => {
- const { result } = renderHook(() =>
- usePageLayoutWithRelationWidgets(undefined),
- );
-
- expect(result.current).toBeUndefined();
- });
-
- it('should return unchanged layout when not a record page', () => {
- (useLayoutRenderingContext as jest.Mock).mockReturnValue({
- targetRecordIdentifier: {
- targetObjectNameSingular: 'company',
- },
- layoutType: PageLayoutType.DASHBOARD,
- });
-
- const { result } = renderHook(() =>
- usePageLayoutWithRelationWidgets(mockBasePageLayout),
- );
-
- expect(result.current).toEqual(mockBasePageLayout);
- });
-
- it('should handle layout without Note widget', () => {
- const layoutWithoutNotes: PageLayout = {
- ...mockBasePageLayout,
- tabs: [
- {
- ...mockBasePageLayout.tabs[0],
- widgets: [
- mockBasePageLayout.tabs[0].widgets[0], // FIELDS widget
- mockBasePageLayout.tabs[0].widgets[2], // OTHER widget
- ],
- },
- ],
- };
-
- const { result } = renderHook(() =>
- usePageLayoutWithRelationWidgets(layoutWithoutNotes),
- );
-
- const firstTab = result.current?.tabs[0];
- const widgets = firstTab?.widgets || [];
-
- expect(widgets.length).toBe(4); // 1 FIELDS + 2 relation + 1 OTHER
-
- expect(widgets[0].type).toBe(WidgetType.FIELDS);
- expect(widgets[1].type).toBe(WidgetType.FIELD);
- expect(widgets[2].type).toBe(WidgetType.FIELD);
- expect(widgets[3].type).toBe(WidgetType.GRAPH);
- });
-});
diff --git a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutAddTabStrategy.ts b/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutAddTabStrategy.ts
index 0223c2fb15..2ba3242b1e 100644
--- a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutAddTabStrategy.ts
+++ b/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutAddTabStrategy.ts
@@ -8,12 +8,11 @@ import { shouldEnableTabEditingFeatures } from '@/page-layout/utils/shouldEnable
import { useNavigatePageLayoutSidePanel } from '@/side-panel/pages/page-layout/hooks/useNavigatePageLayoutSidePanel';
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
-import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { t } from '@lingui/core/macro';
import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { SidePanelPages } from 'twenty-shared/types';
-import { FeatureFlagKey, PageLayoutType } from '~/generated-metadata/graphql';
+import { PageLayoutType } from '~/generated-metadata/graphql';
export const usePageLayoutAddTabStrategy = ({
pageLayoutId,
@@ -25,10 +24,6 @@ export const usePageLayoutAddTabStrategy = ({
const { currentPageLayout } = useCurrentPageLayoutOrThrow();
const isPageLayoutInEditMode = useIsPageLayoutInEditMode();
- const isRecordPageGlobalEditionEnabled = useIsFeatureEnabled(
- FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED,
- );
-
const { createPageLayoutTab } = useCreatePageLayoutTab({
pageLayoutId,
tabListInstanceId,
@@ -66,10 +61,7 @@ export const usePageLayoutAddTabStrategy = ({
const isEnabled =
isPageLayoutInEditMode &&
- shouldEnableTabEditingFeatures(
- currentPageLayout.type,
- isRecordPageGlobalEditionEnabled,
- );
+ shouldEnableTabEditingFeatures(currentPageLayout.type);
if (!isEnabled) {
return undefined;
diff --git a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutWithRelationWidgets.ts b/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutWithRelationWidgets.ts
deleted file mode 100644
index 935200b7fd..0000000000
--- a/packages/twenty-front/src/modules/page-layout/hooks/usePageLayoutWithRelationWidgets.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useFieldListFieldMetadataItems } from '@/object-record/record-field-list/hooks/useFieldListFieldMetadataItems';
-import { type PageLayout } from '@/page-layout/types/PageLayout';
-import { injectRelationWidgetsIntoLayout } from '@/page-layout/utils/injectRelationWidgetsIntoLayout';
-import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
-import { isDefined } from 'twenty-shared/utils';
-import { PageLayoutType } from '~/generated-metadata/graphql';
-
-export const usePageLayoutWithRelationWidgets = (
- basePageLayout: PageLayout | undefined,
-): PageLayout | undefined => {
- const { targetRecordIdentifier, layoutType } = useLayoutRenderingContext();
-
- const { boxedRelationFieldMetadataItems } = useFieldListFieldMetadataItems({
- objectNameSingular: targetRecordIdentifier?.targetObjectNameSingular ?? '',
- });
-
- if (!isDefined(basePageLayout)) {
- return undefined;
- }
-
- const isRecordPage = layoutType === PageLayoutType.RECORD_PAGE;
-
- if (!isRecordPage) {
- return basePageLayout;
- }
-
- return injectRelationWidgetsIntoLayout(
- basePageLayout,
- boxedRelationFieldMetadataItems,
- );
-};
diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useSavePageLayout.ts b/packages/twenty-front/src/modules/page-layout/hooks/useSavePageLayout.ts
index 8bfa57eccc..a1a39718ea 100644
--- a/packages/twenty-front/src/modules/page-layout/hooks/useSavePageLayout.ts
+++ b/packages/twenty-front/src/modules/page-layout/hooks/useSavePageLayout.ts
@@ -8,15 +8,12 @@ import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayo
import { type PageLayout } from '@/page-layout/types/PageLayout';
import { convertPageLayoutDraftToUpdateInput } from '@/page-layout/utils/convertPageLayoutDraftToUpdateInput';
import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLayoutToTabLayouts';
-import { reInjectDynamicRelationWidgetsFromDraft } from '@/page-layout/utils/reInjectDynamicRelationWidgetsFromDraft';
import { transformPageLayout } from '@/page-layout/utils/transformPageLayout';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
-import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useStore } from 'jotai';
import { useCallback } from 'react';
import { isDefined } from 'twenty-shared/utils';
-import { FeatureFlagKey, PageLayoutType } from '~/generated-metadata/graphql';
export const useSavePageLayout = (pageLayoutIdFromProps: string) => {
const pageLayoutId = useAvailableComponentInstanceIdOrThrow(
@@ -49,9 +46,6 @@ export const useSavePageLayout = (pageLayoutIdFromProps: string) => {
const { createPendingRecordTableWidgetViews } =
useCreatePendingRecordTableWidgetViews();
- const featureFlags = useFeatureFlagsMap();
- const isRecordPageLayoutEditingEnabled =
- featureFlags[FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED];
const store = useStore();
const savePageLayout = useCallback(async () => {
@@ -59,9 +53,7 @@ export const useSavePageLayout = (pageLayoutIdFromProps: string) => {
await createPendingRecordTableWidgetViews(pageLayoutId);
const pageLayoutDraft = store.get(pageLayoutDraftCallbackState);
- const updateInput = convertPageLayoutDraftToUpdateInput(pageLayoutDraft, {
- shouldFilterDynamicRelationWidgets: !isRecordPageLayoutEditingEnabled,
- });
+ const updateInput = convertPageLayoutDraftToUpdateInput(pageLayoutDraft);
const result = await updatePageLayoutWithTabsAndWidgets(
pageLayoutId,
@@ -76,19 +68,10 @@ export const useSavePageLayout = (pageLayoutIdFromProps: string) => {
const persistedLayout: PageLayout =
transformPageLayout(updatedPageLayout);
- const pageLayoutToPersist =
- !isRecordPageLayoutEditingEnabled &&
- persistedLayout.type === PageLayoutType.RECORD_PAGE
- ? reInjectDynamicRelationWidgetsFromDraft(
- persistedLayout,
- pageLayoutDraft,
- )
- : persistedLayout;
-
- store.set(pageLayoutPersistedCallbackState, pageLayoutToPersist);
+ store.set(pageLayoutPersistedCallbackState, persistedLayout);
store.set(
pageLayoutCurrentLayoutsCallbackState,
- convertPageLayoutToTabLayouts(pageLayoutToPersist),
+ convertPageLayoutToTabLayouts(persistedLayout),
);
}
}
@@ -97,7 +80,6 @@ export const useSavePageLayout = (pageLayoutIdFromProps: string) => {
}, [
createPendingFieldsWidgetViews,
createPendingRecordTableWidgetViews,
- isRecordPageLayoutEditingEnabled,
pageLayoutCurrentLayoutsCallbackState,
pageLayoutDraftCallbackState,
pageLayoutId,
diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertPageLayoutDraftToUpdateInput.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertPageLayoutDraftToUpdateInput.test.ts
index bd503ec7ea..7b3ae3c5f5 100644
--- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertPageLayoutDraftToUpdateInput.test.ts
+++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/convertPageLayoutDraftToUpdateInput.test.ts
@@ -1,7 +1,6 @@
import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout';
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
import { convertPageLayoutDraftToUpdateInput } from '@/page-layout/utils/convertPageLayoutDraftToUpdateInput';
-import { DYNAMIC_RELATION_WIDGET_ID_PREFIX } from '@/page-layout/utils/isDynamicRelationWidget';
import {
PageLayoutTabLayoutMode,
PageLayoutType,
@@ -350,81 +349,4 @@ describe('convertPageLayoutDraftToUpdateInput', () => {
columnSpan: 6,
});
});
-
- describe('shouldFilterDynamicRelationWidgets', () => {
- it('should filter out dynamic relation widgets when shouldFilterDynamicRelationWidgets is true', () => {
- const regularWidget = makeWidget({ id: 'w1' });
- const dynamicWidget = makeWidget({
- id: `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}relation-1`,
- type: WidgetType.VIEW,
- });
-
- const draft = makeDraft([
- makeTab('tab-1', [regularWidget, dynamicWidget]),
- ]);
-
- const result = convertPageLayoutDraftToUpdateInput(draft, {
- shouldFilterDynamicRelationWidgets: true,
- });
-
- expect(result.tabs[0].widgets).toHaveLength(1);
- expect(result.tabs[0].widgets[0].id).toBe('w1');
- });
-
- it('should keep all non-dynamic widgets when shouldFilterDynamicRelationWidgets is true and multiple widget types exist', () => {
- const fieldsWidget = makeWidget({ id: 'w1', type: WidgetType.FIELDS });
- const timelineWidget = makeWidget({
- id: 'w2',
- type: WidgetType.TIMELINE,
- });
- const dynamicWidget = makeWidget({
- id: `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}rel`,
- });
-
- const draft = makeDraft([
- makeTab('tab-1', [fieldsWidget, dynamicWidget, timelineWidget]),
- ]);
-
- const result = convertPageLayoutDraftToUpdateInput(draft, {
- shouldFilterDynamicRelationWidgets: true,
- });
-
- expect(result.tabs[0].widgets).toHaveLength(2);
- expect(result.tabs[0].widgets.map((w) => w.id)).toEqual(['w1', 'w2']);
- });
-
- it('should not filter dynamic relation widgets when shouldFilterDynamicRelationWidgets is false', () => {
- const regularWidget = makeWidget({ id: 'w1' });
- const dynamicWidget = makeWidget({
- id: `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}relation-1`,
- type: WidgetType.VIEW,
- });
-
- const draft = makeDraft([
- makeTab('tab-1', [regularWidget, dynamicWidget]),
- ]);
-
- const result = convertPageLayoutDraftToUpdateInput(draft, {
- shouldFilterDynamicRelationWidgets: false,
- });
-
- expect(result.tabs[0].widgets).toHaveLength(2);
- });
-
- it('should not filter dynamic relation widgets by default', () => {
- const regularWidget = makeWidget({ id: 'w1' });
- const dynamicWidget = makeWidget({
- id: `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}relation-1`,
- type: WidgetType.VIEW,
- });
-
- const draft = makeDraft([
- makeTab('tab-1', [regularWidget, dynamicWidget]),
- ]);
-
- const result = convertPageLayoutDraftToUpdateInput(draft);
-
- expect(result.tabs[0].widgets).toHaveLength(2);
- });
- });
});
diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/injectRelationWidgetsIntoLayout.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/injectRelationWidgetsIntoLayout.test.ts
deleted file mode 100644
index c19c5e4507..0000000000
--- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/injectRelationWidgetsIntoLayout.test.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
-import { type PageLayout } from '@/page-layout/types/PageLayout';
-import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab';
-import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
-import { injectRelationWidgetsIntoLayout } from '@/page-layout/utils/injectRelationWidgetsIntoLayout';
-import {
- FieldDisplayMode,
- WidgetConfigurationType,
- WidgetType,
-} from '~/generated-metadata/graphql';
-
-const createMockWidget = (
- id: string,
- type: WidgetType = WidgetType.FIELDS,
-): PageLayoutWidget =>
- ({
- __typename: 'PageLayoutWidget',
- id,
- pageLayoutTabId: 'tab-1',
- title: `Widget ${id}`,
- type,
- objectMetadataId: null,
- gridPosition: {
- __typename: 'GridPosition',
- row: 0,
- column: 0,
- rowSpan: 1,
- columnSpan: 12,
- },
- position: {
- __typename: 'PageLayoutWidgetGridPosition',
- layoutMode: 'GRID',
- row: 0,
- column: 0,
- rowSpan: 1,
- columnSpan: 12,
- },
- configuration: {
- __typename: 'FieldsConfiguration',
- configurationType: WidgetConfigurationType.FIELDS,
- viewId: null,
- },
- createdAt: '2024-01-01T00:00:00.000Z',
- updatedAt: '2024-01-01T00:00:00.000Z',
- deletedAt: null,
- }) as PageLayoutWidget;
-
-const createMockTab = (
- id: string,
- widgets: PageLayoutWidget[],
-): PageLayoutTab =>
- ({
- __typename: 'PageLayoutTab',
- applicationId: '',
- id,
- pageLayoutId: 'page-layout-1',
- title: `Tab ${id}`,
- position: 0,
- widgets,
- createdAt: '2024-01-01T00:00:00.000Z',
- updatedAt: '2024-01-01T00:00:00.000Z',
- deletedAt: null,
- }) as PageLayoutTab;
-
-const createMockLayout = (tabs: PageLayoutTab[]): PageLayout =>
- ({
- __typename: 'PageLayout',
- id: 'layout-1',
- tabs,
- }) as PageLayout;
-
-const createMockFieldMetadataItem = (
- id: string,
- label: string,
-): FieldMetadataItem =>
- ({
- id,
- label,
- name: label.toLowerCase(),
- type: 'RELATION',
- }) as FieldMetadataItem;
-
-describe('injectRelationWidgetsIntoLayout', () => {
- it('should return layout unchanged when relation fields array is empty', () => {
- const layout = createMockLayout([
- createMockTab('tab-1', [createMockWidget('w1')]),
- ]);
-
- const result = injectRelationWidgetsIntoLayout(layout, []);
-
- expect(result).toBe(layout);
- });
-
- it('should return layout unchanged when there are no tabs', () => {
- const layout = createMockLayout([]);
- const fields = [createMockFieldMetadataItem('f1', 'Company')];
-
- const result = injectRelationWidgetsIntoLayout(layout, fields);
-
- expect(result).toBe(layout);
- });
-
- it('should append relation widgets when no FIELDS widget exists', () => {
- const otherWidget = createMockWidget('w1', WidgetType.TIMELINE);
- const layout = createMockLayout([createMockTab('tab-1', [otherWidget])]);
- const fields = [createMockFieldMetadataItem('f1', 'Company')];
-
- const result = injectRelationWidgetsIntoLayout(layout, fields);
-
- expect(result.tabs[0].widgets).toHaveLength(2);
- expect(result.tabs[0].widgets[0].id).toBe('w1');
- expect(result.tabs[0].widgets[1].id).toContain('dynamic-relation-widget-');
- expect(result.tabs[0].widgets[1].id).toContain('f1');
- });
-
- it('should inject relation widgets after the first FIELDS widget', () => {
- const fieldsWidget = createMockWidget('fields-1', WidgetType.FIELDS);
- const timelineWidget = createMockWidget('timeline-1', WidgetType.TIMELINE);
- const layout = createMockLayout([
- createMockTab('tab-1', [fieldsWidget, timelineWidget]),
- ]);
- const fields = [createMockFieldMetadataItem('f1', 'Company')];
-
- const result = injectRelationWidgetsIntoLayout(layout, fields);
-
- expect(result.tabs[0].widgets).toHaveLength(3);
- expect(result.tabs[0].widgets[0].id).toBe('fields-1');
- expect(result.tabs[0].widgets[1].id).toContain('f1');
- expect(result.tabs[0].widgets[2].id).toBe('timeline-1');
- });
-
- it('should reposition NOTES widget after relation widgets', () => {
- const fieldsWidget = createMockWidget('fields-1', WidgetType.FIELDS);
- const notesWidget = createMockWidget('notes-1', WidgetType.NOTES);
- const timelineWidget = createMockWidget('timeline-1', WidgetType.TIMELINE);
- const layout = createMockLayout([
- createMockTab('tab-1', [fieldsWidget, notesWidget, timelineWidget]),
- ]);
- const fields = [createMockFieldMetadataItem('f1', 'Company')];
-
- const result = injectRelationWidgetsIntoLayout(layout, fields);
-
- const widgetIds = result.tabs[0].widgets.map((w) => w.id);
-
- expect(widgetIds[0]).toBe('fields-1');
- expect(widgetIds[1]).toContain('f1');
- expect(widgetIds[2]).toBe('notes-1');
- expect(widgetIds[3]).toBe('timeline-1');
- });
-
- it('should only modify the first tab', () => {
- const layout = createMockLayout([
- createMockTab('tab-1', [createMockWidget('fields-1', WidgetType.FIELDS)]),
- createMockTab('tab-2', [createMockWidget('fields-2', WidgetType.FIELDS)]),
- ]);
- const fields = [createMockFieldMetadataItem('f1', 'Company')];
-
- const result = injectRelationWidgetsIntoLayout(layout, fields);
-
- expect(result.tabs[0].widgets).toHaveLength(2);
- expect(result.tabs[1].widgets).toHaveLength(1);
- expect(result.tabs[1].widgets[0].id).toBe('fields-2');
- });
-
- it('should inject multiple relation widgets in order', () => {
- const fieldsWidget = createMockWidget('fields-1', WidgetType.FIELDS);
- const layout = createMockLayout([createMockTab('tab-1', [fieldsWidget])]);
- const fields = [
- createMockFieldMetadataItem('f1', 'Company'),
- createMockFieldMetadataItem('f2', 'Person'),
- ];
-
- const result = injectRelationWidgetsIntoLayout(layout, fields);
-
- expect(result.tabs[0].widgets).toHaveLength(3);
- expect(result.tabs[0].widgets[0].id).toBe('fields-1');
- expect(result.tabs[0].widgets[1].id).toContain('f1');
- expect(result.tabs[0].widgets[2].id).toContain('f2');
- });
-
- it('should set correct properties on injected relation widgets', () => {
- const layout = createMockLayout([
- createMockTab('tab-1', [createMockWidget('fields-1', WidgetType.FIELDS)]),
- ]);
- const fields = [createMockFieldMetadataItem('f1', 'Company')];
-
- const result = injectRelationWidgetsIntoLayout(layout, fields);
-
- const injectedWidget = result.tabs[0].widgets[1];
-
- expect(injectedWidget.type).toBe(WidgetType.FIELD);
- expect(injectedWidget.title).toBe('Company');
- expect(injectedWidget.pageLayoutTabId).toBe('tab-1');
- expect(injectedWidget.configuration).toEqual(
- expect.objectContaining({
- fieldMetadataId: 'f1',
- fieldDisplayMode: FieldDisplayMode.CARD,
- }),
- );
- });
-});
diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/isDynamicRelationWidget.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/isDynamicRelationWidget.test.ts
deleted file mode 100644
index 9247f5d535..0000000000
--- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/isDynamicRelationWidget.test.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
-import {
- DYNAMIC_RELATION_WIDGET_ID_PREFIX,
- isDynamicRelationWidget,
-} from '@/page-layout/utils/isDynamicRelationWidget';
-
-const makeWidget = (id: string): PageLayoutWidget =>
- ({
- id,
- title: 'Widget',
- type: 'FIELDS',
- pageLayoutTabId: 'tab-1',
- gridPosition: { row: 0, column: 0, rowSpan: 1, columnSpan: 1 },
- configuration: {},
- }) as PageLayoutWidget;
-
-describe('isDynamicRelationWidget', () => {
- it('should return true for a widget with the dynamic relation prefix', () => {
- const widget = makeWidget(
- `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}some-relation`,
- );
-
- expect(isDynamicRelationWidget(widget)).toBe(true);
- });
-
- it('should return false for a widget without the dynamic relation prefix', () => {
- const widget = makeWidget('regular-widget-id');
-
- expect(isDynamicRelationWidget(widget)).toBe(false);
- });
-
- it('should return false for a widget with a similar but different prefix', () => {
- const widget = makeWidget('dynamic-relation-other-widget-123');
-
- expect(isDynamicRelationWidget(widget)).toBe(false);
- });
-
- it('should return true for the prefix alone as id', () => {
- const widget = makeWidget(DYNAMIC_RELATION_WIDGET_ID_PREFIX);
-
- expect(isDynamicRelationWidget(widget)).toBe(true);
- });
-});
diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/reInjectDynamicRelationWidgetsFromDraft.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/reInjectDynamicRelationWidgetsFromDraft.test.ts
deleted file mode 100644
index 24ac8657b6..0000000000
--- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/reInjectDynamicRelationWidgetsFromDraft.test.ts
+++ /dev/null
@@ -1,194 +0,0 @@
-import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout';
-import { type PageLayout } from '@/page-layout/types/PageLayout';
-import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
-import { DYNAMIC_RELATION_WIDGET_ID_PREFIX } from '@/page-layout/utils/isDynamicRelationWidget';
-import { reInjectDynamicRelationWidgetsFromDraft } from '@/page-layout/utils/reInjectDynamicRelationWidgetsFromDraft';
-import { WidgetType } from '~/generated-metadata/graphql';
-
-const makeWidget = (
- overrides: Partial & { id: string },
-): PageLayoutWidget =>
- ({
- title: 'Widget',
- type: WidgetType.FIELDS,
- pageLayoutTabId: 'tab-1',
- gridPosition: { row: 0, column: 0, rowSpan: 1, columnSpan: 1 },
- configuration: {},
- ...overrides,
- }) as PageLayoutWidget;
-
-const makeDynamicRelationWidget = (suffix: string): PageLayoutWidget =>
- makeWidget({
- id: `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}${suffix}`,
- type: WidgetType.VIEW,
- title: `Dynamic Relation ${suffix}`,
- });
-
-const makePersistedLayout = (tabs: PageLayout['tabs']): PageLayout =>
- ({
- id: 'layout-1',
- name: 'Layout',
- type: 'RECORD_PAGE',
- createdAt: '2025-01-01',
- updatedAt: '2025-01-01',
- tabs,
- }) as PageLayout;
-
-const makeDraftLayout = (tabs: DraftPageLayout['tabs']): DraftPageLayout =>
- ({
- id: 'layout-1',
- name: 'Layout',
- type: 'RECORD_PAGE',
- tabs,
- }) as DraftPageLayout;
-
-const makeTab = (
- id: string,
- widgets: PageLayoutWidget[],
-): PageLayout['tabs'][number] =>
- ({
- id,
- title: 'Tab',
- position: 0,
- pageLayoutId: 'layout-1',
- applicationId: 'app-1',
- createdAt: '2025-01-01',
- updatedAt: '2025-01-01',
- widgets,
- }) as PageLayout['tabs'][number];
-
-describe('reInjectDynamicRelationWidgetsFromDraft', () => {
- it('should return persisted layout unchanged when draft has no dynamic widgets', () => {
- const persistedLayout = makePersistedLayout([
- makeTab('tab-1', [makeWidget({ id: 'w1' })]),
- ]);
- const draft = makeDraftLayout([
- makeTab('tab-1', [makeWidget({ id: 'w1' })]),
- ]);
-
- const result = reInjectDynamicRelationWidgetsFromDraft(
- persistedLayout,
- draft,
- );
-
- expect(result).toBe(persistedLayout);
- });
-
- it('should inject dynamic widgets after the first FIELDS widget', () => {
- const fieldsWidget = makeWidget({
- id: 'fields-1',
- type: WidgetType.FIELDS,
- });
- const timelineWidget = makeWidget({
- id: 'timeline-1',
- type: WidgetType.TIMELINE,
- });
- const dynamicWidget = makeDynamicRelationWidget('relation-1');
-
- const persistedLayout = makePersistedLayout([
- makeTab('tab-1', [fieldsWidget, timelineWidget]),
- ]);
- const draft = makeDraftLayout([
- makeTab('tab-1', [fieldsWidget, dynamicWidget, timelineWidget]),
- ]);
-
- const result = reInjectDynamicRelationWidgetsFromDraft(
- persistedLayout,
- draft,
- );
-
- expect(result.tabs[0].widgets).toHaveLength(3);
- expect(result.tabs[0].widgets[0].id).toBe('fields-1');
- expect(result.tabs[0].widgets[1].id).toBe(
- `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}relation-1`,
- );
- expect(result.tabs[0].widgets[2].id).toBe('timeline-1');
- });
-
- it('should append dynamic widgets if no FIELDS widget exists in the tab', () => {
- const timelineWidget = makeWidget({
- id: 'timeline-1',
- type: WidgetType.TIMELINE,
- });
- const dynamicWidget = makeDynamicRelationWidget('relation-1');
-
- const persistedLayout = makePersistedLayout([
- makeTab('tab-1', [timelineWidget]),
- ]);
- const draft = makeDraftLayout([
- makeTab('tab-1', [timelineWidget, dynamicWidget]),
- ]);
-
- const result = reInjectDynamicRelationWidgetsFromDraft(
- persistedLayout,
- draft,
- );
-
- expect(result.tabs[0].widgets).toHaveLength(2);
- expect(result.tabs[0].widgets[0].id).toBe('timeline-1');
- expect(result.tabs[0].widgets[1].id).toBe(
- `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}relation-1`,
- );
- });
-
- it('should handle multiple tabs independently', () => {
- const fieldsWidget1 = makeWidget({
- id: 'fields-1',
- type: WidgetType.FIELDS,
- });
- const fieldsWidget2 = makeWidget({
- id: 'fields-2',
- type: WidgetType.FIELDS,
- });
- const dynamicWidget = makeDynamicRelationWidget('rel-1');
-
- const persistedLayout = makePersistedLayout([
- makeTab('tab-1', [fieldsWidget1]),
- makeTab('tab-2', [fieldsWidget2]),
- ]);
- const draft = makeDraftLayout([
- makeTab('tab-1', [fieldsWidget1, dynamicWidget]),
- makeTab('tab-2', [fieldsWidget2]),
- ]);
-
- const result = reInjectDynamicRelationWidgetsFromDraft(
- persistedLayout,
- draft,
- );
-
- // Tab 1 should have dynamic widget injected
- expect(result.tabs[0].widgets).toHaveLength(2);
- // Tab 2 should remain unchanged
- expect(result.tabs[1].widgets).toHaveLength(1);
- });
-
- it('should inject multiple dynamic widgets', () => {
- const fieldsWidget = makeWidget({
- id: 'fields-1',
- type: WidgetType.FIELDS,
- });
- const dynamicWidget1 = makeDynamicRelationWidget('rel-1');
- const dynamicWidget2 = makeDynamicRelationWidget('rel-2');
-
- const persistedLayout = makePersistedLayout([
- makeTab('tab-1', [fieldsWidget]),
- ]);
- const draft = makeDraftLayout([
- makeTab('tab-1', [fieldsWidget, dynamicWidget1, dynamicWidget2]),
- ]);
-
- const result = reInjectDynamicRelationWidgetsFromDraft(
- persistedLayout,
- draft,
- );
-
- expect(result.tabs[0].widgets).toHaveLength(3);
- expect(result.tabs[0].widgets[0].id).toBe('fields-1');
- expect(result.tabs[0].widgets[1].id).toBe(
- `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}rel-1`,
- );
- expect(result.tabs[0].widgets[2].id).toBe(
- `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}rel-2`,
- );
- });
-});
diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/shouldEnableTabEditingFeatures.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/shouldEnableTabEditingFeatures.test.ts
index 7ba93cebb1..502f5fe30e 100644
--- a/packages/twenty-front/src/modules/page-layout/utils/__tests__/shouldEnableTabEditingFeatures.test.ts
+++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/shouldEnableTabEditingFeatures.test.ts
@@ -14,61 +14,13 @@ describe('shouldEnableTabEditingFeatures', () => {
expect(result).toBe(true);
});
- it('should return false for RECORD_PAGE layout type without flag', () => {
+ it('should return true for RECORD_PAGE layout type', () => {
const result = shouldEnableTabEditingFeatures(PageLayoutType.RECORD_PAGE);
- expect(result).toBe(false);
- });
-
- it('should return true for RECORD_PAGE layout type with flag enabled', () => {
- const result = shouldEnableTabEditingFeatures(
- PageLayoutType.RECORD_PAGE,
- true,
- );
expect(result).toBe(true);
});
- it('should return false for RECORD_PAGE layout type with flag disabled', () => {
- const result = shouldEnableTabEditingFeatures(
- PageLayoutType.RECORD_PAGE,
- false,
- );
- expect(result).toBe(false);
- });
-
it('should return false for RECORD_INDEX layout type', () => {
const result = shouldEnableTabEditingFeatures(PageLayoutType.RECORD_INDEX);
expect(result).toBe(false);
});
-
- it('should return false for RECORD_INDEX layout type even with flag', () => {
- const result = shouldEnableTabEditingFeatures(
- PageLayoutType.RECORD_INDEX,
- true,
- );
- expect(result).toBe(false);
- });
-
- describe('behavior validation', () => {
- it('should enable tab editing features only for dashboards, standalone pages, and record pages with flag', () => {
- expect(shouldEnableTabEditingFeatures(PageLayoutType.DASHBOARD)).toBe(
- true,
- );
-
- expect(
- shouldEnableTabEditingFeatures(PageLayoutType.STANDALONE_PAGE),
- ).toBe(true);
-
- expect(shouldEnableTabEditingFeatures(PageLayoutType.RECORD_PAGE)).toBe(
- false,
- );
-
- expect(
- shouldEnableTabEditingFeatures(PageLayoutType.RECORD_PAGE, true),
- ).toBe(true);
-
- expect(shouldEnableTabEditingFeatures(PageLayoutType.RECORD_INDEX)).toBe(
- false,
- );
- });
- });
});
diff --git a/packages/twenty-front/src/modules/page-layout/utils/convertPageLayoutDraftToUpdateInput.ts b/packages/twenty-front/src/modules/page-layout/utils/convertPageLayoutDraftToUpdateInput.ts
index eeb990c31e..a862b81dd7 100644
--- a/packages/twenty-front/src/modules/page-layout/utils/convertPageLayoutDraftToUpdateInput.ts
+++ b/packages/twenty-front/src/modules/page-layout/utils/convertPageLayoutDraftToUpdateInput.ts
@@ -1,6 +1,5 @@
import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout';
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
-import { isDynamicRelationWidget } from '@/page-layout/utils/isDynamicRelationWidget';
import {
PageLayoutTabLayoutMode,
type UpdatePageLayoutWithTabsInput,
@@ -40,10 +39,7 @@ const buildWidgetPosition = (
export const convertPageLayoutDraftToUpdateInput = (
pageLayoutDraft: DraftPageLayout,
- options?: { shouldFilterDynamicRelationWidgets?: boolean },
): UpdatePageLayoutWithTabsInput => {
- const shouldFilter = options?.shouldFilterDynamicRelationWidgets ?? false;
-
return {
name: pageLayoutDraft.name,
type: pageLayoutDraft.type,
@@ -51,17 +47,13 @@ export const convertPageLayoutDraftToUpdateInput = (
tabs: pageLayoutDraft.tabs
.filter((tab) => tab.isActive)
.map((tab) => {
- const widgets = shouldFilter
- ? tab.widgets.filter((widget) => !isDynamicRelationWidget(widget))
- : tab.widgets;
-
return {
id: tab.id,
title: tab.title,
position: tab.position,
icon: tab.icon ?? null,
layoutMode: tab.layoutMode,
- widgets: widgets.map((widget, widgetIndex) => ({
+ widgets: tab.widgets.map((widget, widgetIndex) => ({
id: widget.id,
pageLayoutTabId: widget.pageLayoutTabId,
title: widget.title,
diff --git a/packages/twenty-front/src/modules/page-layout/utils/injectRelationWidgetsIntoLayout.ts b/packages/twenty-front/src/modules/page-layout/utils/injectRelationWidgetsIntoLayout.ts
deleted file mode 100644
index 71d229326f..0000000000
--- a/packages/twenty-front/src/modules/page-layout/utils/injectRelationWidgetsIntoLayout.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
-import { type PageLayout } from '@/page-layout/types/PageLayout';
-import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
-import { DYNAMIC_RELATION_WIDGET_ID_PREFIX } from '@/page-layout/utils/isDynamicRelationWidget';
-import { isDefined } from 'twenty-shared/utils';
-import {
- FieldDisplayMode,
- PageLayoutTabLayoutMode,
- WidgetConfigurationType,
- WidgetType,
-} from '~/generated-metadata/graphql';
-
-const getRelationFieldWidgetToInsert = (
- field: FieldMetadataItem,
- tabId: string,
-): PageLayoutWidget => ({
- __typename: 'PageLayoutWidget' as const,
- id: `${DYNAMIC_RELATION_WIDGET_ID_PREFIX}${field.id}-${field.label}`,
- applicationId: '',
- pageLayoutTabId: tabId,
- title: field.label,
- isActive: true,
- type: WidgetType.FIELD,
- objectMetadataId: null,
- gridPosition: {
- __typename: 'GridPosition' as const,
- row: 0,
- column: 0,
- rowSpan: 1,
- columnSpan: 12,
- },
- position: {
- __typename: 'PageLayoutWidgetGridPosition' as const,
- layoutMode: PageLayoutTabLayoutMode.GRID,
- row: 0,
- column: 0,
- rowSpan: 1,
- columnSpan: 12,
- },
- configuration: {
- __typename: 'FieldConfiguration' as const,
- configurationType: WidgetConfigurationType.FIELD,
- fieldMetadataId: field.id,
- fieldDisplayMode: FieldDisplayMode.CARD,
- },
- createdAt: '2024-01-01T00:00:00.000Z',
- updatedAt: '2024-01-01T00:00:00.000Z',
- deletedAt: null,
-});
-
-const getRelationFieldWidgetsToInsert = (
- relationFields: FieldMetadataItem[],
- tabId: string,
-): PageLayoutWidget[] => {
- return relationFields.map((field) =>
- getRelationFieldWidgetToInsert(field, tabId),
- );
-};
-
-export const injectRelationWidgetsIntoLayout = (
- layout: PageLayout,
- boxedRelationFieldMetadataItems: FieldMetadataItem[],
-): PageLayout => {
- if (boxedRelationFieldMetadataItems.length === 0) {
- return layout;
- }
-
- const firstTab = layout.tabs[0];
- if (!isDefined(firstTab)) {
- return layout;
- }
-
- const relationWidgets = getRelationFieldWidgetsToInsert(
- boxedRelationFieldMetadataItems,
- firstTab.id,
- );
-
- return {
- ...layout,
- tabs: layout.tabs.map((tab) => {
- if (tab.id === firstTab.id) {
- const firstFieldsWidgetIndex = tab.widgets.findIndex(
- (widget) => widget.type === WidgetType.FIELDS,
- );
-
- if (firstFieldsWidgetIndex === -1) {
- return {
- ...tab,
- widgets: [...tab.widgets, ...relationWidgets],
- };
- }
-
- // TODO: This note widget repositioning logic is temporary and will be deleted soon.
- // We need this to ensure the note editor is displayed before record relations,
- // matching the behavior of the old show page.
- const noteWidgetIndex = tab.widgets.findIndex(
- (widget) => widget.type === WidgetType.NOTES,
- );
-
- const widgetsBeforeRelation = tab.widgets.slice(
- 0,
- firstFieldsWidgetIndex + 1,
- );
- const widgetsAfterRelation =
- noteWidgetIndex === -1
- ? tab.widgets.slice(firstFieldsWidgetIndex + 1)
- : [
- ...tab.widgets.slice(
- firstFieldsWidgetIndex + 1,
- noteWidgetIndex,
- ),
- ...tab.widgets.slice(noteWidgetIndex + 1),
- ];
-
- const noteWidget =
- noteWidgetIndex !== -1 ? [tab.widgets[noteWidgetIndex]] : [];
-
- return {
- ...tab,
- widgets: [
- ...widgetsBeforeRelation,
- ...relationWidgets,
- ...noteWidget,
- ...widgetsAfterRelation,
- ],
- };
- }
- return tab;
- }),
- };
-};
diff --git a/packages/twenty-front/src/modules/page-layout/utils/isDynamicRelationWidget.ts b/packages/twenty-front/src/modules/page-layout/utils/isDynamicRelationWidget.ts
deleted file mode 100644
index 4ed4a6fc10..0000000000
--- a/packages/twenty-front/src/modules/page-layout/utils/isDynamicRelationWidget.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
-
-export const DYNAMIC_RELATION_WIDGET_ID_PREFIX = 'dynamic-relation-widget-';
-
-export const isDynamicRelationWidget = (widget: PageLayoutWidget): boolean => {
- return widget.id.startsWith(DYNAMIC_RELATION_WIDGET_ID_PREFIX);
-};
diff --git a/packages/twenty-front/src/modules/page-layout/utils/reInjectDynamicRelationWidgetsFromDraft.ts b/packages/twenty-front/src/modules/page-layout/utils/reInjectDynamicRelationWidgetsFromDraft.ts
deleted file mode 100644
index 5ada10f484..0000000000
--- a/packages/twenty-front/src/modules/page-layout/utils/reInjectDynamicRelationWidgetsFromDraft.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout';
-import { type PageLayout } from '@/page-layout/types/PageLayout';
-import { isDynamicRelationWidget } from '@/page-layout/utils/isDynamicRelationWidget';
-import { WidgetType } from '~/generated-metadata/graphql';
-
-export const reInjectDynamicRelationWidgetsFromDraft = (
- persistedLayout: PageLayout,
- previousDraft: DraftPageLayout,
-): PageLayout => {
- const dynamicWidgetsByTabId = new Map(
- previousDraft.tabs.map((tab) => [
- tab.id,
- tab.widgets.filter(isDynamicRelationWidget),
- ]),
- );
-
- const hasDynamicWidgets = [...dynamicWidgetsByTabId.values()].some(
- (widgets) => widgets.length > 0,
- );
-
- if (!hasDynamicWidgets) {
- return persistedLayout;
- }
-
- return {
- ...persistedLayout,
- tabs: persistedLayout.tabs.map((tab) => {
- const relationWidgets = dynamicWidgetsByTabId.get(tab.id);
-
- if (!relationWidgets || relationWidgets.length === 0) {
- return tab;
- }
-
- const firstFieldsWidgetIndex = tab.widgets.findIndex(
- (widget) => widget.type === WidgetType.FIELDS,
- );
-
- if (firstFieldsWidgetIndex === -1) {
- return {
- ...tab,
- widgets: [...tab.widgets, ...relationWidgets],
- };
- }
-
- const widgetsBefore = tab.widgets.slice(0, firstFieldsWidgetIndex + 1);
- const widgetsAfter = tab.widgets.slice(firstFieldsWidgetIndex + 1);
-
- return {
- ...tab,
- widgets: [...widgetsBefore, ...relationWidgets, ...widgetsAfter],
- };
- }),
- };
-};
diff --git a/packages/twenty-front/src/modules/page-layout/utils/shouldEnableTabEditingFeatures.ts b/packages/twenty-front/src/modules/page-layout/utils/shouldEnableTabEditingFeatures.ts
index 724d32df2d..e006818d2b 100644
--- a/packages/twenty-front/src/modules/page-layout/utils/shouldEnableTabEditingFeatures.ts
+++ b/packages/twenty-front/src/modules/page-layout/utils/shouldEnableTabEditingFeatures.ts
@@ -2,21 +2,10 @@ import { PageLayoutType } from '~/generated-metadata/graphql';
export const shouldEnableTabEditingFeatures = (
pageLayoutType: PageLayoutType,
- isRecordPageGlobalEditionEnabled?: boolean,
): boolean => {
- if (
+ return (
pageLayoutType === PageLayoutType.DASHBOARD ||
- pageLayoutType === PageLayoutType.STANDALONE_PAGE
- ) {
- return true;
- }
-
- if (
- pageLayoutType === PageLayoutType.RECORD_PAGE &&
- isRecordPageGlobalEditionEnabled
- ) {
- return true;
- }
-
- return false;
+ pageLayoutType === PageLayoutType.STANDALONE_PAGE ||
+ pageLayoutType === PageLayoutType.RECORD_PAGE
+ );
};
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/RecordPageWidgetRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/RecordPageWidgetRenderer.tsx
index 2576c0d56e..3bb4166a34 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/components/RecordPageWidgetRenderer.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/components/RecordPageWidgetRenderer.tsx
@@ -2,18 +2,6 @@ import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
import { WidgetCardShell } from '@/page-layout/widgets/components/WidgetCardShell';
import { useWidgetActions } from '@/page-layout/widgets/hooks/useWidgetActions';
import { useWidgetRendererState } from '@/page-layout/widgets/hooks/useWidgetRendererState';
-import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
-import { styled } from '@linaria/react';
-import { themeCssVariables } from 'twenty-ui/theme-constants';
-import {
- FeatureFlagKey,
- PageLayoutType,
- WidgetType,
-} from '~/generated-metadata/graphql';
-
-const StyledEditingWidgetWrapper = styled.div`
- padding: ${themeCssVariables.spacing[2]};
-`;
type RecordPageWidgetRendererProps = {
widget: PageLayoutWidget;
@@ -24,39 +12,13 @@ export const RecordPageWidgetRenderer = ({
}: RecordPageWidgetRendererProps) => {
const state = useWidgetRendererState(widget);
- const isRecordPageGlobalEditionEnabled = useIsFeatureEnabled(
- FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED,
- );
-
- const isRecordPageLayout =
- state.currentPageLayout.type === PageLayoutType.RECORD_PAGE;
-
- const isReorderEnabled =
- !isRecordPageLayout ||
- (isRecordPageLayout && isRecordPageGlobalEditionEnabled);
-
- const isDeletingWidgetEnabled =
- !isRecordPageLayout ||
- (isRecordPageLayout && isRecordPageGlobalEditionEnabled);
-
- const isWidgetEditable =
- state.isPageLayoutInEditMode &&
- (!isRecordPageLayout ||
- (isRecordPageLayout && isRecordPageGlobalEditionEnabled) ||
- widget.type === WidgetType.FIELDS ||
- widget.type === WidgetType.FIELD);
+ const isWidgetEditable = state.isPageLayoutInEditMode;
const actions = useWidgetActions({ widget });
- // TODO: remove once all record page layouts widgets use the editable contain in edit mode
- const shouldWrapWithEditingWrapper =
- isWidgetEditable &&
- state.variant === 'side-column' &&
- !isRecordPageGlobalEditionEnabled;
-
const isCanvasVariant = state.variant === 'canvas';
- const shell = (
+ return (
);
-
- if (shouldWrapWithEditingWrapper) {
- return {shell};
- }
-
- return shell;
};
diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx
index 8bb52491ce..d6057dd77e 100644
--- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx
+++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx
@@ -81,9 +81,6 @@ export const SettingsObjectDetailPage = () => {
const isUniqueIndexesEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_UNIQUE_INDEXES_ENABLED,
);
- const isRecordPageLayoutEditingEnabled = useIsFeatureEnabled(
- FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED,
- );
const [isDeleting, setIsDeleting] = useState(false);
@@ -123,7 +120,6 @@ export const SettingsObjectDetailPage = () => {
title: t`Layout`,
Icon: IconLayout,
hide:
- !isRecordPageLayoutEditingEnabled ||
objectMetadataItem.isRemote ||
objectMetadataItem.nameSingular === CoreObjectNameSingular.Dashboard,
},
diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-23/1-23-workspace-command-1780000001500-backfill-record-page-layouts.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-23/1-23-workspace-command-1780000001500-backfill-record-page-layouts.command.ts
index 3be428364a..2e5f185049 100644
--- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-23/1-23-workspace-command-1780000001500-backfill-record-page-layouts.command.ts
+++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-23/1-23-workspace-command-1780000001500-backfill-record-page-layouts.command.ts
@@ -1,5 +1,5 @@
import { Command } from 'nest-commander';
-import { FeatureFlagKey, ViewType } from 'twenty-shared/types';
+import { type FeatureFlagKey, ViewType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { ActiveOrSuspendedWorkspaceCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspace.command-runner';
@@ -47,7 +47,7 @@ export class BackfillRecordPageLayoutsCommand extends ActiveOrSuspendedWorkspace
const isDryRun = options.dryRun ?? false;
const isAlreadyEnabled = await this.featureFlagService.isFeatureEnabled(
- FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED,
+ 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' as FeatureFlagKey,
workspaceId,
);
@@ -88,12 +88,12 @@ export class BackfillRecordPageLayoutsCommand extends ActiveOrSuspendedWorkspace
});
await this.featureFlagService.enableFeatureFlags(
- [FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED],
+ ['IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' as FeatureFlagKey],
workspaceId,
);
await this.featureFlagService.enableFeatureFlags(
- [FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED],
+ ['IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' as FeatureFlagKey],
workspaceId,
);
diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata.service.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata.service.ts
index d3caadf63a..fd923c6c8d 100644
--- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata.service.ts
+++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata.service.ts
@@ -2,7 +2,6 @@ import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
-import { FeatureFlagKey } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { type FindOneOptions, type Repository } from 'typeorm';
@@ -378,7 +377,6 @@ export class FieldMetadataService extends TypeOrmQueryService ({
objectMetadataUniversalIdentifier:
flatFieldMetadata.objectMetadataUniversalIdentifier,
@@ -445,7 +435,6 @@ export class FieldMetadataService extends TypeOrmQueryService {
IS_UNIQUE_INDEXES_ENABLED: false,
IS_JSON_FILTER_ENABLED: false,
IS_MARKETPLACE_SETTING_TAB_VISIBLE: false,
- IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: false,
IS_PUBLIC_DOMAIN_ENABLED: false,
IS_EMAILING_DOMAIN_ENABLED: false,
IS_EMAIL_GROUP_ENABLED: false,
IS_JUNCTION_RELATIONS_ENABLED: false,
- IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: false,
IS_REST_METADATA_API_NEW_FORMAT_DIRECT: false,
},
userWorkspaceRoleMap: {},
diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts
index de6091ac8f..61aab31f57 100644
--- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts
+++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts
@@ -50,16 +50,6 @@ export const seedFeatureFlags = async ({
workspaceId: workspaceId,
value: true,
},
- {
- key: FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED,
- workspaceId: workspaceId,
- value: true,
- },
- {
- key: FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED,
- workspaceId: workspaceId,
- value: true,
- },
])
.execute();
};
diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-command-menu-item.constant.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-command-menu-item.constant.ts
index c66087e504..38cebc58df 100644
--- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-command-menu-item.constant.ts
+++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-command-menu-item.constant.ts
@@ -264,7 +264,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
shortLabel: 'Edit Layout',
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
conditionalAvailabilityExpression:
- 'pageType == "RECORD_PAGE" and featureFlags.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED and not isLayoutCustomizationModeEnabled and noneDefined(selectedRecords, "deletedAt") and objectPermissions.canUpdateObjectRecords and objectMetadataItem.nameSingular != "dashboard"',
+ 'pageType == "RECORD_PAGE" and not isLayoutCustomizationModeEnabled and noneDefined(selectedRecords, "deletedAt") and objectPermissions.canUpdateObjectRecords and objectMetadataItem.nameSingular != "dashboard"',
availabilityObjectMetadataUniversalIdentifier: null,
frontComponentUniversalIdentifier: null,
engineComponentKey: EngineComponentKey.EDIT_RECORD_PAGE_LAYOUT,
diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/default-feature-flags.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/default-feature-flags.ts
index 33b1242039..a6e31f106e 100644
--- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/default-feature-flags.ts
+++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/default-feature-flags.ts
@@ -1,7 +1,5 @@
import { FeatureFlagKey } from 'twenty-shared/types';
export const DEFAULT_FEATURE_FLAGS = [
- FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED,
- FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED,
FeatureFlagKey.IS_REST_METADATA_API_NEW_FORMAT_DIRECT,
] as const satisfies FeatureFlagKey[];
diff --git a/packages/twenty-shared/src/types/FeatureFlagKey.ts b/packages/twenty-shared/src/types/FeatureFlagKey.ts
index be20bb1247..064b016666 100644
--- a/packages/twenty-shared/src/types/FeatureFlagKey.ts
+++ b/packages/twenty-shared/src/types/FeatureFlagKey.ts
@@ -2,11 +2,9 @@ export enum FeatureFlagKey {
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
IS_MARKETPLACE_SETTING_TAB_VISIBLE = 'IS_MARKETPLACE_SETTING_TAB_VISIBLE',
- IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
IS_EMAILING_DOMAIN_ENABLED = 'IS_EMAILING_DOMAIN_ENABLED',
IS_EMAIL_GROUP_ENABLED = 'IS_EMAIL_GROUP_ENABLED',
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',
- IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED',
IS_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT',
}