mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
feat: open template via URL in linear mode (#6945)
## Summary Adds `mode` as a valid url query param when opening template from URL. https://github.com/user-attachments/assets/8e7efb1c-d842-4953-822a-f3cea7ddecb6 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6945-feat-open-template-via-URL-in-linear-mode-2b76d73d365081d8ad4af3d49a68a4ff) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -8,8 +8,9 @@ import { useTemplateUrlLoader } from '@/platform/workflow/templates/composables/
|
||||
* Tests the behavior of loading templates via URL query parameters:
|
||||
* - ?template=flux_simple loads the template
|
||||
* - ?template=flux_simple&source=custom loads from custom source
|
||||
* - ?template=flux_simple&mode=linear loads template in linear mode
|
||||
* - Invalid template shows error toast
|
||||
* - Input validation for template and source parameters
|
||||
* - Input validation for template, source, and mode parameters
|
||||
*/
|
||||
|
||||
const preservedQueryMocks = vi.hoisted(() => ({
|
||||
@@ -70,10 +71,20 @@ vi.mock('vue-i18n', () => ({
|
||||
})
|
||||
}))
|
||||
|
||||
// Mock canvas store
|
||||
const mockCanvasStore = {
|
||||
linearMode: false
|
||||
}
|
||||
|
||||
vi.mock('@/renderer/core/canvas/canvasStore', () => ({
|
||||
useCanvasStore: () => mockCanvasStore
|
||||
}))
|
||||
|
||||
describe('useTemplateUrlLoader', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockQueryParams = {}
|
||||
mockCanvasStore.linearMode = false
|
||||
})
|
||||
|
||||
it('does not load template when no query param present', () => {
|
||||
@@ -236,6 +247,7 @@ describe('useTemplateUrlLoader', () => {
|
||||
mockQueryParams = {
|
||||
template: 'flux_simple',
|
||||
source: 'custom',
|
||||
mode: 'linear',
|
||||
other: 'param'
|
||||
}
|
||||
|
||||
@@ -270,4 +282,121 @@ describe('useTemplateUrlLoader', () => {
|
||||
query: { other: 'param' }
|
||||
})
|
||||
})
|
||||
|
||||
it('sets linear mode when mode=linear and template loads successfully', async () => {
|
||||
mockQueryParams = { template: 'flux_simple', mode: 'linear' }
|
||||
|
||||
const { loadTemplateFromUrl } = useTemplateUrlLoader()
|
||||
await loadTemplateFromUrl()
|
||||
|
||||
expect(mockLoadWorkflowTemplate).toHaveBeenCalledWith(
|
||||
'flux_simple',
|
||||
'default'
|
||||
)
|
||||
expect(mockCanvasStore.linearMode).toBe(true)
|
||||
})
|
||||
|
||||
it('does not set linear mode when template loading fails', async () => {
|
||||
mockQueryParams = { template: 'invalid-template', mode: 'linear' }
|
||||
mockLoadWorkflowTemplate.mockResolvedValueOnce(false)
|
||||
|
||||
const { loadTemplateFromUrl } = useTemplateUrlLoader()
|
||||
await loadTemplateFromUrl()
|
||||
|
||||
expect(mockCanvasStore.linearMode).toBe(false)
|
||||
})
|
||||
|
||||
it('does not set linear mode when mode parameter is not linear', async () => {
|
||||
mockQueryParams = { template: 'flux_simple', mode: 'graph' }
|
||||
|
||||
const { loadTemplateFromUrl } = useTemplateUrlLoader()
|
||||
await loadTemplateFromUrl()
|
||||
|
||||
expect(mockLoadWorkflowTemplate).toHaveBeenCalledWith(
|
||||
'flux_simple',
|
||||
'default'
|
||||
)
|
||||
expect(mockCanvasStore.linearMode).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects invalid mode parameter with special characters', () => {
|
||||
mockQueryParams = { template: 'flux_simple', mode: '../malicious' }
|
||||
|
||||
const { loadTemplateFromUrl } = useTemplateUrlLoader()
|
||||
void loadTemplateFromUrl()
|
||||
|
||||
expect(mockLoadTemplates).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('handles array mode params correctly', () => {
|
||||
// Vue Router can return string[] for duplicate params
|
||||
mockQueryParams = {
|
||||
template: 'flux_simple',
|
||||
mode: ['linear', 'graph'] as any
|
||||
}
|
||||
|
||||
const { loadTemplateFromUrl } = useTemplateUrlLoader()
|
||||
void loadTemplateFromUrl()
|
||||
|
||||
// Should not load when mode param is an array
|
||||
expect(mockLoadTemplates).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('warns about unsupported mode values but continues loading', async () => {
|
||||
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
mockQueryParams = { template: 'flux_simple', mode: 'unsupported' }
|
||||
|
||||
const { loadTemplateFromUrl } = useTemplateUrlLoader()
|
||||
await loadTemplateFromUrl()
|
||||
|
||||
expect(consoleSpy).toHaveBeenCalledWith(
|
||||
'[useTemplateUrlLoader] Unsupported mode parameter: unsupported. Supported modes: linear'
|
||||
)
|
||||
expect(mockLoadWorkflowTemplate).toHaveBeenCalledWith(
|
||||
'flux_simple',
|
||||
'default'
|
||||
)
|
||||
expect(mockCanvasStore.linearMode).toBe(false)
|
||||
|
||||
consoleSpy.mockRestore()
|
||||
})
|
||||
|
||||
it('accepts supported mode parameter: linear', async () => {
|
||||
mockQueryParams = { template: 'flux_simple', mode: 'linear' }
|
||||
|
||||
const { loadTemplateFromUrl } = useTemplateUrlLoader()
|
||||
await loadTemplateFromUrl()
|
||||
|
||||
expect(mockLoadWorkflowTemplate).toHaveBeenCalledWith(
|
||||
'flux_simple',
|
||||
'default'
|
||||
)
|
||||
expect(mockCanvasStore.linearMode).toBe(true)
|
||||
})
|
||||
|
||||
it('accepts valid format but warns about unsupported modes', async () => {
|
||||
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
const unsupportedModes = ['graph', 'mode123', 'my_mode-2']
|
||||
|
||||
for (const mode of unsupportedModes) {
|
||||
vi.clearAllMocks()
|
||||
consoleSpy.mockClear()
|
||||
mockCanvasStore.linearMode = false
|
||||
mockQueryParams = { template: 'flux_simple', mode }
|
||||
|
||||
const { loadTemplateFromUrl } = useTemplateUrlLoader()
|
||||
await loadTemplateFromUrl()
|
||||
|
||||
expect(consoleSpy).toHaveBeenCalledWith(
|
||||
`[useTemplateUrlLoader] Unsupported mode parameter: ${mode}. Supported modes: linear`
|
||||
)
|
||||
expect(mockLoadWorkflowTemplate).toHaveBeenCalledWith(
|
||||
'flux_simple',
|
||||
'default'
|
||||
)
|
||||
expect(mockCanvasStore.linearMode).toBe(false)
|
||||
}
|
||||
|
||||
consoleSpy.mockRestore()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user