[feat] Add centerView option to force center template workflows on load

Template workflows were not centering on view when loaded because they
contained saved view position data (extra.ds) from when they were created.
This fix adds a centerView option to loadGraphData that forces centering
regardless of saved view state.

Changes:
- Add centerView option to loadGraphData function
- Update view restoration logic to prioritize centering when centerView is true
- Pass centerView: true when loading template workflows
- Add test to verify centerView option is passed correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Christian Byrne
2025-11-01 23:28:03 -07:00
parent d808998863
commit 29ee050213
3 changed files with 32 additions and 7 deletions

View File

@@ -139,7 +139,8 @@ export function useTemplateWorkflows() {
dialogStore.closeDialog()
await app.loadGraphData(json, true, true, workflowName, {
openSource: 'template'
openSource: 'template',
centerView: true
})
return true
@@ -162,7 +163,8 @@ export function useTemplateWorkflows() {
dialogStore.closeDialog()
await app.loadGraphData(json, true, true, workflowName, {
openSource: 'template'
openSource: 'template',
centerView: true
})
return true

View File

@@ -1025,13 +1025,15 @@ export class ComfyApp {
showMissingModelsDialog?: boolean
checkForRerouteMigration?: boolean
openSource?: WorkflowOpenSource
centerView?: boolean
} = {}
) {
const {
showMissingNodesDialog = true,
showMissingModelsDialog = true,
checkForRerouteMigration = false,
openSource
openSource,
centerView = false
} = options
useWorkflowService().beforeLoadNewGraph()
@@ -1179,16 +1181,16 @@ export class ComfyApp {
restore_view &&
useSettingStore().get('Comfy.EnableWorkflowViewRestore')
) {
if (graphData.extra?.ds) {
this.canvas.ds.offset = graphData.extra.ds.offset
this.canvas.ds.scale = graphData.extra.ds.scale
} else {
if (centerView || !graphData.extra?.ds) {
// @note: Set view after the graph has been rendered once. fitView uses
// boundingRect on nodes to calculate the view bounds, which only become
// available after the first render.
requestAnimationFrame(() => {
useLitegraphService().fitView()
})
} else {
this.canvas.ds.offset = graphData.extra.ds.offset
this.canvas.ds.scale = graphData.extra.ds.scale
}
}
} catch (error) {

View File

@@ -278,6 +278,27 @@ describe('useTemplateWorkflows', () => {
expect(fetch).toHaveBeenCalledWith('mock-file-url/templates/template1.json')
})
it('should load templates with centerView option enabled', async () => {
const { app } = await import('@/scripts/app')
const { loadWorkflowTemplate } = useTemplateWorkflows()
// Set the store as loaded
mockWorkflowTemplatesStore.isLoaded = true
// Load a template from the default category
await loadWorkflowTemplate('template1', 'default')
await flushPromises()
// Verify that loadGraphData was called with centerView: true
expect(app.loadGraphData).toHaveBeenCalledWith(
{ workflow: 'data' },
true,
true,
'template1',
{ openSource: 'template', centerView: true }
)
})
it('should handle errors when loading templates', async () => {
const { loadWorkflowTemplate, loadingTemplateId } = useTemplateWorkflows()