mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-03 14:54:37 +00:00
## Summary For users who don't use subgraphs, the workflow name in the top left can be unnecessarily obstructive so this updated collapses it to a simple icon until a subgraph is entered. ## Changes - Add menu button to WorkflowTab for quick workflow actions - Add menu and back button to SubgraphBreadcrumb - Extract shared menu items to useBreadcrumbMenu composable - Add Comfy.RenameWorkflow command for renaming persisted workflows - Menu always shows root workflow menu, even when in subgraph ## Screenshots (if applicable) <img width="399" height="396" alt="image" src="https://github.com/user-attachments/assets/701ab60e-790f-4d1e-a817-dc42b2d98712" /> <img width="569" height="381" alt="image" src="https://github.com/user-attachments/assets/fcea3ab0-8388-4c72-a649-1428c1defd6a" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7852-Subgraph-workflow-breadcrumbs-menu-updates-2df6d73d3650815b8490ca0a9a92d540) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: GitHub Action <action@github.com>
193 lines
4.8 KiB
TypeScript
193 lines
4.8 KiB
TypeScript
import type { MenuItem } from 'primevue/menuitem'
|
|
import type { ComputedRef, Ref } from 'vue'
|
|
import { computed } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
import { useWorkflowService } from '@/platform/workflow/core/services/workflowService'
|
|
import type { ComfyWorkflow } from '@/platform/workflow/management/stores/workflowStore'
|
|
import {
|
|
useWorkflowBookmarkStore,
|
|
useWorkflowStore
|
|
} from '@/platform/workflow/management/stores/workflowStore'
|
|
import { useCommandStore } from '@/stores/commandStore'
|
|
import { useSubgraphStore } from '@/stores/subgraphStore'
|
|
|
|
interface WorkflowActionsMenuOptions {
|
|
/** Whether this is the root workflow level. Defaults to true. */
|
|
isRoot?: boolean
|
|
/** Whether to include the delete workflow action. Defaults to true. */
|
|
includeDelete?: boolean
|
|
/** Override the workflow to operate on. If not provided, uses activeWorkflow. */
|
|
workflow?: Ref<ComfyWorkflow | null> | ComputedRef<ComfyWorkflow | null>
|
|
}
|
|
|
|
export function useWorkflowActionsMenu(
|
|
startRename: () => void,
|
|
options: WorkflowActionsMenuOptions = {}
|
|
) {
|
|
const { isRoot = true, includeDelete = true, workflow } = options
|
|
const { t } = useI18n()
|
|
const workflowStore = useWorkflowStore()
|
|
const workflowService = useWorkflowService()
|
|
const bookmarkStore = useWorkflowBookmarkStore()
|
|
const commandStore = useCommandStore()
|
|
const subgraphStore = useSubgraphStore()
|
|
|
|
const targetWorkflow = computed(
|
|
() => workflow?.value ?? workflowStore.activeWorkflow
|
|
)
|
|
|
|
/** Switch to the target workflow tab if it's not already active */
|
|
const ensureWorkflowActive = async (wf: ComfyWorkflow | null) => {
|
|
if (!wf || wf === workflowStore.activeWorkflow) return
|
|
await workflowService.openWorkflow(wf)
|
|
}
|
|
|
|
const menuItems = computed<MenuItem[]>(() => {
|
|
const workflow = targetWorkflow.value
|
|
const isBlueprint = workflow
|
|
? subgraphStore.isSubgraphBlueprint(workflow)
|
|
: false
|
|
|
|
const items: MenuItem[] = []
|
|
|
|
const addItem = (
|
|
label: string,
|
|
icon: string,
|
|
command: () => void,
|
|
visible = true,
|
|
disabled = false,
|
|
separator = false
|
|
) => {
|
|
if (!visible) return
|
|
if (separator) items.push({ separator: true })
|
|
items.push({ label, icon, command, disabled })
|
|
}
|
|
|
|
addItem(
|
|
t('g.rename'),
|
|
'pi pi-pencil',
|
|
async () => {
|
|
await ensureWorkflowActive(targetWorkflow.value)
|
|
startRename()
|
|
},
|
|
true,
|
|
isRoot && !workflow?.isPersisted
|
|
)
|
|
|
|
addItem(
|
|
t('breadcrumbsMenu.duplicate'),
|
|
'pi pi-copy',
|
|
async () => {
|
|
if (workflow) {
|
|
await workflowService.duplicateWorkflow(workflow)
|
|
}
|
|
},
|
|
isRoot && !isBlueprint
|
|
)
|
|
|
|
addItem(
|
|
t('menuLabels.Save'),
|
|
'pi pi-save',
|
|
async () => {
|
|
await ensureWorkflowActive(workflow)
|
|
await commandStore.execute('Comfy.SaveWorkflow')
|
|
},
|
|
isRoot,
|
|
false,
|
|
true
|
|
)
|
|
|
|
addItem(
|
|
t('menuLabels.Save As'),
|
|
'pi pi-save',
|
|
async () => {
|
|
await ensureWorkflowActive(workflow)
|
|
await commandStore.execute('Comfy.SaveWorkflowAs')
|
|
},
|
|
isRoot
|
|
)
|
|
|
|
addItem(
|
|
bookmarkStore.isBookmarked(workflow?.path ?? '')
|
|
? t('tabMenu.removeFromBookmarks')
|
|
: t('tabMenu.addToBookmarks'),
|
|
'pi pi-bookmark' +
|
|
(bookmarkStore.isBookmarked(workflow?.path ?? '') ? '-fill' : ''),
|
|
async () => {
|
|
if (workflow?.path) {
|
|
await bookmarkStore.toggleBookmarked(workflow.path)
|
|
}
|
|
},
|
|
isRoot,
|
|
workflow?.isTemporary ?? false
|
|
)
|
|
|
|
addItem(
|
|
t('menuLabels.Export'),
|
|
'pi pi-download',
|
|
async () => {
|
|
await ensureWorkflowActive(workflow)
|
|
await commandStore.execute('Comfy.ExportWorkflow')
|
|
},
|
|
isRoot
|
|
)
|
|
|
|
addItem(
|
|
t('menuLabels.Export (API)'),
|
|
'pi pi-download',
|
|
async () => {
|
|
await ensureWorkflowActive(workflow)
|
|
await commandStore.execute('Comfy.ExportWorkflowAPI')
|
|
},
|
|
isRoot
|
|
)
|
|
|
|
addItem(
|
|
t('breadcrumbsMenu.clearWorkflow'),
|
|
'pi pi-trash',
|
|
async () => {
|
|
await ensureWorkflowActive(workflow)
|
|
await commandStore.execute('Comfy.ClearWorkflow')
|
|
},
|
|
true,
|
|
false,
|
|
true
|
|
)
|
|
|
|
addItem(
|
|
t('subgraphStore.publish'),
|
|
'pi pi-upload',
|
|
async () => {
|
|
if (workflow) {
|
|
await workflowService.saveWorkflowAs(workflow)
|
|
}
|
|
},
|
|
isRoot && isBlueprint,
|
|
false,
|
|
true
|
|
)
|
|
|
|
addItem(
|
|
isBlueprint
|
|
? t('breadcrumbsMenu.deleteBlueprint')
|
|
: t('breadcrumbsMenu.deleteWorkflow'),
|
|
'pi pi-times',
|
|
async () => {
|
|
if (workflow) {
|
|
await workflowService.deleteWorkflow(workflow)
|
|
}
|
|
},
|
|
isRoot && includeDelete,
|
|
false,
|
|
true
|
|
)
|
|
|
|
return items
|
|
})
|
|
|
|
return {
|
|
menuItems
|
|
}
|
|
}
|