fix: gpu selector by cluster

This commit is contained in:
jialin
2025-09-16 11:26:17 +08:00
parent 207c90e26c
commit 553ec724c2
40 changed files with 1106 additions and 1233 deletions
@@ -0,0 +1,255 @@
import { queryClusterList } from '@/pages/cluster-management/apis';
import { ClusterListItem } from '@/pages/cluster-management/config/types';
import { queryWorkersList } from '@/pages/resources/apis';
import {
WorkerStatusMap,
WorkerStatusMapValue
} from '@/pages/resources/config';
import { ListItem as WorkerListItem } from '@/pages/resources/config/types';
import _ from 'lodash';
import { useState } from 'react';
import { queryGPUList } from '../apis';
import { backendOptionsMap, setSourceRepoConfigValue } from '../config';
import { GPUListItem, ListItem } from '../config/types';
interface CascaderOption {
label: string;
value: string | number;
parent?: boolean;
disabled?: boolean;
index?: number;
children?: CascaderOption[];
}
export const useGenerateGPUOptions = () => {
const [gpuOptions, setGpuOptions] = useState<CascaderOption[]>([]);
const generateCascaderGPUOptions = (
gpuList: GPUListItem[],
workerList: WorkerListItem[]
) => {
// pick the worker fields from gpuList
const workerFields = new Set(['worker_name', 'worker_id', 'worker_ip']);
// generate a map for workerList by name to data
const workerDataMap = new Map<string, WorkerListItem>();
for (const worker of workerList) {
workerDataMap.set(worker.name, worker);
}
const workersMap = new Map<string, GPUListItem[]>();
for (const gpu of gpuList) {
if (!workersMap.has(gpu.worker_name)) {
workersMap.set(gpu.worker_name, []);
}
workersMap.get(gpu.worker_name)!.push(gpu);
}
const gpuSelectorList = Array.from(workersMap.entries()).map(
([workerName, items]) => {
const firstItem = items[0];
const currentState = workerDataMap.get(workerName)?.state || '';
const disDisabled = WorkerStatusMap.ready !== currentState;
return {
label: disDisabled
? `${workerName} [${WorkerStatusMapValue[currentState]}]`
: workerName,
value: workerName,
parent: true,
disabled: disDisabled,
children: items
.map((item) => ({
label: item.name,
value: item.id,
index: item.index,
...Object.fromEntries(
Object.entries(item).filter(([key]) => !workerFields.has(key))
)
}))
.sort((a, b) => a.index - b.index),
...Object.fromEntries(
Object.entries(firstItem).filter(([key]) => workerFields.has(key))
)
};
}
);
return gpuSelectorList;
};
const getGPUOptionList = async (params?: { clusterId: number }) => {
const { clusterId } = params || {};
const [gpuData, workerData] = await Promise.all([
queryGPUList({
page: 1,
perPage: 100,
cluster_id: clusterId
}),
queryWorkersList({
page: 1,
perPage: 100,
cluster_id: clusterId
})
]);
const gpuList = generateCascaderGPUOptions(gpuData.items, workerData.items);
setGpuOptions(gpuList);
return gpuList;
};
return {
getGPUOptionList,
gpuOptions
};
};
export const useGenerateWorkerOptions = () => {
const [workerOptions, setWorkerOptions] = useState<CascaderOption[]>([]);
const [clusterList, setClusterList] = useState<
Global.BaseOption<number, { provider: string; state: string | number }>[]
>([]);
const [workersList, setWorkersList] = useState<
Global.BaseOption<
number,
{ state: string; labels: Record<string, string> }
>[]
>([]);
const generateCascaderWorkerOptions = (
workerList: WorkerListItem[],
clusterList: ClusterListItem[]
) => {
const options = clusterList.map((cluster) => ({
label: cluster.name,
value: cluster.id,
parent: true,
children: workerList
.filter((worker) => worker.cluster_id === cluster.id)
.map((worker) => ({
disabled: WorkerStatusMap.ready !== worker.state,
label: worker.name,
value: worker.id
}))
}));
setWorkerOptions(options);
return options;
};
const getDataList = async (): Promise<
[WorkerListItem[], ClusterListItem[]]
> => {
const [workerRes, clusterRes] = await Promise.all([
queryWorkersList({
page: 1,
perPage: 100
}),
queryClusterList({
page: 1,
perPage: 100
})
]);
const workerList = workerRes.items || ([] as WorkerListItem[]);
const clusterList = clusterRes.items || ([] as ClusterListItem[]);
return [workerList, clusterList];
};
const getWorkerOptionList = async () => {
const data = await getDataList();
const [workerList, clusterList] = data;
generateCascaderWorkerOptions(workerList, clusterList);
setWorkersList(
workerList.map((item) => ({
state: item.state,
label: item.name,
value: item.id
}))
);
setClusterList(
clusterList.map((item) => ({
label: item.name,
value: item.id,
provider: item.provider,
state: item.state
}))
);
};
return {
getWorkerOptionList,
workerOptions,
clusterList,
workersList
};
};
export default function useFormInitialValues() {
const { getGPUOptionList } = useGenerateGPUOptions();
const [clusterList, setClusterList] = useState<
Global.BaseOption<number, { provider: string; state: string | number }>[]
>([]);
const getClusterList = async (): Promise<Global.BaseOption<number>[]> => {
try {
const response = await queryClusterList({
page: 1,
perPage: 100
});
const list = response.items.map((item) => ({
label: item.name,
value: item.id,
provider: item.provider,
state: item.state
}));
setClusterList(list);
return list;
} catch (error) {
console.error('Failed to fetch cluster list:', error);
setClusterList([]);
return [];
}
};
const generateGPUSelector = (data: any, gpuOptions: any[]) => {
const gpu_ids = _.get(data, 'gpu_selector.gpu_ids', []);
if (gpu_ids.length === 0) {
return [];
}
const valueMap = new Map<string, string>();
gpuOptions?.forEach((item) => {
item.children?.forEach((child: any) => {
valueMap.set(child.value, item.value);
});
});
const gpuids: string[][] = gpu_ids
.map((id: string) => {
const parent = valueMap.get(id);
return parent ? [parent, id] : null;
})
.filter(Boolean) as string[][];
return data.backend === backendOptionsMap.voxBox ? gpuids[0] : gpuids;
};
const generateFormValues = (data: ListItem, gpuOptions: any[]) => {
const result = setSourceRepoConfigValue(data?.source || '', data);
const formData = {
...result.values,
categories: data?.categories?.length ? data.categories[0] : null,
scheduleType: data?.gpu_selector ? 'manual' : 'auto',
gpu_selector: data?.gpu_selector?.gpu_ids?.length
? {
gpu_ids: generateGPUSelector(data, gpuOptions)
}
: null
};
return formData;
};
return {
getGPUOptionList,
generateFormValues,
getClusterList,
clusterList
};
}