@stolostron/multicluster-sdk
Version:
Provides extensions and APIs that dynamic plugins can use to leverage multicluster capabilities provided by Red Hat Advanced Cluster Management.
144 lines • 7.62 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FleetResourceLink = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const dynamic_plugin_sdk_1 = require("@openshift-console/dynamic-plugin-sdk");
const classnames_1 = __importDefault(require("classnames"));
const searchPaths_1 = require("../internal/search/searchPaths");
const useHubClusterName_1 = require("../api/useHubClusterName");
const useIsFleetAvailable_1 = require("../api/useIsFleetAvailable");
const react_router_dom_v5_compat_1 = require("react-router-dom-v5-compat");
const resourceRouteUtils_1 = require("../internal/resourceRouteUtils");
/**
* Enhanced ResourceLink component for ACM fleet environments.
*
* Unlike the standard OpenShift ResourceLink which always links to the OpenShift console,
* FleetResourceLink provides intelligent routing based on cluster context:
* - First-class ACM resources (ManagedCluster) get direct links in all cases
* - For hub clusters: Extension-based routing first, then fallback to OpenShift console
* - For managed clusters: Extension-based routing first, then fallback to ACM search results
*
* This prevents users from having to jump between different consoles when managing
* multi-cluster resources.
*
* @see https://github.com/openshift/console/blob/main/frontend/packages/console-dynamic-plugin-sdk/docs/api.md#resourcelink
*
* @param props - FleetResourceLinkProps extending ResourceLinkProps with cluster information
* @param props.cluster - the target cluster name for the resource
* @param props.groupVersionKind - K8s GroupVersionKind for the resource
* @param props.name - the resource name
* @param props.namespace - the resource namespace (required for namespaced resources)
* @param props.displayName - optional display name override
* @param props.className - additional CSS classes
* @param props.inline - whether to display inline
* @param props.hideIcon - whether to hide the resource icon
* @param props.children - additional content to render
*
* @example
* ```typescript
* // Hub cluster VirtualMachine - routes to ACM VM page via extension system
* <FleetResourceLink
* name="my-vm"
* namespace="default"
* groupVersionKind={{ group: 'kubevirt.io', version: 'v1', kind: 'VirtualMachine' }}
* />
*
* // Managed cluster VirtualMachine - routes to ACM search results
* <FleetResourceLink
* name="remote-vm"
* namespace="default"
* cluster="prod-cluster"
* groupVersionKind={{ group: 'kubevirt.io', version: 'v1', kind: 'VirtualMachine' }}
* />
*
* // ManagedCluster resource (lives on hub) - cluster prop omitted
* <FleetResourceLink
* name="prod-cluster"
* groupVersionKind={{ group: 'cluster.open-cluster-management.io', version: 'v1', kind: 'ManagedCluster' }}
* />
* ```
*/
const FleetResourceLink = ({ cluster, ...resourceLinkProps }) => {
const [hubClusterName, hubLoaded] = (0, useHubClusterName_1.useHubClusterName)();
const [resourceRoutes, resourceRoutesResolved] = (0, dynamic_plugin_sdk_1.useResolvedExtensions)(resourceRouteUtils_1.isResourceRoute);
const isFleetAvailable = (0, useIsFleetAvailable_1.useIsFleetAvailable)();
if (!isFleetAvailable) {
return (0, jsx_runtime_1.jsx)(dynamic_plugin_sdk_1.ResourceLink, { ...resourceLinkProps });
}
const { className, displayName, inline = false, groupVersionKind, name, nameSuffix, namespace, hideIcon, title, children, dataTest, onClick, truncate, } = resourceLinkProps;
const value = displayName || name;
const classes = (0, classnames_1.default)('co-resource-item', className || '', {
'co-resource-item--inline': inline,
'co-resource-item--truncate': truncate,
});
// if cluster name is given but hub name is not loaded yet, show text
if (cluster && !hubLoaded) {
return ((0, jsx_runtime_1.jsxs)("span", { className: classes, children: [!hideIcon && (0, jsx_runtime_1.jsx)(dynamic_plugin_sdk_1.ResourceIcon, { groupVersionKind: groupVersionKind }), (0, jsx_runtime_1.jsxs)("span", { className: "co-resource-item__resource-name", children: [value, nameSuffix] }), children] }));
}
// determine if this is a hub cluster case (if no cluster or it matches hub name)
const isHubCluster = !cluster || cluster === hubClusterName;
const getResourcePath = () => {
if (!name || !groupVersionKind?.kind) {
return null;
}
if (isHubCluster) {
// hub cluster case, extension-based routing for hub cluster resources
if (resourceRoutesResolved && resourceRoutes?.length) {
const extensionPath = (0, resourceRouteUtils_1.getExtensionResourcePath)(resourceRoutes, groupVersionKind.group, groupVersionKind.kind, groupVersionKind.version, {
cluster: cluster ?? hubClusterName ?? '',
namespace,
name,
resource: { cluster: cluster ?? hubClusterName, namespace, name, ...groupVersionKind },
model: {
group: groupVersionKind.group,
version: groupVersionKind.version,
kind: groupVersionKind.kind,
},
});
if (extensionPath) {
return extensionPath;
}
}
// for hub cluster resources without extension handlers, return null to fallback to ResourceLink
return null;
}
else {
// managed cluster case, extensions first, then fallback to search
if (resourceRoutesResolved && resourceRoutes?.length) {
const extensionPath = (0, resourceRouteUtils_1.getExtensionResourcePath)(resourceRoutes, groupVersionKind.group, groupVersionKind.kind, groupVersionKind.version, {
cluster,
namespace,
name,
resource: { cluster, namespace, name, ...groupVersionKind },
model: {
group: groupVersionKind.group,
version: groupVersionKind.version,
kind: groupVersionKind.kind,
},
});
if (extensionPath) {
return extensionPath;
}
}
// fallback to search results for managed cluster resources
return `/multicloud/search/resources${(0, searchPaths_1.getURLSearchParam)({
cluster,
kind: groupVersionKind.kind,
apigroup: groupVersionKind.group,
apiversion: groupVersionKind.version,
name,
namespace,
})}`;
}
};
const path = getResourcePath();
if (!path) {
return (0, jsx_runtime_1.jsx)(dynamic_plugin_sdk_1.ResourceLink, { ...resourceLinkProps });
}
return ((0, jsx_runtime_1.jsxs)("span", { className: classes, children: [!hideIcon && (0, jsx_runtime_1.jsx)(dynamic_plugin_sdk_1.ResourceIcon, { groupVersionKind: groupVersionKind }), (0, jsx_runtime_1.jsxs)(react_router_dom_v5_compat_1.Link, { to: path, title: title, className: "co-resource-item__resource-name", "data-test-id": value, "data-test": dataTest ?? value, onClick: onClick, children: [value, nameSuffix] }), children] }));
};
exports.FleetResourceLink = FleetResourceLink;
//# sourceMappingURL=FleetResourceLink.js.map