mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
[Refactor] Convert dialogService to composable (#2058)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { t } from '@/i18n'
|
||||
import { app } from '@/scripts/app'
|
||||
import { showConfirmationDialog } from '@/services/dialogService'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { electronAPI as getElectronAPI, isElectron } from '@/utils/envUtil'
|
||||
;(async () => {
|
||||
if (!isElectron()) return
|
||||
@@ -114,7 +114,7 @@ import { electronAPI as getElectronAPI, isElectron } from '@/utils/envUtil'
|
||||
label: 'Reinstall',
|
||||
icon: 'pi pi-refresh',
|
||||
async function() {
|
||||
const proceed = await showConfirmationDialog({
|
||||
const proceed = await useDialogService().showConfirmationDialog({
|
||||
message: t('desktopMenu.confirmReinstall'),
|
||||
title: t('desktopMenu.reinstall'),
|
||||
type: 'reinstall'
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
serialise
|
||||
} from '@/extensions/core/vintageClipboard'
|
||||
import type { ComfyNodeDef } from '@/types/apiTypes'
|
||||
import { showPromptDialog } from '@/services/dialogService'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { t } from '@/i18n'
|
||||
|
||||
type GroupNodeWorkflowData = {
|
||||
@@ -80,7 +80,7 @@ class GroupNodeBuilder {
|
||||
}
|
||||
|
||||
async getName() {
|
||||
const name = await showPromptDialog({
|
||||
const name = await useDialogService().showPromptDialog({
|
||||
title: t('groupNode.create'),
|
||||
message: t('groupNode.enterName'),
|
||||
defaultValue: ''
|
||||
|
||||
@@ -6,7 +6,7 @@ import { GroupNodeConfig, GroupNodeHandler } from './groupNode'
|
||||
import { LGraphCanvas } from '@comfyorg/litegraph'
|
||||
import { useToastStore } from '@/stores/toastStore'
|
||||
import { deserialiseAndCreate } from '@/extensions/core/vintageClipboard'
|
||||
import { showPromptDialog } from '@/services/dialogService'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { t } from '@/i18n'
|
||||
|
||||
// Adds the ability to save and add multiple nodes as a template
|
||||
@@ -351,7 +351,7 @@ app.registerExtension({
|
||||
content: `Save Selected as Template`,
|
||||
disabled: !Object.keys(app.canvas.selected_nodes || {}).length,
|
||||
callback: async () => {
|
||||
const name = await showPromptDialog({
|
||||
const name = await useDialogService().showPromptDialog({
|
||||
title: t('nodeTemplates.saveAsTemplate'),
|
||||
message: t('nodeTemplates.enterName'),
|
||||
defaultValue: ''
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { app } from '@/scripts/app'
|
||||
import { api } from '@/scripts/api'
|
||||
import {
|
||||
showSettingsDialog,
|
||||
showTemplateWorkflowsDialog
|
||||
} from '@/services/dialogService'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useWorkflowService } from '@/services/workflowService'
|
||||
import type { ComfyCommand } from '@/stores/commandStore'
|
||||
import { useTitleEditorStore } from '@/stores/graphStore'
|
||||
@@ -23,6 +20,7 @@ import { useSearchBoxStore } from '@/stores/workspace/searchBoxStore'
|
||||
|
||||
export function useCoreCommands(): ComfyCommand[] {
|
||||
const workflowService = useWorkflowService()
|
||||
const dialogService = useDialogService()
|
||||
const getTracker = () => useWorkflowStore()?.activeWorkflow?.changeTracker
|
||||
|
||||
const getSelectedNodes = (): LGraphNode[] => {
|
||||
@@ -200,7 +198,9 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
id: 'Comfy.BrowseTemplates',
|
||||
icon: 'pi pi-folder-open',
|
||||
label: 'Browse Templates',
|
||||
function: showTemplateWorkflowsDialog
|
||||
function: () => {
|
||||
dialogService.showTemplateWorkflowsDialog()
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Canvas.ZoomIn',
|
||||
@@ -302,7 +302,7 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
label: 'Show Settings Dialog',
|
||||
versionAdded: '1.3.7',
|
||||
function: () => {
|
||||
showSettingsDialog()
|
||||
dialogService.showSettingsDialog()
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -509,7 +509,7 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
menubarLabel: 'About ComfyUI',
|
||||
versionAdded: '1.6.4',
|
||||
function: () => {
|
||||
showSettingsDialog('about')
|
||||
dialogService.showSettingsDialog('about')
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -41,11 +41,7 @@ import {
|
||||
} from '@/stores/nodeDefStore'
|
||||
import { INodeInputSlot, Vector2 } from '@comfyorg/litegraph'
|
||||
import _ from 'lodash'
|
||||
import {
|
||||
showExecutionErrorDialog,
|
||||
showLoadWorkflowWarning,
|
||||
showMissingModelsWarning
|
||||
} from '@/services/dialogService'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
import { useToastStore } from '@/stores/toastStore'
|
||||
import { useModelStore } from '@/stores/modelStore'
|
||||
@@ -1528,7 +1524,7 @@ export class ComfyApp {
|
||||
|
||||
api.addEventListener('execution_error', ({ detail }) => {
|
||||
this.lastExecutionError = detail
|
||||
showExecutionErrorDialog(detail)
|
||||
useDialogService().showExecutionErrorDialog(detail)
|
||||
this.canvas.draw(true, true)
|
||||
})
|
||||
|
||||
@@ -1992,13 +1988,13 @@ export class ComfyApp {
|
||||
|
||||
#showMissingNodesError(missingNodeTypes: MissingNodeType[]) {
|
||||
if (useSettingStore().get('Comfy.Workflow.ShowMissingNodesWarning')) {
|
||||
showLoadWorkflowWarning({ missingNodeTypes })
|
||||
useDialogService().showLoadWorkflowWarning({ missingNodeTypes })
|
||||
}
|
||||
}
|
||||
|
||||
#showMissingModelsError(missingModels, paths) {
|
||||
if (useSettingStore().get('Comfy.Workflow.ShowMissingModelsWarning')) {
|
||||
showMissingModelsWarning({
|
||||
useDialogService().showMissingModelsWarning({
|
||||
missingModels,
|
||||
paths
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ import { toggleSwitch } from './ui/toggleSwitch'
|
||||
import { ComfySettingsDialog } from './ui/settings'
|
||||
import { ComfyApp, app } from './app'
|
||||
import { TaskItem, type StatusWsMessageStatus } from '@/types/apiTypes'
|
||||
import { showSettingsDialog } from '@/services/dialogService'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
import { useCommandStore } from '@/stores/commandStore'
|
||||
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
||||
@@ -438,7 +438,9 @@ export class ComfyUI {
|
||||
$el('div.comfy-menu-actions', [
|
||||
$el('button.comfy-settings-btn', {
|
||||
textContent: '⚙️',
|
||||
onclick: showSettingsDialog
|
||||
onclick: () => {
|
||||
useDialogService().showSettingsDialog()
|
||||
}
|
||||
}),
|
||||
$el('button.comfy-close-menu-btn', {
|
||||
textContent: '\u00d7',
|
||||
|
||||
@@ -1,117 +1,15 @@
|
||||
// This module is mocked in tests-ui/
|
||||
// Import vue components here to avoid tests-ui/ reporting errors
|
||||
// about importing primevue components.
|
||||
import { useDialogStore, type ShowDialogOptions } from '@/stores/dialogStore'
|
||||
import type { ExecutionErrorWsMessage } from '@/types/apiTypes'
|
||||
import type { MissingNodeType } from '@/types/comfy'
|
||||
import LoadWorkflowWarning from '@/components/dialog/content/LoadWorkflowWarning.vue'
|
||||
import MissingModelsWarning from '@/components/dialog/content/MissingModelsWarning.vue'
|
||||
import SettingDialogContent from '@/components/dialog/content/SettingDialogContent.vue'
|
||||
import SettingDialogHeader from '@/components/dialog/header/SettingDialogHeader.vue'
|
||||
import type { ExecutionErrorWsMessage } from '@/types/apiTypes'
|
||||
import ExecutionErrorDialogContent from '@/components/dialog/content/ExecutionErrorDialogContent.vue'
|
||||
import TemplateWorkflowsContent from '@/components/templates/TemplateWorkflowsContent.vue'
|
||||
import PromptDialogContent from '@/components/dialog/content/PromptDialogContent.vue'
|
||||
import ConfirmationDialogContent from '@/components/dialog/content/ConfirmationDialogContent.vue'
|
||||
import { t } from '@/i18n'
|
||||
import type { MissingNodeType } from '@/types/comfy'
|
||||
|
||||
export function showLoadWorkflowWarning(props: {
|
||||
missingNodeTypes: MissingNodeType[]
|
||||
[key: string]: any
|
||||
}) {
|
||||
const dialogStore = useDialogStore()
|
||||
dialogStore.showDialog({
|
||||
key: 'global-load-workflow-warning',
|
||||
component: LoadWorkflowWarning,
|
||||
props
|
||||
})
|
||||
}
|
||||
|
||||
export function showMissingModelsWarning(props: {
|
||||
missingModels: any[]
|
||||
paths: Record<string, string[]>
|
||||
[key: string]: any
|
||||
}) {
|
||||
const dialogStore = useDialogStore()
|
||||
dialogStore.showDialog({
|
||||
key: 'global-missing-models-warning',
|
||||
component: MissingModelsWarning,
|
||||
props
|
||||
})
|
||||
}
|
||||
|
||||
export function showSettingsDialog(
|
||||
panel?: 'about' | 'keybinding' | 'extension' | 'server-config'
|
||||
) {
|
||||
const props = panel ? { props: { defaultPanel: panel } } : undefined
|
||||
|
||||
useDialogStore().showDialog({
|
||||
key: 'global-settings',
|
||||
headerComponent: SettingDialogHeader,
|
||||
component: SettingDialogContent,
|
||||
...props
|
||||
})
|
||||
}
|
||||
|
||||
export function showAboutDialog() {
|
||||
useDialogStore().showDialog({
|
||||
key: 'global-settings',
|
||||
headerComponent: SettingDialogHeader,
|
||||
component: SettingDialogContent,
|
||||
props: {
|
||||
defaultPanel: 'about'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function showExecutionErrorDialog(error: ExecutionErrorWsMessage) {
|
||||
useDialogStore().showDialog({
|
||||
key: 'global-execution-error',
|
||||
component: ExecutionErrorDialogContent,
|
||||
props: {
|
||||
error
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function showTemplateWorkflowsDialog() {
|
||||
useDialogStore().showDialog({
|
||||
key: 'global-template-workflows',
|
||||
title: t('templateWorkflows.title'),
|
||||
component: TemplateWorkflowsContent
|
||||
})
|
||||
}
|
||||
|
||||
export async function showPromptDialog({
|
||||
title,
|
||||
message,
|
||||
defaultValue = ''
|
||||
}: {
|
||||
title: string
|
||||
message: string
|
||||
defaultValue?: string
|
||||
}): Promise<string | null> {
|
||||
const dialogStore = useDialogStore()
|
||||
|
||||
return new Promise((resolve) => {
|
||||
dialogStore.showDialog({
|
||||
key: 'global-prompt',
|
||||
title,
|
||||
component: PromptDialogContent,
|
||||
props: {
|
||||
message,
|
||||
defaultValue,
|
||||
onConfirm: (value: string) => {
|
||||
resolve(value)
|
||||
}
|
||||
},
|
||||
dialogComponentProps: {
|
||||
onClose: () => {
|
||||
resolve(null)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export type ConfirmationDialogType =
|
||||
| 'overwrite'
|
||||
@@ -119,43 +17,151 @@ export type ConfirmationDialogType =
|
||||
| 'dirtyClose'
|
||||
| 'reinstall'
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns `true` if the user confirms the dialog,
|
||||
* `false` if denied (e.g. no in yes/no/cancel), or
|
||||
* `null` if the dialog is cancelled or closed
|
||||
*/
|
||||
export async function showConfirmationDialog({
|
||||
title,
|
||||
type,
|
||||
message,
|
||||
itemList = []
|
||||
}: {
|
||||
/** Dialog heading */
|
||||
title: string
|
||||
/** Pre-configured dialog type */
|
||||
type: ConfirmationDialogType
|
||||
/** The main message body */
|
||||
message: string
|
||||
/** Displayed as an unorderd list immediately below the message body */
|
||||
itemList?: string[]
|
||||
}): Promise<boolean | null> {
|
||||
return new Promise((resolve) => {
|
||||
const options: ShowDialogOptions = {
|
||||
key: 'global-prompt',
|
||||
title,
|
||||
component: ConfirmationDialogContent,
|
||||
props: {
|
||||
message,
|
||||
type,
|
||||
itemList,
|
||||
onConfirm: resolve
|
||||
},
|
||||
dialogComponentProps: {
|
||||
onClose: () => resolve(null)
|
||||
}
|
||||
}
|
||||
export const useDialogService = () => {
|
||||
const dialogStore = useDialogStore()
|
||||
function showLoadWorkflowWarning(props: {
|
||||
missingNodeTypes: MissingNodeType[]
|
||||
[key: string]: any
|
||||
}) {
|
||||
dialogStore.showDialog({
|
||||
key: 'global-load-workflow-warning',
|
||||
component: LoadWorkflowWarning,
|
||||
props
|
||||
})
|
||||
}
|
||||
|
||||
useDialogStore().showDialog(options)
|
||||
})
|
||||
function showMissingModelsWarning(props: {
|
||||
missingModels: any[]
|
||||
paths: Record<string, string[]>
|
||||
[key: string]: any
|
||||
}) {
|
||||
dialogStore.showDialog({
|
||||
key: 'global-missing-models-warning',
|
||||
component: MissingModelsWarning,
|
||||
props
|
||||
})
|
||||
}
|
||||
|
||||
function showSettingsDialog(
|
||||
panel?: 'about' | 'keybinding' | 'extension' | 'server-config'
|
||||
) {
|
||||
const props = panel ? { props: { defaultPanel: panel } } : undefined
|
||||
|
||||
dialogStore.showDialog({
|
||||
key: 'global-settings',
|
||||
headerComponent: SettingDialogHeader,
|
||||
component: SettingDialogContent,
|
||||
...props
|
||||
})
|
||||
}
|
||||
|
||||
function showAboutDialog() {
|
||||
dialogStore.showDialog({
|
||||
key: 'global-settings',
|
||||
headerComponent: SettingDialogHeader,
|
||||
component: SettingDialogContent,
|
||||
props: {
|
||||
defaultPanel: 'about'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function showExecutionErrorDialog(error: ExecutionErrorWsMessage) {
|
||||
dialogStore.showDialog({
|
||||
key: 'global-execution-error',
|
||||
component: ExecutionErrorDialogContent,
|
||||
props: {
|
||||
error
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function showTemplateWorkflowsDialog() {
|
||||
dialogStore.showDialog({
|
||||
key: 'global-template-workflows',
|
||||
title: t('templateWorkflows.title'),
|
||||
component: TemplateWorkflowsContent
|
||||
})
|
||||
}
|
||||
|
||||
async function showPromptDialog({
|
||||
title,
|
||||
message,
|
||||
defaultValue = ''
|
||||
}: {
|
||||
title: string
|
||||
message: string
|
||||
defaultValue?: string
|
||||
}): Promise<string | null> {
|
||||
return new Promise((resolve) => {
|
||||
dialogStore.showDialog({
|
||||
key: 'global-prompt',
|
||||
title,
|
||||
component: PromptDialogContent,
|
||||
props: {
|
||||
message,
|
||||
defaultValue,
|
||||
onConfirm: (value: string) => {
|
||||
resolve(value)
|
||||
}
|
||||
},
|
||||
dialogComponentProps: {
|
||||
onClose: () => {
|
||||
resolve(null)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns `true` if the user confirms the dialog,
|
||||
* `false` if denied (e.g. no in yes/no/cancel), or
|
||||
* `null` if the dialog is cancelled or closed
|
||||
*/
|
||||
async function showConfirmationDialog({
|
||||
title,
|
||||
type,
|
||||
message,
|
||||
itemList = []
|
||||
}: {
|
||||
/** Dialog heading */
|
||||
title: string
|
||||
/** Pre-configured dialog type */
|
||||
type: ConfirmationDialogType
|
||||
/** The main message body */
|
||||
message: string
|
||||
/** Displayed as an unorderd list immediately below the message body */
|
||||
itemList?: string[]
|
||||
}): Promise<boolean | null> {
|
||||
return new Promise((resolve) => {
|
||||
const options: ShowDialogOptions = {
|
||||
key: 'global-prompt',
|
||||
title,
|
||||
component: ConfirmationDialogContent,
|
||||
props: {
|
||||
message,
|
||||
type,
|
||||
itemList,
|
||||
onConfirm: resolve
|
||||
},
|
||||
dialogComponentProps: {
|
||||
onClose: () => resolve(null)
|
||||
}
|
||||
}
|
||||
|
||||
dialogStore.showDialog(options)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
showLoadWorkflowWarning,
|
||||
showMissingModelsWarning,
|
||||
showSettingsDialog,
|
||||
showAboutDialog,
|
||||
showExecutionErrorDialog,
|
||||
showTemplateWorkflowsDialog,
|
||||
showPromptDialog,
|
||||
showConfirmationDialog
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { downloadBlob } from '@/scripts/utils'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
import { useWorkflowStore, ComfyWorkflow } from '@/stores/workflowStore'
|
||||
import { showConfirmationDialog, showPromptDialog } from './dialogService'
|
||||
import { useDialogService } from './dialogService'
|
||||
import { app } from '@/scripts/app'
|
||||
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
||||
import { LGraphCanvas } from '@comfyorg/litegraph'
|
||||
@@ -16,10 +16,11 @@ export const useWorkflowService = () => {
|
||||
const settingStore = useSettingStore()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const toastStore = useToastStore()
|
||||
const dialogService = useDialogService()
|
||||
|
||||
async function getFilename(defaultName: string): Promise<string | null> {
|
||||
if (settingStore.get('Comfy.PromptFilename')) {
|
||||
let filename = await showPromptDialog({
|
||||
let filename = await dialogService.showPromptDialog({
|
||||
title: t('workflowService.exportWorkflow'),
|
||||
message: t('workflowService.enterFilename') + ':',
|
||||
defaultValue: defaultName
|
||||
@@ -57,7 +58,7 @@ export const useWorkflowService = () => {
|
||||
* @param workflow The workflow to save
|
||||
*/
|
||||
const saveWorkflowAs = async (workflow: ComfyWorkflow) => {
|
||||
const newFilename = await showPromptDialog({
|
||||
const newFilename = await dialogService.showPromptDialog({
|
||||
title: t('workflowService.saveWorkflow'),
|
||||
message: t('workflowService.enterFilename') + ':',
|
||||
defaultValue: workflow.filename
|
||||
@@ -69,7 +70,7 @@ export const useWorkflowService = () => {
|
||||
const existingWorkflow = workflowStore.getWorkflowByPath(newPath)
|
||||
|
||||
if (existingWorkflow && !existingWorkflow.isTemporary) {
|
||||
const res = await showConfirmationDialog({
|
||||
const res = await dialogService.showConfirmationDialog({
|
||||
title: t('sideToolbar.workflowTab.confirmOverwriteTitle'),
|
||||
type: 'overwrite',
|
||||
message: t('sideToolbar.workflowTab.confirmOverwrite'),
|
||||
@@ -178,7 +179,7 @@ export const useWorkflowService = () => {
|
||||
}
|
||||
|
||||
if (workflow.isModified && options.warnIfUnsaved) {
|
||||
const confirmed = await showConfirmationDialog({
|
||||
const confirmed = await dialogService.showConfirmationDialog({
|
||||
title: t('sideToolbar.workflowTab.dirtyCloseTitle'),
|
||||
type: 'dirtyClose',
|
||||
message: t('sideToolbar.workflowTab.dirtyClose'),
|
||||
@@ -222,7 +223,7 @@ export const useWorkflowService = () => {
|
||||
let confirmed: boolean | null = bypassConfirm || silent
|
||||
|
||||
if (!confirmed) {
|
||||
confirmed = await showConfirmationDialog({
|
||||
confirmed = await dialogService.showConfirmationDialog({
|
||||
title: t('sideToolbar.workflowTab.confirmDeleteTitle'),
|
||||
type: 'delete',
|
||||
message: t('sideToolbar.workflowTab.confirmDelete'),
|
||||
|
||||
Reference in New Issue
Block a user