mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-02 14:27:40 +00:00
refactor: activation events + contributes
This commit is contained in:
committed by
Alexander Brown
parent
bb2c99749a
commit
f1856b7a17
@@ -1,5 +1,7 @@
|
||||
import { defineComfyExtConfig } from '@/extensions/utils'
|
||||
|
||||
export default defineComfyExtConfig({
|
||||
name: 'Comfy.Cloud.Badges',
|
||||
activationEvents: ['*'],
|
||||
comfyCloud: true,
|
||||
})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { defineComfyExtConfig } from '@/extensions/utils'
|
||||
|
||||
export default defineComfyExtConfig({
|
||||
name: 'Comfy.Cloud.FeedbackButton',
|
||||
activationEvents: ['*'],
|
||||
comfyCloud: true,
|
||||
})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { defineComfyExtConfig } from '@/extensions/utils'
|
||||
|
||||
export default defineComfyExtConfig({
|
||||
name: 'Comfy.Cloud.RemoteConfig',
|
||||
activationEvents: ['*'],
|
||||
comfyCloud: true,
|
||||
})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { defineComfyExtConfig } from '@/extensions/utils'
|
||||
|
||||
export default defineComfyExtConfig({
|
||||
name: 'Comfy.Cloud.SessionCookie',
|
||||
activationEvents: ['*'],
|
||||
comfyCloud: true,
|
||||
})
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { defineComfyExtConfig } from '@/extensions/utils'
|
||||
|
||||
export default defineComfyExtConfig({
|
||||
name: 'Comfy.Cloud.Subscription',
|
||||
activationEvents: ['*'],
|
||||
comfyCloud: {
|
||||
subscriptionRequired: true,
|
||||
},
|
||||
|
||||
111
src/extensions/core/extensions/load3d/comfy.ext.config.ts
Normal file
111
src/extensions/core/extensions/load3d/comfy.ext.config.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { defineComfyExtConfig } from '@/extensions/utils'
|
||||
|
||||
export default defineComfyExtConfig({
|
||||
name: 'Comfy.Load3D',
|
||||
activationEvents: ['onWidgets:contributes', 'onCommands:contributes', 'onSettings:contributes'],
|
||||
contributes: [
|
||||
{
|
||||
name: 'Comfy.Preview3D',
|
||||
widgets: ['PREVIEW_3D'],
|
||||
},
|
||||
{
|
||||
name: 'Comfy.Load3D',
|
||||
widgets: ['LOAD_3D'],
|
||||
settings: [
|
||||
{
|
||||
id: 'Comfy.Load3D.ShowGrid',
|
||||
category: ['3D', 'Scene', 'Initial Grid Visibility'],
|
||||
name: 'Initial Grid Visibility',
|
||||
tooltip:
|
||||
'Controls whether the grid is visible by default when a new 3D widget is created. This default can still be toggled individually for each widget after creation.',
|
||||
type: 'boolean',
|
||||
defaultValue: true,
|
||||
experimental: true
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Load3D.BackgroundColor',
|
||||
category: ['3D', 'Scene', 'Initial Background Color'],
|
||||
name: 'Initial Background Color',
|
||||
tooltip:
|
||||
'Controls the default background color of the 3D scene. This setting determines the background appearance when a new 3D widget is created, but can be adjusted individually for each widget after creation.',
|
||||
type: 'color',
|
||||
defaultValue: '282828',
|
||||
experimental: true
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Load3D.CameraType',
|
||||
category: ['3D', 'Camera', 'Initial Camera Type'],
|
||||
name: 'Initial Camera Type',
|
||||
tooltip:
|
||||
'Controls whether the camera is perspective or orthographic by default when a new 3D widget is created. This default can still be toggled individually for each widget after creation.',
|
||||
type: 'combo',
|
||||
options: ['perspective', 'orthographic'],
|
||||
defaultValue: 'perspective',
|
||||
experimental: true
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Load3D.LightIntensity',
|
||||
category: ['3D', 'Light', 'Initial Light Intensity'],
|
||||
name: 'Initial Light Intensity',
|
||||
tooltip:
|
||||
'Sets the default brightness level of lighting in the 3D scene. This value determines how intensely lights illuminate objects when a new 3D widget is created, but can be adjusted individually for each widget after creation.',
|
||||
type: 'number',
|
||||
defaultValue: 3,
|
||||
experimental: true
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Load3D.LightIntensityMaximum',
|
||||
category: ['3D', 'Light', 'Light Intensity Maximum'],
|
||||
name: 'Light Intensity Maximum',
|
||||
tooltip:
|
||||
'Sets the maximum allowable light intensity value for 3D scenes. This defines the upper brightness limit that can be set when adjusting lighting in any 3D widget.',
|
||||
type: 'number',
|
||||
defaultValue: 10,
|
||||
experimental: true
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Load3D.LightIntensityMinimum',
|
||||
category: ['3D', 'Light', 'Light Intensity Minimum'],
|
||||
name: 'Light Intensity Minimum',
|
||||
tooltip:
|
||||
'Sets the minimum allowable light intensity value for 3D scenes. This defines the lower brightness limit that can be set when adjusting lighting in any 3D widget.',
|
||||
type: 'number',
|
||||
defaultValue: 1,
|
||||
experimental: true
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Load3D.LightAdjustmentIncrement',
|
||||
category: ['3D', 'Light', 'Light Adjustment Increment'],
|
||||
name: 'Light Adjustment Increment',
|
||||
tooltip:
|
||||
'Controls the increment size when adjusting light intensity in 3D scenes. A smaller step value allows for finer control over lighting adjustments, while a larger value results in more noticeable changes per adjustment.',
|
||||
type: 'slider',
|
||||
attrs: {
|
||||
min: 0.1,
|
||||
max: 1,
|
||||
step: 0.1
|
||||
},
|
||||
defaultValue: 0.5,
|
||||
experimental: true
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Load3D.3DViewerEnable',
|
||||
category: ['3D', '3DViewer', 'Enable'],
|
||||
name: 'Enable 3D Viewer (Beta)',
|
||||
tooltip:
|
||||
'Enables the 3D Viewer (Beta) for selected nodes. This feature allows you to visualize and interact with 3D models directly within the full size 3d viewer.',
|
||||
type: 'boolean',
|
||||
defaultValue: false,
|
||||
experimental: true
|
||||
}
|
||||
],
|
||||
commands: [
|
||||
{
|
||||
id: 'Comfy.3DViewer.Open3DViewer',
|
||||
icon: 'pi pi-pencil',
|
||||
label: 'Open 3D Viewer (Beta) for Selected Node',
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
12
src/extensions/core/extensions/saveMesh/comfy.ext.config.ts
Normal file
12
src/extensions/core/extensions/saveMesh/comfy.ext.config.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { defineComfyExtConfig } from '@/extensions/utils'
|
||||
|
||||
export default defineComfyExtConfig({
|
||||
name: 'Comfy.SaveGLB',
|
||||
activationEvents: ['onWidgets:contributes', 'onCommands:contributes', 'onSettings:contributes'],
|
||||
contributes: [
|
||||
{
|
||||
name: 'Comfy.SaveGLB',
|
||||
widgets: ['SAVE_GLB'],
|
||||
},
|
||||
],
|
||||
})
|
||||
@@ -1,14 +1,15 @@
|
||||
import { dispatchComfyExtensions } from '../dispatch'
|
||||
import type { ComfyExtensionConfigs, ComfyExtensionEntrance } from '../types'
|
||||
|
||||
export async function importExtensions() {
|
||||
export async function registerExtensions() {
|
||||
console.log('importExtensions running...')
|
||||
|
||||
const extConfigs = import.meta.glob(`./extensions/*/comfy.ext.config.ts`, {
|
||||
// Since each config is small, we only import the default export and use eager mode for better tree-shaking and performance.
|
||||
import: 'default',
|
||||
eager: true,
|
||||
})
|
||||
const extensionEntrance = import.meta.glob(`./extensions/*/index.ts`)
|
||||
}) as ComfyExtensionConfigs
|
||||
const extensionEntrance = import.meta.glob(`./extensions/*/index.ts`) as ComfyExtensionEntrance
|
||||
|
||||
dispatchComfyExtensions({ configs: extConfigs, entrance: extensionEntrance })
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import type {
|
||||
ComfyExtensionEntrance,
|
||||
ComfyExtensionLoadContext
|
||||
} from './types'
|
||||
import { formatExtensions, shouldLoadExtension } from './utils'
|
||||
import { formatExtensions, normalizationActivationEvents } from './utils'
|
||||
|
||||
const extLoadContext: ComfyExtensionLoadContext = {
|
||||
get isCloud() {
|
||||
@@ -22,11 +22,61 @@ export async function dispatchComfyExtensions(options: {
|
||||
const { configs, entrance } = options
|
||||
const extensions = formatExtensions(entrance, configs)
|
||||
for (const extension of Object.values(extensions)) {
|
||||
if (shouldLoadExtension(extLoadContext, extension.config)) {
|
||||
const module = await extension.entry()
|
||||
console.log('✅ extension', extension.name, 'loaded', extension, module)
|
||||
// if (shouldLoadExtension(extLoadContext, extension.config)) {
|
||||
// const module = await extension.entry()
|
||||
// console.log('✅ extension', extension.name, 'loaded', extension, module)
|
||||
// } else {
|
||||
// console.log('❌ extension', extension.name, 'disabled', extension.config)
|
||||
// }
|
||||
const activationEvents = normalizationActivationEvents(
|
||||
extLoadContext,
|
||||
extension.config
|
||||
)
|
||||
if (!activationEvents.length) {
|
||||
console.log(
|
||||
'❌ extension',
|
||||
extension.name,
|
||||
'has no activation events',
|
||||
extension.config
|
||||
)
|
||||
} else {
|
||||
console.log('❌ extension', extension.name, 'disabled', extension.config)
|
||||
console.log(
|
||||
'🧶 extension',
|
||||
extension.name,
|
||||
'has activation events:',
|
||||
activationEvents
|
||||
)
|
||||
}
|
||||
activationEvents.forEach((event) =>
|
||||
onceExtImportEvent(event, async ({ event }) => {
|
||||
console.log(
|
||||
'✅ extension',
|
||||
extension.name,
|
||||
'loaded by',
|
||||
event,
|
||||
extension
|
||||
)
|
||||
await extension.entry()
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
type EventCallback = (ctx: { event: string }) => void | Promise<void>
|
||||
|
||||
const eventMap = new Map<string, Set<EventCallback>>()
|
||||
|
||||
export async function importExtensionsByEvent(event: string) {
|
||||
const callbacks = eventMap.get(event)
|
||||
if (!callbacks) return
|
||||
eventMap.delete(event)
|
||||
await Promise.all([...callbacks].map((cb) => cb({ event })))
|
||||
}
|
||||
|
||||
function onceExtImportEvent(event: string, callback: EventCallback) {
|
||||
if (eventMap.has(event)) {
|
||||
eventMap.get(event)!.add(callback)
|
||||
} else {
|
||||
eventMap.set(event, new Set([callback]))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,47 @@
|
||||
import type { ComfyExtension } from '@/types'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
type ExcludeFunctions<T> = T extends Function ? never : T
|
||||
type StaticOnly<T> = {
|
||||
// eslint-disable-next-line prettier/prettier
|
||||
[K in keyof T as ExcludeFunctions<T[K]> extends never ? never : K]: ExcludeFunctions<T[K]>
|
||||
}
|
||||
|
||||
type StaticComfyCommand = StaticOnly<
|
||||
NonNullable<ComfyExtension['commands']>[number]
|
||||
>
|
||||
type StaticComfySettingParams = StaticOnly<
|
||||
NonNullable<ComfyExtension['settings']>[number]
|
||||
>
|
||||
type StaticComfyKeybinding = StaticOnly<
|
||||
NonNullable<ComfyExtension['keybindings']>[number]
|
||||
>
|
||||
type StaticComfyMenuCommandGroup = StaticOnly<
|
||||
NonNullable<ComfyExtension['menuCommands']>[number]
|
||||
>
|
||||
|
||||
export type ComfyExtensionActivationEvent =
|
||||
| '*'
|
||||
| 'onWidgets:contributes'
|
||||
| 'onCommands:contributes'
|
||||
| 'onSettings:contributes'
|
||||
|
||||
type ComfyExtensionContributes = {
|
||||
name: string
|
||||
widgets?: string[]
|
||||
commands?: StaticComfyCommand[]
|
||||
settings?: StaticComfySettingParams[]
|
||||
keybindings?: StaticComfyKeybinding[]
|
||||
}
|
||||
|
||||
export interface ComfyExtensionConfig {
|
||||
name?: string
|
||||
|
||||
activationEvents: ComfyExtensionActivationEvent[]
|
||||
|
||||
contributes?: ComfyExtensionContributes | ComfyExtensionContributes[]
|
||||
menuCommands?: StaticComfyMenuCommandGroup[]
|
||||
|
||||
comfyCloud?:
|
||||
| boolean
|
||||
| {
|
||||
|
||||
@@ -39,13 +39,64 @@ export function formatExtensions(
|
||||
return pkgs
|
||||
}
|
||||
|
||||
export function shouldLoadExtension(
|
||||
export function normalizationActivationEvents(
|
||||
ctx: ComfyExtensionLoadContext,
|
||||
extConfig: ComfyExtensionConfig | undefined
|
||||
): boolean {
|
||||
// No Config -> Load Extension
|
||||
if (!extConfig) return true
|
||||
config: ComfyExtensionConfig | undefined
|
||||
): string[] {
|
||||
if (!config) return ['*']
|
||||
|
||||
if (!checkAboutCloud(ctx, config)) return []
|
||||
|
||||
const { activationEvents, contributes: _contributes } = config
|
||||
|
||||
if (activationEvents.includes('*')) return ['*']
|
||||
|
||||
const contributes = _contributes
|
||||
? Array.isArray(_contributes)
|
||||
? _contributes
|
||||
: [_contributes]
|
||||
: []
|
||||
|
||||
const events: string[] = []
|
||||
|
||||
if (activationEvents.includes('onCommands:contributes')) {
|
||||
for (const contribute of contributes) {
|
||||
if (contribute.commands) {
|
||||
for (const command of contribute.commands) {
|
||||
events.push(`onCommands:${command}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (activationEvents.includes('onSettings:contributes')) {
|
||||
for (const contribute of contributes) {
|
||||
if (contribute.settings) {
|
||||
for (const setting of contribute.settings) {
|
||||
events.push(`onSettings:${setting.id}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (activationEvents.includes('onWidgets:contributes')) {
|
||||
for (const contribute of contributes) {
|
||||
events.push(`onWidgets:${contribute.name}`)
|
||||
if (contribute.widgets) {
|
||||
for (const widget of contribute.widgets) {
|
||||
events.push(`onWidgets:${widget}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return events
|
||||
}
|
||||
|
||||
function checkAboutCloud(
|
||||
ctx: ComfyExtensionLoadContext,
|
||||
extConfig: ComfyExtensionConfig
|
||||
): boolean {
|
||||
// Cloud Only Extension
|
||||
const { comfyCloud } = extConfig
|
||||
if (comfyCloud) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useWidgetStore } from '@/stores/widgetStore'
|
||||
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'
|
||||
import type { ComfyExtension } from '@/types/comfy'
|
||||
import type { AuthUserInfo } from '@/types/authTypes'
|
||||
import { importExtensionsByEvent } from '@/extensions/dispatch'
|
||||
|
||||
export const useExtensionService = () => {
|
||||
const extensionStore = useExtensionStore()
|
||||
@@ -35,8 +36,12 @@ export const useExtensionService = () => {
|
||||
|
||||
// Need to load core extensions first as some custom extensions
|
||||
// may depend on them.
|
||||
const { importExtensions } = await import('../extensions/core/index')
|
||||
await importExtensions()
|
||||
const { registerExtensions } = await import('../extensions/core/index')
|
||||
await registerExtensions()
|
||||
|
||||
// Import Immediately Loaded Extensions
|
||||
await importExtensionsByEvent('*')
|
||||
|
||||
extensionStore.captureCoreExtensions()
|
||||
await Promise.all(
|
||||
extensions
|
||||
|
||||
Reference in New Issue
Block a user