Skip to content

Commit

Permalink
Expose dialogService to extensionManager (#2113)
Browse files Browse the repository at this point in the history
  • Loading branch information
huchenlei authored Dec 31, 2024
1 parent 0b3c0cc commit 174a9a1
Show file tree
Hide file tree
Showing 11 changed files with 66 additions and 18 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down
20 changes: 20 additions & 0 deletions browser_tests/extensionAPI.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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!'
)
})
})
})
11 changes: 8 additions & 3 deletions browser_tests/fixtures/ComfyPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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()
}

Expand Down
4 changes: 1 addition & 3 deletions browser_tests/fixtures/utils/litegraphUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}`
Expand Down
2 changes: 1 addition & 1 deletion src/extensions/core/electronAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
2 changes: 1 addition & 1 deletion src/extensions/core/groupNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: ''
Expand Down
2 changes: 1 addition & 1 deletion src/extensions/core/nodeTemplates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: ''
Expand Down
8 changes: 4 additions & 4 deletions src/services/dialogService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const useDialogService = () => {
})
}

async function showPromptDialog({
async function prompt({
title,
message,
defaultValue = ''
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -161,7 +161,7 @@ export const useDialogService = () => {
showAboutDialog,
showExecutionErrorDialog,
showTemplateWorkflowsDialog,
showPromptDialog,
showConfirmationDialog
prompt,
confirm
}
}
10 changes: 5 additions & 5 deletions src/services/workflowService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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'),
Expand Down Expand Up @@ -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'),
Expand Down Expand Up @@ -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'),
Expand Down
3 changes: 3 additions & 0 deletions src/stores/workspaceStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -34,6 +35,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
}))
const workflow = computed(() => useWorkflowStore())
const colorPalette = useColorPaletteService()
const dialog = useDialogService()

/**
* Registers a sidebar tab.
Expand Down Expand Up @@ -76,6 +78,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
setting,
workflow,
colorPalette,
dialog,

registerSidebarTab,
unregisterSidebarTab,
Expand Down
2 changes: 2 additions & 0 deletions src/types/extensionTypes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component } from 'vue'

import type { useDialogService } from '@/services/dialogService'
import type { ComfyCommand } from '@/stores/commandStore'

export interface BaseSidebarTabExtension {
Expand Down Expand Up @@ -102,6 +103,7 @@ export interface ExtensionManager {
getSidebarTabs(): SidebarTabExtension[]

toast: ToastManager
dialog: ReturnType<typeof useDialogService>
command: CommandManager
setting: {
get: (id: string) => any
Expand Down

0 comments on commit 174a9a1

Please sign in to comment.