mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-24 06:35:10 +00:00
[backport cloud/1.43] fix: avoid false missing media after shared asset import (#12363)
This commit is contained in:
@@ -222,7 +222,7 @@ describe('useSharedWorkflowUrlLoader', () => {
|
||||
expect(mockHideTemplateSelector).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('calls import when non-owned assets exist and user confirms', async () => {
|
||||
it('imports non-owned assets before loading graph when user confirms', async () => {
|
||||
mockQueryParams = { share: 'share-id-1' }
|
||||
const payload = makePayload({
|
||||
assets: [
|
||||
@@ -242,9 +242,13 @@ describe('useSharedWorkflowUrlLoader', () => {
|
||||
})
|
||||
|
||||
const { loadSharedWorkflowFromUrl } = useSharedWorkflowUrlLoader()
|
||||
await loadSharedWorkflowFromUrl()
|
||||
const loaded = await loadSharedWorkflowFromUrl()
|
||||
|
||||
expect(loaded).toBe('loaded')
|
||||
expect(mockImportPublishedAssets).toHaveBeenCalledWith(['a1'])
|
||||
expect(mockImportPublishedAssets.mock.invocationCallOrder[0]).toBeLessThan(
|
||||
mockLoadGraphData.mock.invocationCallOrder[0]
|
||||
)
|
||||
})
|
||||
|
||||
it('does not call import when user chooses open-only', async () => {
|
||||
@@ -309,6 +313,13 @@ describe('useSharedWorkflowUrlLoader', () => {
|
||||
const loaded = await loadSharedWorkflowFromUrl()
|
||||
|
||||
expect(loaded).toBe('loaded-without-assets')
|
||||
expect(mockLoadGraphData).toHaveBeenCalledWith(
|
||||
{ nodes: [] },
|
||||
true,
|
||||
true,
|
||||
'Test Workflow',
|
||||
{ openSource: 'shared_url' }
|
||||
)
|
||||
expect(mockToastAdd).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
severity: 'error',
|
||||
@@ -317,6 +328,37 @@ describe('useSharedWorkflowUrlLoader', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('clears share intent when graph load fails after importing assets', async () => {
|
||||
mockQueryParams = { share: 'share-id-1', tab: 'assets' }
|
||||
const payload = makePayload({
|
||||
assets: [
|
||||
{
|
||||
id: 'a1',
|
||||
name: 'img.png',
|
||||
preview_url: '',
|
||||
storage_url: '',
|
||||
model: false,
|
||||
public: false,
|
||||
in_library: false
|
||||
}
|
||||
]
|
||||
})
|
||||
mockShowLayoutDialog.mockImplementation(() => {
|
||||
resolveDialogWithConfirm(payload)
|
||||
})
|
||||
mockLoadGraphData.mockRejectedValue(new Error('Graph load failed'))
|
||||
|
||||
const { loadSharedWorkflowFromUrl } = useSharedWorkflowUrlLoader()
|
||||
const loaded = await loadSharedWorkflowFromUrl()
|
||||
|
||||
expect(loaded).toBe('failed')
|
||||
expect(mockImportPublishedAssets).toHaveBeenCalledWith(['a1'])
|
||||
expect(mockRouterReplace).toHaveBeenCalledWith({ query: { tab: 'assets' } })
|
||||
expect(preservedQueryMocks.clearPreservedQuery).toHaveBeenCalledWith(
|
||||
'share'
|
||||
)
|
||||
})
|
||||
|
||||
it('filters out in_library assets before importing', async () => {
|
||||
mockQueryParams = { share: 'share-id-1' }
|
||||
const payload = makePayload({
|
||||
|
||||
@@ -63,6 +63,11 @@ export function useSharedWorkflowUrlLoader() {
|
||||
void router.replace({ query: newQuery })
|
||||
}
|
||||
|
||||
function clearShareIntent() {
|
||||
cleanupUrlParams()
|
||||
clearPreservedQuery(SHARE_NAMESPACE)
|
||||
}
|
||||
|
||||
function showOpenSharedWorkflowDialog(
|
||||
shareId: string
|
||||
): Promise<DialogResult> {
|
||||
@@ -108,8 +113,7 @@ export function useSharedWorkflowUrlLoader() {
|
||||
}
|
||||
|
||||
if (typeof shareParam !== 'string') {
|
||||
cleanupUrlParams()
|
||||
clearPreservedQuery(SHARE_NAMESPACE)
|
||||
clearShareIntent()
|
||||
return 'not-present'
|
||||
}
|
||||
|
||||
@@ -122,16 +126,14 @@ export function useSharedWorkflowUrlLoader() {
|
||||
summary: t('g.error'),
|
||||
detail: t('shareWorkflow.loadFailed')
|
||||
})
|
||||
cleanupUrlParams()
|
||||
clearPreservedQuery(SHARE_NAMESPACE)
|
||||
clearShareIntent()
|
||||
return 'failed'
|
||||
}
|
||||
|
||||
const result = await showOpenSharedWorkflowDialog(shareParam)
|
||||
|
||||
if (result.action === 'cancel') {
|
||||
cleanupUrlParams()
|
||||
clearPreservedQuery(SHARE_NAMESPACE)
|
||||
clearShareIntent()
|
||||
return 'cancelled'
|
||||
}
|
||||
|
||||
@@ -140,6 +142,26 @@ export function useSharedWorkflowUrlLoader() {
|
||||
const { payload } = result
|
||||
const workflowName = payload.name || t('openSharedWorkflow.dialogTitle')
|
||||
const nonOwnedAssets = payload.assets.filter((a) => !a.in_library)
|
||||
let importFailed = false
|
||||
|
||||
if (result.action === 'copy-and-open' && nonOwnedAssets.length > 0) {
|
||||
try {
|
||||
await workflowShareService.importPublishedAssets(
|
||||
nonOwnedAssets.map((a) => a.id)
|
||||
)
|
||||
} catch (importError) {
|
||||
importFailed = true
|
||||
console.error(
|
||||
'[useSharedWorkflowUrlLoader] Failed to import assets:',
|
||||
importError
|
||||
)
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: t('g.error'),
|
||||
detail: t('openSharedWorkflow.importFailed')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await app.loadGraphData(payload.workflowJson, true, true, workflowName, {
|
||||
@@ -155,33 +177,12 @@ export function useSharedWorkflowUrlLoader() {
|
||||
summary: t('g.error'),
|
||||
detail: t('shareWorkflow.loadFailed')
|
||||
})
|
||||
clearShareIntent()
|
||||
return 'failed'
|
||||
}
|
||||
|
||||
if (result.action === 'copy-and-open' && nonOwnedAssets.length > 0) {
|
||||
try {
|
||||
await workflowShareService.importPublishedAssets(
|
||||
nonOwnedAssets.map((a) => a.id)
|
||||
)
|
||||
} catch (importError) {
|
||||
console.error(
|
||||
'[useSharedWorkflowUrlLoader] Failed to import assets:',
|
||||
importError
|
||||
)
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: t('g.error'),
|
||||
detail: t('openSharedWorkflow.importFailed')
|
||||
})
|
||||
cleanupUrlParams()
|
||||
clearPreservedQuery(SHARE_NAMESPACE)
|
||||
return 'loaded-without-assets'
|
||||
}
|
||||
}
|
||||
|
||||
cleanupUrlParams()
|
||||
clearPreservedQuery(SHARE_NAMESPACE)
|
||||
return 'loaded'
|
||||
clearShareIntent()
|
||||
return importFailed ? 'loaded-without-assets' : 'loaded'
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -14,6 +14,7 @@ vi.mock('@/scripts/app', () => ({
|
||||
|
||||
const mockGetShareableAssets = vi.fn()
|
||||
const mockFetchApi = vi.fn()
|
||||
const mockInvalidateInputAssetsIncludingPublic = vi.hoisted(() => vi.fn())
|
||||
|
||||
vi.mock(
|
||||
'@/platform/workflow/validation/schemas/workflowSchema',
|
||||
@@ -32,6 +33,13 @@ vi.mock('@/scripts/api', () => ({
|
||||
}
|
||||
}))
|
||||
|
||||
vi.mock('@/platform/assets/services/assetService', () => ({
|
||||
assetService: {
|
||||
invalidateInputAssetsIncludingPublic:
|
||||
mockInvalidateInputAssetsIncludingPublic
|
||||
}
|
||||
}))
|
||||
|
||||
describe(useWorkflowShareService, () => {
|
||||
const mockShareableAssets: AssetInfo[] = [
|
||||
{
|
||||
@@ -345,6 +353,7 @@ describe(useWorkflowShareService, () => {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ published_asset_ids: ['pa-1', 'pa-2'] })
|
||||
})
|
||||
expect(mockInvalidateInputAssetsIncludingPublic).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('throws when import request fails', async () => {
|
||||
@@ -355,6 +364,7 @@ describe(useWorkflowShareService, () => {
|
||||
await expect(service.importPublishedAssets(['bad-id'])).rejects.toThrow(
|
||||
'Failed to import assets: 400'
|
||||
)
|
||||
expect(mockInvalidateInputAssetsIncludingPublic).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('throws when shared workflow payload is invalid', async () => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
WorkflowPublishResult,
|
||||
WorkflowPublishStatus
|
||||
} from '@/platform/workflow/sharing/types/shareTypes'
|
||||
import { assetService } from '@/platform/assets/services/assetService'
|
||||
import type { ThumbnailType } from '@/platform/workflow/sharing/types/comfyHubTypes'
|
||||
import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
import { validateComfyWorkflow } from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
@@ -265,6 +266,8 @@ export function useWorkflowShareService() {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to import assets: ${response.status}`)
|
||||
}
|
||||
|
||||
assetService.invalidateInputAssetsIncludingPublic()
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user