Refactor ObjectDisplay component to enhance ID validation and handling. Introduced utility functions for ID extraction and validation, ensuring proper object hydration and subscription management. Updated related logic to improve robustness against invalid IDs.
This commit is contained in:
parent
62f0e047e2
commit
545cc0c526
@ -31,12 +31,33 @@ const ObjectDisplay = ({
|
||||
setObjectData((prev) => merge({}, prev, value))
|
||||
}, [])
|
||||
|
||||
// Detect minimal objects that only contain an _id
|
||||
// Ensure ID is valid before hydrate/subscribe (non-empty, not null/undefined)
|
||||
const isValidId = useCallback((id) => {
|
||||
return id != null && String(id).trim() !== ''
|
||||
}, [])
|
||||
|
||||
// Extract string ID from object; handles both primitive _id and populated ref (_id as object)
|
||||
const getStringId = useCallback((obj) => {
|
||||
const id = obj?._id
|
||||
if (id == null) return null
|
||||
if (typeof id === 'string') return id
|
||||
if (typeof id === 'object' && id !== null && typeof id._id === 'string')
|
||||
return id._id
|
||||
return null
|
||||
}, [])
|
||||
|
||||
// Detect minimal objects that only contain an _id (must be string, not populated object)
|
||||
const isMinimalObject = useCallback((obj) => {
|
||||
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return false
|
||||
const keys = Object.keys(obj)
|
||||
return keys.length === 1 && keys[0] === '_id' && obj._id
|
||||
}, [])
|
||||
const id = obj._id
|
||||
return (
|
||||
keys.length === 1 &&
|
||||
keys[0] === '_id' &&
|
||||
typeof id === 'string' &&
|
||||
isValidId(id)
|
||||
)
|
||||
}, [isValidId])
|
||||
|
||||
// If only an _id is provided, fetch the full object via spotlight
|
||||
const fetchFullObjectIfNeeded = useCallback(
|
||||
@ -64,9 +85,10 @@ const ObjectDisplay = ({
|
||||
|
||||
// Subscribe to object updates when component mounts
|
||||
useEffect(() => {
|
||||
if (object?._id && objectType && connected && token != null) {
|
||||
const id = getStringId(object)
|
||||
if (isValidId(id) && objectType && connected && token != null) {
|
||||
const objectUpdatesUnsubscribe = subscribeToObjectUpdates(
|
||||
object._id,
|
||||
id,
|
||||
objectType,
|
||||
updateObjectEventHandler
|
||||
)
|
||||
@ -76,27 +98,31 @@ const ObjectDisplay = ({
|
||||
}
|
||||
}
|
||||
}, [
|
||||
object?._id,
|
||||
object,
|
||||
objectType,
|
||||
subscribeToObjectUpdates,
|
||||
connected,
|
||||
token,
|
||||
updateObjectEventHandler
|
||||
updateObjectEventHandler,
|
||||
isValidId,
|
||||
getStringId
|
||||
])
|
||||
|
||||
// Update local state when object prop changes
|
||||
useEffect(() => {
|
||||
if (token == null) return
|
||||
const id = getStringId(object)
|
||||
if (!isValidId(id)) return
|
||||
const isMinimal = isMinimalObject(object)
|
||||
// Only skip re-fetch when we have a minimal object and already hydrated this id
|
||||
if (isMinimal && idRef.current === object?._id) return
|
||||
if (isMinimal && idRef.current === id) return
|
||||
let cancelled = false
|
||||
if (isMinimal) setIsHydrating(true)
|
||||
const hydrateObject = async () => {
|
||||
const fullObject = await fetchFullObjectIfNeeded(object)
|
||||
if (!cancelled) {
|
||||
setObjectData((prev) => merge({}, prev, fullObject))
|
||||
if (isMinimal) idRef.current = object?._id
|
||||
if (isMinimal) idRef.current = id
|
||||
setIsHydrating(false)
|
||||
}
|
||||
}
|
||||
@ -105,7 +131,7 @@ const ObjectDisplay = ({
|
||||
cancelled = true
|
||||
setIsHydrating(false)
|
||||
}
|
||||
}, [object, fetchFullObjectIfNeeded, isMinimalObject, token])
|
||||
}, [object, fetchFullObjectIfNeeded, isMinimalObject, isValidId, getStringId, token])
|
||||
if (!objectData) {
|
||||
return <Text type='secondary'>n/a</Text>
|
||||
}
|
||||
@ -137,7 +163,7 @@ const ObjectDisplay = ({
|
||||
var hyperlink = null
|
||||
const defaultModelActions =
|
||||
model.actions?.filter((action) => action.default == true) || []
|
||||
const objectId = objectData._id
|
||||
const objectId = getStringId(objectData)
|
||||
|
||||
if (defaultModelActions.length >= 1 && objectId) {
|
||||
hyperlink = defaultModelActions[0].url(objectId)
|
||||
@ -229,9 +255,9 @@ const ObjectDisplay = ({
|
||||
<div style={{ minWidth: 0 }}>
|
||||
{renderNameDisplay()}
|
||||
|
||||
{objectData?._id && !objectData?.name ? (
|
||||
{objectId && !objectData?.name ? (
|
||||
<IdDisplay
|
||||
id={objectData?._id}
|
||||
id={objectId}
|
||||
reference={objectData?._reference || undefined}
|
||||
type={objectType}
|
||||
longId={false}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user