mirror of
https://github.com/langgenius/dify.git
synced 2026-05-09 12:59:18 +08:00
fix(web): filter model selector by model name (#35624)
This commit is contained in:
parent
bfee04be8c
commit
217ab4d2c3
@ -55,7 +55,14 @@ vi.mock('../../hooks', async () => {
|
||||
})
|
||||
|
||||
vi.mock('../popup-item', () => ({
|
||||
default: ({ model }: { model: Model }) => <div>{model.provider}</div>,
|
||||
default: ({ model }: { model: Model }) => (
|
||||
<div>
|
||||
<span>{model.provider}</span>
|
||||
{model.models.map(modelItem => (
|
||||
<span key={modelItem.model}>{modelItem.model}</span>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/provider-context', () => ({
|
||||
@ -207,6 +214,156 @@ describe('Popup', () => {
|
||||
expect((input as HTMLInputElement).value).toBe('')
|
||||
})
|
||||
|
||||
it('should show matching models when searching by model name', () => {
|
||||
renderPopup(
|
||||
<Popup
|
||||
modelList={[
|
||||
makeModel({
|
||||
models: [makeModelItem({ model: 'gpt-4', label: { en_US: 'GPT-4', zh_Hans: 'GPT-4' } })],
|
||||
}),
|
||||
makeModel({
|
||||
provider: 'anthropic',
|
||||
label: { en_US: 'Anthropic', zh_Hans: 'Anthropic' },
|
||||
models: [makeModelItem({ model: 'claude-3', label: { en_US: 'Claude 3', zh_Hans: 'Claude 3' } })],
|
||||
}),
|
||||
]}
|
||||
onSelect={vi.fn()}
|
||||
onHide={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
fireEvent.change(
|
||||
screen.getByPlaceholderText('datasetSettings.form.searchModel'),
|
||||
{ target: { value: 'claude' } },
|
||||
)
|
||||
|
||||
expect(screen.queryByText('openai')).not.toBeInTheDocument()
|
||||
expect(screen.getByText('anthropic')).toBeInTheDocument()
|
||||
expect(screen.getByText('claude-3')).toBeInTheDocument()
|
||||
expect(screen.queryByText('gpt-4')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('No model found for \u201Cclaude\u201D')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should show empty search placeholder when no provider or model name matches', () => {
|
||||
renderPopup(
|
||||
<Popup
|
||||
modelList={[
|
||||
makeModel({
|
||||
label: { en_US: 'OpenAI', zh_Hans: 'OpenAI' },
|
||||
models: [
|
||||
makeModelItem({ model: 'gpt-4', label: { en_US: 'GPT-4', zh_Hans: 'GPT-4' } }),
|
||||
],
|
||||
}),
|
||||
]}
|
||||
onSelect={vi.fn()}
|
||||
onHide={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
fireEvent.change(
|
||||
screen.getByPlaceholderText('datasetSettings.form.searchModel'),
|
||||
{ target: { value: 'mistral' } },
|
||||
)
|
||||
|
||||
expect(screen.getByText('No model found for \u201Cmistral\u201D'))!.toBeInTheDocument()
|
||||
expect(screen.queryByText('openai')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('gpt-4')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should show all models of a provider when searching by provider label', () => {
|
||||
renderPopup(
|
||||
<Popup
|
||||
modelList={[
|
||||
makeModel({
|
||||
provider: 'openai',
|
||||
label: { en_US: 'OpenAI', zh_Hans: 'OpenAI' },
|
||||
models: [
|
||||
makeModelItem({ model: 'gpt-4', label: { en_US: 'GPT-4', zh_Hans: 'GPT-4' } }),
|
||||
makeModelItem({ model: 'gpt-4o', label: { en_US: 'GPT-4o', zh_Hans: 'GPT-4o' } }),
|
||||
],
|
||||
}),
|
||||
makeModel({
|
||||
provider: 'anthropic',
|
||||
label: { en_US: 'Anthropic', zh_Hans: 'Anthropic' },
|
||||
models: [
|
||||
makeModelItem({ model: 'claude-3', label: { en_US: 'Claude 3', zh_Hans: 'Claude 3' } }),
|
||||
],
|
||||
}),
|
||||
]}
|
||||
onSelect={vi.fn()}
|
||||
onHide={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
fireEvent.change(
|
||||
screen.getByPlaceholderText('datasetSettings.form.searchModel'),
|
||||
{ target: { value: 'openai' } },
|
||||
)
|
||||
|
||||
expect(screen.getByText('openai'))!.toBeInTheDocument()
|
||||
expect(screen.getByText('gpt-4'))!.toBeInTheDocument()
|
||||
expect(screen.getByText('gpt-4o'))!.toBeInTheDocument()
|
||||
expect(screen.queryByText('anthropic')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('claude-3')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should match by model provider key when model label does not contain the search text', () => {
|
||||
renderPopup(
|
||||
<Popup
|
||||
modelList={[
|
||||
makeModel({
|
||||
provider: 'azure_openai',
|
||||
label: { en_US: 'Azure', zh_Hans: 'Azure' },
|
||||
models: [
|
||||
makeModelItem({ model: 'gpt-4', label: { en_US: 'GPT-4', zh_Hans: 'GPT-4' } }),
|
||||
],
|
||||
}),
|
||||
]}
|
||||
onSelect={vi.fn()}
|
||||
onHide={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
fireEvent.change(
|
||||
screen.getByPlaceholderText('datasetSettings.form.searchModel'),
|
||||
{ target: { value: 'openai' } },
|
||||
)
|
||||
|
||||
expect(screen.getByText('azure_openai'))!.toBeInTheDocument()
|
||||
expect(screen.getByText('gpt-4'))!.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should still apply scope features when matching by provider label', () => {
|
||||
mockSupportFunctionCall.mockReturnValue(false)
|
||||
|
||||
renderPopup(
|
||||
<Popup
|
||||
modelList={[
|
||||
makeModel({
|
||||
provider: 'openai',
|
||||
label: { en_US: 'OpenAI', zh_Hans: 'OpenAI' },
|
||||
models: [
|
||||
makeModelItem({ model: 'gpt-4', features: [ModelFeatureEnum.vision] }),
|
||||
makeModelItem({ model: 'gpt-4-tool', features: [ModelFeatureEnum.toolCall] }),
|
||||
],
|
||||
}),
|
||||
]}
|
||||
onSelect={vi.fn()}
|
||||
onHide={vi.fn()}
|
||||
scopeFeatures={[ModelFeatureEnum.toolCall]}
|
||||
/>,
|
||||
)
|
||||
|
||||
fireEvent.change(
|
||||
screen.getByPlaceholderText('datasetSettings.form.searchModel'),
|
||||
{ target: { value: 'openai' } },
|
||||
)
|
||||
|
||||
expect(screen.getByText('No model found for \u201Copenai\u201D'))!.toBeInTheDocument()
|
||||
expect(screen.queryByText('gpt-4')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('gpt-4-tool')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should not show compatible-only helper text when no scope features are applied', () => {
|
||||
renderPopup(
|
||||
<Popup
|
||||
|
||||
@ -143,18 +143,26 @@ const Popup: FC<PopupProps> = ({
|
||||
}, [aiCreditVisibleProviders, installedProviderMap, modelList])
|
||||
|
||||
const filteredModelList = useMemo(() => {
|
||||
const normalizedSearch = searchText.toLowerCase()
|
||||
const matchesLabel = (label: Record<string, string>) => {
|
||||
if (label[language] !== undefined)
|
||||
return label[language].toLowerCase().includes(normalizedSearch)
|
||||
return Object.values(label).some(value =>
|
||||
value.toLowerCase().includes(normalizedSearch),
|
||||
)
|
||||
}
|
||||
|
||||
const filtered = installedModelList.map((model) => {
|
||||
const matchesProviderSearch = !searchText
|
||||
|| model.provider.toLowerCase().includes(searchText.toLowerCase())
|
||||
|| Object.values(model.label).some(label => label.toLowerCase().includes(searchText.toLowerCase()))
|
||||
const providerMatched = !!searchText && (
|
||||
matchesLabel(model.label)
|
||||
|| model.provider.toLowerCase().includes(normalizedSearch)
|
||||
)
|
||||
|
||||
const filteredModels = model.models
|
||||
.filter((modelItem) => {
|
||||
if (modelItem.label[language] !== undefined)
|
||||
return modelItem.label[language].toLowerCase().includes(searchText.toLowerCase())
|
||||
return Object.values(modelItem.label).some(label =>
|
||||
label.toLowerCase().includes(searchText.toLowerCase()),
|
||||
)
|
||||
if (!searchText || providerMatched)
|
||||
return true
|
||||
return matchesLabel(modelItem.label)
|
||||
})
|
||||
.filter((modelItem) => {
|
||||
if (scopeFeatures.length === 0)
|
||||
@ -165,8 +173,12 @@ const Popup: FC<PopupProps> = ({
|
||||
return modelItem.features?.includes(feature) ?? false
|
||||
})
|
||||
})
|
||||
if (!matchesProviderSearch || (filteredModels.length === 0 && !aiCreditVisibleProviders.has(model.provider)))
|
||||
if (
|
||||
(searchText && filteredModels.length === 0)
|
||||
|| (!searchText && filteredModels.length === 0 && !aiCreditVisibleProviders.has(model.provider))
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
return { ...model, models: filteredModels }
|
||||
}).filter((model): model is Model => model !== null)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user