dify/web/app/components/plugins/marketplace/context.tsx

291 lines
9.4 KiB
TypeScript
Raw Normal View History

2024-10-12 18:02:24 +08:00
'use client'
2024-10-30 15:27:38 +08:00
import type {
ReactNode,
} from 'react'
2024-10-12 18:02:24 +08:00
import {
2024-10-29 10:51:41 +08:00
useCallback,
useEffect,
2024-11-27 16:14:15 +08:00
useMemo,
2024-10-30 15:27:38 +08:00
useRef,
2024-10-12 18:02:24 +08:00
useState,
} from 'react'
import {
createContext,
useContextSelector,
} from 'use-context-selector'
2024-10-29 10:51:41 +08:00
import { PLUGIN_TYPE_SEARCH_MAP } from './plugin-type-switch'
import type { Plugin } from '../types'
import {
getValidCategoryKeys,
getValidTagKeys,
} from '../utils'
2024-10-29 18:13:47 +08:00
import type {
2024-10-30 15:15:53 +08:00
MarketplaceCollection,
2024-10-29 18:13:47 +08:00
PluginsSort,
SearchParams,
2024-10-29 18:13:47 +08:00
} from './types'
import { DEFAULT_SORT } from './constants'
2024-10-31 18:31:17 +08:00
import {
useMarketplaceCollectionsAndPlugins,
2024-12-05 14:54:04 +08:00
useMarketplaceContainerScroll,
2024-10-31 18:31:17 +08:00
useMarketplacePlugins,
} from './hooks'
2024-12-03 14:34:23 +08:00
import {
getMarketplaceListCondition,
getMarketplaceListFilterType,
} from './utils'
2024-11-27 16:14:15 +08:00
import { useInstalledPluginList } from '@/service/use-plugins'
2024-10-12 18:02:24 +08:00
export type MarketplaceContextValue = {
intersected: boolean
setIntersected: (intersected: boolean) => void
2024-10-29 10:51:41 +08:00
searchPluginText: string
handleSearchPluginTextChange: (text: string) => void
filterPluginTags: string[]
handleFilterPluginTagsChange: (tags: string[]) => void
activePluginType: string
handleActivePluginTypeChange: (type: string) => void
2024-12-03 18:02:57 +08:00
page: number
handlePageChange: (page: number) => void
2024-10-29 10:51:41 +08:00
plugins?: Plugin[]
2024-11-08 18:21:39 +08:00
resetPlugins: () => void
2024-10-29 18:13:47 +08:00
sort: PluginsSort
handleSortChange: (sort: PluginsSort) => void
2024-12-05 14:54:04 +08:00
handleQueryPlugins: () => void
2024-10-30 15:15:53 +08:00
marketplaceCollectionsFromClient?: MarketplaceCollection[]
setMarketplaceCollectionsFromClient: (collections: MarketplaceCollection[]) => void
marketplaceCollectionPluginsMapFromClient?: Record<string, Plugin[]>
setMarketplaceCollectionPluginsMapFromClient: (map: Record<string, Plugin[]>) => void
2024-11-13 16:28:18 +08:00
isLoading: boolean
2024-12-03 18:02:57 +08:00
isSuccessCollections: boolean
2024-10-12 18:02:24 +08:00
}
export const MarketplaceContext = createContext<MarketplaceContextValue>({
intersected: true,
setIntersected: () => {},
2024-10-29 10:51:41 +08:00
searchPluginText: '',
handleSearchPluginTextChange: () => {},
filterPluginTags: [],
handleFilterPluginTagsChange: () => {},
2024-12-03 14:34:23 +08:00
activePluginType: 'all',
2024-10-29 10:51:41 +08:00
handleActivePluginTypeChange: () => {},
2024-12-03 18:02:57 +08:00
page: 1,
handlePageChange: () => {},
2024-10-29 10:51:41 +08:00
plugins: undefined,
2024-11-08 18:21:39 +08:00
resetPlugins: () => {},
2024-10-29 18:13:47 +08:00
sort: DEFAULT_SORT,
handleSortChange: () => {},
2024-12-05 14:54:04 +08:00
handleQueryPlugins: () => {},
2024-10-30 15:15:53 +08:00
marketplaceCollectionsFromClient: [],
setMarketplaceCollectionsFromClient: () => {},
marketplaceCollectionPluginsMapFromClient: {},
setMarketplaceCollectionPluginsMapFromClient: () => {},
2024-11-13 16:28:18 +08:00
isLoading: false,
2024-12-03 18:02:57 +08:00
isSuccessCollections: false,
2024-10-12 18:02:24 +08:00
})
type MarketplaceContextProviderProps = {
children: ReactNode
searchParams?: SearchParams
2024-11-27 16:14:15 +08:00
shouldExclude?: boolean
2024-12-05 14:54:04 +08:00
scrollContainerId?: string
2024-10-12 18:02:24 +08:00
}
export function useMarketplaceContext(selector: (value: MarketplaceContextValue) => any) {
return useContextSelector(MarketplaceContext, selector)
}
export const MarketplaceContextProvider = ({
children,
searchParams,
2024-11-27 16:14:15 +08:00
shouldExclude,
2024-12-05 14:54:04 +08:00
scrollContainerId,
2024-10-12 18:02:24 +08:00
}: MarketplaceContextProviderProps) => {
2024-11-27 16:14:15 +08:00
const { data, isSuccess } = useInstalledPluginList(!shouldExclude)
const exclude = useMemo(() => {
if (shouldExclude)
return data?.plugins.map(plugin => plugin.plugin_id)
}, [data?.plugins, shouldExclude])
const queryFromSearchParams = searchParams?.q || ''
const tagsFromSearchParams = searchParams?.tags ? getValidTagKeys(searchParams.tags.split(',')) : []
const hasValidTags = !!tagsFromSearchParams.length
const hasValidCategory = getValidCategoryKeys(searchParams?.category)
const categoryFromSearchParams = hasValidCategory || PLUGIN_TYPE_SEARCH_MAP.all
2024-10-12 18:02:24 +08:00
const [intersected, setIntersected] = useState(true)
const [searchPluginText, setSearchPluginText] = useState(queryFromSearchParams)
2024-10-30 15:27:38 +08:00
const searchPluginTextRef = useRef(searchPluginText)
const [filterPluginTags, setFilterPluginTags] = useState<string[]>(tagsFromSearchParams)
2024-10-30 15:27:38 +08:00
const filterPluginTagsRef = useRef(filterPluginTags)
const [activePluginType, setActivePluginType] = useState(categoryFromSearchParams)
2024-10-30 15:27:38 +08:00
const activePluginTypeRef = useRef(activePluginType)
2024-12-03 18:02:57 +08:00
const [page, setPage] = useState(1)
const pageRef = useRef(page)
2024-10-29 18:13:47 +08:00
const [sort, setSort] = useState(DEFAULT_SORT)
2024-10-30 15:27:38 +08:00
const sortRef = useRef(sort)
2024-10-31 18:31:17 +08:00
const {
marketplaceCollections: marketplaceCollectionsFromClient,
setMarketplaceCollections: setMarketplaceCollectionsFromClient,
marketplaceCollectionPluginsMap: marketplaceCollectionPluginsMapFromClient,
setMarketplaceCollectionPluginsMap: setMarketplaceCollectionPluginsMapFromClient,
queryMarketplaceCollectionsAndPlugins,
2024-11-13 16:28:18 +08:00
isLoading,
2024-12-03 18:02:57 +08:00
isSuccess: isSuccessCollections,
2024-10-31 18:31:17 +08:00
} = useMarketplaceCollectionsAndPlugins()
const {
plugins,
2024-12-05 14:54:04 +08:00
total: pluginsTotal,
2024-11-08 18:21:39 +08:00
resetPlugins,
2024-10-31 18:31:17 +08:00
queryPlugins,
queryPluginsWithDebounced,
2024-11-13 16:28:18 +08:00
isLoading: isPluginsLoading,
2024-10-31 18:31:17 +08:00
} = useMarketplacePlugins()
2024-10-29 10:51:41 +08:00
useEffect(() => {
if (queryFromSearchParams || hasValidTags || hasValidCategory) {
queryPlugins({
query: queryFromSearchParams,
category: hasValidCategory,
tags: hasValidTags ? tagsFromSearchParams : [],
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
2024-12-03 14:34:23 +08:00
type: getMarketplaceListFilterType(activePluginTypeRef.current),
2024-12-03 18:02:57 +08:00
page: pageRef.current,
})
history.pushState({}, '', `/${searchParams?.language ? `?language=${searchParams?.language}` : ''}`)
}
2024-11-27 16:14:15 +08:00
else {
if (shouldExclude && isSuccess) {
queryMarketplaceCollectionsAndPlugins({
exclude,
2024-12-03 14:34:23 +08:00
type: getMarketplaceListFilterType(activePluginTypeRef.current),
2024-11-27 16:14:15 +08:00
})
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
2024-11-27 16:14:15 +08:00
}, [queryPlugins, queryMarketplaceCollectionsAndPlugins, isSuccess, exclude])
2024-12-05 14:54:04 +08:00
const handleQueryMarketplaceCollectionsAndPlugins = useCallback(() => {
queryMarketplaceCollectionsAndPlugins({
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
condition: getMarketplaceListCondition(activePluginTypeRef.current),
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
})
resetPlugins()
}, [exclude, queryMarketplaceCollectionsAndPlugins, resetPlugins])
2024-10-29 10:51:41 +08:00
2024-12-05 14:54:04 +08:00
const handleQueryPlugins = useCallback((debounced?: boolean) => {
if (debounced) {
queryPluginsWithDebounced({
query: searchPluginTextRef.current,
2024-11-07 15:37:22 +08:00
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
2024-12-05 14:54:04 +08:00
tags: filterPluginTagsRef.current,
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
2024-11-27 16:14:15 +08:00
exclude,
2024-12-03 14:34:23 +08:00
type: getMarketplaceListFilterType(activePluginTypeRef.current),
2024-12-05 14:54:04 +08:00
page: pageRef.current,
2024-11-07 15:37:22 +08:00
})
2024-12-05 14:54:04 +08:00
}
else {
queryPlugins({
query: searchPluginTextRef.current,
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
tags: filterPluginTagsRef.current,
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}
}, [exclude, queryPluginsWithDebounced, queryPlugins])
2024-11-07 15:37:22 +08:00
2024-12-05 14:54:04 +08:00
const handleQuery = useCallback((debounced?: boolean) => {
if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) {
handleQueryMarketplaceCollectionsAndPlugins()
2024-11-07 15:37:22 +08:00
return
}
2024-12-05 14:54:04 +08:00
handleQueryPlugins(debounced)
}, [handleQueryMarketplaceCollectionsAndPlugins, handleQueryPlugins])
const handleSearchPluginTextChange = useCallback((text: string) => {
setSearchPluginText(text)
searchPluginTextRef.current = text
setPage(1)
pageRef.current = 1
handleQuery(true)
}, [handleQuery])
2024-10-29 10:51:41 +08:00
const handleFilterPluginTagsChange = useCallback((tags: string[]) => {
setFilterPluginTags(tags)
2024-10-30 15:27:38 +08:00
filterPluginTagsRef.current = tags
2024-12-03 18:02:57 +08:00
setPage(1)
pageRef.current = 1
2024-10-30 15:15:53 +08:00
2024-12-05 14:54:04 +08:00
handleQuery()
}, [handleQuery])
2024-10-29 10:51:41 +08:00
const handleActivePluginTypeChange = useCallback((type: string) => {
setActivePluginType(type)
2024-10-30 15:27:38 +08:00
activePluginTypeRef.current = type
2024-12-03 18:02:57 +08:00
setPage(1)
pageRef.current = 1
2024-10-30 15:15:53 +08:00
2024-12-05 14:54:04 +08:00
handleQuery()
}, [handleQuery])
2024-12-03 18:02:57 +08:00
2024-10-29 18:13:47 +08:00
const handleSortChange = useCallback((sort: PluginsSort) => {
setSort(sort)
2024-10-30 15:27:38 +08:00
sortRef.current = sort
2024-12-03 18:02:57 +08:00
setPage(1)
pageRef.current = 1
2024-10-30 15:15:53 +08:00
2024-12-05 14:54:04 +08:00
handleQueryPlugins()
}, [handleQueryPlugins])
2024-10-29 18:13:47 +08:00
2024-12-05 14:54:04 +08:00
const handlePageChange = useCallback(() => {
if (pluginsTotal && plugins && pluginsTotal > plugins.length && (!!searchPluginTextRef.current || !!filterPluginTagsRef.current.length)) {
setPage(pageRef.current + 1)
pageRef.current++
handleQueryPlugins()
}
}, [handleQueryPlugins, plugins, pluginsTotal])
2024-12-03 18:02:57 +08:00
2024-12-05 14:54:04 +08:00
useMarketplaceContainerScroll(handlePageChange, scrollContainerId)
2024-12-03 18:02:57 +08:00
2024-10-12 18:02:24 +08:00
return (
<MarketplaceContext.Provider
value={{
intersected,
setIntersected,
2024-10-29 10:51:41 +08:00
searchPluginText,
handleSearchPluginTextChange,
filterPluginTags,
handleFilterPluginTagsChange,
activePluginType,
handleActivePluginTypeChange,
2024-12-03 18:02:57 +08:00
page,
handlePageChange,
2024-10-29 10:51:41 +08:00
plugins,
2024-11-08 18:21:39 +08:00
resetPlugins,
2024-10-29 18:13:47 +08:00
sort,
handleSortChange,
2024-12-05 14:54:04 +08:00
handleQueryPlugins,
2024-10-30 15:15:53 +08:00
marketplaceCollectionsFromClient,
setMarketplaceCollectionsFromClient,
marketplaceCollectionPluginsMapFromClient,
setMarketplaceCollectionPluginsMapFromClient,
2024-11-13 16:28:18 +08:00
isLoading: isLoading || isPluginsLoading,
2024-12-03 18:02:57 +08:00
isSuccessCollections,
2024-10-12 18:02:24 +08:00
}}
>
{children}
</MarketplaceContext.Provider>
)
}