Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins

This commit is contained in:
Yi 2024-11-07 15:31:42 +08:00
commit 65285965b6
8 changed files with 133 additions and 46 deletions

View File

@ -28,6 +28,60 @@ const Marketplace = async ({
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap} marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
showInstallButton={showInstallButton} showInstallButton={showInstallButton}
/> />
<ListWrapper
locale={locale}
marketplaceCollections={marketplaceCollections}
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
showInstallButton={showInstallButton}
/>
<ListWrapper
locale={locale}
marketplaceCollections={marketplaceCollections}
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
showInstallButton={showInstallButton}
/>
<ListWrapper
locale={locale}
marketplaceCollections={marketplaceCollections}
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
showInstallButton={showInstallButton}
/>
<ListWrapper
locale={locale}
marketplaceCollections={marketplaceCollections}
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
showInstallButton={showInstallButton}
/>
<ListWrapper
locale={locale}
marketplaceCollections={marketplaceCollections}
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
showInstallButton={showInstallButton}
/>
<ListWrapper
locale={locale}
marketplaceCollections={marketplaceCollections}
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
showInstallButton={showInstallButton}
/>
<ListWrapper
locale={locale}
marketplaceCollections={marketplaceCollections}
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
showInstallButton={showInstallButton}
/>
<ListWrapper
locale={locale}
marketplaceCollections={marketplaceCollections}
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
showInstallButton={showInstallButton}
/>
<ListWrapper
locale={locale}
marketplaceCollections={marketplaceCollections}
marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap}
showInstallButton={showInstallButton}
/>
</MarketplaceContextProvider> </MarketplaceContextProvider>
) )
} }

View File

