mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-19 22:09:37 +00:00
Compare commits
4 Commits
v1.41.16
...
create_fol
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e6e34cfd3 | ||
|
|
2a445f3f94 | ||
|
|
f8dcb915aa | ||
|
|
11925ce345 |
@@ -4,6 +4,13 @@
|
|||||||
class="workflows-sidebar-tab bg-[var(--p-tree-background)]"
|
class="workflows-sidebar-tab bg-[var(--p-tree-background)]"
|
||||||
>
|
>
|
||||||
<template #tool-buttons>
|
<template #tool-buttons>
|
||||||
|
<Button
|
||||||
|
icon="pi pi-folder-plus"
|
||||||
|
@click="addNewFolder"
|
||||||
|
severity="secondary"
|
||||||
|
text
|
||||||
|
v-tooltip.bottom="$t('g.newFolder')"
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
icon="pi pi-refresh"
|
icon="pi pi-refresh"
|
||||||
@click="workflowStore.syncWorkflows()"
|
@click="workflowStore.syncWorkflows()"
|
||||||
@@ -91,6 +98,7 @@
|
|||||||
:root="renderTreeNode(workflowsTree, WorkflowTreeType.Browse)"
|
:root="renderTreeNode(workflowsTree, WorkflowTreeType.Browse)"
|
||||||
v-model:expandedKeys="expandedKeys"
|
v-model:expandedKeys="expandedKeys"
|
||||||
:selectionKeys="selectionKeys"
|
:selectionKeys="selectionKeys"
|
||||||
|
ref="persistedWorkflowsTreeExplorerRef"
|
||||||
v-if="workflowStore.persistedWorkflows.length > 0"
|
v-if="workflowStore.persistedWorkflows.length > 0"
|
||||||
>
|
>
|
||||||
<template #node="{ node }">
|
<template #node="{ node }">
|
||||||
@@ -136,7 +144,6 @@ import SidebarTabTemplate from '@/components/sidebar/tabs/SidebarTabTemplate.vue
|
|||||||
import WorkflowTreeLeaf from '@/components/sidebar/tabs/workflows/WorkflowTreeLeaf.vue'
|
import WorkflowTreeLeaf from '@/components/sidebar/tabs/workflows/WorkflowTreeLeaf.vue'
|
||||||
import { useTreeExpansion } from '@/composables/useTreeExpansion'
|
import { useTreeExpansion } from '@/composables/useTreeExpansion'
|
||||||
import { useWorkflowService } from '@/services/workflowService'
|
import { useWorkflowService } from '@/services/workflowService'
|
||||||
import { useCommandStore } from '@/stores/commandStore'
|
|
||||||
import { useSettingStore } from '@/stores/settingStore'
|
import { useSettingStore } from '@/stores/settingStore'
|
||||||
import {
|
import {
|
||||||
useWorkflowBookmarkStore,
|
useWorkflowBookmarkStore,
|
||||||
@@ -174,7 +181,6 @@ const handleSearch = (query: string) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const commandStore = useCommandStore()
|
|
||||||
const workflowStore = useWorkflowStore()
|
const workflowStore = useWorkflowStore()
|
||||||
const workflowService = useWorkflowService()
|
const workflowService = useWorkflowService()
|
||||||
const workspaceStore = useWorkspaceStore()
|
const workspaceStore = useWorkspaceStore()
|
||||||
@@ -221,7 +227,6 @@ const renderTreeNode = (
|
|||||||
type: WorkflowTreeType
|
type: WorkflowTreeType
|
||||||
): TreeExplorerNode<ComfyWorkflow> => {
|
): TreeExplorerNode<ComfyWorkflow> => {
|
||||||
const children = node.children?.map((child) => renderTreeNode(child, type))
|
const children = node.children?.map((child) => renderTreeNode(child, type))
|
||||||
|
|
||||||
const workflow: ComfyWorkflow = node.data
|
const workflow: ComfyWorkflow = node.data
|
||||||
|
|
||||||
function handleClick(this: TreeExplorerNode<ComfyWorkflow>, e: MouseEvent) {
|
function handleClick(this: TreeExplorerNode<ComfyWorkflow>, e: MouseEvent) {
|
||||||
@@ -232,7 +237,7 @@ const renderTreeNode = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = node.leaf
|
const actions: Partial<TreeExplorerNode<ComfyWorkflow>> = node.leaf
|
||||||
? {
|
? {
|
||||||
handleClick,
|
handleClick,
|
||||||
async handleRename(newName: string) {
|
async handleRename(newName: string) {
|
||||||
@@ -262,7 +267,16 @@ const renderTreeNode = (
|
|||||||
},
|
},
|
||||||
draggable: true
|
draggable: true
|
||||||
}
|
}
|
||||||
: { handleClick }
|
: {
|
||||||
|
handleClick,
|
||||||
|
async handleAddFolder(folderName: string) {
|
||||||
|
if (folderName === '') return
|
||||||
|
|
||||||
|
const parentPath = this.key.replace(/^root\/?/, '')
|
||||||
|
const folderPath = parentPath + '/' + folderName
|
||||||
|
await workflowStore.createFolder(folderPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
key: node.key,
|
key: node.key,
|
||||||
@@ -282,4 +296,11 @@ const workflowBookmarkStore = useWorkflowBookmarkStore()
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await workflowBookmarkStore.loadBookmarks()
|
await workflowBookmarkStore.loadBookmarks()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const persistedWorkflowsTreeExplorerRef = ref<InstanceType<
|
||||||
|
typeof TreeExplorer
|
||||||
|
> | null>(null)
|
||||||
|
const addNewFolder = () => {
|
||||||
|
persistedWorkflowsTreeExplorerRef.value?.addFolderCommand?.('root')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { UserFile } from './userFileStore'
|
|||||||
|
|
||||||
export class ComfyWorkflow extends UserFile {
|
export class ComfyWorkflow extends UserFile {
|
||||||
static readonly basePath = 'workflows/'
|
static readonly basePath = 'workflows/'
|
||||||
|
static readonly folderPlaceholderFilename = 'folder.index'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The change tracker for the workflow. Non-reactive raw object.
|
* The change tracker for the workflow. Non-reactive raw object.
|
||||||
@@ -32,7 +33,9 @@ export class ComfyWorkflow extends UserFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get key() {
|
get key() {
|
||||||
return this.path.substring(ComfyWorkflow.basePath.length)
|
const key = this.isFolderPlaceholder ? this.directory + '/' : this.path
|
||||||
|
|
||||||
|
return key.substring(ComfyWorkflow.basePath.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
get activeState(): ComfyWorkflowJSON | null {
|
get activeState(): ComfyWorkflowJSON | null {
|
||||||
@@ -55,6 +58,13 @@ export class ComfyWorkflow extends UserFile {
|
|||||||
this._isModified = value
|
this._isModified = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the workflow is a folder placeholder.
|
||||||
|
*/
|
||||||
|
get isFolderPlaceholder(): boolean {
|
||||||
|
return this.fullFilename === ComfyWorkflow.folderPlaceholderFilename
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the workflow content from remote storage. Directly returns the loaded
|
* Load the workflow content from remote storage. Directly returns the loaded
|
||||||
* workflow if the content is already loaded.
|
* workflow if the content is already loaded.
|
||||||
@@ -153,6 +163,8 @@ export interface WorkflowStore {
|
|||||||
getWorkflowByPath: (path: string) => ComfyWorkflow | null
|
getWorkflowByPath: (path: string) => ComfyWorkflow | null
|
||||||
syncWorkflows: (dir?: string) => Promise<void>
|
syncWorkflows: (dir?: string) => Promise<void>
|
||||||
reorderWorkflows: (from: number, to: number) => void
|
reorderWorkflows: (from: number, to: number) => void
|
||||||
|
|
||||||
|
createFolder: (folderPath: string) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useWorkflowStore = defineStore('workflow', () => {
|
export const useWorkflowStore = defineStore('workflow', () => {
|
||||||
@@ -418,6 +430,40 @@ export const useWorkflowStore = defineStore('workflow', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new folder in the workflows directory
|
||||||
|
* @param folderPath The path of the folder to create (relative to workflows/)
|
||||||
|
* @returns Promise that resolves when the folder is created
|
||||||
|
*/
|
||||||
|
const createFolder = async (folderPath: string): Promise<void> => {
|
||||||
|
isBusy.value = true
|
||||||
|
try {
|
||||||
|
// Ensure the path is properly formatted
|
||||||
|
const normalizedPath = folderPath.endsWith('/')
|
||||||
|
? folderPath.slice(0, -1)
|
||||||
|
: folderPath
|
||||||
|
|
||||||
|
// Create the full path including the reserved index file
|
||||||
|
const indexFilePath = `${ComfyWorkflow.basePath}${normalizedPath}/${ComfyWorkflow.folderPlaceholderFilename}`
|
||||||
|
|
||||||
|
// Create an empty file to represent the folder
|
||||||
|
const resp = await api.storeUserData(indexFilePath, '', {
|
||||||
|
overwrite: false,
|
||||||
|
throwOnError: true,
|
||||||
|
full_info: true
|
||||||
|
})
|
||||||
|
|
||||||
|
if (resp.status !== 200) {
|
||||||
|
throw new Error('Failed to create folder')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync workflows to update the file tree
|
||||||
|
await syncWorkflows()
|
||||||
|
} finally {
|
||||||
|
isBusy.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activeWorkflow,
|
activeWorkflow,
|
||||||
isActive,
|
isActive,
|
||||||
@@ -439,7 +485,9 @@ export const useWorkflowStore = defineStore('workflow', () => {
|
|||||||
persistedWorkflows,
|
persistedWorkflows,
|
||||||
modifiedWorkflows,
|
modifiedWorkflows,
|
||||||
getWorkflowByPath,
|
getWorkflowByPath,
|
||||||
syncWorkflows
|
syncWorkflows,
|
||||||
|
|
||||||
|
createFolder
|
||||||
}
|
}
|
||||||
}) as unknown as () => WorkflowStore
|
}) as unknown as () => WorkflowStore
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user