mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 19:59:50 +08:00
Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins
This commit is contained in:
commit
61a70e7a71
|
@ -123,7 +123,7 @@ const ModelProviderPage = ({ searchText }: Props) => {
|
|||
const [collapse, setCollapse] = useState(false)
|
||||
|
||||
const {
|
||||
plugins,
|
||||
plugins = [],
|
||||
queryPlugins,
|
||||
queryPluginsWithDebounced,
|
||||
isLoading: isPluginsLoading,
|
||||
|
|
|
@ -1,72 +1,87 @@
|
|||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type Tag = {
|
||||
name: string
|
||||
label: string
|
||||
}
|
||||
|
||||
export const useTags = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return [
|
||||
const tags = [
|
||||
{
|
||||
name: 'search',
|
||||
label: t('pluginTags.search'),
|
||||
label: t('pluginTags.tags.search'),
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
label: t('pluginTags.image'),
|
||||
label: t('pluginTags.tags.image'),
|
||||
},
|
||||
{
|
||||
name: 'videos',
|
||||
label: t('pluginTags.videos'),
|
||||
label: t('pluginTags.tags.videos'),
|
||||
},
|
||||
{
|
||||
name: 'weather',
|
||||
label: t('pluginTags.weather'),
|
||||
label: t('pluginTags.tags.weather'),
|
||||
},
|
||||
{
|
||||
name: 'finance',
|
||||
label: t('pluginTags.finance'),
|
||||
label: t('pluginTags.tags.finance'),
|
||||
},
|
||||
{
|
||||
name: 'design',
|
||||
label: t('pluginTags.design'),
|
||||
label: t('pluginTags.tags.design'),
|
||||
},
|
||||
{
|
||||
name: 'travel',
|
||||
label: t('pluginTags.travel'),
|
||||
label: t('pluginTags.tags.travel'),
|
||||
},
|
||||
{
|
||||
name: 'social',
|
||||
label: t('pluginTags.social'),
|
||||
label: t('pluginTags.tags.social'),
|
||||
},
|
||||
{
|
||||
name: 'news',
|
||||
label: t('pluginTags.news'),
|
||||
label: t('pluginTags.tags.news'),
|
||||
},
|
||||
{
|
||||
name: 'medical',
|
||||
label: t('pluginTags.medical'),
|
||||
label: t('pluginTags.tags.medical'),
|
||||
},
|
||||
{
|
||||
name: 'productivity',
|
||||
label: t('pluginTags.productivity'),
|
||||
label: t('pluginTags.tags.productivity'),
|
||||
},
|
||||
{
|
||||
name: 'education',
|
||||
label: t('pluginTags.education'),
|
||||
label: t('pluginTags.tags.education'),
|
||||
},
|
||||
{
|
||||
name: 'business',
|
||||
label: t('pluginTags.business'),
|
||||
label: t('pluginTags.tags.business'),
|
||||
},
|
||||
{
|
||||
name: 'entertainment',
|
||||
label: t('pluginTags.entertainment'),
|
||||
label: t('pluginTags.tags.entertainment'),
|
||||
},
|
||||
{
|
||||
name: 'utilities',
|
||||
label: t('pluginTags.utilities'),
|
||||
label: t('pluginTags.tags.utilities'),
|
||||
},
|
||||
{
|
||||
name: 'other',
|
||||
label: t('pluginTags.other'),
|
||||
label: t('pluginTags.tags.other'),
|
||||
},
|
||||
]
|
||||
|
||||
const tagsMap = tags.reduce((acc, tag) => {
|
||||
acc[tag.name] = tag
|
||||
return acc
|
||||
}, {} as Record<string, Tag>)
|
||||
|
||||
return {
|
||||
tags,
|
||||
tagsMap,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiArrowDownSLine,
|
||||
RiCloseCircleFill,
|
||||
|
@ -26,9 +27,10 @@ const TagsFilter = ({
|
|||
onTagsChange,
|
||||
size,
|
||||
}: TagsFilterProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(false)
|
||||
const [searchText, setSearchText] = useState('')
|
||||
const options = useTags()
|
||||
const { tags: options, tagsMap } = useTags()
|
||||
const filteredOptions = options.filter(option => option.label.toLowerCase().includes(searchText.toLowerCase()))
|
||||
const handleCheck = (id: string) => {
|
||||
if (tags.includes(id))
|
||||
|
@ -65,10 +67,10 @@ const TagsFilter = ({
|
|||
size === 'small' && 'px-0.5 py-1',
|
||||
)}>
|
||||
{
|
||||
!selectedTagsLength && 'All Tags'
|
||||
!selectedTagsLength && t('pluginTags.allTags')
|
||||
}
|
||||
{
|
||||
!!selectedTagsLength && tags.slice(0, 2).join(',')
|
||||
!!selectedTagsLength && tags.map(tag => tagsMap[tag].label).slice(0, 2).join(',')
|
||||
}
|
||||
{
|
||||
selectedTagsLength > 2 && (
|
||||
|
@ -100,7 +102,7 @@ const TagsFilter = ({
|
|||
showLeftIcon
|
||||
value={searchText}
|
||||
onChange={e => setSearchText(e.target.value)}
|
||||
placeholder='Search tags'
|
||||
placeholder={t('pluginTags.searchTags') || ''}
|
||||
/>
|
||||
</div>
|
||||
<div className='p-1 max-h-[448px] overflow-y-auto'>
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
RiHardDrive3Line,
|
||||
RiVerifiedBadgeLine,
|
||||
} from '@remixicon/react'
|
||||
import type { InstalledPlugin } from '../types'
|
||||
import type { PluginDetail } from '../types'
|
||||
import { PluginSource } from '../types'
|
||||
import Description from '../card/base/description'
|
||||
import Icon from '../card/base/card-icon'
|
||||
|
@ -30,7 +30,7 @@ import cn from '@/utils/classnames'
|
|||
const i18nPrefix = 'plugin.action'
|
||||
|
||||
type Props = {
|
||||
detail: InstalledPlugin
|
||||
detail: PluginDetail
|
||||
onHide: () => void
|
||||
onDelete: () => void
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ import Badge, { BadgeState } from '@/app/components/base/badge/index'
|
|||
import type { UpdateFromMarketPlacePayload } from '../types'
|
||||
import { pluginManifestToCardPluginProps } from '@/app/components/plugins/install-plugin/utils'
|
||||
import useGetIcon from '../install-plugin/base/use-get-icon'
|
||||
import { updateFromMarketPlace } from '@/service/plugins'
|
||||
import checkTaskStatus from '@/app/components/plugins/install-plugin/base/check-task-status'
|
||||
import { usePluginTasksStore } from '@/app/components/plugins/plugin-page/store'
|
||||
|
||||
const i18nPrefix = 'plugin.upgrade'
|
||||
|
||||
|
@ -43,7 +46,18 @@ const UpdatePluginModal: FC<Props> = ({
|
|||
setIcon(icon)
|
||||
})()
|
||||
}, [originalPackageInfo, getIconUrl])
|
||||
const {
|
||||
check,
|
||||
stop,
|
||||
} = checkTaskStatus()
|
||||
const handleCancel = () => {
|
||||
stop()
|
||||
onCancel()
|
||||
}
|
||||
|
||||
const [uploadStep, setUploadStep] = useState<UploadStep>(UploadStep.notStarted)
|
||||
const setPluginTasksWithPolling = usePluginTasksStore(s => s.setPluginTasksWithPolling)
|
||||
|
||||
const configBtnText = useMemo(() => {
|
||||
return ({
|
||||
[UploadStep.notStarted]: t(`${i18nPrefix}.upgrade`),
|
||||
|
@ -52,19 +66,41 @@ const UpdatePluginModal: FC<Props> = ({
|
|||
})[uploadStep]
|
||||
}, [t, uploadStep])
|
||||
|
||||
const handleConfirm = useCallback(() => {
|
||||
const handleConfirm = useCallback(async () => {
|
||||
if (uploadStep === UploadStep.notStarted) {
|
||||
setUploadStep(UploadStep.upgrading)
|
||||
setTimeout(() => {
|
||||
setUploadStep(UploadStep.installed)
|
||||
}, 1500)
|
||||
return
|
||||
const {
|
||||
all_installed: isInstalled,
|
||||
task_id: taskId,
|
||||
} = await updateFromMarketPlace({
|
||||
original_plugin_unique_identifier: originalPackageInfo.id,
|
||||
new_plugin_unique_identifier: targetPackageInfo.id,
|
||||
})
|
||||
if (isInstalled) {
|
||||
onSave()
|
||||
return
|
||||
}
|
||||
setPluginTasksWithPolling()
|
||||
await check({
|
||||
taskId,
|
||||
pluginUniqueIdentifier: targetPackageInfo.id,
|
||||
})
|
||||
onSave()
|
||||
}
|
||||
if (uploadStep === UploadStep.installed) {
|
||||
onSave()
|
||||
onCancel()
|
||||
}
|
||||
}, [onCancel, onSave, uploadStep])
|
||||
}, [onCancel, onSave, uploadStep, check, originalPackageInfo.id, setPluginTasksWithPolling, targetPackageInfo.id])
|
||||
const usedInAppInfo = useMemo(() => {
|
||||
return (
|
||||
<div className='flex px-0.5 justify-center items-center gap-0.5'>
|
||||
<div className='text-text-warning system-xs-medium'>{t(`${i18nPrefix}.usedInApps`, { num: 3 })}</div>
|
||||
{/* show the used apps */}
|
||||
<RiInformation2Line className='w-4 h-4 text-text-tertiary' />
|
||||
</div>
|
||||
)
|
||||
}, [t])
|
||||
return (
|
||||
<Modal
|
||||
isShow={true}
|
||||
|
@ -89,11 +125,7 @@ const UpdatePluginModal: FC<Props> = ({
|
|||
<Badge className='mx-1' size="s" state={BadgeState.Warning}>
|
||||
{`${originalPackageInfo.payload.version} -> ${targetPackageInfo.version}`}
|
||||
</Badge>
|
||||
<div className='flex px-0.5 justify-center items-center gap-0.5'>
|
||||
<div className='text-text-warning system-xs-medium'>{t(`${i18nPrefix}.usedInApps`, { num: 3 })}</div>
|
||||
{/* show the used apps */}
|
||||
<RiInformation2Line className='w-4 h-4 text-text-tertiary' />
|
||||
</div>
|
||||
{false && usedInAppInfo}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
@ -101,7 +133,7 @@ const UpdatePluginModal: FC<Props> = ({
|
|||
<div className='flex pt-5 justify-end items-center gap-2 self-stretch'>
|
||||
{uploadStep === UploadStep.notStarted && (
|
||||
<Button
|
||||
onClick={onCancel}
|
||||
onClick={handleCancel}
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
</Button>
|
||||
|
|
|
@ -27,7 +27,7 @@ const LabelFilter: FC<LabelFilterProps> = ({
|
|||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const labelList = useTags()
|
||||
const { tags: labelList } = useTags()
|
||||
|
||||
const [keywords, setKeywords] = useState('')
|
||||
const [searchKeywords, setSearchKeywords] = useState('')
|
||||
|
|
|
@ -26,7 +26,7 @@ const LabelSelector: FC<LabelSelectorProps> = ({
|
|||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const labelList = useTags()
|
||||
const { tags: labelList } = useTags()
|
||||
|
||||
const [keywords, setKeywords] = useState('')
|
||||
const [searchKeywords, setSearchKeywords] = useState('')
|
||||
|
|
|
@ -66,7 +66,7 @@ const AllTools = ({
|
|||
|
||||
const {
|
||||
queryPluginsWithDebounced: fetchPlugins,
|
||||
plugins: notInstalledPlugins,
|
||||
plugins: notInstalledPlugins = [],
|
||||
} = useMarketplacePlugins()
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
const translation = {
|
||||
search: 'Search',
|
||||
image: 'Image',
|
||||
videos: 'Videos',
|
||||
weather: 'Weather',
|
||||
finance: 'Finance',
|
||||
design: 'Design',
|
||||
travel: 'Travel',
|
||||
social: 'Social',
|
||||
news: 'News',
|
||||
medical: 'Medical',
|
||||
productivity: 'Productivity',
|
||||
education: 'Education',
|
||||
business: 'Business',
|
||||
entertainment: 'Entertainment',
|
||||
utilities: 'Utilities',
|
||||
other: 'Other',
|
||||
allTags: 'All Tags',
|
||||
searchTags: 'Search Tags',
|
||||
tags: {
|
||||
search: 'Search',
|
||||
image: 'Image',
|
||||
videos: 'Videos',
|
||||
weather: 'Weather',
|
||||
finance: 'Finance',
|
||||
design: 'Design',
|
||||
travel: 'Travel',
|
||||
social: 'Social',
|
||||
news: 'News',
|
||||
medical: 'Medical',
|
||||
productivity: 'Productivity',
|
||||
education: 'Education',
|
||||
business: 'Business',
|
||||
entertainment: 'Entertainment',
|
||||
utilities: 'Utilities',
|
||||
other: 'Other',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
const translation = {
|
||||
search: '搜索',
|
||||
image: '图片',
|
||||
videos: '视频',
|
||||
weather: '天气',
|
||||
finance: '金融',
|
||||
design: '设计',
|
||||
travel: '旅行',
|
||||
social: '社交',
|
||||
news: '新闻',
|
||||
medical: '医疗',
|
||||
productivity: '生产力',
|
||||
education: '教育',
|
||||
business: '商业',
|
||||
entertainment: '娱乐',
|
||||
utilities: '工具',
|
||||
other: '其他',
|
||||
allTags: '所有标签',
|
||||
searchTags: '搜索标签',
|
||||
tags: {
|
||||
search: '搜索',
|
||||
image: '图片',
|
||||
videos: '视频',
|
||||
weather: '天气',
|
||||
finance: '金融',
|
||||
design: '设计',
|
||||
travel: '旅行',
|
||||
social: '社交',
|
||||
news: '新闻',
|
||||
medical: '医疗',
|
||||
productivity: '生产力',
|
||||
education: '教育',
|
||||
business: '商业',
|
||||
entertainment: '娱乐',
|
||||
utilities: '工具',
|
||||
other: '其他',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
@ -71,6 +71,12 @@ export const installPackageFromLocal = async (uniqueIdentifier: string) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const updateFromMarketPlace = async (body: Record<string, string>) => {
|
||||
return post<InstallPackageResponse>('/workspaces/current/plugin/upgrade/marketplace', {
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
export const uploadGitHub = async (repoUrl: string, selectedVersion: string, selectedPackage: string) => {
|
||||
return post<uploadGitHubResponse>('/workspaces/current/plugin/upload/github', {
|
||||
body: {
|
||||
|
|
Loading…
Reference in New Issue
Block a user