mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 10:28:10 +08:00
refactor: update model-selector popup-item to support collapsible items and improve icon color handling
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<g id="arrow-down-round-fill">
|
<g id="arrow-down-round-fill">
|
||||||
<path id="Vector" d="M6.02913 6.23572C5.08582 6.23572 4.56482 7.33027 5.15967 8.06239L7.13093 10.4885C7.57922 11.0403 8.42149 11.0403 8.86986 10.4885L10.8411 8.06239C11.4359 7.33027 10.9149 6.23572 9.97158 6.23572H6.02913Z" fill="#101828"/>
|
<path id="Vector" d="M6.02913 6.23572C5.08582 6.23572 4.56482 7.33027 5.15967 8.06239L7.13093 10.4885C7.57922 11.0403 8.42149 11.0403 8.86986 10.4885L10.8411 8.06239C11.4359 7.33027 10.9149 6.23572 9.97158 6.23572H6.02913Z" fill="currentColor"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 380 B After Width: | Height: | Size: 385 B |
@ -4,6 +4,7 @@ import type {
|
|||||||
Model,
|
Model,
|
||||||
ModelItem,
|
ModelItem,
|
||||||
} from '../declarations'
|
} from '../declarations'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Check } from '@/app/components/base/icons/src/vender/line/general'
|
import { Check } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
@ -41,6 +42,7 @@ const PopupItem: FC<PopupItemProps> = ({
|
|||||||
model,
|
model,
|
||||||
onSelect,
|
onSelect,
|
||||||
}) => {
|
}) => {
|
||||||
|
const [collapsed, setCollapsed] = useState(false)
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const { setShowModelModal } = useModalContext()
|
const { setShowModelModal } = useModalContext()
|
||||||
@ -73,99 +75,101 @@ const PopupItem: FC<PopupItemProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-1">
|
<div className="mb-1">
|
||||||
<div className="flex h-[22px] items-center px-3 text-xs font-medium text-text-tertiary">
|
<div
|
||||||
|
className="flex h-[22px] cursor-pointer items-center px-3 text-xs font-medium text-text-tertiary"
|
||||||
|
onClick={() => setCollapsed(prev => !prev)}
|
||||||
|
>
|
||||||
{model.label[language] || model.label.en_US}
|
{model.label[language] || model.label.en_US}
|
||||||
|
<span className={cn('i-custom-vender-solid-general-arrow-down-round-fill h-4 w-4 text-text-quaternary', collapsed && '-rotate-90')} />
|
||||||
</div>
|
</div>
|
||||||
{
|
{!collapsed && model.models.map(modelItem => (
|
||||||
model.models.map(modelItem => (
|
<Tooltip
|
||||||
<Tooltip
|
key={modelItem.model}
|
||||||
key={modelItem.model}
|
position="right"
|
||||||
position="right"
|
popupClassName="p-3 !w-[206px] bg-components-panel-bg-blur backdrop-blur-sm border-[0.5px] border-components-panel-border rounded-xl"
|
||||||
popupClassName="p-3 !w-[206px] bg-components-panel-bg-blur backdrop-blur-sm border-[0.5px] border-components-panel-border rounded-xl"
|
popupContent={(
|
||||||
popupContent={(
|
<div className="flex flex-col gap-1">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col items-start gap-2">
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<ModelIcon
|
|
||||||
className={cn('h-5 w-5 shrink-0')}
|
|
||||||
provider={model}
|
|
||||||
modelName={modelItem.model}
|
|
||||||
/>
|
|
||||||
<div className="system-md-medium text-wrap break-words text-text-primary">{modelItem.label[language] || modelItem.label.en_US}</div>
|
|
||||||
</div>
|
|
||||||
{/* {currentProvider?.description && (
|
|
||||||
<div className='text-text-tertiary system-xs-regular'>{currentProvider?.description?.[language] || currentProvider?.description?.en_US}</div>
|
|
||||||
)} */}
|
|
||||||
<div className="flex flex-wrap gap-1">
|
|
||||||
{!!modelItem.model_type && (
|
|
||||||
<ModelBadge>
|
|
||||||
{modelTypeFormat(modelItem.model_type)}
|
|
||||||
</ModelBadge>
|
|
||||||
)}
|
|
||||||
{!!modelItem.model_properties.mode && (
|
|
||||||
<ModelBadge>
|
|
||||||
{(modelItem.model_properties.mode as string).toLocaleUpperCase()}
|
|
||||||
</ModelBadge>
|
|
||||||
)}
|
|
||||||
{!!modelItem.model_properties.context_size && (
|
|
||||||
<ModelBadge>
|
|
||||||
{sizeFormat(modelItem.model_properties.context_size as number)}
|
|
||||||
</ModelBadge>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{[ModelTypeEnum.textGeneration, ModelTypeEnum.textEmbedding, ModelTypeEnum.rerank].includes(modelItem.model_type as ModelTypeEnum)
|
|
||||||
&& modelItem.features?.some(feature => [ModelFeatureEnum.vision, ModelFeatureEnum.audio, ModelFeatureEnum.video, ModelFeatureEnum.document].includes(feature))
|
|
||||||
&& (
|
|
||||||
<div className="pt-2">
|
|
||||||
<div className="system-2xs-medium-uppercase mb-1 text-text-tertiary">{t('model.capabilities', { ns: 'common' })}</div>
|
|
||||||
<div className="flex flex-wrap gap-1">
|
|
||||||
{modelItem.features?.map(feature => (
|
|
||||||
<FeatureIcon
|
|
||||||
key={feature}
|
|
||||||
feature={feature}
|
|
||||||
showFeaturesLabel
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
key={modelItem.model}
|
|
||||||
className={cn('group relative flex h-8 items-center gap-1 rounded-lg px-3 py-1.5', modelItem.status === ModelStatusEnum.active ? 'cursor-pointer hover:bg-state-base-hover' : 'cursor-not-allowed hover:bg-state-base-hover-alt')}
|
|
||||||
onClick={() => handleSelect(model.provider, modelItem)}
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<ModelIcon
|
<ModelIcon
|
||||||
className={cn('h-5 w-5 shrink-0')}
|
className={cn('h-5 w-5 shrink-0')}
|
||||||
provider={model}
|
provider={model}
|
||||||
modelName={modelItem.model}
|
modelName={modelItem.model}
|
||||||
/>
|
/>
|
||||||
<ModelName
|
<div className="text-wrap break-words text-text-primary system-md-medium">{modelItem.label[language] || modelItem.label.en_US}</div>
|
||||||
className={cn('system-sm-medium text-text-secondary', modelItem.status !== ModelStatusEnum.active && 'opacity-60')}
|
|
||||||
modelItem={modelItem}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{
|
{/* {currentProvider?.description && (
|
||||||
defaultModel?.model === modelItem.model && defaultModel.provider === currentProvider.provider && (
|
<div className='text-text-tertiary system-xs-regular'>{currentProvider?.description?.[language] || currentProvider?.description?.en_US}</div>
|
||||||
<Check className="h-4 w-4 shrink-0 text-text-accent" />
|
)} */}
|
||||||
)
|
<div className="flex flex-wrap gap-1">
|
||||||
}
|
{!!modelItem.model_type && (
|
||||||
{
|
<ModelBadge>
|
||||||
modelItem.status === ModelStatusEnum.noConfigure && (
|
{modelTypeFormat(modelItem.model_type)}
|
||||||
<div
|
</ModelBadge>
|
||||||
className="hidden cursor-pointer text-xs font-medium text-text-accent group-hover:block"
|
)}
|
||||||
onClick={handleOpenModelModal}
|
{!!modelItem.model_properties.mode && (
|
||||||
>
|
<ModelBadge>
|
||||||
{t('operation.add', { ns: 'common' }).toLocaleUpperCase()}
|
{(modelItem.model_properties.mode as string).toLocaleUpperCase()}
|
||||||
|
</ModelBadge>
|
||||||
|
)}
|
||||||
|
{!!modelItem.model_properties.context_size && (
|
||||||
|
<ModelBadge>
|
||||||
|
{sizeFormat(modelItem.model_properties.context_size as number)}
|
||||||
|
</ModelBadge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{[ModelTypeEnum.textGeneration, ModelTypeEnum.textEmbedding, ModelTypeEnum.rerank].includes(modelItem.model_type as ModelTypeEnum)
|
||||||
|
&& modelItem.features?.some(feature => [ModelFeatureEnum.vision, ModelFeatureEnum.audio, ModelFeatureEnum.video, ModelFeatureEnum.document].includes(feature))
|
||||||
|
&& (
|
||||||
|
<div className="pt-2">
|
||||||
|
<div className="mb-1 text-text-tertiary system-2xs-medium-uppercase">{t('model.capabilities', { ns: 'common' })}</div>
|
||||||
|
<div className="flex flex-wrap gap-1">
|
||||||
|
{modelItem.features?.map(feature => (
|
||||||
|
<FeatureIcon
|
||||||
|
key={feature}
|
||||||
|
feature={feature}
|
||||||
|
showFeaturesLabel
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)}
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
)}
|
||||||
))
|
>
|
||||||
}
|
<div
|
||||||
|
key={modelItem.model}
|
||||||
|
className={cn('group relative flex h-8 items-center gap-1 rounded-lg px-3 py-1.5', modelItem.status === ModelStatusEnum.active ? 'cursor-pointer hover:bg-state-base-hover' : 'cursor-not-allowed hover:bg-state-base-hover-alt')}
|
||||||
|
onClick={() => handleSelect(model.provider, modelItem)}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<ModelIcon
|
||||||
|
className={cn('h-5 w-5 shrink-0')}
|
||||||
|
provider={model}
|
||||||
|
modelName={modelItem.model}
|
||||||
|
/>
|
||||||
|
<ModelName
|
||||||
|
className={cn('text-text-secondary system-sm-medium', modelItem.status !== ModelStatusEnum.active && 'opacity-60')}
|
||||||
|
modelItem={modelItem}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
defaultModel?.model === modelItem.model && defaultModel.provider === currentProvider.provider && (
|
||||||
|
<Check className="h-4 w-4 shrink-0 text-text-accent" />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
modelItem.status === ModelStatusEnum.noConfigure && (
|
||||||
|
<div
|
||||||
|
className="hidden cursor-pointer text-xs font-medium text-text-accent group-hover:block"
|
||||||
|
onClick={handleOpenModelModal}
|
||||||
|
>
|
||||||
|
{t('operation.add', { ns: 'common' }).toLocaleUpperCase()}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -108,13 +108,13 @@ const QuotaPanel: FC<QuotaPanelProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('my-2 min-w-[72px] shrink-0 rounded-xl border-[0.5px] pb-2.5 pl-4 pr-2.5 pt-3 shadow-xs', credits <= 0 ? 'border-state-destructive-border hover:bg-state-destructive-hover' : 'border-components-panel-border bg-third-party-model-bg-default')}>
|
<div className={cn('my-2 min-w-[72px] shrink-0 rounded-xl border-[0.5px] pb-2.5 pl-4 pr-2.5 pt-3 shadow-xs', credits <= 0 ? 'border-state-destructive-border hover:bg-state-destructive-hover' : 'border-components-panel-border bg-third-party-model-bg-default')}>
|
||||||
<div className="system-xs-medium-uppercase mb-2 flex h-4 items-center text-text-tertiary">
|
<div className="mb-2 flex h-4 items-center text-text-tertiary system-xs-medium-uppercase">
|
||||||
{t('modelProvider.quota', { ns: 'common' })}
|
{t('modelProvider.quota', { ns: 'common' })}
|
||||||
<Tooltip popupContent={t('modelProvider.card.tip', { ns: 'common', modelNames: trial_models.map(key => modelNameMap[key as keyof typeof modelNameMap]).filter(Boolean).join(', ') })} />
|
<Tooltip popupContent={t('modelProvider.card.tip', { ns: 'common', modelNames: trial_models.map(key => modelNameMap[key as keyof typeof modelNameMap]).filter(Boolean).join(', ') })} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-1 text-xs text-text-tertiary">
|
<div className="flex items-center gap-1 text-xs text-text-tertiary">
|
||||||
<span className="system-md-semibold-uppercase mr-0.5 text-text-secondary">{formatNumber(credits)}</span>
|
<span className="mr-0.5 text-text-secondary system-md-semibold-uppercase">{formatNumber(credits)}</span>
|
||||||
<span>{t('modelProvider.credits', { ns: 'common' })}</span>
|
<span>{t('modelProvider.credits', { ns: 'common' })}</span>
|
||||||
{currentWorkspace.next_credit_reset_date
|
{currentWorkspace.next_credit_reset_date
|
||||||
? (
|
? (
|
||||||
|
|||||||
@ -4899,9 +4899,6 @@
|
|||||||
"app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx": {
|
"app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx": {
|
||||||
"no-restricted-imports": {
|
"no-restricted-imports": {
|
||||||
"count": 1
|
"count": 1
|
||||||
},
|
|
||||||
"tailwindcss/enforce-consistent-class-order": {
|
|
||||||
"count": 3
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"app/components/header/account-setting/model-provider-page/model-selector/popup.tsx": {
|
"app/components/header/account-setting/model-provider-page/model-selector/popup.tsx": {
|
||||||
@ -4978,9 +4975,6 @@
|
|||||||
"app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx": {
|
"app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx": {
|
||||||
"no-restricted-imports": {
|
"no-restricted-imports": {
|
||||||
"count": 1
|
"count": 1
|
||||||
},
|
|
||||||
"tailwindcss/enforce-consistent-class-order": {
|
|
||||||
"count": 2
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"app/components/header/account-setting/model-provider-page/provider-icon/index.tsx": {
|
"app/components/header/account-setting/model-provider-page/provider-icon/index.tsx": {
|
||||||
|
|||||||
Reference in New Issue
Block a user