mirror of
https://github.com/komodorio/helm-dashboard.git
synced 2026-03-28 15:28:04 +00:00
* Introduced tsconfig.app.json and tsconfig.base.json * yarn.lock * Introduced tsconfig.app.json, tsconfig.base.jsonfig. * Refactored eslint.config.js to latest structure * Returned previous recommended rules. * More rules * Force import rules * Check * Check * Cleanup ESLint configuration and plugins * Cleanup heap: "writable",DD_RUM: "writable" from ESLint configuration * "scripts" moved to the top of package.json
168 lines
5.1 KiB
TypeScript
168 lines
5.1 KiB
TypeScript
import { useQuery } from "@tanstack/react-query";
|
|
import { useEffect, useEffectEvent, useMemo } from "react";
|
|
import { v4 as uuidv4 } from "uuid";
|
|
|
|
import apiService from "../API/apiService";
|
|
import { useAppContext } from "../context/AppContext";
|
|
import type { Cluster, Release } from "../data/types";
|
|
import useCustomSearchParams from "../hooks/useCustomSearchParams";
|
|
|
|
type ClustersListProps = {
|
|
onClusterChange: (clusterName: string) => void;
|
|
selectedCluster: string;
|
|
filteredNamespaces: string[];
|
|
installedReleases?: Release[];
|
|
};
|
|
|
|
function getCleanClusterName(rawClusterName: string) {
|
|
if (rawClusterName.indexOf("arn") === 0) {
|
|
// AWS cluster
|
|
const clusterSplit = rawClusterName.split(":");
|
|
const clusterName = clusterSplit.slice(-1)[0].replace("cluster/", "");
|
|
const region = clusterSplit.at(-3);
|
|
return region + "/" + clusterName + " [AWS]";
|
|
}
|
|
|
|
if (rawClusterName.indexOf("gke") === 0) {
|
|
// GKE cluster
|
|
return (
|
|
rawClusterName.split("_").at(-2) +
|
|
"/" +
|
|
rawClusterName.split("_").at(-1) +
|
|
" [GKE]"
|
|
);
|
|
}
|
|
|
|
return rawClusterName;
|
|
}
|
|
|
|
function ClustersList({
|
|
installedReleases,
|
|
selectedCluster,
|
|
filteredNamespaces,
|
|
onClusterChange,
|
|
}: ClustersListProps) {
|
|
const { upsertSearchParams, removeSearchParam } = useCustomSearchParams();
|
|
const { clusterMode } = useAppContext();
|
|
|
|
const { data: clusters = [], isSuccess } = useQuery<Cluster[]>({
|
|
queryKey: ["clusters", selectedCluster],
|
|
queryFn: apiService.getClusters,
|
|
select: (data) =>
|
|
data?.sort((a, b) =>
|
|
getCleanClusterName(a.Name).localeCompare(getCleanClusterName(b.Name))
|
|
),
|
|
});
|
|
|
|
const onSuccess = useEffectEvent((clusters: Cluster[]) => {
|
|
if (clusters && clusters.length && !selectedCluster) {
|
|
onClusterChange(clusters[0].Name);
|
|
}
|
|
|
|
if (selectedCluster) {
|
|
const cluster = clusters.find(
|
|
(cluster) => getCleanClusterName(cluster.Name) === selectedCluster
|
|
);
|
|
if (!filteredNamespaces && cluster?.Namespace) {
|
|
upsertSearchParams("filteredNamespace", cluster.Namespace);
|
|
}
|
|
}
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (clusters && isSuccess) {
|
|
onSuccess(clusters);
|
|
}
|
|
}, [clusters, isSuccess]);
|
|
|
|
const namespaces = useMemo(() => {
|
|
const mapNamespaces = new Map<string, number>();
|
|
|
|
installedReleases?.forEach((release) => {
|
|
const amount = mapNamespaces.get(release.namespace)
|
|
? Number(mapNamespaces.get(release.namespace)) + 1
|
|
: 1;
|
|
mapNamespaces.set(release.namespace, amount);
|
|
});
|
|
|
|
return Array.from(mapNamespaces, ([key, value]) => ({
|
|
id: uuidv4(),
|
|
name: key,
|
|
amount: value,
|
|
}));
|
|
}, [installedReleases]);
|
|
|
|
const onNamespaceChange = (namespace: string) => {
|
|
const newSelectedNamespaces = filteredNamespaces?.includes(namespace)
|
|
? filteredNamespaces?.filter((ns) => ns !== namespace)
|
|
: [...(filteredNamespaces ?? []), namespace];
|
|
removeSearchParam("filteredNamespace");
|
|
if (newSelectedNamespaces.length > 0) {
|
|
upsertSearchParams(
|
|
"filteredNamespace",
|
|
newSelectedNamespaces.map((ns) => ns).join("+")
|
|
);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="custom- custom-shadow m-5 flex h-fit w-48 flex-col rounded-sm bg-white p-2 pb-4 text-cluster-list">
|
|
{!clusterMode ? (
|
|
<>
|
|
<label className="font-bold">Clusters</label>
|
|
{clusters?.map((cluster) => {
|
|
return (
|
|
<span
|
|
key={cluster.Name + cluster.Namespace}
|
|
className="data-cy-clusterName mt-2 flex items-center text-xs"
|
|
>
|
|
<input
|
|
className="data-cy-clustersInput cursor-pointer"
|
|
onChange={(e) => {
|
|
onClusterChange(e.target.value);
|
|
}}
|
|
type="radio"
|
|
id={cluster.Name}
|
|
value={cluster.Name}
|
|
checked={cluster.Name === selectedCluster}
|
|
name="clusters"
|
|
/>
|
|
<label htmlFor={cluster.Name} className="ml-1">
|
|
{getCleanClusterName(cluster.Name)}
|
|
</label>
|
|
</span>
|
|
);
|
|
})}
|
|
</>
|
|
) : null}
|
|
|
|
<label className="mt-4 font-bold">Namespaces</label>
|
|
{namespaces
|
|
?.sort((a, b) => a.name.localeCompare(b.name))
|
|
?.map((namespace) => (
|
|
<span key={namespace.name} className="mt-2 flex items-center text-xs">
|
|
<input
|
|
type="checkbox"
|
|
id={namespace.name}
|
|
onChange={(event) => {
|
|
onNamespaceChange(event.target.value);
|
|
}}
|
|
value={namespace.name}
|
|
checked={
|
|
filteredNamespaces
|
|
? filteredNamespaces.includes(namespace.name)
|
|
: false
|
|
}
|
|
/>
|
|
<label
|
|
htmlFor={namespace.name}
|
|
className="data-cy-clusterList-namespace ml-1"
|
|
>{`${namespace.name} [${namespace.amount}]`}</label>
|
|
</span>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default ClustersList;
|