From e7fb92e1692d2167be4a345951034fcc11b31e95 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Wed, 30 Oct 2024 15:15:53 +0800 Subject: [PATCH] feat: marketplace list --- .../plugins/marketplace/context.tsx | 84 +++++++++++++++++-- .../plugins/marketplace/empty/index.tsx | 40 +++++++++ .../plugins/marketplace/empty/line.tsx | 21 +++++ .../plugins/marketplace/list/index.tsx | 8 +- .../plugins/marketplace/list/list-wrapper.tsx | 22 +++-- .../components/plugins/marketplace/types.ts | 6 +- .../components/plugins/marketplace/utils.ts | 15 ++-- 7 files changed, 174 insertions(+), 22 deletions(-) create mode 100644 web/app/components/plugins/marketplace/empty/index.tsx create mode 100644 web/app/components/plugins/marketplace/empty/line.tsx diff --git a/web/app/components/plugins/marketplace/context.tsx b/web/app/components/plugins/marketplace/context.tsx index 70e0b5f75a..26a7914268 100644 --- a/web/app/components/plugins/marketplace/context.tsx +++ b/web/app/components/plugins/marketplace/context.tsx @@ -13,10 +13,15 @@ import { useDebounceFn } from 'ahooks' import { PLUGIN_TYPE_SEARCH_MAP } from './plugin-type-switch' import type { Plugin } from '../types' import type { + CollectionsAndPluginsSearchParams, + MarketplaceCollection, PluginsSearchParams, PluginsSort, } from './types' -import { getMarketplacePlugins } from './utils' +import { + getMarketplaceCollectionsAndPlugins, + getMarketplacePlugins, +} from './utils' import { DEFAULT_SORT } from './constants' export type MarketplaceContextValue = { @@ -29,9 +34,13 @@ export type MarketplaceContextValue = { activePluginType: string handleActivePluginTypeChange: (type: string) => void plugins?: Plugin[] - setPlugins?: (plugins: Plugin[]) => void + setPlugins: (plugins: Plugin[]) => void sort: PluginsSort handleSortChange: (sort: PluginsSort) => void + marketplaceCollectionsFromClient?: MarketplaceCollection[] + setMarketplaceCollectionsFromClient: (collections: MarketplaceCollection[]) => void + marketplaceCollectionPluginsMapFromClient?: Record + setMarketplaceCollectionPluginsMapFromClient: (map: Record) => void } export const MarketplaceContext = createContext({ @@ -47,6 +56,10 @@ export const MarketplaceContext = createContext({ setPlugins: () => {}, sort: DEFAULT_SORT, handleSortChange: () => {}, + marketplaceCollectionsFromClient: [], + setMarketplaceCollectionsFromClient: () => {}, + marketplaceCollectionPluginsMapFromClient: {}, + setMarketplaceCollectionPluginsMapFromClient: () => {}, }) type MarketplaceContextProviderProps = { @@ -66,11 +79,26 @@ export const MarketplaceContextProvider = ({ const [activePluginType, setActivePluginType] = useState(PLUGIN_TYPE_SEARCH_MAP.all) const [plugins, setPlugins] = useState() const [sort, setSort] = useState(DEFAULT_SORT) + const [marketplaceCollectionsFromClient, setMarketplaceCollectionsFromClient] = useState(undefined) + const [marketplaceCollectionPluginsMapFromClient, setMarketplaceCollectionPluginsMapFromClient] = useState | undefined>(undefined) const handleUpdatePlugins = useCallback(async (query: PluginsSearchParams) => { const { marketplacePlugins } = await getMarketplacePlugins(query) setPlugins(marketplacePlugins) + setMarketplaceCollectionsFromClient(undefined) + setMarketplaceCollectionPluginsMapFromClient(undefined) + }, []) + + const handleUpdateMarketplaceCollectionsAndPlugins = useCallback(async (query?: CollectionsAndPluginsSearchParams) => { + const { + marketplaceCollections, + marketplaceCollectionPluginsMap, + } = await getMarketplaceCollectionsAndPlugins(query) + + setMarketplaceCollectionsFromClient(marketplaceCollections) + setMarketplaceCollectionPluginsMapFromClient(marketplaceCollectionPluginsMap) + setPlugins(undefined) }, []) const { run: handleUpdatePluginsWithDebounced } = useDebounceFn(handleUpdatePlugins, { @@ -80,20 +108,58 @@ export const MarketplaceContextProvider = ({ const handleSearchPluginTextChange = useCallback((text: string) => { setSearchPluginText(text) - handleUpdatePluginsWithDebounced({ query: text }) - }, [handleUpdatePluginsWithDebounced]) + handleUpdatePluginsWithDebounced({ + query: text, + category: activePluginType === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginType, + tags: filterPluginTags, + sortBy: sort.sortBy, + sortOrder: sort.sortOrder, + }) + }, [handleUpdatePluginsWithDebounced, activePluginType, filterPluginTags, sort]) const handleFilterPluginTagsChange = useCallback((tags: string[]) => { setFilterPluginTags(tags) - }, []) + + handleUpdatePlugins({ + query: searchPluginText, + category: activePluginType === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginType, + tags, + sortBy: sort.sortBy, + sortOrder: sort.sortOrder, + }) + }, [handleUpdatePlugins, searchPluginText, activePluginType, sort]) const handleActivePluginTypeChange = useCallback((type: string) => { setActivePluginType(type) - }, []) + + if (!searchPluginText && !filterPluginTags.length) { + handleUpdateMarketplaceCollectionsAndPlugins({ + category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type, + }) + + return + } + + handleUpdatePlugins({ + query: searchPluginText, + category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type, + tags: filterPluginTags, + sortBy: sort.sortBy, + sortOrder: sort.sortOrder, + }) + }, [handleUpdatePlugins, searchPluginText, filterPluginTags, sort, handleUpdateMarketplaceCollectionsAndPlugins]) const handleSortChange = useCallback((sort: PluginsSort) => { setSort(sort) - }, []) + + handleUpdatePlugins({ + query: searchPluginText, + category: activePluginType === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginType, + tags: filterPluginTags, + sortBy: sort.sortBy, + sortOrder: sort.sortOrder, + }) + }, [handleUpdatePlugins, searchPluginText, activePluginType, filterPluginTags]) return ( {children} diff --git a/web/app/components/plugins/marketplace/empty/index.tsx b/web/app/components/plugins/marketplace/empty/index.tsx new file mode 100644 index 0000000000..a6e71c9eee --- /dev/null +++ b/web/app/components/plugins/marketplace/empty/index.tsx @@ -0,0 +1,40 @@ +import { Group } from '@/app/components/base/icons/src/vender/other' +import Line from './line' + +const Empty = () => { + return ( +
+ { + Array.from({ length: 16 }).map((_, index) => ( +
+
+ )) + } +
+
+
+ + + + + +
+
+ No plugin found +
+
+
+ ) +} + +export default Empty diff --git a/web/app/components/plugins/marketplace/empty/line.tsx b/web/app/components/plugins/marketplace/empty/line.tsx new file mode 100644 index 0000000000..b505b7846a --- /dev/null +++ b/web/app/components/plugins/marketplace/empty/line.tsx @@ -0,0 +1,21 @@ +type LineProps = { + className?: string +} +const Line = ({ + className, +}: LineProps) => { + return ( + + + + + + + + + + + ) +} + +export default Line diff --git a/web/app/components/plugins/marketplace/list/index.tsx b/web/app/components/plugins/marketplace/list/index.tsx index 0d03e8073d..7d1ace6297 100644 --- a/web/app/components/plugins/marketplace/list/index.tsx +++ b/web/app/components/plugins/marketplace/list/index.tsx @@ -3,6 +3,7 @@ import type { Plugin } from '../../types' import type { MarketplaceCollection } from '../types' import ListWithCollection from './list-with-collection' import CardWrapper from './card-wrapper' +import Empty from '../empty' type ListProps = { marketplaceCollections: MarketplaceCollection[] @@ -28,7 +29,7 @@ const List = ({ ) } { - plugins && ( + plugins && !!plugins.length && (
{ plugins.map(plugin => ( @@ -42,6 +43,11 @@ const List = ({
) } + { + plugins && !plugins.length && ( + + ) + } ) } diff --git a/web/app/components/plugins/marketplace/list/list-wrapper.tsx b/web/app/components/plugins/marketplace/list/list-wrapper.tsx index c8c6a30823..bcb929ca2f 100644 --- a/web/app/components/plugins/marketplace/list/list-wrapper.tsx +++ b/web/app/components/plugins/marketplace/list/list-wrapper.tsx @@ -15,18 +15,24 @@ const ListWrapper = ({ marketplaceCollectionPluginsMap, showInstallButton, }: ListWrapperProps) => { - const plugins = useMarketplaceContext(s => s.plugins) + const plugins = useMarketplaceContext(v => v.plugins) + const marketplaceCollectionsFromClient = useMarketplaceContext(v => v.marketplaceCollectionsFromClient) + const marketplaceCollectionPluginsMapFromClient = useMarketplaceContext(v => v.marketplaceCollectionPluginsMapFromClient) return (
-
-
134 results
-
- -
+ { + plugins && ( +
+
{plugins.length} results
+
+ +
+ ) + } diff --git a/web/app/components/plugins/marketplace/types.ts b/web/app/components/plugins/marketplace/types.ts index f10db5c79a..1fe8d5aa37 100644 --- a/web/app/components/plugins/marketplace/types.ts +++ b/web/app/components/plugins/marketplace/types.ts @@ -25,10 +25,14 @@ export type PluginsSearchParams = { sortBy?: string sortOrder?: string category?: string - tag?: string + tags?: string[] } export type PluginsSort = { sortBy: string sortOrder: string } + +export type CollectionsAndPluginsSearchParams = { + category?: string +} diff --git a/web/app/components/plugins/marketplace/utils.ts b/web/app/components/plugins/marketplace/utils.ts index 88ca1da0fa..df20c4517d 100644 --- a/web/app/components/plugins/marketplace/utils.ts +++ b/web/app/components/plugins/marketplace/utils.ts @@ -1,11 +1,16 @@ import type { Plugin } from '@/app/components/plugins/types' import type { + CollectionsAndPluginsSearchParams, MarketplaceCollection, PluginsSearchParams, } from '@/app/components/plugins/marketplace/types' import { MARKETPLACE_API_PREFIX } from '@/config' -export const getMarketplaceCollectionsAndPlugins = async () => { +export const getPluginIconInMarketplace = (plugin: Plugin) => { + return `${MARKETPLACE_API_PREFIX}/plugins/${plugin.org}/${plugin.name}/icon` +} + +export const getMarketplaceCollectionsAndPlugins = async (query?: CollectionsAndPluginsSearchParams) => { let marketplaceCollections = [] as MarketplaceCollection[] let marketplaceCollectionPluginsMap = {} as Record try { @@ -13,12 +18,12 @@ export const getMarketplaceCollectionsAndPlugins = async () => { const marketplaceCollectionsDataJson = await marketplaceCollectionsData.json() marketplaceCollections = marketplaceCollectionsDataJson.data.collections await Promise.all(marketplaceCollections.map(async (collection: MarketplaceCollection) => { - const marketplaceCollectionPluginsData = await globalThis.fetch(`${MARKETPLACE_API_PREFIX}/collections/${collection.name}/plugins`) + const marketplaceCollectionPluginsData = await globalThis.fetch(`${MARKETPLACE_API_PREFIX}/collections/${collection.name}/plugins?category=${query?.category}`) const marketplaceCollectionPluginsDataJson = await marketplaceCollectionPluginsData.json() const plugins = marketplaceCollectionPluginsDataJson.data.plugins.map((plugin: Plugin) => { return { ...plugin, - icon: `${MARKETPLACE_API_PREFIX}/plugins/${plugin.org}/${plugin.name}/icon`, + icon: getPluginIconInMarketplace(plugin), } }) @@ -54,7 +59,7 @@ export const getMarketplacePlugins = async (query: PluginsSearchParams) => { sort_by: query.sortBy, sort_order: query.sortOrder, category: query.category, - tag: query.tag, + tags: query.tags, }), }, ) @@ -62,7 +67,7 @@ export const getMarketplacePlugins = async (query: PluginsSearchParams) => { marketplacePlugins = marketplacePluginsDataJson.data.plugins.map((plugin: Plugin) => { return { ...plugin, - icon: `${MARKETPLACE_API_PREFIX}/plugins/${plugin.org}/${plugin.name}/icon`, + icon: getPluginIconInMarketplace(plugin), } }) }