fix: filter modelInstance by cluster in benchmark form

This commit is contained in:
jialin
2026-06-11 14:13:08 +08:00
committed by jialin
parent 12649c7ccf
commit 2ba5118bc2
3 changed files with 41 additions and 27 deletions
+13 -1
View File
@@ -48,6 +48,15 @@ const BasicForm: React.FC = () => {
); );
}, [orgScoped, scopedClusterList, clusterList, scopeOrgId]); }, [orgScoped, scopedClusterList, clusterList, scopeOrgId]);
const handleOnOrgChange = (value: any) => {
form.setFieldsValue({
model_name: undefined,
model_id: undefined,
model_instance_name: undefined,
model_instance: undefined
});
};
useEffect(() => { useEffect(() => {
if (action === PageAction.CREATE && orgScoped) { if (action === PageAction.CREATE && orgScoped) {
fetchScopedClusters({ page: -1 }); fetchScopedClusters({ page: -1 });
@@ -108,7 +117,10 @@ const BasicForm: React.FC = () => {
required required
></CInput.Input> ></CInput.Input>
</Form.Item> </Form.Item>
<PluginExtraFields name="CreateOrgScopeField" context={{ action }} /> <PluginExtraFields
name="CreateOrgScopeField"
context={{ action, onChange: handleOnOrgChange }}
/>
<Form.Item<FormData> <Form.Item<FormData>
name="cluster_id" name="cluster_id"
rules={[ rules={[
+27 -26
View File
@@ -9,8 +9,9 @@ import { useQueryModelInstancesList } from '@/pages/llmodels/services/use-query-
import { useQueryModelList } from '@/pages/llmodels/services/use-query-model-list'; import { useQueryModelList } from '@/pages/llmodels/services/use-query-model-list';
import { Cascader as SealCascader, useAppUtils } from '@gpustack/core-ui'; import { Cascader as SealCascader, useAppUtils } from '@gpustack/core-ui';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Form, Tooltip } from 'antd'; import { Form, Tooltip } from 'antd';
import React, { useEffect, useRef } from 'react'; import React, { useEffect } from 'react';
import { useFormContext } from '../config/form-context'; import { useFormContext } from '../config/form-context';
import { FormData } from '../config/types'; import { FormData } from '../config/types';
@@ -45,11 +46,7 @@ const ModelInstanceForm: React.FC = () => {
const form = Form.useFormInstance(); const form = Form.useFormInstance();
const { getRuleMessage } = useAppUtils(); const { getRuleMessage } = useAppUtils();
const { action, open } = useFormContext(); const { action, open } = useFormContext();
// Owned by the create-scope picker slot (admin "All" view). The model list const clusterId = Form.useWatch('cluster_id', form);
// is tenant-scoped by the request header, so refetch it when the org
// changes so only the chosen org's models/instances are offered.
const scopeOrgId = Form.useWatch('organization_id', form);
const prevScopeRef = useRef<number | null | undefined>(undefined);
const [modelList, setModelList] = React.useState<any[]>([]); const [modelList, setModelList] = React.useState<any[]>([]);
const { const {
loading: modelLoading, loading: modelLoading,
@@ -84,6 +81,16 @@ const ModelInstanceForm: React.FC = () => {
}; };
}; };
const clearModelInstance = () => {
setModelList([]);
form.setFieldsValue({
model_name: '',
model_id: '',
model_instance_name: '',
model_instance: ''
});
};
const loadInstances = async (selectedOptions: any[]) => { const loadInstances = async (selectedOptions: any[]) => {
const targetOption = selectedOptions[selectedOptions.length - 1]; const targetOption = selectedOptions[selectedOptions.length - 1];
if (targetOption && targetOption.children.length === 0) { if (targetOption && targetOption.children.length === 0) {
@@ -107,10 +114,12 @@ const ModelInstanceForm: React.FC = () => {
}); });
} }
}; };
const initModelInstance = useMemoizedFn(async () => {
const initModelInstance = async () => { if (!clusterId) {
return;
}
// fetch model list when dropdown is opened // fetch model list when dropdown is opened
const list = await fetchModelList({ page: -1 }); const list = await fetchModelList({ page: -1, cluster_id: clusterId });
const modelOptions = list const modelOptions = list
.filter((model: any) => model.replicas > 0) .filter((model: any) => model.replicas > 0)
.map((model: any) => ({ .map((model: any) => ({
@@ -124,6 +133,7 @@ const ModelInstanceForm: React.FC = () => {
})); }));
if (modelOptions.length === 0) { if (modelOptions.length === 0) {
clearModelInstance();
return; return;
} }
@@ -133,6 +143,12 @@ const ModelInstanceForm: React.FC = () => {
); );
if (!selectedllmModel) { if (!selectedllmModel) {
setModelList(modelOptions); setModelList(modelOptions);
form.setFieldsValue({
model_name: '',
model_id: '',
model_instance_name: '',
model_instance: ''
});
return; return;
} }
const instanceList = await fetchInstanceList({ id: selectedllmModel.id }); const instanceList = await fetchInstanceList({ id: selectedllmModel.id });
@@ -159,33 +175,18 @@ const ModelInstanceForm: React.FC = () => {
} }
setModelList(modelOptions); setModelList(modelOptions);
}; });
useEffect(() => { useEffect(() => {
if (open && action === PageAction.CREATE) { if (open && action === PageAction.CREATE) {
// On a genuine org change, clear the stale (possibly cross-org) target
// so the refetched list re-selects within the new org.
if (
prevScopeRef.current !== undefined &&
prevScopeRef.current !== scopeOrgId
) {
form.setFieldsValue({
model_name: undefined,
model_id: undefined,
model_instance_name: undefined,
model_instance: undefined
});
}
prevScopeRef.current = scopeOrgId;
initModelInstance(); initModelInstance();
} }
if (!open) { if (!open) {
prevScopeRef.current = undefined;
cancelModelRequest(); cancelModelRequest();
cancelInstanceRequest(); cancelInstanceRequest();
clearBenchmarkTargetInstance(); clearBenchmarkTargetInstance();
} }
}, [open, benchmarkTargetInstance, action, scopeOrgId]); }, [open, action, clusterId]);
return ( return (
<Form.Item<FormData> <Form.Item<FormData>
@@ -109,6 +109,7 @@ const InputList: React.FC<InputListProps> = forwardRef(
<div key={item.uid} className="input-item" data-uid={item.uid}> <div key={item.uid} className="input-item" data-uid={item.uid}>
<div className="input-wrap"> <div className="input-wrap">
<RowTextarea <RowTextarea
showUpload={false}
height={height} height={height}
label={showLabel ? `${index + 1}` : null} label={showLabel ? `${index + 1}` : null}
data={item} data={item}