fix: deduplicate in select provider models and target models
This commit is contained in:
@@ -9,7 +9,7 @@ import {
|
|||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Form, Tooltip } from 'antd';
|
import { Button, Form, Tooltip } from 'antd';
|
||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { useFormContext } from '../config/form-context';
|
import { useFormContext } from '../config/form-context';
|
||||||
import { FormData, ProviderModel } from '../config/types';
|
import { FormData, ProviderModel } from '../config/types';
|
||||||
@@ -128,25 +128,36 @@ const ModelItem: React.FC<ModelItemProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// filter out already selected models, but keep the current one
|
// filter out already selected models, but keep the current one
|
||||||
const selectedModelMap = new Map(
|
const selectedModelSet = useMemo(() => {
|
||||||
selectedModelList?.map((model) => [model.name, true])
|
return new Set(selectedModelList?.map((model) => model.name));
|
||||||
);
|
}, [selectedModelList]);
|
||||||
const filteredOptions = () => {
|
|
||||||
|
const filteredOptions = useMemo(() => {
|
||||||
return providerModelList.filter((model) => {
|
return providerModelList.filter((model) => {
|
||||||
return model.value === item.name || !selectedModelMap.has(model.value);
|
return model.value === item.name || !selectedModelSet.has(model.value);
|
||||||
});
|
});
|
||||||
};
|
}, [providerModelList, item.name, selectedModelSet]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectWrapper>
|
<SelectWrapper>
|
||||||
<AutoComplete
|
<AutoComplete
|
||||||
loading={loading}
|
loading={loading}
|
||||||
showSearch
|
showSearch={{
|
||||||
|
filterOption: (inputValue, option: any) => {
|
||||||
|
return (
|
||||||
|
option!.value.toLowerCase().includes(inputValue.toLowerCase()) ||
|
||||||
|
option.label
|
||||||
|
?.toString()
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(inputValue.toLowerCase())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
onOpenChange={onOpenChange}
|
onOpenChange={onOpenChange}
|
||||||
suffixIcon={renderSuffixIcon()}
|
suffixIcon={renderSuffixIcon()}
|
||||||
value={item.name}
|
value={item.name}
|
||||||
onChange={handleOnChange}
|
onChange={handleOnChange}
|
||||||
options={filteredOptions()}
|
options={filteredOptions}
|
||||||
placeholder={intl.formatMessage({ id: 'providers.table.models' })}
|
placeholder={intl.formatMessage({ id: 'providers.table.models' })}
|
||||||
/>
|
/>
|
||||||
<SealSelect
|
<SealSelect
|
||||||
|
|||||||
@@ -31,9 +31,10 @@ const SupportedModels = () => {
|
|||||||
|
|
||||||
const handleOpenChange = async (open: boolean) => {
|
const handleOpenChange = async (open: boolean) => {
|
||||||
try {
|
try {
|
||||||
await form.validateFields(['api_key']);
|
await form.validateFields(['api_key', ['config', 'type']]);
|
||||||
|
|
||||||
const currentAPIKey = form.getFieldValue('api_key') || '';
|
const currentAPIKey = form.getFieldValue('api_key') || '';
|
||||||
|
console.log('handleOpenChange', { open, currentAPIKey });
|
||||||
|
|
||||||
// Avoid repeated requests with the same API key
|
// Avoid repeated requests with the same API key
|
||||||
if (
|
if (
|
||||||
@@ -54,7 +55,9 @@ const SupportedModels = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {}
|
} catch (error) {
|
||||||
|
prevAPIKeyRef.current = '';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateModelList = (models: ProviderModel[]) => {
|
const updateModelList = (models: ProviderModel[]) => {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ const RouteItem: React.FC<TargetItemProps> = ({
|
|||||||
<Col span={5} style={{ paddingLeft: 56 }}>
|
<Col span={5} style={{ paddingLeft: 56 }}>
|
||||||
<CellContent>{renderProviderSource()}</CellContent>
|
<CellContent>{renderProviderSource()}</CellContent>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={3}>
|
<Col span={2}>
|
||||||
<CellContent>
|
<CellContent>
|
||||||
{data.weight > 0 && (
|
{data.weight > 0 && (
|
||||||
<AutoTooltip ghost>
|
<AutoTooltip ghost>
|
||||||
@@ -112,7 +112,7 @@ const RouteItem: React.FC<TargetItemProps> = ({
|
|||||||
)}
|
)}
|
||||||
</CellContent>
|
</CellContent>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={2}>
|
<Col span={3}>
|
||||||
<CellContent>
|
<CellContent>
|
||||||
<AutoTooltip ghost>
|
<AutoTooltip ghost>
|
||||||
<StatusTag
|
<StatusTag
|
||||||
|
|||||||
@@ -134,16 +134,18 @@ const TargetsForm = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
const selectedDataList = [...dataList, { value: fallbackValues.value }];
|
const selectedDataList = [...dataList, { value: fallbackValues.value }];
|
||||||
|
|
||||||
const selectedKeys = selectedDataList
|
const selectedKeys = new Set(
|
||||||
.filter((item) => item.value)
|
selectedDataList
|
||||||
.map((item) => buildKey(item.value));
|
.filter((item) => item.value)
|
||||||
|
.map((item) => buildKey(item.value))
|
||||||
|
);
|
||||||
|
|
||||||
return sourceModels
|
return sourceModels
|
||||||
.map((model) => {
|
.map((model) => {
|
||||||
const children = model.children?.filter((child) => {
|
const children = model.children?.filter((child) => {
|
||||||
const key = buildKey([child.data?.parentId, child.value]);
|
const key = buildKey([child.data?.parentId, child.value]);
|
||||||
|
|
||||||
return !selectedKeys.includes(key) || key === currKey;
|
return !selectedKeys.has(key) || key === currKey;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { queryMaasProviders } from '@/pages/maas-provider/apis';
|
|||||||
import ProviderLogo from '@/pages/maas-provider/components/provider-logo';
|
import ProviderLogo from '@/pages/maas-provider/components/provider-logo';
|
||||||
import { MaasProviderItem } from '@/pages/maas-provider/config/types';
|
import { MaasProviderItem } from '@/pages/maas-provider/config/types';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
|
import _ from 'lodash';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@@ -52,30 +53,27 @@ const useTargetSourceModels = () => {
|
|||||||
value: 'deployments',
|
value: 'deployments',
|
||||||
providerType: 'deployments',
|
providerType: 'deployments',
|
||||||
parent: true,
|
parent: true,
|
||||||
children: models.items?.map?.((model: ModelListItem) => ({
|
children: _.uniqBy(
|
||||||
label: model.name,
|
models.items?.map?.((model: ModelListItem) => [
|
||||||
value: model.id,
|
model.id,
|
||||||
data: {
|
{
|
||||||
model_id: model.id,
|
label: model.name,
|
||||||
parentId: 'deployments'
|
value: model.id,
|
||||||
},
|
data: {
|
||||||
source: 'deployment'
|
model_id: model.id,
|
||||||
}))
|
parentId: 'deployments'
|
||||||
|
},
|
||||||
|
source: 'deployment'
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
'value'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
].filter((group) => group.children && group.children.length > 0);
|
].filter((group) => group.children && group.children.length > 0);
|
||||||
|
|
||||||
const providerOptions: CascaderOption[] = providers.items
|
const providerOptions: CascaderOption[] = providers.items
|
||||||
?.map?.((provider: MaasProviderItem) => ({
|
?.map?.((provider: MaasProviderItem) => {
|
||||||
label: (
|
const children = provider.models?.map?.((model) => ({
|
||||||
<OptionWrapper>
|
|
||||||
<ProviderLogo provider={provider.config?.type as string} />
|
|
||||||
<span>{provider.name}</span>
|
|
||||||
</OptionWrapper>
|
|
||||||
),
|
|
||||||
value: provider.id,
|
|
||||||
parent: true,
|
|
||||||
providerType: provider.config?.type,
|
|
||||||
children: provider.models?.map?.((model) => ({
|
|
||||||
label: model.name,
|
label: model.name,
|
||||||
value: model.name,
|
value: model.name,
|
||||||
data: {
|
data: {
|
||||||
@@ -84,8 +82,21 @@ const useTargetSourceModels = () => {
|
|||||||
parentId: provider.id
|
parentId: provider.id
|
||||||
},
|
},
|
||||||
source: 'providerModel'
|
source: 'providerModel'
|
||||||
}))
|
}));
|
||||||
}))
|
|
||||||
|
return {
|
||||||
|
label: (
|
||||||
|
<OptionWrapper>
|
||||||
|
<ProviderLogo provider={provider.config?.type as string} />
|
||||||
|
<span>{provider.name}</span>
|
||||||
|
</OptionWrapper>
|
||||||
|
),
|
||||||
|
value: provider.id,
|
||||||
|
parent: true,
|
||||||
|
providerType: provider.config?.type,
|
||||||
|
children: _.uniqBy(children, 'value')
|
||||||
|
};
|
||||||
|
})
|
||||||
.filter((group) => group.children && group.children.length > 0);
|
.filter((group) => group.children && group.children.length > 0);
|
||||||
|
|
||||||
setSourceModels([...modelsList, ...providerOptions]);
|
setSourceModels([...modelsList, ...providerOptions]);
|
||||||
|
|||||||
@@ -65,8 +65,13 @@ const ModelRoutes: React.FC = () => {
|
|||||||
const { watchDataList: allRouteTargets, deleteItemFromCache } =
|
const { watchDataList: allRouteTargets, deleteItemFromCache } =
|
||||||
useWatchList(MODEL_ROUTE_TARGETS);
|
useWatchList(MODEL_ROUTE_TARGETS);
|
||||||
const [expandAtom] = useAtom(expandKeysAtom);
|
const [expandAtom] = useAtom(expandKeysAtom);
|
||||||
const { handleExpandChange, handleExpandAll, expandedRowKeys } =
|
const {
|
||||||
useExpandedRowKeys(expandAtom);
|
handleExpandChange,
|
||||||
|
handleExpandAll,
|
||||||
|
updateExpandedRowKeys,
|
||||||
|
removeExpandedRowKey,
|
||||||
|
expandedRowKeys
|
||||||
|
} = useExpandedRowKeys(expandAtom);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { openRouteModalStatus, openRouteModal, closeRouteModal } =
|
const { openRouteModalStatus, openRouteModal, closeRouteModal } =
|
||||||
useCreateRoute();
|
useCreateRoute();
|
||||||
@@ -109,17 +114,22 @@ const ModelRoutes: React.FC = () => {
|
|||||||
...data
|
...data
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
|
let data: ListItem = {} as any;
|
||||||
if (openRouteModalStatus.action === PageAction.EDIT) {
|
if (openRouteModalStatus.action === PageAction.EDIT) {
|
||||||
await updateModelRoute({
|
data = await updateModelRoute({
|
||||||
data: params,
|
data: params,
|
||||||
id: openRouteModalStatus.currentData!.id
|
id: openRouteModalStatus.currentData!.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (openRouteModalStatus.action === PageAction.CREATE) {
|
if (openRouteModalStatus.action === PageAction.CREATE) {
|
||||||
await createModelRoute({
|
data = await createModelRoute({
|
||||||
data: params
|
data: params
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.targets > 0) {
|
||||||
|
updateExpandedRowKeys([data.id, ...expandedRowKeys]);
|
||||||
|
}
|
||||||
fetchData();
|
fetchData();
|
||||||
closeRouteModal();
|
closeRouteModal();
|
||||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||||
|
|||||||
Reference in New Issue
Block a user