From 1b4a85f87b237ff8dd9838e463900f1879827f17 Mon Sep 17 00:00:00 2001 From: Andres Galindo Date: Tue, 11 Feb 2025 12:11:19 -0800 Subject: [PATCH 1/2] Use Local State for Immediate UI Updates with Deferred Global Store Sync (#3193) closes https://github.com/zesty-io/manager-ui/issues/3178 This approach mimics the [useDeferredValue](https://react.dev/reference/react/useDeferredValue ) hook value method that is only available on react 19 - Introduces a local state to handle immediate UI updates for text based controlled inputs. - Ensures smoother user experience by eliminating lag caused by global store updates. - Global state updates are now deferred, preventing excessive store updates on key clicks in order to keep the UI update process free and responsive. - Syncs local state with external value changes to maintain consistency. **This approach ensures real-time user feedback with zero lag** An alternative but much larger scope approach would be to restructure the component tree and optimize the use of selectors to minimize re-renders caused the global store and prop drilling. However it could potentially not reach the zero lag achieved by the deferring approach as it guarantees UI update calls have the highest priority --- .../src/app/components/Editor/Field/Field.tsx | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx index 5d1bfd130..754624bb7 100644 --- a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx +++ b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx @@ -71,6 +71,7 @@ import { import { ResolvedOption } from "./ResolvedOption"; import { LinkOption } from "./LinkOption"; import { FieldTypeMedia } from "../../FieldTypeMedia"; +import { debounce } from "lodash"; const AIFieldShell = withAI(FieldShell); @@ -203,6 +204,22 @@ export const Field = ({ const value = item?.data?.[name]; const version = item?.meta?.version; const fieldData = fields?.find((field) => field.ZUID === ZUID); + const [inputValue, setInputValue] = useState(value || ""); + + const debouncedOnChange = useMemo(() => debounce(onChange, 300), [onChange]); + + const deferredChange = useCallback( + (value, name) => { + setInputValue(value); + debouncedOnChange(value, name); + }, + [debouncedOnChange] + ); + + // Keep local input value in sync with global field value + useEffect(() => { + setInputValue(value || ""); + }, [value]); useEffect(() => { if (datatype !== "date" && datatype !== "datetime") { @@ -288,7 +305,7 @@ export const Field = ({ ZUID={fieldData?.ZUID} name={fieldData?.name || name} label={fieldData?.label || label} - valueLength={(value as string)?.length ?? 0} + valueLength={(inputValue as string)?.length ?? 0} settings={ fieldData || { name: name, @@ -304,11 +321,11 @@ export const Field = ({ minLength={minLength} errors={errors} aiType="text" - value={value} + value={inputValue} > onChange(evt.target.value, name)} + value={inputValue} + onChange={(evt) => deferredChange(evt.target.value, name)} fullWidth inputProps={{ name: fieldData?.name || name, @@ -322,12 +339,12 @@ export const Field = ({ return ( onChange(evt.target.value, name)} + value={inputValue} + onChange={(evt) => deferredChange(evt.target.value, name)} fullWidth error={errors && Object.values(errors)?.some((error) => !!error)} /> @@ -338,14 +355,14 @@ export const Field = ({ return ( onChange(evt.target.value, name)} + value={inputValue} + onChange={(evt) => deferredChange(evt.target.value, name)} fullWidth type="url" error={errors && Object.values(errors)?.some((error) => !!error)} @@ -377,7 +394,7 @@ export const Field = ({ ZUID={fieldData?.ZUID} name={fieldData?.name} label={fieldData?.label} - valueLength={(value as string)?.length ?? 0} + valueLength={(inputValue as string)?.length ?? 0} settings={fieldData} onChange={(evt: ChangeEvent) => onChange(evt.target.value, name) @@ -387,11 +404,11 @@ export const Field = ({ aiType="word" maxLength={maxLength} minLength={minLength} - value={value} + value={inputValue} > onChange(evt.target.value, name)} + value={inputValue} + onChange={(evt) => deferredChange(evt.target.value, name)} fullWidth multiline rows={6} @@ -424,7 +441,7 @@ export const Field = ({ name={name} value={value} version={version} - onChange={onChange} + onChange={deferredChange} onSave={onSave} onCharacterCountChange={(charCount: number) => setCharacterCount(charCount) @@ -448,7 +465,7 @@ export const Field = ({ ZUID={fieldData?.ZUID} name={fieldData?.name} label={fieldData?.label} - valueLength={(value as string)?.length ?? 0} + valueLength={(inputValue as string)?.length ?? 0} settings={fieldData} onChange={onChange} errors={errors} @@ -456,14 +473,14 @@ export const Field = ({ datatype={fieldData?.datatype} editorType={editorType} onEditorChange={(value: EditorType) => setEditorType(value)} - value={value} + value={inputValue} > { setImageModal(opts); @@ -918,10 +935,10 @@ export const Field = ({ return ( !!error)} /> @@ -937,8 +954,8 @@ export const Field = ({ !!error)} /> From 78cf4c8c75d860c8e80c688264b3009570c7ed89 Mon Sep 17 00:00:00 2001 From: Nar -- <28705606+finnar-bin@users.noreply.github.com> Date: Wed, 12 Feb 2025 13:47:34 +0800 Subject: [PATCH 2/2] [Content | Schema] VQA Round 2 updates for the one-to-one/many revamp (#3198) --- .../src/app/components/Editor/Field/Field.tsx | 2 + .../src/app/views/ItemEdit/ItemEdit.js | 5 + .../ItemEditHeader/ItemEditHeaderActions.tsx | 94 +++++++++++-------- .../ItemEditHeader/UnpublishedRelatedItem.tsx | 16 +++- .../components/AddFieldModal/DefaultValue.tsx | 3 + .../AddFieldModal/DefaultValueInput.tsx | 4 + .../components/AddFieldModal/views/Rules.tsx | 1 + src/shell/components/ConfirmPublishModal.tsx | 6 +- .../components/NoSearchResults/index.tsx | 4 +- .../ActiveItem/ActiveItemLoading.tsx | 4 +- .../RelationalFieldBase/ActiveItem/index.tsx | 75 ++++++++++----- .../FieldSelectorDialog/DialogHeader.tsx | 6 +- .../FieldSelectorDialog/index.tsx | 24 ++++- .../components/RelationalFieldBase/index.tsx | 14 ++- 14 files changed, 174 insertions(+), 84 deletions(-) diff --git a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx index 754624bb7..603952dd6 100644 --- a/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx +++ b/src/apps/content-editor/src/app/components/Editor/Field/Field.tsx @@ -806,6 +806,7 @@ export const Field = ({ relatedModelZUID={relatedModelZUID} relatedFieldZUID={relatedFieldZUID} onChange={onChange} + fieldLabel={fieldData?.label} /> {/** {/** state.headTags, @@ -416,6 +420,7 @@ export default function ItemEdit() { } finally { if (isMounted.current) { setSaving(false); + dispatch(fetchItemPublishings()); } } } diff --git a/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/ItemEditHeaderActions.tsx b/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/ItemEditHeaderActions.tsx index d7a05a1b9..dafbf137f 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/ItemEditHeaderActions.tsx +++ b/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/ItemEditHeaderActions.tsx @@ -89,7 +89,7 @@ export const ItemEditHeaderActions = ({ const [isConfirmPublishModalOpen, setIsConfirmPublishModalOpen] = useState(false); const [relatedItemsToPublish, setRelatedItemsToPublish] = useState< - ContentItem[] + ContentItemWithDirtyAndPublishing[] >([]); const [isPublishing, setIsPublishing] = useState(false); const item = useSelector( @@ -184,10 +184,11 @@ export const ItemEditHeaderActions = ({ if (!!item) { const draftVersion = item?.meta?.version; const publishedVersion = item?.publishing?.version || 0; + const scheduledVersion = item?.scheduling?.version || 0; if ( - draftVersion > publishedVersion && - !item?.scheduling?.isScheduled + draftVersion > publishedVersion || + scheduledVersion > publishedVersion ) { return { ...item, @@ -225,45 +226,60 @@ export const ItemEditHeaderActions = ({ const handlePublish = async () => { setIsPublishing(true); - // If item is scheduled, delete the scheduled publishing first - if (itemState === ITEM_STATES.scheduled) { - await deleteItemPublishing({ - modelZUID, - itemZUID, - publishingZUID: item?.scheduling?.ZUID, - }); - } + try { + // Delete scheduled publishings first + const deleteScheduledPromises = [ + // Delete main item's scheduled publishing if it exists + itemState === ITEM_STATES.scheduled && + deleteItemPublishing({ + modelZUID, + itemZUID, + publishingZUID: item?.scheduling?.ZUID, + }), + // Delete related items' scheduled publishings if they exist + ...relatedItemsToPublish + .filter((item) => !!item.scheduling?.ZUID) + .map((item) => + deleteItemPublishing({ + modelZUID: item.meta.contentModelZUID, + itemZUID: item.meta.ZUID, + publishingZUID: item.scheduling.ZUID, + }) + ), + ].filter((item) => !!item); + + await Promise.all(deleteScheduledPromises); - Promise.allSettled([ - createPublishing({ - modelZUID, - itemZUID, - body: { - version: item?.meta.version, - publishAt: "now", - unpublishAt: "never", - }, - }), - relatedItemsToPublish.map((item) => { - return createPublishing({ - modelZUID: item.meta.contentModelZUID, - itemZUID: item.meta.ZUID, + // Proceed with publishing + await Promise.allSettled([ + createPublishing({ + modelZUID, + itemZUID, body: { - version: item.meta.version, + version: item?.meta.version, publishAt: "now", unpublishAt: "never", }, - }); - }), - ]) - .then(() => { - // Retain non rtk-query fetch of item publishing for legacy code - dispatch(fetchItemPublishings()); - }) - .finally(() => { - setIsPublishing(false); - setIsConfirmPublishModalOpen(false); - }); + }), + ...relatedItemsToPublish.map((item) => + createPublishing({ + modelZUID: item.meta.contentModelZUID, + itemZUID: item.meta.ZUID, + body: { + version: item.meta.version, + publishAt: "now", + unpublishAt: "never", + }, + }) + ), + ]); + + // Retain non rtk-query fetch of item publishing for legacy code + dispatch(fetchItemPublishings()); + } finally { + setIsPublishing(false); + setIsConfirmPublishModalOpen(false); + } }; const handleUnpublish = async () => { @@ -649,7 +665,7 @@ export const ItemEditHeaderActions = ({ Also publish related items - + This will publish all items selected in the list below @@ -657,7 +673,7 @@ export const ItemEditHeaderActions = ({ index + 1} + divider selected={relatedItemsToPublish.some( (i) => i.meta.ZUID === item.meta.ZUID )} diff --git a/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/UnpublishedRelatedItem.tsx b/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/UnpublishedRelatedItem.tsx index e2ed3cf89..072f4419a 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/UnpublishedRelatedItem.tsx +++ b/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/UnpublishedRelatedItem.tsx @@ -23,7 +23,7 @@ type UnpublishedRelatedItemProps = { contentItem: ContentItemWithRelatedZUIDs; onChange: (payload: { action: "add" | "remove"; - contentItem: ContentItem; + contentItem: ContentItemWithDirtyAndPublishing; }) => void; selected: boolean; divider?: boolean; @@ -79,15 +79,27 @@ export const UnpublishedRelatedItem = ({ return ( - + onChange({ contentItem, action: evt.target.checked ? "add" : "remove", }) } + sx={{ + pl: 0, + pr: 2, + "&:hover": { + bgcolor: "transparent", + }, + }} /> {!!imageFieldName && diff --git a/src/apps/schema/src/app/components/AddFieldModal/DefaultValue.tsx b/src/apps/schema/src/app/components/AddFieldModal/DefaultValue.tsx index 0a4d2ac97..71786aa39 100644 --- a/src/apps/schema/src/app/components/AddFieldModal/DefaultValue.tsx +++ b/src/apps/schema/src/app/components/AddFieldModal/DefaultValue.tsx @@ -28,6 +28,7 @@ type DefaultValueProps = { }; options: FieldSettingsOptions[]; currency?: string; + fieldLabel: string; }; export const DefaultValue = ({ @@ -41,6 +42,7 @@ export const DefaultValue = ({ relationshipFields, options, currency, + fieldLabel, }: DefaultValueProps) => { return ( @@ -91,6 +93,7 @@ export const DefaultValue = ({ relationshipFields={relationshipFields} options={options} currency={currency} + fieldLabel={fieldLabel} /> diff --git a/src/apps/schema/src/app/components/AddFieldModal/DefaultValueInput.tsx b/src/apps/schema/src/app/components/AddFieldModal/DefaultValueInput.tsx index 77f361419..fea9fa710 100644 --- a/src/apps/schema/src/app/components/AddFieldModal/DefaultValueInput.tsx +++ b/src/apps/schema/src/app/components/AddFieldModal/DefaultValueInput.tsx @@ -56,6 +56,7 @@ type DefaultValueInputProps = { }; options: FieldSettingsOptions[]; currency?: string; + fieldLabel: string; }; export const DefaultValueInput = ({ @@ -67,6 +68,7 @@ export const DefaultValueInput = ({ relationshipFields: { relatedModelZUID, relatedFieldZUID }, options, currency, + fieldLabel, }: DefaultValueInputProps) => { const [imageModal, setImageModal] = useState(null); const dispatch = useDispatch(); @@ -308,6 +310,7 @@ export const DefaultValueInput = ({ relatedModelZUID={relatedModelZUID} relatedFieldZUID={relatedFieldZUID} onChange={(value) => onChange(value)} + fieldLabel={fieldLabel} /> ); case "one_to_many": @@ -319,6 +322,7 @@ export const DefaultValueInput = ({ relatedModelZUID={relatedModelZUID} relatedFieldZUID={relatedFieldZUID} onChange={(value) => onChange(value)} + fieldLabel={fieldLabel} /> ); case "link": diff --git a/src/apps/schema/src/app/components/AddFieldModal/views/Rules.tsx b/src/apps/schema/src/app/components/AddFieldModal/views/Rules.tsx index 7a4c95a7b..ee388a338 100644 --- a/src/apps/schema/src/app/components/AddFieldModal/views/Rules.tsx +++ b/src/apps/schema/src/app/components/AddFieldModal/views/Rules.tsx @@ -67,6 +67,7 @@ export const Rules = ({ }} options={formData["options"] as FieldSettingsOptions[]} currency={(formData["currency"] as string) || "USD"} + fieldLabel={formData["label"] as string} /> {type === "images" && ( diff --git a/src/shell/components/ConfirmPublishModal.tsx b/src/shell/components/ConfirmPublishModal.tsx index ef794fcf3..5401b7c08 100644 --- a/src/shell/components/ConfirmPublishModal.tsx +++ b/src/shell/components/ConfirmPublishModal.tsx @@ -12,7 +12,6 @@ import { } from "@mui/material"; import CloudUploadRoundedIcon from "@mui/icons-material/CloudUploadRounded"; import { LoadingButton } from "@mui/lab"; -import pluralizeWord from "../../utility/pluralizeWord"; export type ConfirmPublishModal = { contentTitle: string; @@ -90,10 +89,7 @@ export const ConfirmPublishModal = ({ onClick={onConfirm} data-cy="ConfirmPublishButton" > - Publish{" "} - {!!altText - ? pluralizeWord(altText, relatedItemsToPublishCount) - : pluralizeWord("Item", relatedItemsToPublishCount)}{" "} + Publish {altText || !!relatedItemsToPublishCount ? "Items " : "Item "} {!!relatedItemsToPublishCount && `(${relatedItemsToPublishCount + 1})`} diff --git a/src/shell/components/NoSearchResults/index.tsx b/src/shell/components/NoSearchResults/index.tsx index 3ef5ca94f..428ff93a1 100644 --- a/src/shell/components/NoSearchResults/index.tsx +++ b/src/shell/components/NoSearchResults/index.tsx @@ -18,6 +18,7 @@ type Props = { hideBackButton?: boolean; onSearchAgain?: () => void; imageHeight?: number; + isFilter?: boolean; }; export const NoSearchResults: FC = ({ @@ -26,6 +27,7 @@ export const NoSearchResults: FC = ({ ignoreFilters, hideBackButton, imageHeight = 200, + isFilter, }) => { const history = useHistory(); const [params, setParams] = useParams(); @@ -68,7 +70,7 @@ export const NoSearchResults: FC = ({ "No results that matched your filters could be found" ) : ( <> - Your search + Your {isFilter ? "filter" : "search"} {" "} "{query}"{" "} diff --git a/src/shell/components/RelationalFieldBase/ActiveItem/ActiveItemLoading.tsx b/src/shell/components/RelationalFieldBase/ActiveItem/ActiveItemLoading.tsx index d0200f8e7..b8673f32f 100644 --- a/src/shell/components/RelationalFieldBase/ActiveItem/ActiveItemLoading.tsx +++ b/src/shell/components/RelationalFieldBase/ActiveItem/ActiveItemLoading.tsx @@ -10,7 +10,7 @@ export const ActiveItemLoading = ({ draggable }: ActiveItemLoadingProps) => { direction="row" sx={{ bgcolor: "background.paper", - height: 64, + height: 62, width: "100%", border: 1, borderColor: "border", @@ -20,7 +20,7 @@ export const ActiveItemLoading = ({ draggable }: ActiveItemLoadingProps) => { > {draggable && ( - + )} diff --git a/src/shell/components/RelationalFieldBase/ActiveItem/index.tsx b/src/shell/components/RelationalFieldBase/ActiveItem/index.tsx index 88be97e37..c2c3281ec 100644 --- a/src/shell/components/RelationalFieldBase/ActiveItem/index.tsx +++ b/src/shell/components/RelationalFieldBase/ActiveItem/index.tsx @@ -8,6 +8,7 @@ import { ListItemText, ListItemIcon, IconButton, + Tooltip, } from "@mui/material"; import { DragIndicatorRounded, @@ -67,6 +68,7 @@ export const ActiveItem = memo( const [isPublishModalOpen, setIsPublishModalOpen] = useState(false); const [isScheduleModalOpen, setIsScheduleModalOpen] = useState(false); const [isCopied, setIsCopied] = useState(false); + const [showTooltip, setShowTooltip] = useState(false); const history = useHistory(); const dispatch = useDispatch(); const domain = useDomain(); @@ -242,7 +244,7 @@ export const ActiveItem = memo( direction="row" sx={{ bgcolor: "background.paper", - height: 64, + height: !!imageFieldName ? 62 : 58, width: "100%", border: 1, borderColor: "border", @@ -250,20 +252,31 @@ export const ActiveItem = memo( alignItems: "center", overflow: "hidden", opacity: isDragging ? 0 : 1, + transform: "translate(0, 0)", }} > {draggable && ( - setShowTooltip(true)} + onClose={() => setShowTooltip(false)} > - - + setShowTooltip(false)} + > + + + )} {!!imageFieldName && (!!imageURL && !imageError ? ( @@ -349,22 +362,36 @@ export const ActiveItem = memo( /> )} - - history.push(`/content/${relatedModelData?.ZUID}/${itemZUID}`) - } - disabled={!contentItem} + - - - setAnchorEl(evt.currentTarget)} + + history.push( + `/content/${relatedModelData?.ZUID}/${itemZUID}` + ) + } + disabled={!contentItem} + > + + + + - - + setAnchorEl(evt.currentTarget)} + > + + + diff --git a/src/shell/components/RelationalFieldBase/FieldSelectorDialog/DialogHeader.tsx b/src/shell/components/RelationalFieldBase/FieldSelectorDialog/DialogHeader.tsx index 278666128..ab0cd76ae 100644 --- a/src/shell/components/RelationalFieldBase/FieldSelectorDialog/DialogHeader.tsx +++ b/src/shell/components/RelationalFieldBase/FieldSelectorDialog/DialogHeader.tsx @@ -9,7 +9,7 @@ import { CheckRounded, CloseRounded } from "@mui/icons-material"; type DialogHeaderProps = { selectedCount: number; - modelName: string; + fieldLabel: string; onClose: () => void; onDeselectAll: () => void; onDone: () => void; @@ -18,7 +18,7 @@ type DialogHeaderProps = { }; export const DialogHeader = ({ selectedCount, - modelName, + fieldLabel, onClose, onDone, onDeselectAll, @@ -39,7 +39,7 @@ export const DialogHeader = ({ }} > - Select {modelName} + Select {fieldLabel} diff --git a/src/shell/components/RelationalFieldBase/FieldSelectorDialog/index.tsx b/src/shell/components/RelationalFieldBase/FieldSelectorDialog/index.tsx index b751486d5..4515d2b91 100644 --- a/src/shell/components/RelationalFieldBase/FieldSelectorDialog/index.tsx +++ b/src/shell/components/RelationalFieldBase/FieldSelectorDialog/index.tsx @@ -71,19 +71,19 @@ export type FieldFilters = { type FieldSelectorDialogProps = { onClose: () => void; modelZUID: string; - modelName: string; relatedFieldName: string; selectedZUIDs: string[]; onUpdateSelectedZUIDs: (selectedZUIDs: string[]) => void; + fieldLabel: string; multiselect?: boolean; }; export const FieldSelectorDialog = ({ onClose, modelZUID, - modelName, relatedFieldName, selectedZUIDs, onUpdateSelectedZUIDs, + fieldLabel, multiselect, }: FieldSelectorDialogProps) => { const dispatch = useDispatch(); @@ -538,7 +538,7 @@ export const FieldSelectorDialog = ({ }} > {!rows?.length && isFilteringResults ? ( { if (!!filterKeyword) { @@ -660,6 +661,23 @@ export const FieldSelectorDialog = ({ mx: "3px", }, + "& .MuiDataGrid-row.Mui-selected": { + borderBottom: (theme) => + `1px solid ${theme.palette.primary.main}`, + + "& .MuiDataGrid-cell": { + borderBottom: 0, + }, + }, + + "& .MuiDataGrid-cell:focus-within": { + outline: "none", + }, + + ".MuiDataGrid-row": { + cursor: "pointer", + }, + "& [data-field='image']": { p: 0, }, diff --git a/src/shell/components/RelationalFieldBase/index.tsx b/src/shell/components/RelationalFieldBase/index.tsx index 4f29c23c5..14de000f3 100644 --- a/src/shell/components/RelationalFieldBase/index.tsx +++ b/src/shell/components/RelationalFieldBase/index.tsx @@ -21,6 +21,7 @@ import { ActiveItemLoading } from "./ActiveItem/ActiveItemLoading"; type RelationalFieldBaseProps = { name: string; value: string; + fieldLabel: string; relatedModelZUID: string; relatedFieldZUID: string; onChange: (value: string, name: string) => void; @@ -29,6 +30,7 @@ type RelationalFieldBaseProps = { export const RelationalFieldBase = ({ name, value, + fieldLabel, relatedModelZUID, relatedFieldZUID, onChange, @@ -71,10 +73,12 @@ export const RelationalFieldBase = ({ onChange(itemZUIDs?.join(","), name); }, [itemZUIDs]); + const isLoading = isLoadingModelData || isLoadingModelFields; + return ( - {isLoadingModelData || isLoadingModelFields ? ( + {isLoading ? ( [...Array(multiselect ? 5 : 1)].map((_, index) => ( )) @@ -134,11 +138,11 @@ export const RelationalFieldBase = ({ fullWidth onClick={(evt) => setAnchorEl(evt.currentTarget)} sx={{ - mt: 1, + mt: !!itemZUIDs?.length || isLoading ? 1 : 0, }} - disabled={isLoadingModelData || isLoadingModelFields || !modelData} + disabled={isLoading || !modelData} > - Add Existing {modelData?.label} + Add Existing {fieldLabel} )} {!!anchorEl && ( @@ -146,7 +150,7 @@ export const RelationalFieldBase = ({ multiselect={multiselect} onClose={() => setAnchorEl(null)} modelZUID={relatedModelZUID} - modelName={modelData?.label} + fieldLabel={fieldLabel} relatedFieldName={ modelFields?.find((field) => field.ZUID === relatedFieldZUID)?.name }