portainer/app/react/kubernetes/cluster/HomeView/NodesDatatable/NodesDatatable.tsx

109 lines
3.7 KiB
TypeScript

import { Node, Endpoints } from 'kubernetes-types/core/v1';
import { HardDrive } from 'lucide-react';
import { useMemo } from 'react';
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
import { createStore } from '@/react/kubernetes/datatables/default-kube-datatable-store';
import { IndexOptional } from '@/react/kubernetes/configs/types';
import { useEnvironment } from '@/react/portainer/environments/queries';
import { Datatable, TableSettingsMenu } from '@@/datatables';
import { useTableState } from '@@/datatables/useTableState';
import { TableSettingsMenuAutoRefresh } from '@@/datatables/TableSettingsMenuAutoRefresh';
import { useNodesQuery } from '../nodes.service';
import { useKubernetesEndpointsQuery } from '../../kubernetesEndpoint.service';
import { getColumns } from './columns';
import { NodeRowData } from './types';
import { getInternalNodeIpAddress } from './utils';
const storageKey = 'k8sNodesDatatable';
const settingsStore = createStore(storageKey);
export function NodesDatatable() {
const tableState = useTableState(settingsStore, storageKey);
const environmentId = useEnvironmentId();
const { data: nodes, ...nodesQuery } = useNodesQuery(environmentId, {
autoRefreshRate: tableState.autoRefreshRate * 1000,
});
const { data: kubernetesEndpoints, ...kubernetesEndpointsQuery } =
useKubernetesEndpointsQuery(environmentId, {
autoRefreshRate: tableState.autoRefreshRate * 1000,
});
const { data: environment, ...environmentQuery } =
useEnvironment(environmentId);
const environmentUrl = environment?.URL;
const isServerMetricsEnabled =
!!environment?.Kubernetes?.Configuration.UseServerMetrics;
const nodeRowData = useNodeRowData(
nodes,
kubernetesEndpoints,
environmentUrl
);
return (
<Datatable<IndexOptional<NodeRowData>>
disableSelect
dataset={nodeRowData ?? []}
columns={getColumns(isServerMetricsEnabled)}
settingsManager={tableState}
isLoading={
nodesQuery.isLoading ||
kubernetesEndpointsQuery.isLoading ||
environmentQuery.isLoading
}
emptyContentLabel="No Nodes found"
title="Nodes"
titleIcon={HardDrive}
getRowId={(row) => row.metadata?.uid ?? ''}
renderTableSettings={() => (
<TableSettingsMenu>
<TableSettingsMenuAutoRefresh
value={tableState.autoRefreshRate}
onChange={(value) => tableState.setAutoRefreshRate(value)}
/>
</TableSettingsMenu>
)}
/>
);
}
/**
* This function is used to add the isApi property to the node row data.
*/
function useNodeRowData(
nodes?: Node[],
kubernetesEndpoints?: Endpoints[],
environmentUrl?: string
): NodeRowData[] {
return useMemo<NodeRowData[]>(() => {
if (!nodes || !kubernetesEndpoints) {
return [];
}
const subsetAddresses = kubernetesEndpoints?.flatMap(
(endpoint) =>
endpoint.subsets?.flatMap((subset) => subset.addresses ?? [])
);
const nodeRowData = nodes.map((node) => {
const nodeAddress = getInternalNodeIpAddress(node);
// if the node address is in the endpoints subset addresses, then it is an api node
const isApi = subsetAddresses?.some(
(subsetAddress) => subsetAddress?.ip === nodeAddress
);
// if the environment url includes the node address, then it is a published node
const isPublishedNode =
!!nodeAddress &&
!!environmentUrl &&
environmentUrl?.includes(nodeAddress);
return {
...node,
isApi,
isPublishedNode,
Name: `${node.metadata?.name}${isApi ? 'api' : ''}` ?? '',
};
});
return nodeRowData;
}, [nodes, kubernetesEndpoints, environmentUrl]);
}