mirror of
https://github.com/langgenius/dify.git
synced 2026-01-08 07:14:14 +00:00
feat: can select plugins
This commit is contained in:
@@ -4,6 +4,6 @@ export const defaultValue: AutoUpdateConfig = {
|
||||
strategy_setting: AUTO_UPDATE_STRATEGY.fixOnly, // For test
|
||||
upgrade_time_of_day: 0,
|
||||
upgrade_mode: AUTO_UPDATE_MODE.exclude, // For test
|
||||
exclude_plugins: ['a', 'c'],
|
||||
include_plugins: ['b'],
|
||||
exclude_plugins: ['langgenius/openai_api_compatible', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai', 'langgenius/openai'],
|
||||
include_plugins: ['langgenius/openai'],
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ const PluginsPicker: FC<Props> = ({
|
||||
|
||||
<ToolPicker
|
||||
trigger={
|
||||
<Button className='mt-2 w-[350px]' size='small' variant='secondary-accent'>
|
||||
<Button className='mt-2 w-[412px]' size='small' variant='secondary-accent'>
|
||||
<RiAddLine className='size-3.5' />
|
||||
{t(`${i18nPrefix}.operation.select`)}
|
||||
</Button>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
import { MARKETPLACE_API_PREFIX } from '@/config'
|
||||
import Icon from '@/app/components/plugins/card/base/card-icon'
|
||||
|
||||
const MAX_DISPLAY_COUNT = 14
|
||||
type Props = {
|
||||
@@ -14,17 +16,13 @@ const PluginsSelected: FC<Props> = ({
|
||||
plugins,
|
||||
}) => {
|
||||
const isShowAll = plugins.length < MAX_DISPLAY_COUNT
|
||||
const displayPlugins = isShowAll ? plugins.slice(0, MAX_DISPLAY_COUNT) : plugins
|
||||
const displayPlugins = plugins.slice(0, MAX_DISPLAY_COUNT)
|
||||
return (
|
||||
<div className={cn('flex space-x-1', className)}>
|
||||
{displayPlugins.map((plugin, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className='size-6 rounded-lg border-[0.5px] border-[components-panel-border-subtle] bg-background-default-dodge text-center text-xs leading-6 text-text-secondary'
|
||||
>
|
||||
</div>
|
||||
<div className={cn('flex items-center space-x-1', className)}>
|
||||
{displayPlugins.map(plugin => (
|
||||
<Icon key={plugin} size='tiny' src={`${MARKETPLACE_API_PREFIX}/plugins/${plugin}/icon`} />
|
||||
))}
|
||||
{!isShowAll && <div>+{plugins.length - MAX_DISPLAY_COUNT}</div>}
|
||||
{!isShowAll && <div className='system-xs-medium text-text-tertiary'>+{plugins.length - MAX_DISPLAY_COUNT}</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import type { Plugin } from '@/app/components/plugins/types'
|
||||
import Icon from '@/app/components/plugins/card/base/card-icon'
|
||||
import { renderI18nObject } from '@/i18n'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
import { MARKETPLACE_API_PREFIX } from '@/config'
|
||||
import Checkbox from '@/app/components/base/checkbox'
|
||||
|
||||
type Props = {
|
||||
payload: Plugin
|
||||
isChecked?: boolean
|
||||
onCheckChange: () => void
|
||||
}
|
||||
|
||||
const ToolItem: FC<Props> = ({
|
||||
payload,
|
||||
isChecked,
|
||||
onCheckChange,
|
||||
}) => {
|
||||
const language = useGetLanguage()
|
||||
|
||||
const { plugin_id, label, org } = payload
|
||||
return (
|
||||
<div className='p-1'>
|
||||
<div
|
||||
className='flex w-full select-none items-center rounded-lg pr-2 hover:bg-state-base-hover'
|
||||
>
|
||||
<div className='flex h-8 grow items-center space-x-2 pl-3 pr-2'>
|
||||
<Icon size='tiny' src={`${MARKETPLACE_API_PREFIX}/plugins/${plugin_id}/icon`} />
|
||||
<div className='system-sm-medium max-w-[150px] shrink-0 truncate text-text-primary'>{renderI18nObject(label, language)}</div>
|
||||
<div className='system-xs-regular max-w-[150px] shrink-0 truncate text-text-quaternary'>{org}</div>
|
||||
</div>
|
||||
<Checkbox
|
||||
checked={isChecked}
|
||||
onCheck={onCheckChange}
|
||||
className='shrink-0'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(ToolItem)
|
||||
@@ -11,6 +11,7 @@ import { PLUGIN_TYPE_SEARCH_MAP } from '../../marketplace/plugin-type-switch'
|
||||
import SearchBox from '@/app/components/plugins/marketplace/search-box'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import cn from '@/utils/classnames'
|
||||
import ToolItem from './tool-item'
|
||||
|
||||
type Props = {
|
||||
trigger: React.ReactNode
|
||||
@@ -70,13 +71,19 @@ const ToolPicker: FC<Props> = ({
|
||||
})
|
||||
const isBundle = pluginType === PLUGIN_TYPE_SEARCH_MAP.bundle
|
||||
const list = (isBundle ? data?.data?.bundles : data?.data?.plugins) || []
|
||||
|
||||
console.log(list)
|
||||
const handleCheckChange = useCallback((pluginId: string) => {
|
||||
return () => {
|
||||
const newValue = value.includes(pluginId)
|
||||
? value.filter(id => id !== pluginId)
|
||||
: [...value, pluginId]
|
||||
onChange(newValue)
|
||||
}
|
||||
}, [onChange, value])
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
placement='top-start'
|
||||
placement='top'
|
||||
offset={0}
|
||||
open={true}
|
||||
open={isShow}
|
||||
onOpenChange={onShowChange}
|
||||
>
|
||||
<PortalToFollowElemTrigger
|
||||
@@ -85,7 +92,7 @@ const ToolPicker: FC<Props> = ({
|
||||
{trigger}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
<div className={cn('relative min-h-20 w-[356px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur pb-2 shadow-lg backdrop-blur-sm')}>
|
||||
<div className={cn('relative min-h-20 w-[436px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur pb-2 shadow-lg backdrop-blur-sm')}>
|
||||
<div className='p-2 pb-1'>
|
||||
<SearchBox
|
||||
search={query}
|
||||
@@ -116,6 +123,18 @@ const ToolPicker: FC<Props> = ({
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{list.length > 0 && (
|
||||
<div className='max-h-[396px] overflow-y-auto'>
|
||||
{list.map(item => (
|
||||
<ToolItem
|
||||
key={item.plugin_id}
|
||||
payload={item}
|
||||
isChecked={value.includes(item.plugin_id)}
|
||||
onCheckChange={handleCheckChange(item.plugin_id)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
|
||||
@@ -51,9 +51,9 @@ const PluginSettingModal: FC<Props> = ({
|
||||
isShow
|
||||
onClose={onHide}
|
||||
closable
|
||||
className='w-[420px] !p-0'
|
||||
className='w-[480px] !p-0'
|
||||
>
|
||||
<div className='shadows-shadow-xl flex w-[420px] flex-col items-start rounded-2xl border border-components-panel-border bg-components-panel-bg'>
|
||||
<div className='shadows-shadow-xl flex w-[480px] flex-col items-start rounded-2xl border border-components-panel-border bg-components-panel-bg'>
|
||||
<div className='flex items-start gap-2 self-stretch pb-3 pl-6 pr-14 pt-6'>
|
||||
<span className='title-2xl-semi-bold self-stretch text-text-primary'>{t(`${i18nPrefix}.title`)}</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user