mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
Expose dialogService to extensionManager (#2113)
This commit is contained in:
20
README.md
20
README.md
@@ -229,6 +229,26 @@ https://github.com/user-attachments/assets/c142c43f-2fe9-4030-8196-b3bfd4c6977d
|
|||||||
|
|
||||||
### Developer APIs
|
### Developer APIs
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>v1.6.13: Prompt dialog</summary>
|
||||||
|
|
||||||
|
`window.prompt` is not available in ComfyUI desktop's electron environment. Please use the following API to show a prompt dialog.
|
||||||
|
|
||||||
|
```js
|
||||||
|
window['app'].extensionManager.dialog
|
||||||
|
.prompt({
|
||||||
|
title: 'Test Prompt',
|
||||||
|
message: 'Test Prompt Message'
|
||||||
|
})
|
||||||
|
.then((value: string) => {
|
||||||
|
// Do something with the value user entered
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>v1.3.34: Register about panel badges</summary>
|
<summary>v1.3.34: Register about panel badges</summary>
|
||||||
|
|
||||||
|
|||||||
@@ -158,4 +158,24 @@ test.describe('Topbar commands', () => {
|
|||||||
expect(await badge.textContent()).toContain('Test Badge')
|
expect(await badge.textContent()).toContain('Test Badge')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test.describe('Dialog', () => {
|
||||||
|
test('Should allow showing a prompt dialog', async ({ comfyPage }) => {
|
||||||
|
await comfyPage.page.evaluate(() => {
|
||||||
|
window['app'].extensionManager.dialog
|
||||||
|
.prompt({
|
||||||
|
title: 'Test Prompt',
|
||||||
|
message: 'Test Prompt Message'
|
||||||
|
})
|
||||||
|
.then((value: string) => {
|
||||||
|
window['value'] = value
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
await comfyPage.fillPromptDialog('Hello, world!')
|
||||||
|
expect(await comfyPage.page.evaluate(() => window['value'])).toBe(
|
||||||
|
'Hello, world!'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -530,6 +530,13 @@ export class ComfyPage {
|
|||||||
return this.page.locator('.p-dialog-content input[type="text"]')
|
return this.page.locator('.p-dialog-content input[type="text"]')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fillPromptDialog(value: string) {
|
||||||
|
await this.promptDialogInput.fill(value)
|
||||||
|
await this.page.keyboard.press('Enter')
|
||||||
|
await this.promptDialogInput.waitFor({ state: 'hidden' })
|
||||||
|
await this.nextFrame()
|
||||||
|
}
|
||||||
|
|
||||||
async disconnectEdge() {
|
async disconnectEdge() {
|
||||||
await this.dragAndDrop(this.clipTextEncodeNode1InputSlot, this.emptySpace)
|
await this.dragAndDrop(this.clipTextEncodeNode1InputSlot, this.emptySpace)
|
||||||
}
|
}
|
||||||
@@ -797,9 +804,7 @@ export class ComfyPage {
|
|||||||
await this.canvas.press('Control+a')
|
await this.canvas.press('Control+a')
|
||||||
const node = await this.getFirstNodeRef()
|
const node = await this.getFirstNodeRef()
|
||||||
await node!.clickContextMenuOption('Convert to Group Node')
|
await node!.clickContextMenuOption('Convert to Group Node')
|
||||||
await this.promptDialogInput.fill(groupNodeName)
|
await this.fillPromptDialog(groupNodeName)
|
||||||
await this.page.keyboard.press('Enter')
|
|
||||||
await this.promptDialogInput.waitFor({ state: 'hidden' })
|
|
||||||
await this.nextFrame()
|
await this.nextFrame()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -235,9 +235,7 @@ export class NodeReference {
|
|||||||
}
|
}
|
||||||
async convertToGroupNode(groupNodeName: string = 'GroupNode') {
|
async convertToGroupNode(groupNodeName: string = 'GroupNode') {
|
||||||
await this.clickContextMenuOption('Convert to Group Node')
|
await this.clickContextMenuOption('Convert to Group Node')
|
||||||
await this.comfyPage.promptDialogInput.fill(groupNodeName)
|
await this.comfyPage.fillPromptDialog(groupNodeName)
|
||||||
await this.comfyPage.page.keyboard.press('Enter')
|
|
||||||
await this.comfyPage.promptDialogInput.waitFor({ state: 'hidden' })
|
|
||||||
await this.comfyPage.nextFrame()
|
await this.comfyPage.nextFrame()
|
||||||
const nodes = await this.comfyPage.getNodeRefsByType(
|
const nodes = await this.comfyPage.getNodeRefsByType(
|
||||||
`workflow>${groupNodeName}`
|
`workflow>${groupNodeName}`
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ import { electronAPI as getElectronAPI, isElectron } from '@/utils/envUtil'
|
|||||||
label: 'Reinstall',
|
label: 'Reinstall',
|
||||||
icon: 'pi pi-refresh',
|
icon: 'pi pi-refresh',
|
||||||
async function() {
|
async function() {
|
||||||
const proceed = await useDialogService().showConfirmationDialog({
|
const proceed = await useDialogService().confirm({
|
||||||
message: t('desktopMenu.confirmReinstall'),
|
message: t('desktopMenu.confirmReinstall'),
|
||||||
title: t('desktopMenu.reinstall'),
|
title: t('desktopMenu.reinstall'),
|
||||||
type: 'reinstall'
|
type: 'reinstall'
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class GroupNodeBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getName() {
|
async getName() {
|
||||||
const name = await useDialogService().showPromptDialog({
|
const name = await useDialogService().prompt({
|
||||||
title: t('groupNode.create'),
|
title: t('groupNode.create'),
|
||||||
message: t('groupNode.enterName'),
|
message: t('groupNode.enterName'),
|
||||||
defaultValue: ''
|
defaultValue: ''
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ app.registerExtension({
|
|||||||
content: `Save Selected as Template`,
|
content: `Save Selected as Template`,
|
||||||
disabled: !Object.keys(app.canvas.selected_nodes || {}).length,
|
disabled: !Object.keys(app.canvas.selected_nodes || {}).length,
|
||||||
callback: async () => {
|
callback: async () => {
|
||||||
const name = await useDialogService().showPromptDialog({
|
const name = await useDialogService().prompt({
|
||||||
title: t('nodeTemplates.saveAsTemplate'),
|
title: t('nodeTemplates.saveAsTemplate'),
|
||||||
message: t('nodeTemplates.enterName'),
|
message: t('nodeTemplates.enterName'),
|
||||||
defaultValue: ''
|
defaultValue: ''
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export const useDialogService = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function showPromptDialog({
|
async function prompt({
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
defaultValue = ''
|
defaultValue = ''
|
||||||
@@ -119,7 +119,7 @@ export const useDialogService = () => {
|
|||||||
* `false` if denied (e.g. no in yes/no/cancel), or
|
* `false` if denied (e.g. no in yes/no/cancel), or
|
||||||
* `null` if the dialog is cancelled or closed
|
* `null` if the dialog is cancelled or closed
|
||||||
*/
|
*/
|
||||||
async function showConfirmationDialog({
|
async function confirm({
|
||||||
title,
|
title,
|
||||||
type,
|
type,
|
||||||
message,
|
message,
|
||||||
@@ -161,7 +161,7 @@ export const useDialogService = () => {
|
|||||||
showAboutDialog,
|
showAboutDialog,
|
||||||
showExecutionErrorDialog,
|
showExecutionErrorDialog,
|
||||||
showTemplateWorkflowsDialog,
|
showTemplateWorkflowsDialog,
|
||||||
showPromptDialog,
|
prompt,
|
||||||
showConfirmationDialog
|
confirm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export const useWorkflowService = () => {
|
|||||||
|
|
||||||
async function getFilename(defaultName: string): Promise<string | null> {
|
async function getFilename(defaultName: string): Promise<string | null> {
|
||||||
if (settingStore.get('Comfy.PromptFilename')) {
|
if (settingStore.get('Comfy.PromptFilename')) {
|
||||||
let filename = await dialogService.showPromptDialog({
|
let filename = await dialogService.prompt({
|
||||||
title: t('workflowService.exportWorkflow'),
|
title: t('workflowService.exportWorkflow'),
|
||||||
message: t('workflowService.enterFilename') + ':',
|
message: t('workflowService.enterFilename') + ':',
|
||||||
defaultValue: defaultName
|
defaultValue: defaultName
|
||||||
@@ -60,7 +60,7 @@ export const useWorkflowService = () => {
|
|||||||
* @param workflow The workflow to save
|
* @param workflow The workflow to save
|
||||||
*/
|
*/
|
||||||
const saveWorkflowAs = async (workflow: ComfyWorkflow) => {
|
const saveWorkflowAs = async (workflow: ComfyWorkflow) => {
|
||||||
const newFilename = await dialogService.showPromptDialog({
|
const newFilename = await dialogService.prompt({
|
||||||
title: t('workflowService.saveWorkflow'),
|
title: t('workflowService.saveWorkflow'),
|
||||||
message: t('workflowService.enterFilename') + ':',
|
message: t('workflowService.enterFilename') + ':',
|
||||||
defaultValue: workflow.filename
|
defaultValue: workflow.filename
|
||||||
@@ -72,7 +72,7 @@ export const useWorkflowService = () => {
|
|||||||
const existingWorkflow = workflowStore.getWorkflowByPath(newPath)
|
const existingWorkflow = workflowStore.getWorkflowByPath(newPath)
|
||||||
|
|
||||||
if (existingWorkflow && !existingWorkflow.isTemporary) {
|
if (existingWorkflow && !existingWorkflow.isTemporary) {
|
||||||
const res = await dialogService.showConfirmationDialog({
|
const res = await dialogService.confirm({
|
||||||
title: t('sideToolbar.workflowTab.confirmOverwriteTitle'),
|
title: t('sideToolbar.workflowTab.confirmOverwriteTitle'),
|
||||||
type: 'overwrite',
|
type: 'overwrite',
|
||||||
message: t('sideToolbar.workflowTab.confirmOverwrite'),
|
message: t('sideToolbar.workflowTab.confirmOverwrite'),
|
||||||
@@ -181,7 +181,7 @@ export const useWorkflowService = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (workflow.isModified && options.warnIfUnsaved) {
|
if (workflow.isModified && options.warnIfUnsaved) {
|
||||||
const confirmed = await dialogService.showConfirmationDialog({
|
const confirmed = await dialogService.confirm({
|
||||||
title: t('sideToolbar.workflowTab.dirtyCloseTitle'),
|
title: t('sideToolbar.workflowTab.dirtyCloseTitle'),
|
||||||
type: 'dirtyClose',
|
type: 'dirtyClose',
|
||||||
message: t('sideToolbar.workflowTab.dirtyClose'),
|
message: t('sideToolbar.workflowTab.dirtyClose'),
|
||||||
@@ -225,7 +225,7 @@ export const useWorkflowService = () => {
|
|||||||
let confirmed: boolean | null = bypassConfirm || silent
|
let confirmed: boolean | null = bypassConfirm || silent
|
||||||
|
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
confirmed = await dialogService.showConfirmationDialog({
|
confirmed = await dialogService.confirm({
|
||||||
title: t('sideToolbar.workflowTab.confirmDeleteTitle'),
|
title: t('sideToolbar.workflowTab.confirmDeleteTitle'),
|
||||||
type: 'delete',
|
type: 'delete',
|
||||||
message: t('sideToolbar.workflowTab.confirmDelete'),
|
message: t('sideToolbar.workflowTab.confirmDelete'),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
|
|||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
import { useColorPaletteService } from '@/services/colorPaletteService'
|
import { useColorPaletteService } from '@/services/colorPaletteService'
|
||||||
|
import { useDialogService } from '@/services/dialogService'
|
||||||
import type { SidebarTabExtension, ToastManager } from '@/types/extensionTypes'
|
import type { SidebarTabExtension, ToastManager } from '@/types/extensionTypes'
|
||||||
|
|
||||||
import { useCommandStore } from './commandStore'
|
import { useCommandStore } from './commandStore'
|
||||||
@@ -34,6 +35,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
|
|||||||
}))
|
}))
|
||||||
const workflow = computed(() => useWorkflowStore())
|
const workflow = computed(() => useWorkflowStore())
|
||||||
const colorPalette = useColorPaletteService()
|
const colorPalette = useColorPaletteService()
|
||||||
|
const dialog = useDialogService()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a sidebar tab.
|
* Registers a sidebar tab.
|
||||||
@@ -76,6 +78,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
|
|||||||
setting,
|
setting,
|
||||||
workflow,
|
workflow,
|
||||||
colorPalette,
|
colorPalette,
|
||||||
|
dialog,
|
||||||
|
|
||||||
registerSidebarTab,
|
registerSidebarTab,
|
||||||
unregisterSidebarTab,
|
unregisterSidebarTab,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Component } from 'vue'
|
import { Component } from 'vue'
|
||||||
|
|
||||||
|
import type { useDialogService } from '@/services/dialogService'
|
||||||
import type { ComfyCommand } from '@/stores/commandStore'
|
import type { ComfyCommand } from '@/stores/commandStore'
|
||||||
|
|
||||||
export interface BaseSidebarTabExtension {
|
export interface BaseSidebarTabExtension {
|
||||||
@@ -102,6 +103,7 @@ export interface ExtensionManager {
|
|||||||
getSidebarTabs(): SidebarTabExtension[]
|
getSidebarTabs(): SidebarTabExtension[]
|
||||||
|
|
||||||
toast: ToastManager
|
toast: ToastManager
|
||||||
|
dialog: ReturnType<typeof useDialogService>
|
||||||
command: CommandManager
|
command: CommandManager
|
||||||
setting: {
|
setting: {
|
||||||
get: (id: string) => any
|
get: (id: string) => any
|
||||||
|
|||||||
Reference in New Issue
Block a user