[ExtensionPanel] Distinguish core and 3rd party extensions (#2020)

This commit is contained in:
Chenlei Hu
2024-12-22 19:41:28 -05:00
committed by GitHub
parent b81ccc0507
commit 920266e1ff
3 changed files with 79 additions and 20 deletions

View File

@@ -5,7 +5,12 @@
v-model="filters['global'].value" v-model="filters['global'].value"
:placeholder="$t('g.searchExtensions') + '...'" :placeholder="$t('g.searchExtensions') + '...'"
/> />
<Message v-if="hasChanges" severity="info" pt:text="w-full"> <Message
v-if="hasChanges"
severity="info"
pt:text="w-full"
class="max-h-96 overflow-y-auto"
>
<ul> <ul>
<li v-for="ext in changedExtensions" :key="ext.name"> <li v-for="ext in changedExtensions" :key="ext.name">
<span> <span>
@@ -30,7 +35,15 @@
size="small" size="small"
:filters="filters" :filters="filters"
> >
<Column field="name" :header="$t('g.extensionName')" sortable></Column> <Column :header="$t('g.extensionName')" sortable>
<template #body="slotProps">
{{ slotProps.data.name }}
<Tag
v-if="extensionStore.isCoreExtension(slotProps.data.name)"
value="Core"
/>
</template>
</Column>
<Column <Column
:pt="{ :pt="{
headerCell: 'flex items-center justify-end', headerCell: 'flex items-center justify-end',
@@ -48,9 +61,7 @@
</template> </template>
<template #body="slotProps"> <template #body="slotProps">
<ToggleSwitch <ToggleSwitch
:disabled=" :disabled="extensionStore.isExtensionReadOnly(slotProps.data.name)"
extensionStore.isExtensionAlwaysEnabled(slotProps.data.name)
"
v-model="editingEnabledExtensions[slotProps.data.name]" v-model="editingEnabledExtensions[slotProps.data.name]"
@change="updateExtensionStatus" @change="updateExtensionStatus"
/> />
@@ -67,6 +78,7 @@ import { useSettingStore } from '@/stores/settingStore'
import DataTable from 'primevue/datatable' import DataTable from 'primevue/datatable'
import Column from 'primevue/column' import Column from 'primevue/column'
import ToggleSwitch from 'primevue/toggleswitch' import ToggleSwitch from 'primevue/toggleswitch'
import Tag from 'primevue/tag'
import Button from 'primevue/button' import Button from 'primevue/button'
import ContextMenu from 'primevue/contextmenu' import ContextMenu from 'primevue/contextmenu'
import Message from 'primevue/message' import Message from 'primevue/message'
@@ -117,6 +129,8 @@ const updateExtensionStatus = () => {
const enableAllExtensions = () => { const enableAllExtensions = () => {
extensionStore.extensions.forEach((ext) => { extensionStore.extensions.forEach((ext) => {
if (extensionStore.isExtensionReadOnly(ext.name)) return
editingEnabledExtensions.value[ext.name] = true editingEnabledExtensions.value[ext.name] = true
}) })
updateExtensionStatus() updateExtensionStatus()
@@ -124,7 +138,16 @@ const enableAllExtensions = () => {
const disableAllExtensions = () => { const disableAllExtensions = () => {
extensionStore.extensions.forEach((ext) => { extensionStore.extensions.forEach((ext) => {
if (extensionStore.isExtensionAlwaysEnabled(ext.name)) return if (extensionStore.isExtensionReadOnly(ext.name)) return
editingEnabledExtensions.value[ext.name] = false
})
updateExtensionStatus()
}
const disableThirdPartyExtensions = () => {
extensionStore.extensions.forEach((ext) => {
if (extensionStore.isCoreExtension(ext.name)) return
editingEnabledExtensions.value[ext.name] = false editingEnabledExtensions.value[ext.name] = false
}) })
@@ -147,6 +170,12 @@ const contextMenuItems = [
label: 'Disable All', label: 'Disable All',
icon: 'pi pi-times', icon: 'pi pi-times',
command: disableAllExtensions command: disableAllExtensions
},
{
label: 'Disable 3rd Party',
icon: 'pi pi-times',
command: disableThirdPartyExtensions,
disabled: !extensionStore.hasThirdPartyExtensions
} }
] ]
</script> </script>

View File

@@ -1640,13 +1640,15 @@ export class ComfyApp {
* Loads all extensions from the API into the window in parallel * Loads all extensions from the API into the window in parallel
*/ */
async #loadExtensions() { async #loadExtensions() {
useExtensionStore().loadDisabledExtensionNames() const extensionStore = useExtensionStore()
extensionStore.loadDisabledExtensionNames()
const extensions = await api.getExtensions() const extensions = await api.getExtensions()
// Need to load core extensions first as some custom extensions // Need to load core extensions first as some custom extensions
// may depend on them. // may depend on them.
await import('../extensions/core/index') await import('../extensions/core/index')
extensionStore.captureCoreExtensions()
await Promise.all( await Promise.all(
extensions extensions
.filter((extension) => !extension.includes('extensions/core')) .filter((extension) => !extension.includes('extensions/core'))

View File

@@ -19,6 +19,17 @@ export const ALWAYS_ENABLED_EXTENSIONS: readonly string[] = [
'Comfy.ColorPalette' 'Comfy.ColorPalette'
] ]
export const ALWAYS_DISABLED_EXTENSIONS: readonly string[] = [
// pysssss.Locking is replaced by pin/unpin in ComfyUI core.
// https://github.com/Comfy-Org/litegraph.js/pull/117
'pysssss.Locking',
// pysssss.SnapToGrid is replaced by Comfy.Graph.AlwaysSnapToGrid in ComfyUI core.
// pysssss.SnapToGrid tries to write global app.shiftDown state, which is no longer
// allowed since v1.3.12.
// https://github.com/Comfy-Org/ComfyUI_frontend/issues/1176
'pysssss.SnapToGrid'
]
export const useExtensionStore = defineStore('extension', () => { export const useExtensionStore = defineStore('extension', () => {
// For legacy reasons, the name uniquely identifies an extension // For legacy reasons, the name uniquely identifies an extension
const extensionByName = ref<Record<string, ComfyExtension>>({}) const extensionByName = ref<Record<string, ComfyExtension>>({})
@@ -42,8 +53,11 @@ export const useExtensionStore = defineStore('extension', () => {
return extensions.value.filter((ext) => isExtensionEnabled(ext.name)) return extensions.value.filter((ext) => isExtensionEnabled(ext.name))
}) })
function isExtensionAlwaysEnabled(name: string) { function isExtensionReadOnly(name: string) {
return ALWAYS_ENABLED_EXTENSIONS.includes(name) return (
ALWAYS_DISABLED_EXTENSIONS.includes(name) ||
ALWAYS_ENABLED_EXTENSIONS.includes(name)
)
} }
function registerExtension(extension: ComfyExtension) { function registerExtension(extension: ComfyExtension) {
@@ -86,20 +100,31 @@ export const useExtensionStore = defineStore('extension', () => {
disabledExtensionNames.value = new Set( disabledExtensionNames.value = new Set(
useSettingStore().get('Comfy.Extension.Disabled') useSettingStore().get('Comfy.Extension.Disabled')
) )
// pysssss.Locking is replaced by pin/unpin in ComfyUI core. for (const name of ALWAYS_DISABLED_EXTENSIONS) {
// https://github.com/Comfy-Org/litegraph.js/pull/117 disabledExtensionNames.value.add(name)
disabledExtensionNames.value.add('pysssss.Locking') }
// pysssss.SnapToGrid is replaced by Comfy.Graph.AlwaysSnapToGrid in ComfyUI core.
// pysssss.SnapToGrid tries to write global app.shiftDown state, which is no longer
// allowed since v1.3.12.
// https://github.com/Comfy-Org/ComfyUI_frontend/issues/1176
disabledExtensionNames.value.add('pysssss.SnapToGrid')
for (const name of ALWAYS_ENABLED_EXTENSIONS) { for (const name of ALWAYS_ENABLED_EXTENSIONS) {
disabledExtensionNames.value.delete(name) disabledExtensionNames.value.delete(name)
} }
} }
/**
* Core extensions are extensions that are defined in the core package.
* See /extensions/core/index.ts for the list.
*/
const coreExtensionNames = ref<string[]>([])
function captureCoreExtensions() {
coreExtensionNames.value = app.extensions.map((ext) => ext.name)
}
function isCoreExtension(name: string) {
return coreExtensionNames.value.includes(name)
}
const hasThirdPartyExtensions = computed(() => {
return extensions.value.some((ext) => !isCoreExtension(ext.name))
})
// Some core extensions are registered before the store is initialized, e.g. // Some core extensions are registered before the store is initialized, e.g.
// colorPalette. // colorPalette.
// Register them manually here so the state of app.extensions and // Register them manually here so the state of app.extensions and
@@ -113,8 +138,11 @@ export const useExtensionStore = defineStore('extension', () => {
enabledExtensions, enabledExtensions,
inactiveDisabledExtensionNames, inactiveDisabledExtensionNames,
isExtensionEnabled, isExtensionEnabled,
isExtensionAlwaysEnabled, isExtensionReadOnly,
registerExtension, registerExtension,
loadDisabledExtensionNames loadDisabledExtensionNames,
captureCoreExtensions,
isCoreExtension,
hasThirdPartyExtensions
} }
}) })