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 ( > 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={() => ( tableState.setAutoRefreshRate(value)} /> )} /> ); } /** * 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(() => { 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]); }