Refactor record layouts for backend-driven configuration (#15021)

## Refactor: Prepare frontend record layouts for backend-driven
configuration

This PR simplifies and prepares the frontend record layout system for
eventual migration to backend-driven layouts, aligning the architecture
with the existing PageLayout system used for dashboards.

### Key Changes

**Architecture Improvements:**
- Created unified LayoutRenderingContext that works for both record
pages (with targetRecord) and dashboards (standalone)
- Replaced prop drilling with context-based data flow - cards access
targetRecord and isInRightDrawer via context hooks
- Introduced useTargetRecord() helper hook that provides type-safe
access to the current record
- Created generic CardRenderer component that handles configuration
injection and context guards uniformly

**Configuration System:**
- Converted all tab icons from React components to JSON-serializable
strings (e.g., Icon: IconCheckbox → icon: 'IconCheckbox')
- Added configuration field to cards, matching the widget configuration
pattern on the backend
- Created CardConfiguration types system similar to WidgetConfiguration
on the backend
- Moved widget-specific props (like showDuplicatesSection) into
configuration objects

**Code Organization:**
- Extracted visibility evaluation logic into reusable
evaluateTabVisibility() utility
- Organized layouts into dedicated files (one per object:
base-record-layout.ts, company-record-layout.ts, etc.)
- Renamed components to match their purpose: Notes → NotesCard,
Attachments → FilesCard, etc.
- Consolidated card rendering from registry object to direct
getCardComponent() function

**API Alignment:**
- Made ifNoReadPermissionObject an explicit part of TabVisibilityConfig
(follows if* naming convention)
- Removed redundant targetObjectNameSingular from tab-level (now derived
from visibility config)
- Card API now mirrors Widget API (both use type, configuration,
accessed via context)
This commit is contained in:
Félix Malfait
2025-10-10 16:26:17 +02:00
committed by GitHub
parent 5013222db4
commit 938debd83e
46 changed files with 993 additions and 777 deletions
@@ -1,6 +1,7 @@
import { useFormContext } from 'react-hook-form';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/components/SettingsDataModelPreviewFormCard';
import { RELATION_TYPES } from '@/settings/data-model/constants/RelationTypes';
import {
@@ -82,7 +83,8 @@ export const SettingsDataModelFieldRelationSettingsFormCard = ({
}}
shrink
objectNameSingulars={[
relationObjectMetadataItem?.nameSingular ?? 'company',
relationObjectMetadataItem?.nameSingular ??
CoreObjectNameSingular.Company,
]}
fieldPreviewTargetObjectNameSingular={objectNameSingular}
pluralizeLabel={oppositeRelationType === RelationType.ONE_TO_MANY}
@@ -2,6 +2,7 @@ import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { type FieldMetadataItemRelation } from '@/object-metadata/types/FieldMetadataItemRelation';
import { FieldDisplay } from '@/object-record/record-field/ui/components/FieldDisplay';
@@ -75,7 +76,7 @@ export const SettingsDataModelRelationFieldPreview = ({
const metadata = {
fieldName,
objectMetadataNameSingular: 'company',
objectMetadataNameSingular: CoreObjectNameSingular.Company,
relationObjectMetadataNameSingular: relationTargetObjectNameSingular,
options: [],
settings: fieldMetadataItem.settings,