mirror of https://github.com/langgenius/dify.git
refactor plugin installation query state
This commit is contained in:
parent
4c0fc56dd5
commit
1785dce04e
|
|
@ -86,15 +86,13 @@ const PluginPage = ({
|
|||
return
|
||||
}
|
||||
if (bundleInfo) {
|
||||
// bundleInfo is a JSON string from URL, needs parsing
|
||||
try {
|
||||
const parsedBundleInfo = typeof bundleInfo === 'string' ? JSON.parse(bundleInfo) : bundleInfo
|
||||
const { data } = await fetchBundleInfoFromMarketPlace(parsedBundleInfo)
|
||||
const { data } = await fetchBundleInfoFromMarketPlace(bundleInfo)
|
||||
setDependencies(data.version.dependencies)
|
||||
showInstallFromMarketplace()
|
||||
}
|
||||
catch (e) {
|
||||
console.error('Failed to parse bundle info:', e)
|
||||
catch (error) {
|
||||
console.error('Failed to load bundle info:', error)
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
|
|
|||
|
|
@ -474,9 +474,10 @@ describe('useQueryParams hooks', () => {
|
|||
describe('usePluginInstallation', () => {
|
||||
it('should parse package ids from JSON arrays', () => {
|
||||
// Arrange
|
||||
const bundleInfo = { org: 'org', name: 'bundle', version: '1.0.0' }
|
||||
const { result } = renderWithAdapter(
|
||||
() => usePluginInstallation(),
|
||||
'?package-ids=%5B%22org%2Fplugin%22%5D&bundle-info=bundle',
|
||||
`?package-ids=%5B%22org%2Fplugin%22%5D&bundle-info=${encodeURIComponent(JSON.stringify(bundleInfo))}`,
|
||||
)
|
||||
|
||||
// Act
|
||||
|
|
@ -484,7 +485,7 @@ describe('useQueryParams hooks', () => {
|
|||
|
||||
// Assert
|
||||
expect(state.packageId).toBe('org/plugin')
|
||||
expect(state.bundleInfo).toBe('bundle')
|
||||
expect(state.bundleInfo).toEqual(bundleInfo)
|
||||
})
|
||||
|
||||
it('should return raw package id when JSON parsing fails', () => {
|
||||
|
|
@ -532,24 +533,26 @@ describe('useQueryParams hooks', () => {
|
|||
|
||||
it('should set bundle info when provided', async () => {
|
||||
// Arrange
|
||||
const bundleInfo = { org: 'org', name: 'bundle', version: '1.0.0' }
|
||||
const { result, onUrlUpdate } = renderWithAdapter(() => usePluginInstallation())
|
||||
|
||||
// Act
|
||||
act(() => {
|
||||
result.current[1]({ bundleInfo: 'bundle' })
|
||||
result.current[1]({ bundleInfo })
|
||||
})
|
||||
|
||||
// Assert
|
||||
await waitFor(() => expect(onUrlUpdate).toHaveBeenCalled())
|
||||
const update = onUrlUpdate.mock.calls[onUrlUpdate.mock.calls.length - 1][0]
|
||||
expect(update.searchParams.get('bundle-info')).toBe('bundle')
|
||||
expect(update.searchParams.get('bundle-info')).toBe(JSON.stringify(bundleInfo))
|
||||
})
|
||||
|
||||
it('should clear installation params when state is null', async () => {
|
||||
// Arrange
|
||||
const bundleInfo = { org: 'org', name: 'bundle', version: '1.0.0' }
|
||||
const { result, onUrlUpdate } = renderWithAdapter(
|
||||
() => usePluginInstallation(),
|
||||
'?package-ids=%5B%22org%2Fplugin%22%5D&bundle-info=bundle',
|
||||
`?package-ids=%5B%22org%2Fplugin%22%5D&bundle-info=${encodeURIComponent(JSON.stringify(bundleInfo))}`,
|
||||
)
|
||||
|
||||
// Act
|
||||
|
|
@ -566,9 +569,10 @@ describe('useQueryParams hooks', () => {
|
|||
|
||||
it('should preserve bundle info when only packageId is updated', async () => {
|
||||
// Arrange
|
||||
const bundleInfo = { org: 'org', name: 'bundle', version: '1.0.0' }
|
||||
const { result, onUrlUpdate } = renderWithAdapter(
|
||||
() => usePluginInstallation(),
|
||||
'?bundle-info=bundle',
|
||||
`?bundle-info=${encodeURIComponent(JSON.stringify(bundleInfo))}`,
|
||||
)
|
||||
|
||||
// Act
|
||||
|
|
@ -579,7 +583,7 @@ describe('useQueryParams hooks', () => {
|
|||
// Assert
|
||||
await waitFor(() => expect(onUrlUpdate).toHaveBeenCalled())
|
||||
const update = onUrlUpdate.mock.calls[onUrlUpdate.mock.calls.length - 1][0]
|
||||
expect(update.searchParams.get('bundle-info')).toBe('bundle')
|
||||
expect(update.searchParams.get('bundle-info')).toBe(JSON.stringify(bundleInfo))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -141,6 +141,47 @@ export function useMarketplaceFilters() {
|
|||
*/
|
||||
const PACKAGE_IDS_PARAM = 'package-ids'
|
||||
const BUNDLE_INFO_PARAM = 'bundle-info'
|
||||
type BundleInfoQuery = {
|
||||
org: string
|
||||
name: string
|
||||
version: string
|
||||
}
|
||||
|
||||
const parseAsPackageId = createParser<string>({
|
||||
parse: (value) => {
|
||||
try {
|
||||
const parsed = JSON.parse(value)
|
||||
if (Array.isArray(parsed)) {
|
||||
const first = parsed[0]
|
||||
return typeof first === 'string' ? first : null
|
||||
}
|
||||
return value
|
||||
}
|
||||
catch {
|
||||
return value
|
||||
}
|
||||
},
|
||||
serialize: value => JSON.stringify([value]),
|
||||
})
|
||||
|
||||
const parseAsBundleInfo = createParser<BundleInfoQuery>({
|
||||
parse: (value) => {
|
||||
try {
|
||||
const parsed = JSON.parse(value) as Partial<BundleInfoQuery>
|
||||
if (parsed
|
||||
&& typeof parsed.org === 'string'
|
||||
&& typeof parsed.name === 'string'
|
||||
&& typeof parsed.version === 'string') {
|
||||
return { org: parsed.org, name: parsed.name, version: parsed.version }
|
||||
}
|
||||
}
|
||||
catch {
|
||||
return null
|
||||
}
|
||||
return null
|
||||
},
|
||||
serialize: value => JSON.stringify(value),
|
||||
})
|
||||
|
||||
/**
|
||||
* Hook to manage plugin installation state via URL
|
||||
|
|
@ -149,53 +190,45 @@ const BUNDLE_INFO_PARAM = 'bundle-info'
|
|||
* @example
|
||||
* const [installState, setInstallState] = usePluginInstallation()
|
||||
* setInstallState({ packageId: 'org/plugin' }) // Sets ?package-ids=["org/plugin"]
|
||||
* setInstallState({ bundleInfo: { org: 'org', name: 'bundle', version: '1.0.0' } }) // Sets ?bundle-info=...
|
||||
* setInstallState(null) // Clears installation params
|
||||
*/
|
||||
export function usePluginInstallation() {
|
||||
const [packageIds, setPackageIds] = useQueryState(
|
||||
PACKAGE_IDS_PARAM,
|
||||
parseAsString,
|
||||
)
|
||||
const [bundleInfo, setBundleInfo] = useQueryState(
|
||||
BUNDLE_INFO_PARAM,
|
||||
parseAsString,
|
||||
const [installState, setInstallStateState] = useQueryStates(
|
||||
{
|
||||
packageId: parseAsPackageId,
|
||||
bundleInfo: parseAsBundleInfo,
|
||||
},
|
||||
{
|
||||
urlKeys: {
|
||||
packageId: PACKAGE_IDS_PARAM,
|
||||
bundleInfo: BUNDLE_INFO_PARAM,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
const setInstallState = useCallback(
|
||||
(state: { packageId?: string, bundleInfo?: string } | null) => {
|
||||
(state: { packageId?: string, bundleInfo?: BundleInfoQuery } | null) => {
|
||||
if (!state) {
|
||||
setPackageIds(null)
|
||||
setBundleInfo(null)
|
||||
setInstallStateState(null)
|
||||
return
|
||||
}
|
||||
if (state.packageId) {
|
||||
// Store as JSON array for consistency with existing code
|
||||
setPackageIds(JSON.stringify([state.packageId]))
|
||||
}
|
||||
if (state.bundleInfo) {
|
||||
setBundleInfo(state.bundleInfo)
|
||||
}
|
||||
const patch: { packageId?: string, bundleInfo?: BundleInfoQuery } = {}
|
||||
if (state.packageId)
|
||||
patch.packageId = state.packageId
|
||||
if (state.bundleInfo)
|
||||
patch.bundleInfo = state.bundleInfo
|
||||
if (Object.keys(patch).length === 0)
|
||||
return
|
||||
setInstallStateState(patch)
|
||||
},
|
||||
[setBundleInfo, setPackageIds],
|
||||
[setInstallStateState],
|
||||
)
|
||||
|
||||
// Parse packageIds from JSON array
|
||||
const currentPackageId = packageIds
|
||||
? (() => {
|
||||
try {
|
||||
const parsed = JSON.parse(packageIds)
|
||||
return Array.isArray(parsed) ? parsed[0] : packageIds
|
||||
}
|
||||
catch {
|
||||
return packageIds
|
||||
}
|
||||
})()
|
||||
: null
|
||||
|
||||
return [
|
||||
{
|
||||
packageId: currentPackageId,
|
||||
bundleInfo,
|
||||
packageId: installState.packageId,
|
||||
bundleInfo: installState.bundleInfo,
|
||||
},
|
||||
setInstallState,
|
||||
] as const
|
||||
|
|
|
|||
Loading…
Reference in New Issue