mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-21 21:09:00 +00:00
fix: prevent first user template popup when following shared link (#12024)
## Summary When a user who has not used the app before first loads up, they are presented with the template selection dialog. This conflicts when the first-time user visits the app via a share link - both the share & template dialog are triggered. ## Changes - **What**: - Skip the templates browser when share param is in URL - Tests - Add `url` to `setup`/`goto` to allow specifying the `share` parameter ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12024-fix-prevent-first-user-template-popup-when-following-shared-link-3586d73d365081cbbcecdba45a1ad1ea) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -285,10 +285,12 @@ export class ComfyPage {
|
||||
|
||||
async setup({
|
||||
clearStorage = true,
|
||||
mockReleases = true
|
||||
mockReleases = true,
|
||||
url
|
||||
}: {
|
||||
clearStorage?: boolean
|
||||
mockReleases?: boolean
|
||||
url?: string
|
||||
} = {}) {
|
||||
// Mock release endpoint to prevent changelog popups (before navigation)
|
||||
if (mockReleases) {
|
||||
@@ -320,7 +322,7 @@ export class ComfyPage {
|
||||
}, this.id)
|
||||
}
|
||||
|
||||
await this.goto()
|
||||
await this.goto({ url })
|
||||
|
||||
await this.page.waitForFunction(() => document.fonts.ready)
|
||||
await this.waitForAppReady()
|
||||
@@ -347,8 +349,8 @@ export class ComfyPage {
|
||||
return assetPath(fileName)
|
||||
}
|
||||
|
||||
async goto() {
|
||||
await this.page.goto(this.url)
|
||||
async goto({ url }: { url?: string } = {}) {
|
||||
await this.page.goto(url ? new URL(url, this.url).toString() : this.url)
|
||||
}
|
||||
|
||||
async nextFrame() {
|
||||
|
||||
@@ -106,6 +106,49 @@ test.describe('Templates', { tag: ['@slow', '@workflow'] }, () => {
|
||||
await expect(comfyPage.templates.content).toBeVisible()
|
||||
})
|
||||
|
||||
test('dialog should not be shown when first-time user opens a shared workflow link', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
await comfyPage.page.route(
|
||||
'**/workflows/published/test-share-id',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
share_id: 'test-share-id',
|
||||
workflow_id: 'wf-1',
|
||||
name: 'Shared Workflow',
|
||||
listed: true,
|
||||
publish_time: new Date().toISOString(),
|
||||
workflow_json: {
|
||||
version: 0.4,
|
||||
nodes: [],
|
||||
links: [],
|
||||
groups: [],
|
||||
config: {},
|
||||
extra: {}
|
||||
},
|
||||
assets: []
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
await comfyPage.settings.setSetting('Comfy.TutorialCompleted', false)
|
||||
|
||||
await comfyPage.setup({
|
||||
clearStorage: true,
|
||||
url: '/?share=test-share-id'
|
||||
})
|
||||
|
||||
await expect(
|
||||
comfyPage.page.getByRole('heading', { name: 'Open shared workflow' })
|
||||
).toBeVisible()
|
||||
|
||||
await expect(comfyPage.templates.content).toBeHidden()
|
||||
})
|
||||
|
||||
test('Uses proper locale files for templates', async ({ comfyPage }) => {
|
||||
await comfyPage.settings.setSetting('Comfy.Locale', 'fr')
|
||||
|
||||
|
||||
@@ -76,15 +76,25 @@ vi.mock(
|
||||
})
|
||||
)
|
||||
|
||||
const commandStoreMocks = vi.hoisted(() => ({
|
||||
execute: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/stores/commandStore', () => ({
|
||||
useCommandStore: () => ({
|
||||
execute: vi.fn()
|
||||
execute: commandStoreMocks.execute
|
||||
})
|
||||
}))
|
||||
|
||||
const routeMocks = vi.hoisted(() => ({
|
||||
query: {} as Record<string, unknown>
|
||||
}))
|
||||
|
||||
vi.mock('vue-router', () => ({
|
||||
useRoute: () => ({
|
||||
query: {}
|
||||
get query() {
|
||||
return routeMocks.query
|
||||
}
|
||||
}),
|
||||
useRouter: () => ({
|
||||
replace: vi.fn()
|
||||
@@ -97,13 +107,30 @@ vi.mock('@/composables/auth/useCurrentUser', () => ({
|
||||
})
|
||||
}))
|
||||
|
||||
const preservedQueryMocks = vi.hoisted(() => ({
|
||||
payloads: {} as Record<string, Record<string, string> | undefined>
|
||||
}))
|
||||
|
||||
vi.mock('@/platform/navigation/preservedQueryManager', () => ({
|
||||
hydratePreservedQuery: vi.fn(),
|
||||
mergePreservedQueryIntoQuery: vi.fn(() => null)
|
||||
mergePreservedQueryIntoQuery: vi.fn(
|
||||
(namespace: string, query: Record<string, unknown> = {}) => {
|
||||
const payload = preservedQueryMocks.payloads[namespace]
|
||||
if (!payload) return undefined
|
||||
const next: Record<string, unknown> = { ...query }
|
||||
let changed = false
|
||||
for (const [key, value] of Object.entries(payload)) {
|
||||
if (typeof next[key] === 'string') continue
|
||||
next[key] = value
|
||||
changed = true
|
||||
}
|
||||
return changed ? next : undefined
|
||||
}
|
||||
)
|
||||
}))
|
||||
|
||||
vi.mock('@/platform/navigation/preservedQueryNamespaces', () => ({
|
||||
PRESERVED_QUERY_NAMESPACES: { TEMPLATE: 'template' }
|
||||
PRESERVED_QUERY_NAMESPACES: { TEMPLATE: 'template', SHARE: 'share' }
|
||||
}))
|
||||
|
||||
vi.mock('@/platform/distribution/types', () => ({
|
||||
@@ -178,6 +205,9 @@ describe('useWorkflowPersistenceV2', () => {
|
||||
mocks.apiMock.removeEventListener.mockImplementation(() => {})
|
||||
openWorkflowMock.mockReset()
|
||||
loadBlankWorkflowMock.mockReset()
|
||||
commandStoreMocks.execute.mockReset()
|
||||
routeMocks.query = {}
|
||||
preservedQueryMocks.payloads = {}
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -357,4 +387,43 @@ describe('useWorkflowPersistenceV2', () => {
|
||||
expect(openWorkflowMock).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('loadDefaultWorkflow', () => {
|
||||
it('opens templates browser for first-time users', async () => {
|
||||
const { initializeWorkflow } = useWorkflowPersistenceV2()
|
||||
await initializeWorkflow()
|
||||
|
||||
expect(loadBlankWorkflowMock).toHaveBeenCalled()
|
||||
expect(commandStoreMocks.execute).toHaveBeenCalledWith(
|
||||
'Comfy.BrowseTemplates'
|
||||
)
|
||||
})
|
||||
|
||||
it('does not open templates browser when share param is in URL', async () => {
|
||||
routeMocks.query = { share: 'test-share-id' }
|
||||
|
||||
const { initializeWorkflow } = useWorkflowPersistenceV2()
|
||||
await initializeWorkflow()
|
||||
|
||||
expect(loadBlankWorkflowMock).toHaveBeenCalled()
|
||||
expect(commandStoreMocks.execute).not.toHaveBeenCalledWith(
|
||||
'Comfy.BrowseTemplates'
|
||||
)
|
||||
})
|
||||
|
||||
it('does not open templates browser when share intent is preserved across /user-select redirect', async () => {
|
||||
// No-local-user flow: ?share=... was captured into sessionStorage and the
|
||||
// URL query was dropped during the /user-select redirect before
|
||||
// initializeWorkflow() runs.
|
||||
preservedQueryMocks.payloads.share = { share: 'test-share-id' }
|
||||
|
||||
const { initializeWorkflow } = useWorkflowPersistenceV2()
|
||||
await initializeWorkflow()
|
||||
|
||||
expect(loadBlankWorkflowMock).toHaveBeenCalled()
|
||||
expect(commandStoreMocks.execute).not.toHaveBeenCalledWith(
|
||||
'Comfy.BrowseTemplates'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -48,6 +48,7 @@ export function useWorkflowPersistenceV2() {
|
||||
const sharedWorkflowUrlLoader = useSharedWorkflowUrlLoader()
|
||||
const templateUrlLoader = useTemplateUrlLoader()
|
||||
const TEMPLATE_NAMESPACE = PRESERVED_QUERY_NAMESPACES.TEMPLATE
|
||||
const SHARE_NAMESPACE = PRESERVED_QUERY_NAMESPACES.SHARE
|
||||
const draftStore = useWorkflowDraftStoreV2()
|
||||
const tabState = useWorkflowTabState()
|
||||
const toast = useToast()
|
||||
@@ -160,11 +161,20 @@ export function useWorkflowPersistenceV2() {
|
||||
})
|
||||
}
|
||||
|
||||
const hasSharedWorkflowIntent = () => {
|
||||
if (typeof route.query.share === 'string') return true
|
||||
hydratePreservedQuery(SHARE_NAMESPACE)
|
||||
const merged = mergePreservedQueryIntoQuery(SHARE_NAMESPACE, route.query)
|
||||
return typeof merged?.share === 'string'
|
||||
}
|
||||
|
||||
const loadDefaultWorkflow = async () => {
|
||||
if (!settingStore.get('Comfy.TutorialCompleted')) {
|
||||
await settingStore.set('Comfy.TutorialCompleted', true)
|
||||
await useWorkflowService().loadBlankWorkflow()
|
||||
await useCommandStore().execute('Comfy.BrowseTemplates')
|
||||
if (!hasSharedWorkflowIntent()) {
|
||||
await useCommandStore().execute('Comfy.BrowseTemplates')
|
||||
}
|
||||
} else {
|
||||
await comfyApp.loadGraphData()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user