@ -1,17 +1,16 @@
import { useEffect } from 'react' import { useEffect } from 'react'
import { usePluginPageContext } from '@/app/components/plugins/plugin-page/context'
import { useMarketplaceContext } from '@/app/components/plugins/marketplace/context' import { useMarketplaceContext } from '@/app/components/plugins/marketplace/context'
export const useScrollIntersection = ( export const useScrollIntersection = (
anchorRef: React.RefObject<HTMLDivElement>, anchorRef: React.RefObject<HTMLDivElement>,
) => { ) => {
const containerRef = usePluginPageContext(v => v.containerRef)
const intersected = useMarketplaceContext(v => v.intersected) const intersected = useMarketplaceContext(v => v.intersected)
const setIntersected = useMarketplaceContext(v => v.setIntersected) const setIntersected = useMarketplaceContext(v => v.setIntersected)
useEffect(() => { useEffect(() => {
const container = document.getElementById('marketplace-container')
let observer: IntersectionObserver | undefined let observer: IntersectionObserver | undefined
if (containerRef?.current && anchorRef.current) { if (container && anchorRef.current) {
observer = new IntersectionObserver((entries) => { observer = new IntersectionObserver((entries) => {
const isIntersecting = entries[0].isIntersecting const isIntersecting = entries[0].isIntersecting
@ -21,10 +20,10 @@ export const useScrollIntersection = (
if (!isIntersecting && intersected) if (!isIntersecting && intersected)
setIntersected(false) setIntersected(false)
}, { }, {
root: containerRef.current, root: container,
}) })
observer.observe(anchorRef.current) observer.observe(anchorRef.current)
} }
return () => observer?.disconnect() return () => observer?.disconnect()
}, [containerRef, anchorRef, intersected, setIntersected]) }, [anchorRef, intersected, setIntersected])
} }

View File

@ -121,6 +121,7 @@ const PluginPage = ({
return ( return (
<div <div
id='marketplace-container'
ref={containerRef} ref={containerRef}
className={cn('grow relative flex flex-col overflow-y-auto border-t border-divider-subtle', activeTab === 'plugins' className={cn('grow relative flex flex-col overflow-y-auto border-t border-divider-subtle', activeTab === 'plugins'
? 'rounded-t-xl bg-components-panel-bg' ? 'rounded-t-xl bg-components-panel-bg'

View File

@ -1,7 +1,7 @@
'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useEffect, useState } from 'react' import { useState } from 'react'
import { import {
PortalToFollowElem, PortalToFollowElem,
PortalToFollowElemContent, PortalToFollowElemContent,
@ -13,12 +13,7 @@ import type {
} from '@floating-ui/react' } from '@floating-ui/react'
import AllTools from '@/app/components/workflow/block-selector/all-tools' import AllTools from '@/app/components/workflow/block-selector/all-tools'
import type { ToolDefaultValue } from './types' import type { ToolDefaultValue } from './types'
import { import type { BlockEnum } from '@/app/components/workflow/types'
fetchAllBuiltInTools,
fetchAllCustomTools,
fetchAllWorkflowTools,
} from '@/service/tools'
import type { BlockEnum, ToolWithProvider } from '@/app/components/workflow/types'
import SearchBox from '@/app/components/plugins/marketplace/search-box' import SearchBox from '@/app/components/plugins/marketplace/search-box'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks' import { useBoolean } from 'ahooks'
@ -28,6 +23,7 @@ import {
} from '@/service/tools' } from '@/service/tools'
import type { CustomCollectionBackend } from '@/app/components/tools/types' import type { CustomCollectionBackend } from '@/app/components/tools/types'
import Toast from '@/app/components/base/toast' import Toast from '@/app/components/base/toast'
import { useAllBuiltInTools, useAllCustomTools, useAllWorkflowTools, useInvalidateAllCustomTools } from '@/service/use-tools'
type Props = { type Props = {
disabled: boolean disabled: boolean
@ -53,25 +49,12 @@ const ToolPicker: FC<Props> = ({
const { t } = useTranslation() const { t } = useTranslation()
const [searchText, setSearchText] = useState('') const [searchText, setSearchText] = useState('')
const [buildInTools, setBuildInTools] = useState<ToolWithProvider[]>([]) const { data: buildInTools } = useAllBuiltInTools()
const [customTools, setCustomTools] = useState<ToolWithProvider[]>([]) const { data: customTools } = useAllCustomTools()
const [workflowTools, setWorkflowTools] = useState<ToolWithProvider[]>([]) const { invalidate: invalidateCustomTools } = useInvalidateAllCustomTools()
const { data: workflowTools } = useAllWorkflowTools()
useEffect(() => { const handleAddedCustomTool = invalidateCustomTools
(async () => {
const buildInTools = await fetchAllBuiltInTools()
const customTools = await fetchAllCustomTools()
const workflowTools = await fetchAllWorkflowTools()
setBuildInTools(buildInTools)
setCustomTools(customTools)
setWorkflowTools(workflowTools)
})()
}, [])
const handleAddedCustomTool = async () => {
const customTools = await fetchAllCustomTools()
setCustomTools(customTools)
}
const handleTriggerClick = () => { const handleTriggerClick = () => {
if (disabled) return if (disabled) return
@ -138,9 +121,9 @@ const ToolPicker: FC<Props> = ({
className='mt-1' className='mt-1'
searchText={searchText} searchText={searchText}
onSelect={handleSelect} onSelect={handleSelect}
buildInTools={buildInTools} buildInTools={buildInTools || []}
customTools={customTools} customTools={customTools || []}
workflowTools={workflowTools} workflowTools={workflowTools || []}
supportAddCustomTool={supportAddCustomTool} supportAddCustomTool={supportAddCustomTool}
onAddedCustomTool={handleAddedCustomTool} onAddedCustomTool={handleAddedCustomTool}
onShowAddCustomCollectionModal={showEditCustomCollectionModal} onShowAddCustomCollectionModal={showEditCustomCollectionModal}

View File

@ -6,7 +6,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
const client = new QueryClient() const client = new QueryClient()
export const TanstackQueryIniter: FC <PropsWithChildren> = (props) => { export const TanstackQueryIniter: FC<PropsWithChildren> = (props) => {
const { children } = props const { children } = props
return <QueryClientProvider client={client}> return <QueryClientProvider client={client}>
{children} {children}

View File

@ -27,7 +27,7 @@
"@babel/runtime": "^7.22.3", "@babel/runtime": "^7.22.3",
"@dagrejs/dagre": "^1.1.4", "@dagrejs/dagre": "^1.1.4",
"@emoji-mart/data": "^1.2.1", "@emoji-mart/data": "^1.2.1",
"@floating-ui/react": "^0.25.2", "@floating-ui/react": "^0.26.25",
"@formatjs/intl-localematcher": "^0.5.6", "@formatjs/intl-localematcher": "^0.5.6",
"@headlessui/react": "^1.7.13", "@headlessui/react": "^1.7.13",
"@heroicons/react": "^2.0.16", "@heroicons/react": "^2.0.16",

17
web/pnpm-lock.yaml generated
View File

@ -23,8 +23,8 @@ importers:
specifier: ^1.2.1 specifier: ^1.2.1
version: 1.2.1 version: 1.2.1
'@floating-ui/react': '@floating-ui/react':
specifier: ^0.25.2 specifier: ^0.26.25
version: 0.25.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 0.26.27(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@formatjs/intl-localematcher': '@formatjs/intl-localematcher':
specifier: ^0.5.6 specifier: ^0.5.6
version: 0.5.6 version: 0.5.6
@ -1445,15 +1445,12 @@ packages:
react: '>=16.8.0' react: '>=16.8.0'
react-dom: '>=16.8.0' react-dom: '>=16.8.0'
'@floating-ui/react@0.25.4': '@floating-ui/react@0.26.27':
resolution: {integrity: sha512-lWRQ/UiTvSIBxohn0/2HFHEmnmOVRjl7j6XcRJuLH0ls6f/9AyHMWVzkAJFuwx0n9gaEeCmg9VccCSCJzbEJig==} resolution: {integrity: sha512-jLP72x0Kr2CgY6eTYi/ra3VA9LOkTo4C+DUTrbFgFOExKy3omYVmwMjNKqxAHdsnyLS96BIDLcO2SlnsNf8KUQ==}
peerDependencies: peerDependencies:
react: '>=16.8.0' react: '>=16.8.0'
react-dom: '>=16.8.0' react-dom: '>=16.8.0'
'@floating-ui/utils@0.1.6':
resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==}
'@floating-ui/utils@0.2.8': '@floating-ui/utils@0.2.8':
resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==}
@ -9353,16 +9350,14 @@ snapshots:
react: 18.2.0 react: 18.2.0
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
'@floating-ui/react@0.25.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': '@floating-ui/react@0.26.27(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies: dependencies:
'@floating-ui/react-dom': 2.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@floating-ui/react-dom': 2.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@floating-ui/utils': 0.1.6 '@floating-ui/utils': 0.2.8
react: 18.2.0 react: 18.2.0
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
tabbable: 6.2.0 tabbable: 6.2.0
'@floating-ui/utils@0.1.6': {}
'@floating-ui/utils@0.2.8': {} '@floating-ui/utils@0.2.8': {}
'@formatjs/intl-localematcher@0.5.6': '@formatjs/intl-localematcher@0.5.6':

55
web/service/use-tools.ts Normal file
View File

@ -0,0 +1,55 @@
import { get } from './base'
import type {
Tool,
} from '@/app/components/tools/types'
import type { ToolWithProvider } from '@/app/components/workflow/types'
import {
useQueryClient,
} from '@tanstack/react-query'
import {
useQuery,
} from '@tanstack/react-query'
const NAME_SPACE = 'tools'
export const useAllBuiltInTools = () => {
return useQuery<ToolWithProvider[]>({
queryKey: [NAME_SPACE, 'builtIn'],
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/tools/builtin'),
})
}
const useAllCustomToolsKey = [NAME_SPACE, 'customTools']
export const useAllCustomTools = () => {
return useQuery<ToolWithProvider[]>({
queryKey: useAllCustomToolsKey,
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/tools/api'),
})
}
export const useInvalidateAllCustomTools = () => {
const queryClient = useQueryClient()
return {
invalidate: () => {
queryClient.invalidateQueries(
{
queryKey: useAllCustomToolsKey,
})
},
}
}
export const useAllWorkflowTools = () => {
return useQuery<ToolWithProvider[]>({
queryKey: [NAME_SPACE, 'workflowTools'],
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/tools/workflow'),
})
}
export const useBuiltInTools = (collectionName: string) => {
return useQuery({
queryKey: [NAME_SPACE, 'builtIn', collectionName],
queryFn: () => get<Tool[]>(`/workspaces/current/tool-provider/builtin/${collectionName}/tools`),
})
}