Add a Table display mode to relation field widgets (#20929)
## Context Adds a new Table layout to the FIELD widget for to-many relation fields. On a record page, a relation can now be displayed as a full record table (the same component used for record indexes and dashboard table widgets) scoped to the records related to the current record. https://github.com/user-attachments/assets/320b24dc-f019-4d0e-bc71-3e64d032d75a https://github.com/user-attachments/assets/2f6d4f8e-de26-4fc1-ae12-c9b9c19654dc https://github.com/user-attachments/assets/3fb6d512-f83c-4818-823e-46ad2644fbc2
This commit is contained in:
+19
-1
@@ -348,7 +348,7 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
|
||||
}
|
||||
|
||||
case WidgetConfigurationType.FIELD: {
|
||||
const { fieldMetadataId, fieldDisplayMode, configurationType } =
|
||||
const { fieldMetadataId, fieldDisplayMode, configurationType, viewId } =
|
||||
configuration;
|
||||
|
||||
const fieldMetadataUniversalIdentifier =
|
||||
@@ -358,10 +358,28 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
|
||||
shouldThrowOnMissingIdentifier,
|
||||
});
|
||||
|
||||
let viewUniversalIdentifier: string | undefined = undefined;
|
||||
|
||||
if (isDefined(viewId)) {
|
||||
viewUniversalIdentifier =
|
||||
viewUniversalIdentifierById[viewId] ?? undefined;
|
||||
|
||||
if (
|
||||
!isDefined(viewUniversalIdentifier) &&
|
||||
shouldThrowOnMissingIdentifier
|
||||
) {
|
||||
throw new FlatEntityMapsException(
|
||||
`View universal identifier not found for id: ${viewId}`,
|
||||
FlatEntityMapsExceptionCode.RELATION_UNIVERSAL_IDENTIFIER_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
configurationType,
|
||||
fieldMetadataId: fieldMetadataUniversalIdentifier ?? fieldMetadataId,
|
||||
fieldDisplayMode,
|
||||
viewId: viewUniversalIdentifier,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+13
-1
@@ -1,6 +1,13 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { IsEnum, IsIn, IsNotEmpty, IsString } from 'class-validator';
|
||||
import {
|
||||
IsEnum,
|
||||
IsIn,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUUID,
|
||||
} from 'class-validator';
|
||||
|
||||
import { type FieldConfiguration } from 'twenty-shared/types';
|
||||
|
||||
@@ -23,4 +30,9 @@ export class FieldConfigurationDTO implements FieldConfiguration {
|
||||
@IsEnum(FieldDisplayMode)
|
||||
@IsNotEmpty()
|
||||
fieldDisplayMode: FieldDisplayMode;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
viewId?: string;
|
||||
}
|
||||
|
||||
+1
@@ -5,6 +5,7 @@ export enum FieldDisplayMode {
|
||||
EDITOR = 'EDITOR',
|
||||
FIELD = 'FIELD',
|
||||
VIEW = 'VIEW',
|
||||
TABLE = 'TABLE',
|
||||
}
|
||||
|
||||
registerEnumType(FieldDisplayMode, {
|
||||
|
||||
+24
-8
@@ -20,6 +20,7 @@ import { resolveEntityRelationUniversalIdentifiers } from 'src/engine/metadata-m
|
||||
import { splitEntitiesByRemovalStrategy } from 'src/engine/metadata-modules/flat-entity/utils/split-entities-by-removal-strategy.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { isFlatPageLayoutWidgetConfigurationOfType } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/is-flat-page-layout-widget-configuration-of-type.util';
|
||||
import { FieldDisplayMode } from 'src/engine/metadata-modules/page-layout-widget/enums/field-display-mode.enum';
|
||||
import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/metadata-modules/flat-view-field/constants/default-view-field-size.constant';
|
||||
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
|
||||
import { fromViewFieldOverridesToUniversalOverrides } from 'src/engine/metadata-modules/flat-view-field/utils/from-view-field-overrides-to-universal-overrides.util';
|
||||
@@ -121,20 +122,35 @@ export class ViewWidgetUpsertService {
|
||||
flatEntityMaps: flatPageLayoutWidgetMaps,
|
||||
});
|
||||
|
||||
if (
|
||||
!isDefined(widget) ||
|
||||
!isFlatPageLayoutWidgetConfigurationOfType(
|
||||
widget,
|
||||
WidgetConfigurationType.RECORD_TABLE,
|
||||
)
|
||||
) {
|
||||
if (!isDefined(widget)) {
|
||||
throw new ViewException(
|
||||
t`Record table widget not found`,
|
||||
ViewExceptionCode.VIEW_WIDGET_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const viewId = widget.configuration.viewId;
|
||||
const isRecordTableWidget = isFlatPageLayoutWidgetConfigurationOfType(
|
||||
widget,
|
||||
WidgetConfigurationType.RECORD_TABLE,
|
||||
);
|
||||
|
||||
const isFieldTableWidget =
|
||||
isFlatPageLayoutWidgetConfigurationOfType(
|
||||
widget,
|
||||
WidgetConfigurationType.FIELD,
|
||||
) && widget.configuration.fieldDisplayMode === FieldDisplayMode.TABLE;
|
||||
|
||||
if (!isRecordTableWidget && !isFieldTableWidget) {
|
||||
throw new ViewException(
|
||||
t`Record table widget not found`,
|
||||
ViewExceptionCode.VIEW_WIDGET_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const viewId =
|
||||
'viewId' in widget.configuration
|
||||
? widget.configuration.viewId
|
||||
: undefined;
|
||||
|
||||
if (!isDefined(viewId)) {
|
||||
throw new ViewException(
|
||||
|
||||
Reference in New Issue
Block a user