mirror of
https://github.com/langgenius/dify.git
synced 2026-09-08 11:04:27 +08:00
feat: add utility functions for building search parameters and marketplace URLs
This commit is contained in:
parent
7934b0222d
commit
61b6b838de
@ -13,7 +13,7 @@ import { cn } from '@/utils/classnames'
|
|||||||
import { getIconFromMarketPlace } from '@/utils/get-icon'
|
import { getIconFromMarketPlace } from '@/utils/get-icon'
|
||||||
import { formatUsedCount } from '@/utils/template'
|
import { formatUsedCount } from '@/utils/template'
|
||||||
import { getMarketplaceUrl } from '@/utils/var'
|
import { getMarketplaceUrl } from '@/utils/var'
|
||||||
import { getTemplateIconUrl } from '../utils'
|
import { buildSearchParamsString, getTemplateIconUrl } from '../utils'
|
||||||
|
|
||||||
type TemplateCardProps = {
|
type TemplateCardProps = {
|
||||||
template: Template
|
template: Template
|
||||||
@ -45,7 +45,7 @@ const TemplateCardComponent = ({
|
|||||||
}
|
}
|
||||||
return includeSource
|
return includeSource
|
||||||
? getMarketplaceUrl(`/template/${publisher_handle}/${template_name}`, queryParams)
|
? getMarketplaceUrl(`/template/${publisher_handle}/${template_name}`, queryParams)
|
||||||
: `${MARKETPLACE_URL_PREFIX}/template/${publisher_handle}/${template_name}?${new URLSearchParams(queryParams).toString()}`
|
: `${MARKETPLACE_URL_PREFIX}/template/${publisher_handle}/${template_name}?${buildSearchParamsString(queryParams)}`
|
||||||
}, [publisher_handle, template_name, theme, locale, id, includeSource])
|
}, [publisher_handle, template_name, theme, locale, id, includeSource])
|
||||||
|
|
||||||
const visibleDepsPlugins = deps_plugins?.slice(0, MAX_VISIBLE_DEPS_PLUGINS) || []
|
const visibleDepsPlugins = deps_plugins?.slice(0, MAX_VISIBLE_DEPS_PLUGINS) || []
|
||||||
|
|||||||
@ -9,9 +9,8 @@ import { useCategories } from '@/app/components/plugins/hooks'
|
|||||||
import { useRenderI18nObject } from '@/hooks/use-i18n'
|
import { useRenderI18nObject } from '@/hooks/use-i18n'
|
||||||
import { cn } from '@/utils/classnames'
|
import { cn } from '@/utils/classnames'
|
||||||
import { formatUsedCount } from '@/utils/template'
|
import { formatUsedCount } from '@/utils/template'
|
||||||
import { getMarketplaceUrl } from '@/utils/var'
|
|
||||||
import { MARKETPLACE_TYPE_ICON_COMPONENTS } from '../../plugin-type-icons'
|
import { MARKETPLACE_TYPE_ICON_COMPONENTS } from '../../plugin-type-icons'
|
||||||
import { getCreatorAvatarUrl, getPluginDetailLinkInMarketplace, getTemplateIconUrl } from '../../utils'
|
import { buildMarketplaceHref, getCreatorAvatarUrl, getPluginDetailLinkInMarketplace, getTemplateIconUrl } from '../../utils'
|
||||||
|
|
||||||
const DROPDOWN_PANEL = 'w-[472px] max-h-[710px] overflow-y-auto rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-xl backdrop-blur-sm'
|
const DROPDOWN_PANEL = 'w-[472px] max-h-[710px] overflow-y-auto rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-xl backdrop-blur-sm'
|
||||||
const ICON_BOX_BASE = 'flex shrink-0 items-center justify-center overflow-hidden border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge'
|
const ICON_BOX_BASE = 'flex shrink-0 items-center justify-center overflow-hidden border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge'
|
||||||
@ -79,29 +78,6 @@ const ItemMeta = ({ items }: { items: (React.ReactNode | string)[] }) => (
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const getSearchParamsString = (params?: Record<string, string | undefined>) => {
|
|
||||||
const searchParams = new URLSearchParams()
|
|
||||||
if (params) {
|
|
||||||
Object.keys(params).forEach((key) => {
|
|
||||||
const value = params[key]
|
|
||||||
if (value !== undefined && value !== null)
|
|
||||||
searchParams.append(key, value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return searchParams.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
const getDropdownMarketplaceUrl = (
|
|
||||||
path: string,
|
|
||||||
params: Record<string, string | undefined> | undefined,
|
|
||||||
includeSource: boolean,
|
|
||||||
) => {
|
|
||||||
if (includeSource)
|
|
||||||
return getMarketplaceUrl(path, params)
|
|
||||||
const query = getSearchParamsString(params)
|
|
||||||
return query ? `${path}?${query}` : path
|
|
||||||
}
|
|
||||||
|
|
||||||
type SearchDropdownProps = {
|
type SearchDropdownProps = {
|
||||||
query: string
|
query: string
|
||||||
plugins: Plugin[]
|
plugins: Plugin[]
|
||||||
@ -226,7 +202,7 @@ function TemplatesSection({ templates, includeSource, t }: {
|
|||||||
return (
|
return (
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
key={template.id}
|
key={template.id}
|
||||||
href={getDropdownMarketplaceUrl(
|
href={buildMarketplaceHref(
|
||||||
`/template/${template.publisher_handle}/${template.template_name}`,
|
`/template/${template.publisher_handle}/${template.template_name}`,
|
||||||
{ templateId: template.id },
|
{ templateId: template.id },
|
||||||
includeSource,
|
includeSource,
|
||||||
@ -326,7 +302,7 @@ function CreatorsSection({ creators, includeSource, t }: {
|
|||||||
<a
|
<a
|
||||||
key={creator.unique_handle}
|
key={creator.unique_handle}
|
||||||
className="flex items-center gap-2 rounded-lg px-3 py-2 hover:bg-state-base-hover"
|
className="flex items-center gap-2 rounded-lg px-3 py-2 hover:bg-state-base-hover"
|
||||||
href={getDropdownMarketplaceUrl(`/creators/${creator.unique_handle}`, undefined, includeSource)}
|
href={buildMarketplaceHref(`/creators/${creator.unique_handle}`, undefined, includeSource)}
|
||||||
>
|
>
|
||||||
<div className="flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-full border-[0.5px] border-divider-regular">
|
<div className="flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-full border-[0.5px] border-divider-regular">
|
||||||
<img
|
<img
|
||||||
|
|||||||
41
web/app/components/plugins/marketplace/utils.spec.ts
Normal file
41
web/app/components/plugins/marketplace/utils.spec.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { buildMarketplaceHref, buildSearchParamsString } from './utils'
|
||||||
|
|
||||||
|
describe('buildSearchParamsString', () => {
|
||||||
|
it('filters undefined and null values', () => {
|
||||||
|
const query = buildSearchParamsString({
|
||||||
|
theme: undefined,
|
||||||
|
language: 'en-US',
|
||||||
|
templateId: 'tpl-1',
|
||||||
|
empty: null as unknown as string,
|
||||||
|
})
|
||||||
|
expect(query).toBe('language=en-US&templateId=tpl-1')
|
||||||
|
expect(query).not.toContain('theme=undefined')
|
||||||
|
expect(query).not.toContain('empty=')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('buildMarketplaceHref', () => {
|
||||||
|
it('returns relative path with filtered query when includeSource is false', () => {
|
||||||
|
const href = buildMarketplaceHref('/template/foo/bar', {
|
||||||
|
theme: undefined,
|
||||||
|
language: 'en-US',
|
||||||
|
templateId: 'tpl-1',
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
expect(href).toBe('/template/foo/bar?language=en-US&templateId=tpl-1')
|
||||||
|
expect(href).not.toContain('theme=undefined')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delegates to marketplace source URL when includeSource is true', () => {
|
||||||
|
const href = buildMarketplaceHref('/template/foo/bar', {
|
||||||
|
language: 'en-US',
|
||||||
|
templateId: 'tpl-1',
|
||||||
|
}, true)
|
||||||
|
|
||||||
|
expect(href).toContain('/template/foo/bar?')
|
||||||
|
expect(href).toContain('source=')
|
||||||
|
expect(href).toContain('language=en-US')
|
||||||
|
expect(href).toContain('templateId=tpl-1')
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -102,6 +102,28 @@ export const getPluginDetailLinkInMarketplace = (plugin: Plugin) => {
|
|||||||
return `/plugin/${plugin.org}/${plugin.name}`
|
return `/plugin/${plugin.org}/${plugin.name}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const buildSearchParamsString = (params?: Record<string, string | undefined>) => {
|
||||||
|
const searchParams = new URLSearchParams()
|
||||||
|
if (params) {
|
||||||
|
for (const [key, value] of Object.entries(params)) {
|
||||||
|
if (value !== undefined && value !== null)
|
||||||
|
searchParams.append(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return searchParams.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const buildMarketplaceHref = (
|
||||||
|
path: string,
|
||||||
|
params: Record<string, string | undefined> | undefined,
|
||||||
|
includeSource: boolean,
|
||||||
|
) => {
|
||||||
|
if (includeSource)
|
||||||
|
return getMarketplaceUrl(path, params)
|
||||||
|
const query = buildSearchParamsString(params)
|
||||||
|
return query ? `${path}?${query}` : path
|
||||||
|
}
|
||||||
|
|
||||||
export const getMarketplacePluginsByCollectionId = async (
|
export const getMarketplacePluginsByCollectionId = async (
|
||||||
collectionId: string,
|
collectionId: string,
|
||||||
query?: CollectionsAndPluginsSearchParams,
|
query?: CollectionsAndPluginsSearchParams,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user