mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 10:59:53 +00:00
feat: add settings option to always show advanced widgets on all nodes (#8244)
Solved issue: Currently, the display status of advanced widgets can only be set individually for each node, but users would like to have a global switch to always display all advanced widgets. I also adjusted some related code to solve the issue of code duplication. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8244-feat-add-settings-option-to-always-show-advanced-widgets-on-all-nodes-2f06d73d365081358023efa3e1ff3094) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -8,7 +8,7 @@ import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
||||
import FormSearchInput from '@/renderer/extensions/vueNodes/widgets/components/form/FormSearchInput.vue'
|
||||
import { useRightSidePanelStore } from '@/stores/workspace/rightSidePanelStore'
|
||||
|
||||
import { searchWidgetsAndNodes } from '../shared'
|
||||
import { computedSectionDataList, searchWidgetsAndNodes } from '../shared'
|
||||
import type { NodeWidgetsListList } from '../shared'
|
||||
import SectionWidgets from './SectionWidgets.vue'
|
||||
|
||||
@@ -24,18 +24,7 @@ const nodes = computed((): LGraphNode[] => {
|
||||
const rightSidePanelStore = useRightSidePanelStore()
|
||||
const { searchQuery } = storeToRefs(rightSidePanelStore)
|
||||
|
||||
const widgetsSectionDataList = computed((): NodeWidgetsListList => {
|
||||
return nodes.value.map((node) => {
|
||||
const { widgets = [] } = node
|
||||
const shownWidgets = widgets
|
||||
.filter((w) => !(w.options?.canvasOnly || w.options?.hidden))
|
||||
.map((widget) => ({ node, widget }))
|
||||
return {
|
||||
widgets: shownWidgets,
|
||||
node
|
||||
}
|
||||
})
|
||||
})
|
||||
const { widgetsSectionDataList } = computedSectionDataList(nodes)
|
||||
|
||||
const searchedWidgetsSectionDataList = shallowRef<NodeWidgetsListList>(
|
||||
widgetsSectionDataList.value
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import FormSearchInput from '@/renderer/extensions/vueNodes/widgets/components/form/FormSearchInput.vue'
|
||||
import { useRightSidePanelStore } from '@/stores/workspace/rightSidePanelStore'
|
||||
|
||||
import { searchWidgetsAndNodes } from '../shared'
|
||||
import { computedSectionDataList, searchWidgetsAndNodes } from '../shared'
|
||||
import type { NodeWidgetsListList } from '../shared'
|
||||
import SectionWidgets from './SectionWidgets.vue'
|
||||
|
||||
@@ -21,21 +21,14 @@ const { t } = useI18n()
|
||||
const rightSidePanelStore = useRightSidePanelStore()
|
||||
const { searchQuery } = storeToRefs(rightSidePanelStore)
|
||||
|
||||
const widgetsSectionDataList = computed((): NodeWidgetsListList => {
|
||||
return nodes.map((node) => {
|
||||
const { widgets = [] } = node
|
||||
const shownWidgets = widgets
|
||||
.filter(
|
||||
(w) =>
|
||||
!(w.options?.canvasOnly || w.options?.hidden || w.options?.advanced)
|
||||
)
|
||||
.map((widget) => ({ node, widget }))
|
||||
|
||||
return { widgets: shownWidgets, node }
|
||||
})
|
||||
})
|
||||
const { widgetsSectionDataList, includesAdvanced } = computedSectionDataList(
|
||||
() => nodes
|
||||
)
|
||||
|
||||
const advancedWidgetsSectionDataList = computed((): NodeWidgetsListList => {
|
||||
if (includesAdvanced.value) {
|
||||
return []
|
||||
}
|
||||
return nodes
|
||||
.map((node) => {
|
||||
const { widgets = [] } = node
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import InputNumber from 'primevue/inputnumber'
|
||||
import Select from 'primevue/select'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import Button from '@/components/ui/button/Button.vue'
|
||||
@@ -23,7 +23,11 @@ const settingStore = useSettingStore()
|
||||
const dialogService = useDialogService()
|
||||
|
||||
// NODES settings
|
||||
const showAdvancedParameters = ref(false) // Placeholder for future implementation
|
||||
const showAdvancedParameters = computed({
|
||||
get: () => settingStore.get('Comfy.Node.AlwaysShowAdvancedWidgets'),
|
||||
set: (value) =>
|
||||
settingStore.set('Comfy.Node.AlwaysShowAdvancedWidgets', value)
|
||||
})
|
||||
|
||||
const showToolbox = computed({
|
||||
get: () => settingStore.get('Comfy.Canvas.SelectionToolbox'),
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { LGraphGroup } from '@/lib/litegraph/src/LGraphGroup'
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
|
||||
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
|
||||
import { isLGraphGroup, isLGraphNode } from '@/utils/litegraphUtil'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
|
||||
export const GetNodeParentGroupKey: InjectionKey<
|
||||
(node: LGraphNode) => LGraphGroup | null
|
||||
@@ -203,3 +204,33 @@ function repeatItems<T>(items: T[]): T[] {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export function computedSectionDataList(nodes: MaybeRefOrGetter<LGraphNode[]>) {
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
const includesAdvanced = computed(() =>
|
||||
settingStore.get('Comfy.Node.AlwaysShowAdvancedWidgets')
|
||||
)
|
||||
|
||||
const widgetsSectionDataList = computed((): NodeWidgetsListList => {
|
||||
return toValue(nodes).map((node) => {
|
||||
const { widgets = [] } = node
|
||||
const shownWidgets = widgets
|
||||
.filter(
|
||||
(w) =>
|
||||
!(
|
||||
w.options?.canvasOnly ||
|
||||
w.options?.hidden ||
|
||||
(w.options?.advanced && !includesAdvanced.value)
|
||||
)
|
||||
)
|
||||
.map((widget) => ({ node, widget }))
|
||||
return { widgets: shownWidgets, node }
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
widgetsSectionDataList,
|
||||
includesAdvanced
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2683,7 +2683,8 @@
|
||||
"noneSearchDesc": "No items match your search",
|
||||
"nodesNoneDesc": "NO NODES",
|
||||
"fallbackGroupTitle": "Group",
|
||||
"fallbackNodeTitle": "Node"
|
||||
"fallbackNodeTitle": "Node",
|
||||
"hideAdvancedInputsButton": "Hide advanced inputs"
|
||||
},
|
||||
"help": {
|
||||
"recentReleases": "Recent releases",
|
||||
|
||||
@@ -1174,5 +1174,15 @@ export const CORE_SETTINGS: SettingParams[] = [
|
||||
'Replaces the floating job queue panel with an equivalent job queue embedded in the Assets side panel. You can disable this to return to the floating panel layout.',
|
||||
defaultValue: true,
|
||||
experimental: true
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Node.AlwaysShowAdvancedWidgets',
|
||||
category: ['LiteGraph', 'Node Widget', 'AlwaysShowAdvancedWidgets'],
|
||||
name: 'Always show advanced widgets on all nodes',
|
||||
tooltip:
|
||||
'When enabled, advanced widgets are always visible on all nodes without needing to expand them individually.',
|
||||
type: 'boolean',
|
||||
defaultValue: false,
|
||||
versionAdded: '1.39.0'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -130,10 +130,16 @@
|
||||
'transition-all cursor-pointer hover:bg-accent-background duration-150 active:scale-95'
|
||||
)
|
||||
"
|
||||
@click.stop="handleShowAdvancedInputs"
|
||||
@click.stop="showAdvancedState = !showAdvancedState"
|
||||
>
|
||||
<template v-if="showAdvancedState">
|
||||
<i class="icon-[lucide--chevron-up] size-4" />
|
||||
<span>{{ t('rightSidePanel.hideAdvancedInputsButton') }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<i class="icon-[lucide--settings-2] size-4" />
|
||||
<span>{{ t('rightSidePanel.showAdvancedInputsButton') }}</span>
|
||||
<span>{{ t('rightSidePanel.showAdvancedInputsButton') }} </span>
|
||||
</template>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -152,7 +158,15 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, nextTick, onErrorCaptured, onMounted, ref, watch } from 'vue'
|
||||
import {
|
||||
computed,
|
||||
customRef,
|
||||
nextTick,
|
||||
onErrorCaptured,
|
||||
onMounted,
|
||||
ref,
|
||||
watch
|
||||
} from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import type { VueNodeData } from '@/composables/graph/useGraphNodeManager'
|
||||
@@ -212,6 +226,8 @@ const { nodeData, error = null } = defineProps<LGraphNodeProps>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
const { handleNodeCollapse, handleNodeTitleUpdate, handleNodeRightClick } =
|
||||
useNodeEventHandlers()
|
||||
const { bringNodeToFront } = useNodeZIndex()
|
||||
@@ -248,7 +264,7 @@ const bypassed = computed(
|
||||
const muted = computed((): boolean => nodeData.mode === LGraphEventMode.NEVER)
|
||||
|
||||
const nodeOpacity = computed(() => {
|
||||
const globalOpacity = useSettingStore().get('Comfy.Node.Opacity') ?? 1
|
||||
const globalOpacity = settingStore.get('Comfy.Node.Opacity') ?? 1
|
||||
|
||||
// For muted/bypassed nodes, apply the 0.5 multiplier on top of global opacity
|
||||
if (bypassed.value || muted.value) {
|
||||
@@ -493,20 +509,45 @@ const showAdvancedInputsButton = computed(() => {
|
||||
|
||||
// For regular nodes: show button if there are advanced widgets and they're currently hidden
|
||||
const hasAdvancedWidgets = nodeData.widgets?.some((w) => w.options?.advanced)
|
||||
return hasAdvancedWidgets && !node.showAdvanced
|
||||
const alwaysShowAdvanced = settingStore.get(
|
||||
'Comfy.Node.AlwaysShowAdvancedWidgets'
|
||||
)
|
||||
return hasAdvancedWidgets && !alwaysShowAdvanced
|
||||
})
|
||||
|
||||
function handleShowAdvancedInputs() {
|
||||
const showAdvancedState = customRef((track, trigger) => {
|
||||
let internalState = false
|
||||
|
||||
const node = lgraphNode.value
|
||||
if (node && !(node instanceof SubgraphNode)) {
|
||||
internalState = !!node.showAdvanced
|
||||
}
|
||||
|
||||
return {
|
||||
get() {
|
||||
track()
|
||||
return internalState
|
||||
},
|
||||
set(value: boolean) {
|
||||
const node = lgraphNode.value
|
||||
if (!node) return
|
||||
|
||||
if (node instanceof SubgraphNode) {
|
||||
// Do not modify internalState for subgraph nodes
|
||||
const rightSidePanelStore = useRightSidePanelStore()
|
||||
if (value) {
|
||||
rightSidePanelStore.focusSection('advanced-inputs')
|
||||
} else {
|
||||
node.showAdvanced = true
|
||||
rightSidePanelStore.closePanel()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node.showAdvanced = value
|
||||
internalState = value
|
||||
}
|
||||
trigger()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const nodeMedia = computed(() => {
|
||||
const newOutputs = nodeOutputs.nodeOutputs[nodeOutputLocatorId.value]
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<div
|
||||
v-if="
|
||||
!widget.simplified.options?.hidden &&
|
||||
(!widget.simplified.options?.advanced || nodeData?.showAdvanced)
|
||||
(!widget.simplified.options?.advanced || showAdvanced)
|
||||
"
|
||||
class="lg-node-widget group col-span-full grid grid-cols-subgrid items-stretch"
|
||||
>
|
||||
@@ -78,6 +78,7 @@ import type {
|
||||
VueNodeData,
|
||||
WidgetSlotMetadata
|
||||
} from '@/composables/graph/useGraphNodeManager'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useErrorHandling } from '@/composables/useErrorHandling'
|
||||
import { st } from '@/i18n'
|
||||
import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
|
||||
@@ -130,6 +131,12 @@ onErrorCaptured((error) => {
|
||||
})
|
||||
|
||||
const nodeType = computed(() => nodeData?.type || '')
|
||||
const settingStore = useSettingStore()
|
||||
const showAdvanced = computed(
|
||||
() =>
|
||||
nodeData?.showAdvanced ||
|
||||
settingStore.get('Comfy.Node.AlwaysShowAdvancedWidgets')
|
||||
)
|
||||
const { getWidgetTooltip, createTooltipConfig } = useNodeTooltips(
|
||||
nodeType.value
|
||||
)
|
||||
@@ -213,7 +220,7 @@ const gridTemplateRows = computed((): string => {
|
||||
(w) =>
|
||||
processedNames.has(w.name) &&
|
||||
!w.options?.hidden &&
|
||||
(!w.options?.advanced || nodeData?.showAdvanced)
|
||||
(!w.options?.advanced || showAdvanced.value)
|
||||
)
|
||||
.map((w) =>
|
||||
shouldExpand(w.type) || w.hasLayoutSize ? 'auto' : 'min-content'
|
||||
|
||||
@@ -430,7 +430,8 @@ const zSettings = z.object({
|
||||
'LiteGraph.Node.DefaultPadding': z.boolean(),
|
||||
'LiteGraph.Pointer.TrackpadGestures': z.boolean(),
|
||||
'Comfy.VersionCompatibility.DisableWarnings': z.boolean(),
|
||||
'Comfy.RightSidePanel.IsOpen': z.boolean()
|
||||
'Comfy.RightSidePanel.IsOpen': z.boolean(),
|
||||
'Comfy.Node.AlwaysShowAdvancedWidgets': z.boolean()
|
||||
})
|
||||
|
||||
export type EmbeddingsResponse = z.infer<typeof zEmbeddingsResponse>
|
||||
|
||||
Reference in New Issue
Block a user