From 957a767ed0bf64c7c5f2b47a706b8aa9c9c582ce Mon Sep 17 00:00:00 2001 From: Chenlei Hu Date: Thu, 24 Oct 2024 16:26:01 +0200 Subject: [PATCH] New settings API (#1292) * Add settings API * Add playwright test * Update README --- README.md | 48 +++++++++++++++++++++++++++++- browser_tests/ComfyPage.ts | 4 +-- browser_tests/extensionAPI.spec.ts | 19 ++++++++++++ src/scripts/ui/settings.ts | 17 +++++++++++ src/stores/extensionStore.ts | 1 + src/stores/settingStore.ts | 7 +++++ src/stores/workspaceStateStore.ts | 7 +++++ src/types/comfy.d.ts | 5 ++++ src/types/extensionTypes.ts | 5 +++- 9 files changed, 109 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b7f0b6312..e6d1ad4cc 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,53 @@ https://github.com/user-attachments/assets/c142c43f-2fe9-4030-8196-b3bfd4c6977d https://github.com/user-attachments/assets/5696a89d-4a47-4fcc-9e8c-71e1264943f2 -### Node developers API +### Developer APIs + +
+ v1.3.22: New settings API + +Legacy settings API. + +```js +// Register a new setting +app.ui.settings.addSetting({ + id: 'TestSetting', + name: 'Test Setting', + type: 'text', + defaultValue: 'Hello, world!' +}) + +// Get the value of a setting +const value = app.ui.settings.getSettingValue('TestSetting') + +// Set the value of a setting +app.ui.settings.setSettingValue('TestSetting', 'Hello, universe!') +``` + +New settings API. + +```js +// Register a new setting +app.registerExtension({ + name: 'TestExtension1', + settings: [ + { + id: 'TestSetting', + name: 'Test Setting', + type: 'text', + defaultValue: 'Hello, world!' + } + ] +}) + +// Get the value of a setting +const value = app.extensionManager.setting.get('TestSetting') + +// Set the value of a setting +app.extensionManager.setting.set('TestSetting', 'Hello, universe!') +``` + +
v1.3.7: Register commands and keybindings diff --git a/browser_tests/ComfyPage.ts b/browser_tests/ComfyPage.ts index 7c4d13644..b4f92d669 100644 --- a/browser_tests/ComfyPage.ts +++ b/browser_tests/ComfyPage.ts @@ -528,7 +528,7 @@ export class ComfyPage { async setSetting(settingId: string, settingValue: any) { return await this.page.evaluate( async ({ id, value }) => { - await window['app'].ui.settings.setSettingValueAsync(id, value) + await window['app'].extensionManager.setting.set(id, value) }, { id: settingId, value: settingValue } ) @@ -536,7 +536,7 @@ export class ComfyPage { async getSetting(settingId: string) { return await this.page.evaluate(async (id) => { - return await window['app'].ui.settings.getSettingValue(id) + return await window['app'].extensionManager.setting.get(id) }, settingId) } diff --git a/browser_tests/extensionAPI.spec.ts b/browser_tests/extensionAPI.spec.ts index 4c028ab60..ff7977210 100644 --- a/browser_tests/extensionAPI.spec.ts +++ b/browser_tests/extensionAPI.spec.ts @@ -83,4 +83,23 @@ test.describe('Topbar commands', () => { true ) }) + + test('Should allow adding settings', async ({ comfyPage }) => { + await comfyPage.page.evaluate(() => { + window['app'].registerExtension({ + name: 'TestExtension1', + settings: [ + { + id: 'TestSetting', + name: 'Test Setting', + type: 'text', + defaultValue: 'Hello, world!' + } + ] + }) + }) + expect(await comfyPage.getSetting('TestSetting')).toBe('Hello, world!') + await comfyPage.setSetting('TestSetting', 'Hello, universe!') + expect(await comfyPage.getSetting('TestSetting')).toBe('Hello, universe!') + }) }) diff --git a/src/scripts/ui/settings.ts b/src/scripts/ui/settings.ts index 5cade7b5b..8121f474b 100644 --- a/src/scripts/ui/settings.ts +++ b/src/scripts/ui/settings.ts @@ -169,6 +169,23 @@ export class ComfySettingsDialog extends ComfyDialog { this.#dispatchChange(id, value) } + /** + * Deprecated for external callers/extensions. Use `ComfyExtension.settings` field instead. + * Example: + * ```ts + * app.registerExtension({ + * name: 'My Extension', + * settings: [ + * { + * id: 'My.Setting', + * name: 'My Setting', + * type: 'text', + * defaultValue: 'Hello, world!' + * } + * ] + * }) + * ``` + */ addSetting(params: SettingParams) { const { id, diff --git a/src/stores/extensionStore.ts b/src/stores/extensionStore.ts index 440c3147d..dc02284f4 100644 --- a/src/stores/extensionStore.ts +++ b/src/stores/extensionStore.ts @@ -47,6 +47,7 @@ export const useExtensionStore = defineStore('extension', () => { useKeybindingStore().loadExtensionKeybindings(extension) useCommandStore().loadExtensionCommands(extension) useMenuItemStore().loadExtensionMenuCommands(extension) + useSettingStore().loadExtensionSettings(extension) /* * Extensions are currently stored in both extensionStore and app.extensions. diff --git a/src/stores/settingStore.ts b/src/stores/settingStore.ts index c44957937..220271233 100644 --- a/src/stores/settingStore.ts +++ b/src/stores/settingStore.ts @@ -16,6 +16,7 @@ import { buildTree } from '@/utils/treeUtil' import { defineStore } from 'pinia' import type { TreeNode } from 'primevue/treenode' import { CORE_SETTINGS } from '@/stores/coreSettings' +import { ComfyExtension } from '@/types/comfy' export interface SettingTreeNode extends TreeNode { data?: SettingParams @@ -68,6 +69,12 @@ export const useSettingStore = defineStore('setting', { }) }, + loadExtensionSettings(extension: ComfyExtension) { + extension.settings?.forEach((setting: SettingParams) => { + app.ui.settings.addSetting(setting) + }) + }, + async set(key: K, value: Settings[K]) { this.settingValues[key] = value await app.ui.settings.setSettingValueAsync(key, value) diff --git a/src/stores/workspaceStateStore.ts b/src/stores/workspaceStateStore.ts index 07127fd5d..32683c831 100644 --- a/src/stores/workspaceStateStore.ts +++ b/src/stores/workspaceStateStore.ts @@ -4,6 +4,7 @@ import { useToastStore } from './toastStore' import { useQueueSettingsStore } from './queueStore' import { useCommandStore } from './commandStore' import { useSidebarTabStore } from './workspace/sidebarTabStore' +import { useSettingStore } from './settingStore' interface WorkspaceState { spinner: boolean @@ -30,6 +31,12 @@ export const useWorkspaceStore = defineStore('workspace', { }, sidebarTab() { return useSidebarTabStore() + }, + setting() { + return { + get: useSettingStore().get, + set: useSettingStore().set + } } }, actions: { diff --git a/src/types/comfy.d.ts b/src/types/comfy.d.ts index ddec8d0e7..2e3b9c46b 100644 --- a/src/types/comfy.d.ts +++ b/src/types/comfy.d.ts @@ -3,6 +3,7 @@ import { ComfyApp } from '../scripts/app' import type { ComfyNodeDef } from '@/types/apiTypes' import type { Keybinding } from '@/types/keyBindingTypes' import type { ComfyCommand } from '@/stores/commandStore' +import { SettingParams } from './settingTypes' export type Widgets = Record< string, @@ -43,6 +44,10 @@ export interface ComfyExtension { * Menu commands to add to the menu bar */ menuCommands?: MenuCommandGroup[] + /** + * Settings to add to the settings menu + */ + settings?: SettingParams[] /** * Allows any initialisation, e.g. loading resources. Called after the canvas is created but before nodes are added * @param app The ComfyUI app instance diff --git a/src/types/extensionTypes.ts b/src/types/extensionTypes.ts index 1e71f6b11..5cfb393ab 100644 --- a/src/types/extensionTypes.ts +++ b/src/types/extensionTypes.ts @@ -37,9 +37,12 @@ export interface ExtensionManager { unregisterSidebarTab(id: string): void getSidebarTabs(): SidebarTabExtension[] - // Toast toast: ToastManager command: CommandManager + setting: { + get: (id: string) => any + set: (id: string, value: any) => void + } } export interface CommandManager {