Record page layout edition frontend (#17519)

Hidden behind a new feature flag:
`IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED`


https://github.com/user-attachments/assets/112f5a8d-0dd0-4b9f-8825-9980db35fcbd
This commit is contained in:
Baptiste Devessier
2026-01-29 12:13:09 +01:00
committed by GitHub
parent 97a37604bd
commit b15d092abd
22 changed files with 369 additions and 79 deletions
@@ -1,13 +0,0 @@
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { PageLayoutType } from '~/generated/graphql';
export const usePageLayoutShouldUseWhiteBackground = () => {
const isMobile = useIsMobile();
const { isInRightDrawer, layoutType } = useLayoutRenderingContext();
const shouldUseWhiteBackground =
layoutType === PageLayoutType.RECORD_PAGE && (isMobile || isInRightDrawer);
return { shouldUseWhiteBackground };
};
@@ -1,30 +1,7 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { DEFAULT_COMPANY_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultCompanyRecordPageLayoutId';
import { DEFAULT_NOTE_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultNoteRecordPageLayoutId';
import { DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultOpportunityRecordPageLayoutId';
import { DEFAULT_PERSON_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultPersonRecordPageLayoutId';
import { DEFAULT_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultRecordPageLayoutId';
import { DEFAULT_TASK_RECORD_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultTaskRecordPageLayoutId';
import { DEFAULT_WORKFLOW_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultWorkflowPageLayoutId';
import { DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultWorkflowRunPageLayoutId';
import { DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultWorkflowVersionPageLayoutId';
import { getRecordPageLayoutId } from '@/page-layout/utils/getRecordPageLayoutId';
import { type TargetRecordIdentifier } from '@/ui/layout/contexts/TargetRecordIdentifier';
import { isDefined } from 'twenty-shared/utils';
const OBJECT_NAME_TO_DEFAULT_LAYOUT_ID: Record<string, string> = {
[CoreObjectNameSingular.Company]: DEFAULT_COMPANY_RECORD_PAGE_LAYOUT_ID,
[CoreObjectNameSingular.Person]: DEFAULT_PERSON_RECORD_PAGE_LAYOUT_ID,
[CoreObjectNameSingular.Opportunity]:
DEFAULT_OPPORTUNITY_RECORD_PAGE_LAYOUT_ID,
[CoreObjectNameSingular.Note]: DEFAULT_NOTE_RECORD_PAGE_LAYOUT_ID,
[CoreObjectNameSingular.Task]: DEFAULT_TASK_RECORD_PAGE_LAYOUT_ID,
[CoreObjectNameSingular.Workflow]: DEFAULT_WORKFLOW_PAGE_LAYOUT_ID,
[CoreObjectNameSingular.WorkflowVersion]:
DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT_ID,
[CoreObjectNameSingular.WorkflowRun]: DEFAULT_WORKFLOW_RUN_PAGE_LAYOUT_ID,
};
export const useRecordPageLayoutId = ({
id,
@@ -37,23 +14,12 @@ export const useRecordPageLayoutId = ({
},
);
if (!isDefined(record)) {
return {
pageLayoutId: null,
};
}
if (isDefined(record.pageLayoutId)) {
return {
pageLayoutId: record.pageLayoutId,
};
}
const defaultLayoutId =
OBJECT_NAME_TO_DEFAULT_LAYOUT_ID[targetObjectNameSingular] ??
DEFAULT_RECORD_PAGE_LAYOUT_ID;
const pageLayoutId = getRecordPageLayoutId({
record,
targetObjectNameSingular,
});
return {
pageLayoutId: defaultLayoutId,
pageLayoutId,
};
};
@@ -0,0 +1,29 @@
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { getRecordPageLayoutId } from '@/page-layout/utils/getRecordPageLayoutId';
import { type TargetRecordIdentifier } from '@/ui/layout/contexts/TargetRecordIdentifier';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
export const useRecordPageLayoutIdFromRecordStoreOrThrow = ({
id,
targetObjectNameSingular,
}: TargetRecordIdentifier) => {
const record = useRecoilValue(recordStoreFamilyState(id));
if (!isDefined(record)) {
throw new Error(`Record with id ${id} not found in record store`);
}
const pageLayoutId = getRecordPageLayoutId({
record,
targetObjectNameSingular,
});
if (!isDefined(pageLayoutId)) {
throw new Error(`Page layout id not found for record with id ${id}`);
}
return {
pageLayoutId,
};
};