Create fields widget (#16403)
https://github.com/user-attachments/assets/b150815a-5d54-4d4a-b984-20dcf7b29aa7
This commit is contained in:
committed by
GitHub
parent
7b98804ec1
commit
fd54a2af5c
+172
-12
@@ -1,9 +1,38 @@
|
||||
import { RecordFieldList } from '@/object-record/record-field-list/components/RecordFieldList';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly';
|
||||
import { isRecordFieldReadOnly } from '@/object-record/read-only/utils/isRecordFieldReadOnly';
|
||||
import { RecordDetailSectionContainer } from '@/object-record/record-field-list/record-detail-section/components/RecordDetailSectionContainer';
|
||||
import { RecordFieldListComponentInstanceContext } from '@/object-record/record-field-list/states/contexts/RecordFieldListComponentInstanceContext';
|
||||
import { recordFieldListHoverPositionComponentState } from '@/object-record/record-field-list/states/recordFieldListHoverPositionComponentState';
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
|
||||
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
|
||||
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
|
||||
import { PropertyBoxSkeletonLoader } from '@/object-record/record-inline-cell/property-box/components/PropertyBoxSkeletonLoader';
|
||||
import { useRecordShowContainerActions } from '@/object-record/record-show/hooks/useRecordShowContainerActions';
|
||||
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
|
||||
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
||||
import { FieldsWidgetCellEditModePortal } from '@/page-layout/widgets/fields/components/FieldsWidgetCellEditModePortal';
|
||||
import { FieldsWidgetCellHoveredPortal } from '@/page-layout/widgets/fields/components/FieldsWidgetCellHoveredPortal';
|
||||
import { useFieldsWidgetSectionsWithIndices } from '@/page-layout/widgets/fields/hooks/useFieldsWidgetSectionsWithIndices';
|
||||
import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/role-permissions/objects-permissions/utils/getObjectPermissionsFromMapByObjectMetadataId';
|
||||
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
|
||||
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
|
||||
import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import styled from '@emotion/styled';
|
||||
import { type PageLayoutWidget } from '~/generated/graphql';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
AnimatedPlaceholder,
|
||||
AnimatedPlaceholderEmptyContainer,
|
||||
AnimatedPlaceholderEmptySubTitle,
|
||||
AnimatedPlaceholderEmptyTextContainer,
|
||||
AnimatedPlaceholderEmptyTitle,
|
||||
EMPTY_PLACEHOLDER_TRANSITION_PROPS,
|
||||
} from 'twenty-ui/layout';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
@@ -19,17 +48,148 @@ export const FieldsWidget = ({ widget: _widget }: FieldsWidgetProps) => {
|
||||
const targetRecord = useTargetRecord();
|
||||
const { isInRightDrawer } = useLayoutRenderingContext();
|
||||
|
||||
const instanceId = `fields-widget-${targetRecord.id}-${isInRightDrawer ? 'right-drawer' : ''}`;
|
||||
|
||||
const { recordLoading, isPrefetchLoading } = useRecordShowContainerData({
|
||||
objectRecordId: targetRecord.id,
|
||||
});
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular: targetRecord.targetObjectNameSingular,
|
||||
});
|
||||
|
||||
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||
|
||||
const { useUpdateOneObjectRecordMutation } = useRecordShowContainerActions({
|
||||
objectNameSingular: targetRecord.targetObjectNameSingular,
|
||||
objectRecordId: targetRecord.id,
|
||||
});
|
||||
|
||||
const isRecordReadOnly = useIsRecordReadOnly({
|
||||
recordId: targetRecord.id,
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
});
|
||||
|
||||
const setRecordFieldListHoverPosition = useSetRecoilComponentState(
|
||||
recordFieldListHoverPositionComponentState,
|
||||
instanceId,
|
||||
);
|
||||
|
||||
const { sectionsWithFieldIndices } = useFieldsWidgetSectionsWithIndices(
|
||||
targetRecord.targetObjectNameSingular,
|
||||
);
|
||||
|
||||
if (sectionsWithFieldIndices.length === 0) {
|
||||
return (
|
||||
<RightDrawerProvider value={{ isInRightDrawer }}>
|
||||
<StyledContainer>
|
||||
<AnimatedPlaceholderEmptyContainer
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...EMPTY_PLACEHOLDER_TRANSITION_PROPS}
|
||||
>
|
||||
<AnimatedPlaceholder type="noRecord" />
|
||||
<AnimatedPlaceholderEmptyTextContainer>
|
||||
<AnimatedPlaceholderEmptyTitle>
|
||||
{t`No fields to display`}
|
||||
</AnimatedPlaceholderEmptyTitle>
|
||||
<AnimatedPlaceholderEmptySubTitle>
|
||||
{t`Configure this widget to display fields`}
|
||||
</AnimatedPlaceholderEmptySubTitle>
|
||||
</AnimatedPlaceholderEmptyTextContainer>
|
||||
</AnimatedPlaceholderEmptyContainer>
|
||||
</StyledContainer>
|
||||
</RightDrawerProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<RightDrawerProvider value={{ isInRightDrawer }}>
|
||||
<StyledContainer>
|
||||
<RecordFieldList
|
||||
instanceId={`fields-widget-${targetRecord.id}-${isInRightDrawer ? 'right-drawer' : ''}`}
|
||||
objectNameSingular={targetRecord.targetObjectNameSingular}
|
||||
objectRecordId={targetRecord.id}
|
||||
// TODO: pick the value from the widget configuration
|
||||
showDuplicatesSection={true}
|
||||
<StyledContainer>
|
||||
<RecordFieldListComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId,
|
||||
}}
|
||||
>
|
||||
{sectionsWithFieldIndices.map((section) => (
|
||||
<RecordDetailSectionContainer key={section.id} title={section.title}>
|
||||
<PropertyBox>
|
||||
{isPrefetchLoading ? (
|
||||
<PropertyBoxSkeletonLoader />
|
||||
) : (
|
||||
<>
|
||||
{section.fields.map(
|
||||
({ field: fieldMetadataItem, globalIndex }) => {
|
||||
return (
|
||||
<FieldContext.Provider
|
||||
key={targetRecord.id + fieldMetadataItem.id}
|
||||
value={{
|
||||
recordId: targetRecord.id,
|
||||
maxWidth: 200,
|
||||
isLabelIdentifier: false,
|
||||
fieldDefinition:
|
||||
formatFieldMetadataItemAsColumnDefinition({
|
||||
field: fieldMetadataItem,
|
||||
position: globalIndex,
|
||||
objectMetadataItem,
|
||||
showLabel: true,
|
||||
labelWidth: 90,
|
||||
}),
|
||||
useUpdateRecord: useUpdateOneObjectRecordMutation,
|
||||
isDisplayModeFixHeight: true,
|
||||
isRecordFieldReadOnly: isRecordFieldReadOnly({
|
||||
isRecordReadOnly,
|
||||
objectPermissions:
|
||||
getObjectPermissionsFromMapByObjectMetadataId({
|
||||
objectPermissionsByObjectMetadataId,
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
}),
|
||||
fieldMetadataItem: {
|
||||
id: fieldMetadataItem.id,
|
||||
isUIReadOnly:
|
||||
fieldMetadataItem.isUIReadOnly ?? false,
|
||||
},
|
||||
}),
|
||||
onMouseEnter: () =>
|
||||
setRecordFieldListHoverPosition(globalIndex),
|
||||
anchorId: `${getRecordFieldInputInstanceId({
|
||||
recordId: targetRecord.id,
|
||||
fieldName: fieldMetadataItem.name,
|
||||
prefix: instanceId,
|
||||
})}`,
|
||||
}}
|
||||
>
|
||||
<RecordFieldComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: getRecordFieldInputInstanceId({
|
||||
recordId: targetRecord.id,
|
||||
fieldName: fieldMetadataItem.name,
|
||||
prefix: instanceId,
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<RecordInlineCell
|
||||
loading={recordLoading}
|
||||
instanceIdPrefix={instanceId}
|
||||
/>
|
||||
</RecordFieldComponentInstanceContext.Provider>
|
||||
</FieldContext.Provider>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</PropertyBox>
|
||||
</RecordDetailSectionContainer>
|
||||
))}
|
||||
|
||||
<FieldsWidgetCellHoveredPortal
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
recordId={targetRecord.id}
|
||||
/>
|
||||
</StyledContainer>
|
||||
</RightDrawerProvider>
|
||||
<FieldsWidgetCellEditModePortal
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
recordId={targetRecord.id}
|
||||
/>
|
||||
</RecordFieldListComponentInstanceContext.Provider>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { RecordFieldListInputContextProvider } from '@/object-record/record-field-list/anchored-portal/components/RecordFieldListInputContextProvider';
|
||||
import { RecordFieldListComponentInstanceContext } from '@/object-record/record-field-list/states/contexts/RecordFieldListComponentInstanceContext';
|
||||
import { recordFieldListCellEditModePositionComponentState } from '@/object-record/record-field-list/states/recordFieldListCellEditModePositionComponentState';
|
||||
import { FieldInput } from '@/object-record/record-field/ui/components/FieldInput';
|
||||
import { RecordInlineCellAnchoredPortal } from '@/object-record/record-inline-cell/components/RecordInlineCellAnchoredPortal';
|
||||
import { RecordInlineCellEditMode } from '@/object-record/record-inline-cell/components/RecordInlineCellEditMode';
|
||||
import { useFieldsWidgetFlattenedFields } from '@/page-layout/widgets/fields/hooks/useFieldsWidgetFlattenedFields';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type FieldsWidgetCellEditModePortalProps = {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
recordId: string;
|
||||
};
|
||||
|
||||
export const FieldsWidgetCellEditModePortal = ({
|
||||
objectMetadataItem,
|
||||
recordId,
|
||||
}: FieldsWidgetCellEditModePortalProps) => {
|
||||
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||
RecordFieldListComponentInstanceContext,
|
||||
);
|
||||
|
||||
const editModePosition = useRecoilComponentValue(
|
||||
recordFieldListCellEditModePositionComponentState,
|
||||
);
|
||||
|
||||
const { flattenedFieldMetadataItems } = useFieldsWidgetFlattenedFields(
|
||||
objectMetadataItem.nameSingular,
|
||||
);
|
||||
|
||||
const editedFieldMetadataItem = isDefined(editModePosition)
|
||||
? flattenedFieldMetadataItems.at(editModePosition)
|
||||
: undefined;
|
||||
|
||||
if (!isDefined(editModePosition) || !isDefined(editedFieldMetadataItem)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecordInlineCellAnchoredPortal
|
||||
fieldMetadataItem={editedFieldMetadataItem}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
recordId={recordId}
|
||||
instanceIdPrefix={instanceId}
|
||||
>
|
||||
<RecordFieldListInputContextProvider>
|
||||
<RecordInlineCellEditMode>
|
||||
<FieldInput />
|
||||
</RecordInlineCellEditMode>
|
||||
</RecordFieldListInputContextProvider>
|
||||
</RecordInlineCellAnchoredPortal>
|
||||
);
|
||||
};
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { RecordFieldListCellHoveredPortalContent } from '@/object-record/record-field-list/anchored-portal/components/RecordFieldListCellHoveredPortalContent';
|
||||
import { RecordFieldListInputContextProvider } from '@/object-record/record-field-list/anchored-portal/components/RecordFieldListInputContextProvider';
|
||||
import { RecordFieldListComponentInstanceContext } from '@/object-record/record-field-list/states/contexts/RecordFieldListComponentInstanceContext';
|
||||
import { recordFieldListHoverPositionComponentState } from '@/object-record/record-field-list/states/recordFieldListHoverPositionComponentState';
|
||||
import { RecordInlineCellAnchoredPortal } from '@/object-record/record-inline-cell/components/RecordInlineCellAnchoredPortal';
|
||||
import { useFieldsWidgetFlattenedFields } from '@/page-layout/widgets/fields/hooks/useFieldsWidgetFlattenedFields';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type FieldsWidgetCellHoveredPortalProps = {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
recordId: string;
|
||||
};
|
||||
|
||||
export const FieldsWidgetCellHoveredPortal = ({
|
||||
objectMetadataItem,
|
||||
recordId,
|
||||
}: FieldsWidgetCellHoveredPortalProps) => {
|
||||
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||
RecordFieldListComponentInstanceContext,
|
||||
);
|
||||
|
||||
const hoverPosition = useRecoilComponentValue(
|
||||
recordFieldListHoverPositionComponentState,
|
||||
);
|
||||
|
||||
const { flattenedFieldMetadataItems } = useFieldsWidgetFlattenedFields(
|
||||
objectMetadataItem.nameSingular,
|
||||
);
|
||||
|
||||
const hoveredFieldMetadataItem = isDefined(hoverPosition)
|
||||
? flattenedFieldMetadataItems.at(hoverPosition)
|
||||
: undefined;
|
||||
|
||||
if (!isDefined(hoverPosition) || !isDefined(hoveredFieldMetadataItem)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecordInlineCellAnchoredPortal
|
||||
fieldMetadataItem={hoveredFieldMetadataItem}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
recordId={recordId}
|
||||
instanceIdPrefix={instanceId}
|
||||
>
|
||||
<RecordFieldListInputContextProvider>
|
||||
<RecordFieldListCellHoveredPortalContent />
|
||||
</RecordFieldListInputContextProvider>
|
||||
</RecordInlineCellAnchoredPortal>
|
||||
);
|
||||
};
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { isFieldCellSupported } from '@/object-record/utils/isFieldCellSupported';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
type UseFieldsWidgetFieldMetadataItemsProps = {
|
||||
objectNameSingular: string;
|
||||
};
|
||||
|
||||
export const useFieldsWidgetFieldMetadataItems = ({
|
||||
objectNameSingular,
|
||||
}: UseFieldsWidgetFieldMetadataItemsProps): FieldMetadataItem[] => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
|
||||
const fieldMetadataItems = objectMetadataItem.readableFields.filter(
|
||||
(fieldMetadataItem) =>
|
||||
isFieldCellSupported(fieldMetadataItem, objectMetadataItems) &&
|
||||
fieldMetadataItem.type !== FieldMetadataType.RELATION &&
|
||||
fieldMetadataItem.type !== FieldMetadataType.MORPH_RELATION &&
|
||||
fieldMetadataItem.type !== FieldMetadataType.RICH_TEXT_V2,
|
||||
);
|
||||
|
||||
return fieldMetadataItems;
|
||||
};
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { useFieldsWidgetSectionsWithFields } from '@/page-layout/widgets/fields/hooks/useFieldsWidgetSectionsWithFields';
|
||||
|
||||
export const useFieldsWidgetFlattenedFields = (objectNameSingular: string) => {
|
||||
const { sectionsWithFields } =
|
||||
useFieldsWidgetSectionsWithFields(objectNameSingular);
|
||||
|
||||
const flattenedFieldMetadataItems = sectionsWithFields.flatMap(
|
||||
(section) => section.fields,
|
||||
);
|
||||
|
||||
return { flattenedFieldMetadataItems };
|
||||
};
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import { useTemporaryFieldsConfiguration } from '@/page-layout/hooks/useTemporaryFieldsConfiguration';
|
||||
import { buildWidgetVisibilityContext } from '@/page-layout/utils/buildWidgetVisibilityContext';
|
||||
import { useFieldsWidgetFieldMetadataItems } from '@/page-layout/widgets/fields/hooks/useFieldsWidgetFieldMetadataItems';
|
||||
import { filterAndOrderFieldsFromConfiguration } from '@/page-layout/widgets/fields/utils/filterAndOrderFieldsFromConfiguration';
|
||||
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
|
||||
export const useFieldsWidgetSectionsWithFields = (
|
||||
objectNameSingular: string,
|
||||
) => {
|
||||
const isMobile = useIsMobile();
|
||||
const { isInRightDrawer } = useLayoutRenderingContext();
|
||||
const fieldMetadataItems = useFieldsWidgetFieldMetadataItems({
|
||||
objectNameSingular,
|
||||
});
|
||||
const temporaryConfiguration =
|
||||
useTemporaryFieldsConfiguration(objectNameSingular);
|
||||
|
||||
const context = buildWidgetVisibilityContext({ isMobile, isInRightDrawer });
|
||||
|
||||
const sectionsWithFields = filterAndOrderFieldsFromConfiguration({
|
||||
configuration: temporaryConfiguration ?? {
|
||||
__typename: 'FieldsConfiguration',
|
||||
sections: [],
|
||||
},
|
||||
availableFieldMetadataItems: fieldMetadataItems,
|
||||
context,
|
||||
});
|
||||
|
||||
return { sectionsWithFields };
|
||||
};
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
import { useFieldsWidgetSectionsWithFields } from '@/page-layout/widgets/fields/hooks/useFieldsWidgetSectionsWithFields';
|
||||
|
||||
export const useFieldsWidgetSectionsWithIndices = (
|
||||
objectNameSingular: string,
|
||||
) => {
|
||||
const { sectionsWithFields } =
|
||||
useFieldsWidgetSectionsWithFields(objectNameSingular);
|
||||
|
||||
const sectionsWithFieldIndices = sectionsWithFields.map(
|
||||
(section, sectionIndex) => {
|
||||
const startIndex = sectionsWithFields
|
||||
.slice(0, sectionIndex)
|
||||
.reduce((sum, s) => sum + s.fields.length, 0);
|
||||
|
||||
return {
|
||||
...section,
|
||||
fields: section.fields.map((field, fieldIndex) => ({
|
||||
field,
|
||||
globalIndex: startIndex + fieldIndex,
|
||||
})),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
return { sectionsWithFieldIndices };
|
||||
};
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type FieldsConfiguration } from '@/page-layout/types/FieldsConfiguration';
|
||||
import { type WidgetVisibilityContext } from '@/page-layout/types/WidgetVisibilityContext';
|
||||
import { evaluateWidgetVisibility } from '@/page-layout/utils/evaluateWidgetVisibility';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export type FieldsConfigurationSectionWithFields = {
|
||||
id: string;
|
||||
title: string;
|
||||
position: number;
|
||||
fields: FieldMetadataItem[];
|
||||
};
|
||||
|
||||
type FilterAndOrderFieldsFromConfigurationParams = {
|
||||
configuration: FieldsConfiguration;
|
||||
availableFieldMetadataItems: FieldMetadataItem[];
|
||||
context: WidgetVisibilityContext;
|
||||
};
|
||||
|
||||
export const filterAndOrderFieldsFromConfiguration = ({
|
||||
configuration,
|
||||
availableFieldMetadataItems,
|
||||
context,
|
||||
}: FilterAndOrderFieldsFromConfigurationParams): FieldsConfigurationSectionWithFields[] => {
|
||||
const fieldMetadataItemsMap = new Map(
|
||||
availableFieldMetadataItems.map((field) => [field.id, field]),
|
||||
);
|
||||
|
||||
const sortedSections = [...configuration.sections].sort(
|
||||
(a, b) => a.position - b.position,
|
||||
);
|
||||
|
||||
const sectionsWithFields = sortedSections
|
||||
.map((section) => {
|
||||
const sortedFields = [...section.fields].sort(
|
||||
(a, b) => a.position - b.position,
|
||||
);
|
||||
|
||||
const visibleFields = sortedFields
|
||||
.map((fieldConfig) => {
|
||||
const fieldMetadataItem = fieldMetadataItemsMap.get(
|
||||
fieldConfig.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(fieldMetadataItem)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isVisible = evaluateWidgetVisibility({
|
||||
conditionalDisplay: fieldConfig.conditionalDisplay,
|
||||
context,
|
||||
});
|
||||
|
||||
if (!isVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fieldMetadataItem;
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
if (visibleFields.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
id: section.id,
|
||||
title: section.title,
|
||||
position: section.position,
|
||||
fields: visibleFields,
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
return sectionsWithFields;
|
||||
};
|
||||
Reference in New Issue
Block a user