[feat] Allow opening workflows with same name as new tabs (#7104)

When importing a workflow file that has the same name as an existing
open workflow, create a new tab with a unique suffix (2), (3), etc.
instead of silently failing or replacing the existing workflow.

- Add forceNew parameter to createTemporary() in workflowStore
- Always create new temporary workflow when importing via file picker
- Remove logic that looked up persisted workflows by name during import




https://github.com/user-attachments/assets/9c9aebd3-37c2-464f-9fb4-9ef871ec2673





┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7104-feat-Allow-opening-workflows-with-same-name-as-new-tabs-2bd6d73d365081cd9182eaa35bf37c29)
by [Unito](https://www.unito.io)
This commit is contained in:
Johnpaul Chiwetelu
2025-12-03 03:47:26 +01:00
committed by GitHub
parent d50a2fabc0
commit c6988380c2
2 changed files with 73 additions and 32 deletions

View File

@@ -310,23 +310,29 @@ export const useWorkflowService = () => {
value: string | ComfyWorkflow | null,
workflowData: ComfyWorkflowJSON
) => {
// Use workspaceStore here as it is patched in unit tests.
const workflowStore = useWorkspaceStore().workflow
if (typeof value === 'string') {
const workflow = workflowStore.getWorkflowByPath(
ComfyWorkflow.basePath + appendJsonExt(value)
)
if (workflow?.isPersisted) {
const loadedWorkflow = await workflowStore.openWorkflow(workflow)
loadedWorkflow.changeTracker.restore()
loadedWorkflow.changeTracker.reset(workflowData)
return
}
}
if (value === null || typeof value === 'string') {
const path = value as string | null
const tempWorkflow = workflowStore.createTemporary(
// Check if a persisted workflow with this path exists
if (path) {
const fullPath = ComfyWorkflow.basePath + appendJsonExt(path)
const existingWorkflow = workflowStore.getWorkflowByPath(fullPath)
// If the workflow exists and is NOT loaded yet (restoration case),
// use the existing workflow instead of creating a new one.
// If it IS loaded, this is a re-import case - create new with suffix.
if (existingWorkflow?.isPersisted && !existingWorkflow.isLoaded) {
const loadedWorkflow =
await workflowStore.openWorkflow(existingWorkflow)
loadedWorkflow.changeTracker.reset(workflowData)
loadedWorkflow.changeTracker.restore()
return
}
}
const tempWorkflow = workflowStore.createNewTemporary(
path ? appendJsonExt(path) : undefined,
workflowData
)
@@ -334,7 +340,6 @@ export const useWorkflowService = () => {
return
}
// value is a ComfyWorkflow.
const loadedWorkflow = await workflowStore.openWorkflow(value)
loadedWorkflow.changeTracker.reset(workflowData)
loadedWorkflow.changeTracker.restore()

View File

@@ -172,6 +172,10 @@ interface WorkflowStore {
path?: string,
workflowData?: ComfyWorkflowJSON
) => ComfyWorkflow
createNewTemporary: (
path?: string,
workflowData?: ComfyWorkflowJSON
) => ComfyWorkflow
renameWorkflow: (workflow: ComfyWorkflow, newPath: string) => Promise<void>
deleteWorkflow: (workflow: ComfyWorkflow) => Promise<void>
saveWorkflow: (workflow: ComfyWorkflow) => Promise<void>
@@ -365,25 +369,15 @@ export const useWorkflowStore = defineStore('workflow', () => {
return workflow
}
const createTemporary = (path?: string, workflowData?: ComfyWorkflowJSON) => {
const fullPath = getUnconflictedPath(
ComfyWorkflow.basePath + (path ?? 'Unsaved Workflow.json')
)
const existingWorkflow = workflows.value.find((w) => w.fullFilename == path)
if (
path &&
workflowData &&
existingWorkflow?.changeTracker &&
!existingWorkflow.directory.startsWith(
ComfyWorkflow.basePath.slice(0, -1)
)
) {
existingWorkflow.changeTracker.reset(workflowData)
return existingWorkflow
}
/**
* Helper to create a new temporary workflow
*/
const createNewWorkflow = (
path: string,
workflowData?: ComfyWorkflowJSON
): ComfyWorkflow => {
const workflow = new ComfyWorkflow({
path: fullPath,
path,
modified: Date.now(),
size: -1
})
@@ -396,6 +390,47 @@ export const useWorkflowStore = defineStore('workflow', () => {
return workflow
}
/**
* Create a temporary workflow, attempting to reuse an existing workflow if conditions match
*/
const createTemporary = (path?: string, workflowData?: ComfyWorkflowJSON) => {
const fullPath = getUnconflictedPath(
ComfyWorkflow.basePath + (path ?? 'Unsaved Workflow.json')
)
// Try to reuse an existing loaded workflow with the same filename
// that is not stored in the workflows directory
if (path && workflowData) {
const existingWorkflow = workflows.value.find(
(w) => w.fullFilename === path
)
if (
existingWorkflow?.changeTracker &&
!existingWorkflow.directory.startsWith(
ComfyWorkflow.basePath.slice(0, -1)
)
) {
existingWorkflow.changeTracker.reset(workflowData)
return existingWorkflow
}
}
return createNewWorkflow(fullPath, workflowData)
}
/**
* Create a new temporary workflow without attempting to reuse existing workflows
*/
const createNewTemporary = (
path?: string,
workflowData?: ComfyWorkflowJSON
): ComfyWorkflow => {
const fullPath = getUnconflictedPath(
ComfyWorkflow.basePath + (path ?? 'Unsaved Workflow.json')
)
return createNewWorkflow(fullPath, workflowData)
}
const closeWorkflow = async (workflow: ComfyWorkflow) => {
openWorkflowPaths.value = openWorkflowPaths.value.filter(
(path) => path !== workflow.path
@@ -777,6 +812,7 @@ export const useWorkflowStore = defineStore('workflow', () => {
isBusy,
closeWorkflow,
createTemporary,
createNewTemporary,
renameWorkflow,
deleteWorkflow,
saveAs,