Expose dialogService to extensionManager (#2113)

This commit is contained in:
Chenlei Hu
2024-12-31 17:01:37 -05:00
committed by GitHub
parent 0b3c0cc0c9
commit 174a9a114a
11 changed files with 66 additions and 18 deletions

View File

@@ -229,6 +229,26 @@ https://github.com/user-attachments/assets/c142c43f-2fe9-4030-8196-b3bfd4c6977d
### 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
})
```
![image](https://github.com/user-attachments/assets/c73f74d0-9bb4-4555-8d56-83f1be4a1d7e)
</details>
<details>
<summary>v1.3.34: Register about panel badges</summary>

View File

@@ -158,4 +158,24 @@ test.describe('Topbar commands', () => {
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!'
)
})
})
})

View File

@@ -530,6 +530,13 @@ export class ComfyPage {
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() {
await this.dragAndDrop(this.clipTextEncodeNode1InputSlot, this.emptySpace)
}
@@ -797,9 +804,7 @@ export class ComfyPage {
await this.canvas.press('Control+a')
const node = await this.getFirstNodeRef()
await node!.clickContextMenuOption('Convert to Group Node')
await this.promptDialogInput.fill(groupNodeName)
await this.page.keyboard.press('Enter')
await this.promptDialogInput.waitFor({ state: 'hidden' })
await this.fillPromptDialog(groupNodeName)
await this.nextFrame()
}

View File

@@ -235,9 +235,7 @@ export class NodeReference {
}
async convertToGroupNode(groupNodeName: string = 'GroupNode') {
await this.clickContextMenuOption('Convert to Group Node')
await this.comfyPage.promptDialogInput.fill(groupNodeName)
await this.comfyPage.page.keyboard.press('Enter')
await this.comfyPage.promptDialogInput.waitFor({ state: 'hidden' })
await this.comfyPage.fillPromptDialog(groupNodeName)
await this.comfyPage.nextFrame()
const nodes = await this.comfyPage.getNodeRefsByType(
`workflow>${groupNodeName}`

View File

@@ -115,7 +115,7 @@ import { electronAPI as getElectronAPI, isElectron } from '@/utils/envUtil'
label: 'Reinstall',
icon: 'pi pi-refresh',
async function() {
const proceed = await useDialogService().showConfirmationDialog({
const proceed = await useDialogService().confirm({
message: t('desktopMenu.confirmReinstall'),
title: t('desktopMenu.reinstall'),
type: 'reinstall'

View File

@@ -79,7 +79,7 @@ class GroupNodeBuilder {
}
async getName() {
const name = await useDialogService().showPromptDialog({
const name = await useDialogService().prompt({
title: t('groupNode.create'),
message: t('groupNode.enterName'),
defaultValue: ''

View File

@@ -353,7 +353,7 @@ app.registerExtension({
content: `Save Selected as Template`,
disabled: !Object.keys(app.canvas.selected_nodes || {}).length,
callback: async () => {
const name = await useDialogService().showPromptDialog({
const name = await useDialogService().prompt({
title: t('nodeTemplates.saveAsTemplate'),
message: t('nodeTemplates.enterName'),
defaultValue: ''

View File

@@ -84,7 +84,7 @@ export const useDialogService = () => {
})
}
async function showPromptDialog({
async function prompt({
title,
message,
defaultValue = ''
@@ -119,7 +119,7 @@ export const useDialogService = () => {
* `false` if denied (e.g. no in yes/no/cancel), or
* `null` if the dialog is cancelled or closed
*/
async function showConfirmationDialog({
async function confirm({
title,
type,
message,
@@ -161,7 +161,7 @@ export const useDialogService = () => {
showAboutDialog,
showExecutionErrorDialog,
showTemplateWorkflowsDialog,
showPromptDialog,
showConfirmationDialog
prompt,
confirm
}
}

View File

@@ -22,7 +22,7 @@ export const useWorkflowService = () => {
async function getFilename(defaultName: string): Promise<string | null> {
if (settingStore.get('Comfy.PromptFilename')) {
let filename = await dialogService.showPromptDialog({
let filename = await dialogService.prompt({
title: t('workflowService.exportWorkflow'),
message: t('workflowService.enterFilename') + ':',
defaultValue: defaultName
@@ -60,7 +60,7 @@ export const useWorkflowService = () => {
* @param workflow The workflow to save
*/
const saveWorkflowAs = async (workflow: ComfyWorkflow) => {
const newFilename = await dialogService.showPromptDialog({
const newFilename = await dialogService.prompt({
title: t('workflowService.saveWorkflow'),
message: t('workflowService.enterFilename') + ':',
defaultValue: workflow.filename
@@ -72,7 +72,7 @@ export const useWorkflowService = () => {
const existingWorkflow = workflowStore.getWorkflowByPath(newPath)
if (existingWorkflow && !existingWorkflow.isTemporary) {
const res = await dialogService.showConfirmationDialog({
const res = await dialogService.confirm({
title: t('sideToolbar.workflowTab.confirmOverwriteTitle'),
type: 'overwrite',
message: t('sideToolbar.workflowTab.confirmOverwrite'),
@@ -181,7 +181,7 @@ export const useWorkflowService = () => {
}
if (workflow.isModified && options.warnIfUnsaved) {
const confirmed = await dialogService.showConfirmationDialog({
const confirmed = await dialogService.confirm({
title: t('sideToolbar.workflowTab.dirtyCloseTitle'),
type: 'dirtyClose',
message: t('sideToolbar.workflowTab.dirtyClose'),
@@ -225,7 +225,7 @@ export const useWorkflowService = () => {
let confirmed: boolean | null = bypassConfirm || silent
if (!confirmed) {
confirmed = await dialogService.showConfirmationDialog({
confirmed = await dialogService.confirm({
title: t('sideToolbar.workflowTab.confirmDeleteTitle'),
type: 'delete',
message: t('sideToolbar.workflowTab.confirmDelete'),

View File

@@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { useColorPaletteService } from '@/services/colorPaletteService'
import { useDialogService } from '@/services/dialogService'
import type { SidebarTabExtension, ToastManager } from '@/types/extensionTypes'
import { useCommandStore } from './commandStore'
@@ -34,6 +35,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
}))
const workflow = computed(() => useWorkflowStore())
const colorPalette = useColorPaletteService()
const dialog = useDialogService()
/**
* Registers a sidebar tab.
@@ -76,6 +78,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
setting,
workflow,
colorPalette,
dialog,
registerSidebarTab,
unregisterSidebarTab,

View File

@@ -1,5 +1,6 @@
import { Component } from 'vue'
import type { useDialogService } from '@/services/dialogService'
import type { ComfyCommand } from '@/stores/commandStore'
export interface BaseSidebarTabExtension {
@@ -102,6 +103,7 @@ export interface ExtensionManager {
getSidebarTabs(): SidebarTabExtension[]
toast: ToastManager
dialog: ReturnType<typeof useDialogService>
command: CommandManager
setting: {
get: (id: string) => any