Remove the code of old show pages (#17811)

Closes https://github.com/twentyhq/core-team-issues/issues/2213
This commit is contained in:
Baptiste Devessier
2026-02-10 10:10:00 +01:00
committed by GitHub
parent 2d42b0a726
commit b250de216e
36 changed files with 10 additions and 1265 deletions
@@ -1500,7 +1500,6 @@ export enum FeatureFlagKey {
IS_NOTE_TARGET_MIGRATED = 'IS_NOTE_TARGET_MIGRATED',
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
IS_RECORD_PAGE_LAYOUT_ENABLED = 'IS_RECORD_PAGE_LAYOUT_ENABLED',
IS_SSE_DB_EVENTS_ENABLED = 'IS_SSE_DB_EVENTS_ENABLED',
IS_TASK_TARGET_MIGRATED = 'IS_TASK_TARGET_MIGRATED',
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED'
@@ -1472,7 +1472,6 @@ export enum FeatureFlagKey {
IS_NOTE_TARGET_MIGRATED = 'IS_NOTE_TARGET_MIGRATED',
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
IS_RECORD_PAGE_LAYOUT_ENABLED = 'IS_RECORD_PAGE_LAYOUT_ENABLED',
IS_SSE_DB_EVENTS_ENABLED = 'IS_SSE_DB_EVENTS_ENABLED',
IS_TASK_TARGET_MIGRATED = 'IS_TASK_TARGET_MIGRATED',
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED'
@@ -60,7 +60,6 @@ export const CommandMenuCalendarEventPage = () => {
},
layoutType: PageLayoutType.RECORD_PAGE,
isInRightDrawer: true,
isLegacyRecordShowPage: true,
}}
>
<CalendarEventDetailsEffect record={calendarEvent} />
@@ -6,7 +6,7 @@ import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/c
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
import { INFORMATION_BANNER_HEIGHT } from '@/information-banner/constants/InformationBannerHeight';
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
import { PageLayoutDispatcher } from '@/object-record/record-show/components/PageLayoutDispatcher';
import { PageLayoutRecordPageRenderer } from '@/object-record/record-show/components/PageLayoutRecordPageRenderer';
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
@@ -80,7 +80,7 @@ export const CommandMenuRecordPage = () => {
recordId: objectRecordId,
}}
>
<PageLayoutDispatcher
<PageLayoutRecordPageRenderer
targetRecordIdentifier={{
id: objectRecordId,
targetObjectNameSingular: objectNameSingular,
@@ -23,9 +23,6 @@ type RecordDetailRecordsListItemContainerProps = {
className?: string;
};
/**
* TODO: Remove noHorizontalPadding logic once the traditional record show page is removed.
*/
export const RecordDetailRecordsListItemContainer = ({
children,
className,
@@ -33,8 +30,7 @@ export const RecordDetailRecordsListItemContainer = ({
const layoutRenderingContext = useLayoutRenderingContext();
const isInRecordPageLayout =
layoutRenderingContext?.layoutType === PageLayoutType.RECORD_PAGE &&
!layoutRenderingContext?.isLegacyRecordShowPage;
layoutRenderingContext?.layoutType === PageLayoutType.RECORD_PAGE;
return (
<StyledListItem
@@ -28,8 +28,6 @@ const meta: Meta<typeof RecordDetailDuplicatesSection> = {
},
layoutType: PageLayoutType.RECORD_PAGE,
isInRightDrawer: false,
// TODO: Remove once the traditional record show page is removed.
isLegacyRecordShowPage: true,
}}
>
<Story />
@@ -43,8 +43,6 @@ const meta: Meta<typeof RecordDetailRelationSection> = {
},
layoutType: PageLayoutType.RECORD_PAGE,
isInRightDrawer: false,
// TODO: Remove once the traditional record show page is removed.
isLegacyRecordShowPage: true,
}}
>
<ContextStoreComponentInstanceContext.Provider
@@ -26,9 +26,6 @@ const StyledPropertyBoxContainer = styled('div', {
noHorizontalPadding ? 0 : theme.spacing(2)};
`;
/**
* TODO: Remove noHorizontalPadding logic once the traditional record show page is removed.
*/
export const PropertyBox = ({
children,
className,
@@ -37,8 +34,7 @@ export const PropertyBox = ({
const layoutRenderingContext = useLayoutRenderingContext();
const isInRecordPageLayout =
layoutRenderingContext.layoutType === PageLayoutType.RECORD_PAGE &&
!layoutRenderingContext.isLegacyRecordShowPage;
layoutRenderingContext.layoutType === PageLayoutType.RECORD_PAGE;
return (
<StyledPropertyBoxContainer
@@ -1,62 +0,0 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { PageLayoutRecordPageRenderer } from '@/object-record/record-show/components/PageLayoutRecordPageRenderer';
import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer';
import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect';
import { LayoutRenderingProvider } from '@/ui/layout/contexts/LayoutRenderingContext';
import { type TargetRecordIdentifier } from '@/ui/layout/contexts/TargetRecordIdentifier';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { FeatureFlagKey, PageLayoutType } from '~/generated/graphql';
export const PageLayoutDispatcher = ({
targetRecordIdentifier,
isInRightDrawer = false,
}: {
targetRecordIdentifier: TargetRecordIdentifier;
isInRightDrawer?: boolean;
}) => {
const isRecordPageEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED,
);
if (
targetRecordIdentifier.targetObjectNameSingular ===
CoreObjectNameSingular.Dashboard ||
isRecordPageEnabled
) {
return (
<PageLayoutRecordPageRenderer
targetRecordIdentifier={targetRecordIdentifier}
isInRightDrawer={isInRightDrawer}
/>
);
}
return (
<>
<RecordShowEffect
objectNameSingular={targetRecordIdentifier.targetObjectNameSingular}
recordId={targetRecordIdentifier.id}
/>
<LayoutRenderingProvider
value={{
targetRecordIdentifier: {
id: targetRecordIdentifier.id,
targetObjectNameSingular:
targetRecordIdentifier.targetObjectNameSingular,
},
layoutType: PageLayoutType.RECORD_PAGE,
isInRightDrawer,
// TODO: Remove once the traditional record show page is removed.
isLegacyRecordShowPage: true,
}}
>
<RecordShowContainer
objectNameSingular={targetRecordIdentifier.targetObjectNameSingular}
objectRecordId={targetRecordIdentifier.id}
isInRightDrawer={isInRightDrawer}
/>
</LayoutRenderingProvider>
</>
);
};
@@ -1,79 +0,0 @@
import { type CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { ShowPageContainer } from '@/ui/layout/page/components/ShowPageContainer';
import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { RecordShowContainerContextStoreTargetedRecordsEffect } from '@/object-record/record-show/components/RecordShowContainerContextStoreTargetedRecordsEffect';
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
import { useRecordShowContainerTabs } from '@/object-record/record-show/hooks/useRecordShowContainerTabs';
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
import { ShowPageSubContainer } from '@/ui/layout/show-page/components/ShowPageSubContainer';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
const StyledShowPageBannerContainer = styled.div`
z-index: 1;
`;
type RecordShowContainerProps = {
objectNameSingular: string;
objectRecordId: string;
isInRightDrawer?: boolean;
};
export const RecordShowContainer = ({
objectNameSingular,
objectRecordId,
isInRightDrawer = false,
}: RecordShowContainerProps) => {
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular,
});
const { isPrefetchLoading, recordLoading } = useRecordShowContainerData({
objectRecordId,
});
const recordDeletedAt = useRecoilValue<string | null>(
recordStoreFamilySelector({
recordId: objectRecordId,
fieldName: 'deletedAt',
}),
);
const { layout, tabs } = useRecordShowContainerTabs(
objectNameSingular as CoreObjectNameSingular,
isInRightDrawer,
objectMetadataItem,
);
return (
<RightDrawerProvider value={{ isInRightDrawer }}>
<RecordShowContainerContextStoreTargetedRecordsEffect
recordId={objectRecordId}
/>
{recordDeletedAt && (
<StyledShowPageBannerContainer>
<InformationBannerDeletedRecord
recordId={objectRecordId}
objectNameSingular={objectNameSingular}
/>
</StyledShowPageBannerContainer>
)}
<ShowPageContainer>
<ShowPageSubContainer
tabs={tabs}
layout={layout}
targetRecordIdentifier={{
id: objectRecordId,
targetObjectNameSingular: objectMetadataItem?.nameSingular,
}}
isInRightDrawer={isInRightDrawer}
loading={isPrefetchLoading || recordLoading}
/>
</ShowPageContainer>
</RightDrawerProvider>
);
};
@@ -1,131 +0,0 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { BASE_RECORD_LAYOUT } from '@/object-record/record-show/layouts/base-record-layout';
import { COMPANY_RECORD_LAYOUT } from '@/object-record/record-show/layouts/company-record-layout';
import { NOTE_RECORD_LAYOUT } from '@/object-record/record-show/layouts/note-record-layout';
import { OPPORTUNITY_RECORD_LAYOUT } from '@/object-record/record-show/layouts/opportunity-record-layout';
import { PERSON_RECORD_LAYOUT } from '@/object-record/record-show/layouts/person-record-layout';
import { TASK_RECORD_LAYOUT } from '@/object-record/record-show/layouts/task-record-layout';
import { WORKFLOW_RECORD_LAYOUT } from '@/object-record/record-show/layouts/workflow-record-layout';
import { WORKFLOW_RUN_RECORD_LAYOUT } from '@/object-record/record-show/layouts/workflow-run-record-layout';
import { WORKFLOW_VERSION_RECORD_LAYOUT } from '@/object-record/record-show/layouts/workflow-version-record-layout';
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
import { evaluateTabVisibility } from '@/object-record/record-show/utils/evaluateTabVisibility';
import { type RecordLayoutTab } from '@/ui/layout/tab-list/types/RecordLayoutTab';
import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { useLingui } from '@lingui/react/macro';
import { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import { IconHome, useIcons } from 'twenty-ui/display';
// Object-specific layouts that override or extend the base layout
const OBJECT_SPECIFIC_LAYOUTS: Partial<
Record<CoreObjectNameSingular, RecordLayout>
> = {
[CoreObjectNameSingular.Note]: NOTE_RECORD_LAYOUT,
[CoreObjectNameSingular.Task]: TASK_RECORD_LAYOUT,
[CoreObjectNameSingular.Company]: COMPANY_RECORD_LAYOUT,
[CoreObjectNameSingular.Person]: PERSON_RECORD_LAYOUT,
[CoreObjectNameSingular.Opportunity]: OPPORTUNITY_RECORD_LAYOUT,
[CoreObjectNameSingular.Workflow]: WORKFLOW_RECORD_LAYOUT,
[CoreObjectNameSingular.WorkflowVersion]: WORKFLOW_VERSION_RECORD_LAYOUT,
[CoreObjectNameSingular.WorkflowRun]: WORKFLOW_RUN_RECORD_LAYOUT,
};
export const useRecordShowContainerTabs = (
targetObjectNameSingular: CoreObjectNameSingular,
isInRightDrawer: boolean,
objectMetadataItem: ObjectMetadataItem,
): { layout: RecordLayout; tabs: SingleTabProps[] } => {
const { t } = useLingui();
const isMobile = useIsMobile();
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const { getIcon } = useIcons();
// Merge base layout with object-specific layout
const recordLayout: RecordLayout = useMemo(() => {
return {
...BASE_RECORD_LAYOUT,
...(OBJECT_SPECIFIC_LAYOUTS[targetObjectNameSingular] || {}),
tabs: {
...BASE_RECORD_LAYOUT.tabs,
...(OBJECT_SPECIFIC_LAYOUTS[targetObjectNameSingular]?.tabs || {}),
},
};
}, [targetObjectNameSingular]);
return {
layout: recordLayout,
tabs: Object.entries(recordLayout.tabs)
.filter(
(entry): entry is [string, NonNullable<RecordLayoutTab>] =>
entry[1] !== null && entry[1] !== undefined,
)
.sort(([, a], [, b]) => a.position - b.position)
.map(([key, { title, icon, hide, cards }]) => {
const Icon = getIcon(icon);
// Special handling for fields tab
if (key === 'fields') {
return {
id: key,
title,
Icon,
cards,
hide:
!(isMobile || isInRightDrawer) ||
recordLayout.hideFieldsInSidePanel,
};
}
// Use extracted visibility evaluation logic
const shouldHide = evaluateTabVisibility(hide, {
isMobile,
isInRightDrawer,
currentWorkspace,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
targetObjectMetadataItem: objectMetadataItem,
});
return {
id: key,
title,
Icon,
cards,
hide: shouldHide,
};
})
// When isInRightDrawer === true, we merge first and second tab into first tab
.reduce<SingleTabProps[]>((acc, tab, index, array) => {
if (isInRightDrawer && array.length > 1) {
if (index === 0) {
return [
...acc,
{
id: 'home',
title: t`Home`,
Icon: IconHome,
cards: [
...(tab.hide ? [] : tab.cards),
...(array[1].hide ? [] : array[1].cards),
],
hide: false,
},
];
}
if (index === 1) {
return acc;
}
}
return [...acc, tab];
}, []),
};
};
@@ -1,82 +0,0 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { CardType } from '@/object-record/record-show/types/CardType';
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
export const BASE_RECORD_LAYOUT: RecordLayout = {
tabs: {
fields: {
title: 'Fields',
icon: 'IconList',
position: 100,
cards: [{ type: CardType.FieldCard }],
hide: {
ifMobile: false,
ifDesktop: true,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
timeline: {
title: 'Timeline',
icon: 'IconTimelineEvent',
position: 200,
cards: [{ type: CardType.TimelineCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: true,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
tasks: {
title: 'Tasks',
icon: 'IconCheckbox',
position: 300,
cards: [{ type: CardType.TaskCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [CoreObjectNameSingular.Task],
ifRelationsMissing: ['taskTargets'],
ifNoReadPermission: true,
ifNoReadPermissionObject: CoreObjectNameSingular.Task,
},
},
notes: {
title: 'Notes',
icon: 'IconNotes',
position: 400,
cards: [{ type: CardType.NoteCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [CoreObjectNameSingular.Note],
ifRelationsMissing: ['noteTargets'],
ifNoReadPermission: true,
ifNoReadPermissionObject: CoreObjectNameSingular.Note,
},
},
files: {
title: 'Files',
icon: 'IconPaperclip',
position: 500,
cards: [{ type: CardType.FileCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [CoreObjectNameSingular.Attachment],
ifRelationsMissing: ['attachments'],
},
},
},
};
@@ -1,35 +0,0 @@
import { CardType } from '@/object-record/record-show/types/CardType';
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
export const COMPANY_RECORD_LAYOUT: RecordLayout = {
tabs: {
emails: {
title: 'Emails',
position: 600,
icon: 'IconMail',
cards: [{ type: CardType.EmailCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
calendar: {
title: 'Calendar',
position: 700,
icon: 'IconCalendarEvent',
cards: [{ type: CardType.CalendarCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
},
};
@@ -1,23 +0,0 @@
import { CardType } from '@/object-record/record-show/types/CardType';
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
export const NOTE_RECORD_LAYOUT: RecordLayout = {
tabs: {
richText: {
title: 'Note',
position: 101,
icon: 'IconNotes',
cards: [{ type: CardType.FieldRichTextCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
tasks: null,
notes: null,
},
};
@@ -1,35 +0,0 @@
import { CardType } from '@/object-record/record-show/types/CardType';
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
export const OPPORTUNITY_RECORD_LAYOUT: RecordLayout = {
tabs: {
emails: {
title: 'Emails',
position: 600,
icon: 'IconMail',
cards: [{ type: CardType.EmailCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
calendar: {
title: 'Calendar',
position: 700,
icon: 'IconCalendarEvent',
cards: [{ type: CardType.CalendarCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
},
};
@@ -1,35 +0,0 @@
import { CardType } from '@/object-record/record-show/types/CardType';
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
export const PERSON_RECORD_LAYOUT: RecordLayout = {
tabs: {
emails: {
title: 'Emails',
position: 600,
icon: 'IconMail',
cards: [{ type: CardType.EmailCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
calendar: {
title: 'Calendar',
position: 700,
icon: 'IconCalendarEvent',
cards: [{ type: CardType.CalendarCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
},
};
@@ -1,23 +0,0 @@
import { CardType } from '@/object-record/record-show/types/CardType';
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
export const TASK_RECORD_LAYOUT: RecordLayout = {
tabs: {
richText: {
title: 'Note',
position: 101,
icon: 'IconNotes',
cards: [{ type: CardType.FieldRichTextCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
tasks: null,
notes: null,
},
};
@@ -1,27 +0,0 @@
import { CardType } from '@/object-record/record-show/types/CardType';
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
export const WORKFLOW_RECORD_LAYOUT: RecordLayout = {
hideSummaryAndFields: true,
tabs: {
workflow: {
title: 'Flow',
position: 101,
icon: 'IconSettings',
cards: [{ type: CardType.WorkflowCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
timeline: null,
fields: null,
tasks: null,
notes: null,
files: null,
},
};
@@ -1,25 +0,0 @@
import { CardType } from '@/object-record/record-show/types/CardType';
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
export const WORKFLOW_RUN_RECORD_LAYOUT: RecordLayout = {
tabs: {
workflowRun: {
title: 'Flow',
position: 101,
icon: 'IconSettings',
cards: [{ type: CardType.WorkflowRunCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
timeline: null,
tasks: null,
notes: null,
files: null,
},
};
@@ -1,25 +0,0 @@
import { CardType } from '@/object-record/record-show/types/CardType';
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
export const WORKFLOW_VERSION_RECORD_LAYOUT: RecordLayout = {
tabs: {
workflowVersion: {
title: 'Flow',
position: 101,
icon: 'IconSettings',
cards: [{ type: CardType.WorkflowVersionCard }],
hide: {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
},
},
timeline: null,
tasks: null,
notes: null,
files: null,
},
};
@@ -1,7 +0,0 @@
import { type RecordLayoutTab } from '@/ui/layout/tab-list/types/RecordLayoutTab';
export type RecordLayout = {
hideSummaryAndFields?: boolean;
hideFieldsInSidePanel?: boolean;
tabs: Record<string, RecordLayoutTab | null>;
};
@@ -1,3 +0,0 @@
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
export type RecordLayoutMap = Record<string, RecordLayout | null>;
@@ -1,273 +0,0 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import {
type TabVisibilityContext,
evaluateTabVisibility,
} from '@/object-record/record-show/utils/evaluateTabVisibility';
import { type ObjectPermissions } from 'twenty-shared/types';
import { FeatureFlagKey, FieldMetadataType } from '~/generated/graphql';
const makeObjectMetadataItem = (
overrides: Partial<ObjectMetadataItem> = {},
): ObjectMetadataItem => {
return {
id: '1',
nameSingular: CoreObjectNameSingular.Company,
namePlural: 'companies',
labelSingular: 'Company',
labelPlural: 'Companies',
isActive: true,
isCustom: false,
isLabelSyncedWithName: false,
isRemote: false,
isSearchable: true,
isSystem: false,
isUIReadOnly: false,
createdAt: '',
updatedAt: '',
description: '',
fields: [],
readableFields: [],
updatableFields: [],
labelIdentifierFieldMetadataId: '',
indexMetadatas: [],
icon: '',
shortcut: '',
standardOverrides: undefined,
imageIdentifierFieldMetadataId: undefined,
duplicateCriteria: undefined,
...overrides,
};
};
const makeObjectPermissions = (
overrides: Partial<ObjectPermissions> = {},
): ObjectPermissions => {
return {
canReadObjectRecords: true,
canUpdateObjectRecords: true,
canSoftDeleteObjectRecords: true,
canDestroyObjectRecords: true,
restrictedFields: {},
rowLevelPermissionPredicates: [],
rowLevelPermissionPredicateGroups: [],
...overrides,
};
};
describe('evaluateTabVisibility', () => {
const baseContext: TabVisibilityContext = {
isMobile: false,
isInRightDrawer: false,
currentWorkspace: {
featureFlags: [{ key: FeatureFlagKey.IS_AI_ENABLED, value: true }],
},
objectMetadataItems: [makeObjectMetadataItem()],
objectPermissionsByObjectMetadataId: {
'1': { ...makeObjectPermissions(), objectMetadataId: '1' },
},
targetObjectMetadataItem: makeObjectMetadataItem(),
};
const baseConfig = {
ifMobile: false,
ifDesktop: false,
ifInRightDrawer: false,
ifFeaturesDisabled: [],
ifRequiredObjectsInactive: [],
ifRelationsMissing: [],
};
it('returns true if ifMobile and isMobile', () => {
expect(
evaluateTabVisibility(
{ ...baseConfig, ifMobile: true },
{ ...baseContext, isMobile: true },
),
).toBe(true);
});
it('returns true if ifDesktop and not isMobile', () => {
expect(
evaluateTabVisibility(
{ ...baseConfig, ifDesktop: true },
{ ...baseContext, isMobile: false },
),
).toBe(true);
});
it('returns true if ifInRightDrawer and isInRightDrawer', () => {
expect(
evaluateTabVisibility(
{ ...baseConfig, ifInRightDrawer: true },
{ ...baseContext, isInRightDrawer: true },
),
).toBe(true);
});
it('returns true if feature flag is disabled', () => {
expect(
evaluateTabVisibility(
{
...baseConfig,
ifFeaturesDisabled: [FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED],
},
baseContext,
),
).toBe(true);
});
it('returns false if feature flag is enabled', () => {
const ctx = {
...baseContext,
currentWorkspace: {
featureFlags: [
{ key: FeatureFlagKey.IS_AI_ENABLED, value: true },
{ key: FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED, value: true },
],
},
};
expect(
evaluateTabVisibility(
{
...baseConfig,
ifFeaturesDisabled: [FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED],
},
ctx,
),
).toBe(false);
});
it('returns true if required object is inactive', () => {
const ctx = {
...baseContext,
objectMetadataItems: [
...baseContext.objectMetadataItems,
makeObjectMetadataItem({
id: '2',
nameSingular: CoreObjectNameSingular.Person,
isActive: false,
}),
],
};
expect(
evaluateTabVisibility(
{
...baseConfig,
ifRequiredObjectsInactive: [CoreObjectNameSingular.Person],
},
ctx,
),
).toBe(true);
});
it('returns true if relation is missing', () => {
const ctx = {
...baseContext,
targetObjectMetadataItem: makeObjectMetadataItem({ fields: [] }),
};
expect(
evaluateTabVisibility(
{ ...baseConfig, ifRelationsMissing: ['contact'] },
ctx,
),
).toBe(true);
});
it('returns true if no read permission', () => {
const ctx = {
...baseContext,
objectMetadataItems: [
...baseContext.objectMetadataItems,
makeObjectMetadataItem({
id: '2',
nameSingular: CoreObjectNameSingular.Person,
}),
],
objectPermissionsByObjectMetadataId: {
...baseContext.objectPermissionsByObjectMetadataId,
'2': {
...makeObjectPermissions({ canReadObjectRecords: false }),
objectMetadataId: '2',
},
},
};
expect(
evaluateTabVisibility(
{
...baseConfig,
ifNoReadPermission: true,
ifNoReadPermissionObject: CoreObjectNameSingular.Person,
},
ctx,
),
).toBe(true);
});
it('returns false if no hide conditions are met', () => {
expect(evaluateTabVisibility(baseConfig, baseContext)).toBe(false);
});
it('returns false if required object is active', () => {
expect(
evaluateTabVisibility(
{
...baseConfig,
ifRequiredObjectsInactive: [CoreObjectNameSingular.Company],
},
baseContext,
),
).toBe(false);
});
it('returns false if relation exists and is active', () => {
const ctx = {
...baseContext,
targetObjectMetadataItem: makeObjectMetadataItem({
fields: [
{
name: 'contact',
type: FieldMetadataType.RELATION,
isActive: true,
} as any,
],
}),
};
expect(
evaluateTabVisibility(
{ ...baseConfig, ifRelationsMissing: ['contact'] },
ctx,
),
).toBe(false);
});
it('returns false if read permission exists', () => {
const ctx = {
...baseContext,
objectMetadataItems: [
...baseContext.objectMetadataItems,
makeObjectMetadataItem({
id: '2',
nameSingular: CoreObjectNameSingular.Person,
}),
],
objectPermissionsByObjectMetadataId: {
...baseContext.objectPermissionsByObjectMetadataId,
'2': {
...makeObjectPermissions({ canReadObjectRecords: true }),
objectMetadataId: '2',
},
},
};
expect(
evaluateTabVisibility(
{
...baseConfig,
ifNoReadPermission: true,
ifNoReadPermissionObject: CoreObjectNameSingular.Person,
},
ctx,
),
).toBe(false);
});
});
@@ -1,109 +0,0 @@
import { isDefined } from 'twenty-shared/utils';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
import { type TabVisibilityConfig } from '@/ui/layout/tab-list/types/TabVisibilityConfig';
import { type ObjectPermissions } from 'twenty-shared/types';
import { FieldMetadataType, type FeatureFlagDto } from '~/generated/graphql';
export type TabVisibilityContext = {
isMobile: boolean;
isInRightDrawer: boolean;
currentWorkspace: {
featureFlags?: FeatureFlagDto[] | null;
} | null;
objectMetadataItems: ObjectMetadataItem[];
objectPermissionsByObjectMetadataId: Record<
string,
ObjectPermissions & { objectMetadataId: string }
>;
targetObjectMetadataItem: ObjectMetadataItem;
};
export const evaluateTabVisibility = (
hide: TabVisibilityConfig,
context: TabVisibilityContext,
): boolean => {
const {
isMobile,
isInRightDrawer,
currentWorkspace,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
} = context;
const baseHide =
(hide.ifMobile && isMobile) ||
(hide.ifDesktop && !isMobile) ||
(hide.ifInRightDrawer && isInRightDrawer);
if (baseHide) {
return true;
}
const featureNotEnabled =
hide.ifFeaturesDisabled.length > 0 &&
!hide.ifFeaturesDisabled.every((flagKey) => {
const featureFlags = currentWorkspace?.featureFlags;
if (!featureFlags) {
return false;
}
return !!featureFlags.find((flag) => flag.key === flagKey && flag.value);
});
if (featureNotEnabled) {
return true;
}
const requiredObjectInactive = hide.ifRequiredObjectsInactive.some(
(requiredObjectName) => {
const objectMetadataItem = objectMetadataItems.find(
(item) => item.nameSingular === requiredObjectName,
);
return !objectMetadataItem?.isActive;
},
);
if (requiredObjectInactive) {
return true;
}
const relationMissing = hide.ifRelationsMissing.some((relationName) => {
return !context.targetObjectMetadataItem.fields.some(
(field) =>
field.name === relationName &&
field.type === FieldMetadataType.RELATION &&
field.isActive === true,
);
});
if (relationMissing) {
return true;
}
const noReadPermission =
hide.ifNoReadPermission === true &&
isDefined(hide.ifNoReadPermissionObject) &&
(() => {
const targetObjectMetadataId = objectMetadataItems.find(
(item) => item.nameSingular === hide.ifNoReadPermissionObject,
)?.id;
if (!isDefined(targetObjectMetadataId)) {
return false;
}
const objectPermissions = getObjectPermissionsForObject(
objectPermissionsByObjectMetadataId,
targetObjectMetadataId,
);
return objectPermissions.canReadObjectRecords === false;
})();
if (noReadPermission) {
return true;
}
return false;
};
@@ -8,18 +8,9 @@ import { usePageLayoutTabWithVisibleWidgetsOrThrow } from '@/page-layout/hooks/u
import { useReorderPageLayoutWidgets } from '@/page-layout/hooks/useReorderPageLayoutWidgets';
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import {
FeatureFlagKey,
PageLayoutTabLayoutMode,
PageLayoutType,
} from '~/generated/graphql';
import { PageLayoutTabLayoutMode, PageLayoutType } from '~/generated/graphql';
export const PageLayoutContent = () => {
const isRecordPageEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED,
);
const isPageLayoutInEditMode = useRecoilComponentValue(
isPageLayoutInEditModeComponentState,
);
@@ -37,10 +28,8 @@ export const PageLayoutContent = () => {
const isRecordPageLayout =
currentPageLayout.type === PageLayoutType.RECORD_PAGE;
const isCanvasLayout =
isRecordPageEnabled && layoutMode === PageLayoutTabLayoutMode.CANVAS;
const isVerticalList =
isRecordPageEnabled && layoutMode === PageLayoutTabLayoutMode.VERTICAL_LIST;
const isCanvasLayout = layoutMode === PageLayoutTabLayoutMode.CANVAS;
const isVerticalList = layoutMode === PageLayoutTabLayoutMode.VERTICAL_LIST;
if (isCanvasLayout) {
return <PageLayoutCanvasViewer widgets={activeTab.widgets} />;
@@ -11,9 +11,6 @@ export type LayoutRenderingContextType = {
layoutType: PageLayoutType;
isInRightDrawer: boolean;
/** TODO: Remove once the traditional record show page is removed. */
isLegacyRecordShowPage?: boolean;
};
export const [LayoutRenderingProvider, useLayoutRenderingContext] =
@@ -1,62 +0,0 @@
import styled from '@emotion/styled';
import { type ReactNode } from 'react';
import { PAGE_LAYOUT_LEFT_PANEL_CONTAINER_WIDTH } from '@/page-layout/constants/PageLayoutLeftPanelContainerWidth';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
const StyledOuterContainer = styled.div<{ isMobile: boolean }>`
background: ${({ theme }) => theme.background.secondary};
border-bottom-left-radius: 8px;
border-right: ${({ theme, isMobile }) =>
isMobile ? 'none' : `1px solid ${theme.border.color.medium}`};
border-top-left-radius: 8px;
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(3)};
z-index: 10;
width: 'auto';
`;
const StyledInnerContainer = styled.div<{ isMobile: boolean }>`
display: flex;
flex-direction: column;
width: ${({ isMobile }) =>
isMobile ? `100%` : `${PAGE_LAYOUT_LEFT_PANEL_CONTAINER_WIDTH}px`};
`;
const StyledIntermediateContainer = styled.div`
display: flex;
flex-direction: column;
padding-bottom: ${({ theme }) => theme.spacing(3)};
`;
export type ShowPageLeftContainerProps = {
children: ReactNode;
};
export const ShowPageLeftContainer = ({
children,
}: ShowPageLeftContainerProps) => {
const isMobile = useIsMobile();
return (
<StyledOuterContainer isMobile={isMobile}>
{isMobile ? (
<StyledInnerContainer isMobile={isMobile}>
{children}
</StyledInnerContainer>
) : (
<ScrollWrapper
componentInstanceId={`scroll-wrapper-show-page-left-container`}
>
<StyledIntermediateContainer>
<StyledInnerContainer isMobile={isMobile}>
{children}
</StyledInnerContainer>
</StyledIntermediateContainer>
</ScrollWrapper>
)}
</StyledOuterContainer>
);
};
@@ -1,158 +0,0 @@
import { RecordShowRightDrawerActionMenu } from '@/action-menu/components/RecordShowRightDrawerActionMenu';
import { RecordShowRightDrawerOpenRecordButton } from '@/action-menu/components/RecordShowRightDrawerOpenRecordButton';
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
import { FieldsCard } from '@/object-record/record-show/components/FieldsCard';
import { SummaryCard } from '@/object-record/record-show/components/SummaryCard';
import { type RecordLayout } from '@/object-record/record-show/types/RecordLayout';
import { getCardComponent } from '@/object-record/record-show/utils/getCardComponent';
import { RightDrawerFooter } from '@/ui/layout/right-drawer/components/RightDrawerFooter';
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { type TargetRecordIdentifier } from '@/ui/layout/contexts/TargetRecordIdentifier';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { TabListComponentInstanceContext } from '@/ui/layout/tab-list/states/contexts/TabListComponentInstanceContext';
import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import React from 'react';
import { isDefined } from 'twenty-shared/utils';
const StyledShowPageRightContainer = styled.div`
display: flex;
flex-direction: column;
height: 100%;
justify-content: start;
width: 100%;
overflow: auto;
`;
const StyledTabListContainer = styled.div<{ shouldDisplay: boolean }>`
${({ shouldDisplay }) =>
!shouldDisplay &&
css`
height: 0;
overflow: hidden;
visibility: hidden;
`}
`;
const StyledTabList = styled(TabList)`
padding-left: ${({ theme }) => theme.spacing(2)};
`;
const StyledContentContainer = styled.div<{ isInRightDrawer: boolean }>`
flex: 1;
overflow-y: auto;
background: ${({ theme }) => theme.background.primary};
padding-bottom: ${({ theme, isInRightDrawer }) =>
isInRightDrawer ? theme.spacing(16) : 0};
`;
type ShowPageSubContainerProps = {
layout?: RecordLayout;
tabs: SingleTabProps[];
targetRecordIdentifier: TargetRecordIdentifier;
isInRightDrawer?: boolean;
loading: boolean;
};
export const ShowPageSubContainer = ({
tabs,
layout,
targetRecordIdentifier,
loading,
isInRightDrawer = false,
}: ShowPageSubContainerProps) => {
const commandMenuPageComponentInstance = useComponentInstanceStateContext(
CommandMenuPageComponentInstanceContext,
);
const tabListComponentId = getShowPageTabListComponentId({
pageId: commandMenuPageComponentInstance?.instanceId,
targetObjectId: targetRecordIdentifier.id,
});
const activeTabId = useRecoilComponentValue(
activeTabIdComponentState,
tabListComponentId,
);
const isMobile = useIsMobile();
const summaryCard = (
<SummaryCard
objectNameSingular={targetRecordIdentifier.targetObjectNameSingular}
objectRecordId={targetRecordIdentifier.id}
isInRightDrawer={isInRightDrawer}
/>
);
const fieldsCard = <FieldsCard />;
const renderActiveTabContent = () => {
const activeTab = tabs.find((tab) => tab.id === activeTabId);
if (!activeTab?.cards?.length) return null;
return (
<>
{activeTab.cards.map((card, index) => (
<React.Fragment key={`${activeTab.id}-card-${index}`}>
{getCardComponent(card.type, card.configuration)}
</React.Fragment>
))}
</>
);
};
const visibleTabs = tabs.filter((tab) => !tab.hide);
const isInCommandMenu = isDefined(commandMenuPageComponentInstance);
const displaySummaryAndFields =
layout && !layout.hideSummaryAndFields && !isMobile && !isInRightDrawer;
return (
<TabListComponentInstanceContext.Provider
value={{ instanceId: tabListComponentId }}
>
{displaySummaryAndFields && (
<ShowPageLeftContainer>
{summaryCard}
{fieldsCard}
</ShowPageLeftContainer>
)}
<StyledShowPageRightContainer>
<StyledTabListContainer shouldDisplay={visibleTabs.length > 1}>
<StyledTabList
behaveAsLinks={!isInRightDrawer}
loading={loading}
tabs={tabs}
isInRightDrawer={isInRightDrawer}
componentInstanceId={tabListComponentId}
/>
</StyledTabListContainer>
{(isMobile || isInRightDrawer) && !isInCommandMenu && summaryCard}
<StyledContentContainer isInRightDrawer={isInRightDrawer}>
{renderActiveTabContent()}
</StyledContentContainer>
{isInRightDrawer && (
<RightDrawerFooter
actions={[
<RecordShowRightDrawerActionMenu />,
<RecordShowRightDrawerOpenRecordButton
objectNameSingular={
targetRecordIdentifier.targetObjectNameSingular
}
recordId={targetRecordIdentifier.id}
/>,
]}
/>
)}
</StyledShowPageRightContainer>
</TabListComponentInstanceContext.Provider>
);
};
@@ -1 +0,0 @@
export const SHOW_PAGE_ADD_BUTTON_DROPDOWN_ID = 'show-page-add-button-dropdown';
@@ -1,10 +0,0 @@
import { type LayoutCard } from '@/ui/layout/tab-list/types/LayoutCard';
import { type TabVisibilityConfig } from '@/ui/layout/tab-list/types/TabVisibilityConfig';
export type RecordLayoutTab = {
title: string;
position: number;
icon: string;
hide: TabVisibilityConfig;
cards: LayoutCard[];
};
@@ -1,13 +0,0 @@
import { type CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { type FeatureFlagKey } from '~/generated/graphql';
export type TabVisibilityConfig = {
ifMobile: boolean;
ifDesktop: boolean;
ifInRightDrawer: boolean;
ifFeaturesDisabled: FeatureFlagKey[];
ifRequiredObjectsInactive: CoreObjectNameSingular[];
ifRelationsMissing: string[];
ifNoReadPermission?: boolean;
ifNoReadPermissionObject?: CoreObjectNameSingular;
};
@@ -7,7 +7,7 @@ import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainCo
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
import { MainContainerLayoutWithCommandMenu } from '@/object-record/components/MainContainerLayoutWithCommandMenu';
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
import { PageLayoutDispatcher } from '@/object-record/record-show/components/PageLayoutDispatcher';
import { PageLayoutRecordPageRenderer } from '@/object-record/record-show/components/PageLayoutRecordPageRenderer';
import { RecordShowPageSSESubscribeEffect } from '@/object-record/record-show/components/RecordShowPageSSESubscribeEffect';
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
import { computeRecordShowComponentInstanceId } from '@/object-record/record-show/utils/computeRecordShowComponentInstanceId';
@@ -58,11 +58,12 @@ export const RecordShowPage = () => {
recordId: objectRecordId,
}}
>
<PageLayoutDispatcher
<PageLayoutRecordPageRenderer
targetRecordIdentifier={{
id: objectRecordId,
targetObjectNameSingular: objectNameSingular,
}}
isInRightDrawer={false}
/>
<RecordShowPageSSESubscribeEffect
objectNameSingular={objectNameSingular}
@@ -5,7 +5,6 @@ export enum FeatureFlagKey {
IS_APPLICATION_ENABLED = 'IS_APPLICATION_ENABLED',
IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED = 'IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED',
IS_MARKETPLACE_ENABLED = 'IS_MARKETPLACE_ENABLED',
IS_RECORD_PAGE_LAYOUT_ENABLED = 'IS_RECORD_PAGE_LAYOUT_ENABLED',
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',
@@ -226,7 +226,6 @@ describe('WorkspaceEntityManager', () => {
IS_AI_ENABLED: false,
IS_APPLICATION_ENABLED: false,
IS_IMAP_SMTP_CALDAV_ENABLED: false,
IS_RECORD_PAGE_LAYOUT_ENABLED: false,
IS_PUBLIC_DOMAIN_ENABLED: false,
IS_EMAILING_DOMAIN_ENABLED: false,
IS_DASHBOARD_V2_ENABLED: false,
@@ -264,7 +263,6 @@ describe('WorkspaceEntityManager', () => {
IS_JSON_FILTER_ENABLED: false,
IS_AI_ENABLED: false,
IS_APPLICATION_ENABLED: false,
IS_RECORD_PAGE_LAYOUT_ENABLED: false,
IS_PUBLIC_DOMAIN_ENABLED: false,
IS_EMAILING_DOMAIN_ENABLED: false,
IS_DASHBOARD_V2_ENABLED: false,
@@ -36,11 +36,6 @@ export const seedFeatureFlags = async ({
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED,
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKey.IS_PUBLIC_DOMAIN_ENABLED,
workspaceId: workspaceId,
@@ -4,5 +4,4 @@ export const DEFAULT_FEATURE_FLAGS = [
FeatureFlagKey.IS_ATTACHMENT_MIGRATED,
FeatureFlagKey.IS_NOTE_TARGET_MIGRATED,
FeatureFlagKey.IS_TASK_TARGET_MIGRATED,
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED,
] as const satisfies FeatureFlagKey[];