Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 40 additions & 6 deletions frontend/src/components/common/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import React from 'react';
import { Link as RouterLink } from 'react-router-dom';
import { formatClusterPathParam, getCluster, getSelectedClusters } from '../../lib/cluster';
import { kubeObjectQueryKey, useEndpoints } from '../../lib/k8s/api/v2/hooks';
import type { KubeObject } from '../../lib/k8s/KubeObject';
import type { KubeObject, KubeObjectClass } from '../../lib/k8s/KubeObject';
import type { RouteURLProps } from '../../lib/router/createRouteURL';
import { createRouteURL } from '../../lib/router/createRouteURL';
import { useTypedSelector } from '../../redux/hooks';
Expand Down Expand Up @@ -64,7 +64,10 @@ function KubeObjectLink(props: {

const client = useQueryClient();
const { namespace, name } = kubeObject.metadata;
const { endpoint } = useEndpoints(kubeObject._class().apiEndpoint.apiInfo, kubeObject.cluster);
const { endpoint } = useEndpoints(
(kubeObject.constructor as KubeObjectClass).apiEndpoint.apiInfo,
kubeObject.cluster
);

return (
<MuiLink
Expand Down Expand Up @@ -141,19 +144,52 @@ function PureLink(
);
}

function getApiGroup(apiVersion: string) {
if (!apiVersion) return '';
if (!apiVersion.includes('/')) return '';
return apiVersion.split('/')[0];
}

export default function Link(props: React.PropsWithChildren<LinkProps | LinkObjectProps>) {
const drawerEnabled = useTypedSelector(state => state?.drawerMode?.isDetailDrawerEnabled);

const { tooltip, ...propsRest } = props as LinkObjectProps;

const kind = 'kubeObject' in props ? props.kubeObject?._class().kind : props?.routeName;
const kind = 'kubeObject' in props ? props.kubeObject?.kind : props?.routeName;
const cluster =
'kubeObject' in props && props.kubeObject?.cluster
? props.kubeObject?.cluster
: props.activeCluster ?? getCluster() ?? '';

let matchesStandard = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the matchesStandard check currently returns true for colliding crds because it compares the object's api group against its own constructor's apigroup,,, headlamp instantiates Custom Resources using dynamic classes that correctly match the crd api group, the check passes, and the standard drawer is still triggered.


if ('kubeObject' in props && props.kubeObject) {
const obj = props.kubeObject;
const objClass = obj.constructor as KubeObjectClass;

// 1. The Class explicitly claims the same 'kind' as the object instance.
// 2. The Class explicitly claims the same 'apiGroup' (via apiVersion) as the object instance.
const kindMatches = objClass.kind === obj.kind;
let groupMatches = false;

if (obj.jsonData && obj.jsonData.apiVersion && objClass.apiVersion) {
const instanceGroup = getApiGroup(obj.jsonData.apiVersion);
const classVersions = Array.isArray(objClass.apiVersion)
? objClass.apiVersion
: [objClass.apiVersion];

if (classVersions.find(v => getApiGroup(v) === instanceGroup)) {
groupMatches = true;
}
}

if (!kindMatches || !groupMatches) {
matchesStandard = false;
}
}

const openDrawer =
drawerEnabled && canRenderDetails(kind)
drawerEnabled && canRenderDetails(kind) && matchesStandard
? () => {
// Object information can be provided throught kubeObject or route parameters
const name = 'kubeObject' in props ? props.kubeObject?.getName() : props.params?.name;
Expand All @@ -163,8 +199,6 @@ export default function Link(props: React.PropsWithChildren<LinkProps | LinkObje
const selectedResource =
kind === 'customresource'
? {
// Custom resource links don't follow the same convention
// so we need to create a different object
kind,
metadata: {
name: props.params?.crName,
Expand Down
Loading