UNPKG

@kinvolk/headlamp-plugin

Version:

The needed infrastructure for building Headlamp plugins.

85 lines (84 loc) 3.3 kB
/* * Copyright 2025 The Kubernetes Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { useEffect, useMemo, useState } from 'react'; import { ResourceClasses } from '../../../lib/k8s'; import { KubeObject } from '../../../lib/k8s/cluster'; import { useNamespaces } from '../../../redux/filterSlice'; /** * A hook that fetches and returns a list of Kubernetes objects for the specified resources. * * @param resources - An array of ApiResource objects specifying the kinds of resources to fetch. * @param clusters - An array of cluster names from which to fetch the resources. * @param maxItems - Maximum amount of items per resource. * @param refetchIntervalMs - How often to refresh resources. In milliseconds. * @returns An array of Kubernetes objects from the specified resources and clusters. */ export const useKubeLists = (resources, clusters, maxItems, refetchIntervalMs, namespaces) => { const defaultNamespaces = useNamespaces(); const classes = useMemo(() => resources .map(it => { var _a; return ResourceClasses[it.kind] ?? (_a = class extends KubeObject { }, _a.kind = it.kind, _a.apiVersion = it.apiVersion, _a.apiName = it.pluralName, _a.isNamespaced = it.isNamespaced, _a); }) .filter(Boolean), [resources]); const data = classes.map(it => it.useList({ clusters, refetchInterval: refetchIntervalMs, namespace: namespaces ?? defaultNamespaces, })); const [items, setItems] = useState([]); const isLoading = data.some(it => !it.items && !it.isError); useEffect(() => { if (isLoading) return; const newItems = data.flatMap(it => { if (it.items && it.items.length < maxItems) { return it.items; } else { // The amount of items exceeds the limit return []; } }); setItems(oldItems => (equal(oldItems, newItems) ? oldItems : newItems)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [data, classes, isLoading]); const errors = useMemo(() => { return data .map((it, index) => { const resource = resources[index]; if (it.errors && it.errors.length === 1 && it.errors[0].status === 404) { return; } if (it.errors?.length) { return { resource, errors: it.errors }; } }) .filter(Boolean); }, [data, resources]); return { items, errors, isLoading }; }; const equal = (arr1, arr2) => { if (arr1.length !== arr2.length) return false; return arr1.every((it, i) => it === arr2[i]); };