From 55f7fc247aced75ebe86fc556e274d68c69631c8 Mon Sep 17 00:00:00 2001 From: platex-rehor-bot Date: Fri, 21 Aug 2026 13:32:07 +0000 Subject: [PATCH 1/2] OCPBUGS-85013: Fix Topology page TypeError when resource object is null The Topology view crashes with "can't access property kind, e is null" when rendering nodes whose resource object has not yet loaded or is unavailable (e.g. Helm release group nodes without a matching Secret). getTopologyResourceObject() can return null, but several components pass its result directly to referenceFor() which destructures {kind} from the argument, causing a TypeError on null. Add null guards with optional chaining across all affected call sites: WorkloadNode, BaseNode, BindableNode, withEditReviewAccess, OdcBaseNode, and getResourceKind utility. Co-Authored-By: Claude Opus 4.6 --- .../graph-view/components/nodes/BaseNode.tsx | 6 +++--- .../graph-view/components/nodes/BindableNode.tsx | 2 +- .../graph-view/components/nodes/WorkloadNode.tsx | 4 ++-- .../packages/topology/src/elements/OdcBaseNode.ts | 2 +- .../packages/topology/src/utils/topology-utils.ts | 11 +++++++---- .../topology/src/utils/withEditReviewAccess.tsx | 10 +++++----- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/frontend/packages/topology/src/components/graph-view/components/nodes/BaseNode.tsx b/frontend/packages/topology/src/components/graph-view/components/nodes/BaseNode.tsx index 05b71d75429..cf63ee0e22d 100644 --- a/frontend/packages/topology/src/components/graph-view/components/nodes/BaseNode.tsx +++ b/frontend/packages/topology/src/components/graph-view/components/nodes/BaseNode.tsx @@ -50,14 +50,14 @@ const BaseNodeComponent: FC = ({ const cx = width / 2; const cy = height / 2; const resourceObj = getTopologyResourceObject(element.getData()); - const resourceModel = modelFor(referenceFor(resourceObj)); + const resourceModel = resourceObj ? modelFor(referenceFor(resourceObj)) : undefined; const iconRadius = innerRadius * 0.9; const editAccess = useAccessReview({ group: resourceModel?.apiGroup, verb: createConnectorAccessVerb, resource: resourceModel?.plural, - name: resourceObj.metadata.name, - namespace: resourceObj.metadata.namespace, + name: resourceObj?.metadata?.name, + namespace: resourceObj?.metadata?.namespace, }); const [filtered] = useSearchFilter(element.getLabel(), resourceObj?.metadata?.labels); const showLabel = useShowLabel(isHovering); diff --git a/frontend/packages/topology/src/components/graph-view/components/nodes/BindableNode.tsx b/frontend/packages/topology/src/components/graph-view/components/nodes/BindableNode.tsx index d3203f30713..20d850ea422 100644 --- a/frontend/packages/topology/src/components/graph-view/components/nodes/BindableNode.tsx +++ b/frontend/packages/topology/src/components/graph-view/components/nodes/BindableNode.tsx @@ -36,7 +36,7 @@ const BindableNode: FC = ({ const iconRadius = Math.min(width, height) * 0.25; const [dndDropProps, dndDropRef] = useDndDrop(spec, { element: nodeElement, ...rest }); const resourceObj = getTopologyResourceObject(element.getData()); - const resourceModel = modelFor(referenceFor(resourceObj)); + const resourceModel = resourceObj ? modelFor(referenceFor(resourceObj)) : undefined; const iconData = element.getData()?.data?.icon || openshiftImg; const kind = resourceModel && referenceForModel(resourceModel); diff --git a/frontend/packages/topology/src/components/graph-view/components/nodes/WorkloadNode.tsx b/frontend/packages/topology/src/components/graph-view/components/nodes/WorkloadNode.tsx index f77d388de14..236649792fe 100644 --- a/frontend/packages/topology/src/components/graph-view/components/nodes/WorkloadNode.tsx +++ b/frontend/packages/topology/src/components/graph-view/components/nodes/WorkloadNode.tsx @@ -234,8 +234,8 @@ const WorkloadNode: FC = observer(({ element, ...rest }) => { const resource = getTopologyResourceObject(element.getData()); const { podData, loadError, loaded } = usePodsWatcher( resource, - resource.kind, - resource.metadata.namespace, + resource?.kind, + resource?.metadata?.namespace, ); return ( (node: GraphElement return (resource as T) || (getTopologyResourceObject(node?.getData()) as T); }; -export const getResourceKind = (node: Node): K8sResourceKindReference => - node instanceof OdcBaseNode - ? (node as OdcBaseNode).getResourceKind() - : referenceFor(getTopologyResourceObject(node?.getData())); +export const getResourceKind = (node: Node): K8sResourceKindReference => { + if (node instanceof OdcBaseNode) { + return (node as OdcBaseNode).getResourceKind(); + } + const resource = getTopologyResourceObject(node?.getData()); + return resource ? referenceFor(resource) : undefined; +}; export const updateTopologyResourceApplication = ( item: Node, diff --git a/frontend/packages/topology/src/utils/withEditReviewAccess.tsx b/frontend/packages/topology/src/utils/withEditReviewAccess.tsx index cc55007b1d4..a2e28fb7f12 100644 --- a/frontend/packages/topology/src/utils/withEditReviewAccess.tsx +++ b/frontend/packages/topology/src/utils/withEditReviewAccess.tsx @@ -11,13 +11,13 @@ import { getResource } from './topology-utils'; export const withEditReviewAccess: WithEditReviewAccess = (verb) => (WrappedComponent) => { const Component: FC = (props) => { const resourceObj = getResource(props.element); - const resourceModel = modelFor(referenceFor(resourceObj)); + const resourceModel = resourceObj ? modelFor(referenceFor(resourceObj)) : undefined; const editAccess = useAccessReview({ - group: resourceModel.apiGroup, + group: resourceModel?.apiGroup, verb, - resource: resourceModel.plural, - name: resourceObj.metadata.name, - namespace: resourceObj.metadata.namespace, + resource: resourceModel?.plural, + name: resourceObj?.metadata?.name, + namespace: resourceObj?.metadata?.namespace, }); return ; }; From 7e9ae248aaf6dab8c552a0906dfe86943ef6bd23 Mon Sep 17 00:00:00 2001 From: platex-rehor-bot Date: Mon, 24 Aug 2026 19:15:14 +0000 Subject: [PATCH 2/2] OCPBUGS-85013: Address review feedback on null resource handling - Fix getResourceKind return type to include undefined - Prevent edit controls showing on unresolvable nodes by defaulting canEdit to false when resource is null OCPBUGS-85013 Co-Authored-By: Claude Opus 4.6 --- frontend/packages/topology/src/utils/topology-utils.ts | 2 +- frontend/packages/topology/src/utils/withEditReviewAccess.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/packages/topology/src/utils/topology-utils.ts b/frontend/packages/topology/src/utils/topology-utils.ts index 8a6329378ac..c51ab64b88c 100644 --- a/frontend/packages/topology/src/utils/topology-utils.ts +++ b/frontend/packages/topology/src/utils/topology-utils.ts @@ -125,7 +125,7 @@ export const getResource: GetResource = (node: GraphElement return (resource as T) || (getTopologyResourceObject(node?.getData()) as T); }; -export const getResourceKind = (node: Node): K8sResourceKindReference => { +export const getResourceKind = (node: Node): K8sResourceKindReference | undefined => { if (node instanceof OdcBaseNode) { return (node as OdcBaseNode).getResourceKind(); } diff --git a/frontend/packages/topology/src/utils/withEditReviewAccess.tsx b/frontend/packages/topology/src/utils/withEditReviewAccess.tsx index a2e28fb7f12..c832f4fb81d 100644 --- a/frontend/packages/topology/src/utils/withEditReviewAccess.tsx +++ b/frontend/packages/topology/src/utils/withEditReviewAccess.tsx @@ -19,7 +19,7 @@ export const withEditReviewAccess: WithEditReviewAccess = (verb) => (WrappedComp name: resourceObj?.metadata?.name, namespace: resourceObj?.metadata?.namespace, }); - return ; + return ; }; Component.displayName = `withEditReviewAccess(${ WrappedComponent.displayName || WrappedComponent.name