mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 03:01:54 +00:00
Move widget configuration out of sidebar
This commit is contained in:
@@ -22,7 +22,8 @@
|
|||||||
<ColorPickerButton v-if="showColorPicker" />
|
<ColorPickerButton v-if="showColorPicker" />
|
||||||
<FrameNodes v-if="showFrameNodes" />
|
<FrameNodes v-if="showFrameNodes" />
|
||||||
<ConvertToSubgraphButton v-if="showConvertToSubgraph" />
|
<ConvertToSubgraphButton v-if="showConvertToSubgraph" />
|
||||||
<PublishSubgraphButton v-if="showPublishSubgraph" />
|
<ConfigureSubgraph v-if="showSubgraphButtons" />
|
||||||
|
<PublishSubgraphButton v-if="showSubgraphButtons" />
|
||||||
<MaskEditorButton v-if="showMaskEditor" />
|
<MaskEditorButton v-if="showMaskEditor" />
|
||||||
<VerticalDivider
|
<VerticalDivider
|
||||||
v-if="showAnyPrimaryActions && showAnyControlActions"
|
v-if="showAnyPrimaryActions && showAnyControlActions"
|
||||||
@@ -50,6 +51,7 @@ import { computed, ref } from 'vue'
|
|||||||
|
|
||||||
import BypassButton from '@/components/graph/selectionToolbox/BypassButton.vue'
|
import BypassButton from '@/components/graph/selectionToolbox/BypassButton.vue'
|
||||||
import ColorPickerButton from '@/components/graph/selectionToolbox/ColorPickerButton.vue'
|
import ColorPickerButton from '@/components/graph/selectionToolbox/ColorPickerButton.vue'
|
||||||
|
import ConfigureSubgraph from '@/components/graph/selectionToolbox/ConfigureSubgraph.vue'
|
||||||
import ConvertToSubgraphButton from '@/components/graph/selectionToolbox/ConvertToSubgraphButton.vue'
|
import ConvertToSubgraphButton from '@/components/graph/selectionToolbox/ConvertToSubgraphButton.vue'
|
||||||
import DeleteButton from '@/components/graph/selectionToolbox/DeleteButton.vue'
|
import DeleteButton from '@/components/graph/selectionToolbox/DeleteButton.vue'
|
||||||
import ExecuteButton from '@/components/graph/selectionToolbox/ExecuteButton.vue'
|
import ExecuteButton from '@/components/graph/selectionToolbox/ExecuteButton.vue'
|
||||||
@@ -112,7 +114,7 @@ const showInfoButton = computed(() => !!nodeDef.value)
|
|||||||
const showColorPicker = computed(() => hasAnySelection.value)
|
const showColorPicker = computed(() => hasAnySelection.value)
|
||||||
const showConvertToSubgraph = computed(() => hasAnySelection.value)
|
const showConvertToSubgraph = computed(() => hasAnySelection.value)
|
||||||
const showFrameNodes = computed(() => hasMultipleSelection.value)
|
const showFrameNodes = computed(() => hasMultipleSelection.value)
|
||||||
const showPublishSubgraph = computed(() => isSingleSubgraph.value)
|
const showSubgraphButtons = computed(() => isSingleSubgraph.value)
|
||||||
|
|
||||||
const showBypass = computed(
|
const showBypass = computed(
|
||||||
() =>
|
() =>
|
||||||
@@ -130,7 +132,7 @@ const showAnyPrimaryActions = computed(
|
|||||||
showColorPicker.value ||
|
showColorPicker.value ||
|
||||||
showConvertToSubgraph.value ||
|
showConvertToSubgraph.value ||
|
||||||
showFrameNodes.value ||
|
showFrameNodes.value ||
|
||||||
showPublishSubgraph.value
|
showSubgraphButtons.value
|
||||||
)
|
)
|
||||||
|
|
||||||
const showAnyControlActions = computed(() => showBypass.value)
|
const showAnyControlActions = computed(() => showBypass.value)
|
||||||
|
|||||||
24
src/components/graph/selectionToolbox/ConfigureSubgraph.vue
Normal file
24
src/components/graph/selectionToolbox/ConfigureSubgraph.vue
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<template>
|
||||||
|
<Button
|
||||||
|
v-tooltip.top="{
|
||||||
|
value: t('Edit Subgraph Widgets'),
|
||||||
|
showDelay: 1000
|
||||||
|
}"
|
||||||
|
severity="secondary"
|
||||||
|
text
|
||||||
|
@click="showSubgraphNodeDialog"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<i-lucide:settings2 />
|
||||||
|
</template>
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Button from 'primevue/button'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
import { showSubgraphNodeDialog } from '@/core/graph/subgraph/useSubgraphNodeDialog'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
</script>
|
||||||
@@ -5,7 +5,6 @@ import draggable from 'vuedraggable'
|
|||||||
|
|
||||||
import SearchBox from '@/components/common/SearchBox.vue'
|
import SearchBox from '@/components/common/SearchBox.vue'
|
||||||
import SubgraphNodeWidget from '@/components/selectionbar/SubgraphNodeWidget.vue'
|
import SubgraphNodeWidget from '@/components/selectionbar/SubgraphNodeWidget.vue'
|
||||||
import SidebarTabTemplate from '@/components/sidebar/tabs/SidebarTabTemplate.vue'
|
|
||||||
import {
|
import {
|
||||||
type ProxyWidgetsProperty,
|
type ProxyWidgetsProperty,
|
||||||
parseProxyWidgets
|
parseProxyWidgets
|
||||||
@@ -14,6 +13,7 @@ import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
|||||||
import { SubgraphNode } from '@/lib/litegraph/src/subgraph/SubgraphNode'
|
import { SubgraphNode } from '@/lib/litegraph/src/subgraph/SubgraphNode'
|
||||||
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
|
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
|
||||||
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
||||||
|
import { useDialogStore } from '@/stores/dialogStore'
|
||||||
|
|
||||||
type WidgetItem = [LGraphNode, IBaseWidget]
|
type WidgetItem = [LGraphNode, IBaseWidget]
|
||||||
|
|
||||||
@@ -32,6 +32,7 @@ function toKey(item: WidgetItem) {
|
|||||||
const activeNode = computed(() => {
|
const activeNode = computed(() => {
|
||||||
const node = canvasStore.selectedItems[0]
|
const node = canvasStore.selectedItems[0]
|
||||||
if (node instanceof SubgraphNode) return node
|
if (node instanceof SubgraphNode) return node
|
||||||
|
useDialogStore().closeDialog()
|
||||||
return undefined
|
return undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -184,85 +185,76 @@ const filteredActive = computed<WidgetItem[]>(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<SidebarTabTemplate
|
<SearchBox
|
||||||
:title="'Parameters'"
|
v-model:model-value="searchQuery"
|
||||||
class="workflows-sidebar-tab bg-[var(--p-tree-background)]"
|
class="model-lib-search-box p-2 2xl:p-4"
|
||||||
>
|
:placeholder="$t('g.search') + '...'"
|
||||||
<template #header>
|
/>
|
||||||
<SearchBox
|
<div v-if="filteredActive.length" class="widgets-section">
|
||||||
v-model:model-value="searchQuery"
|
<div class="widgets-section-header">
|
||||||
class="model-lib-search-box p-2 2xl:p-4"
|
<div>{{ t('subgraphStore.shown') }}</div>
|
||||||
:placeholder="$t('g.search') + '...'"
|
<a @click.stop="hideAll"> {{ t('subgraphStore.hideAll') }}</a>
|
||||||
|
</div>
|
||||||
|
<div v-if="searchQuery" class="w-full">
|
||||||
|
<div
|
||||||
|
v-for="element in filteredActive"
|
||||||
|
:key="toKey(element)"
|
||||||
|
class="w-full"
|
||||||
|
>
|
||||||
|
<SubgraphNodeWidget
|
||||||
|
:node-id="`${element[0].id}`"
|
||||||
|
:node-title="element[0].title"
|
||||||
|
:widget-name="element[1].name"
|
||||||
|
:toggle-visibility="toggleVisibility"
|
||||||
|
:is-shown="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<draggable
|
||||||
|
v-else
|
||||||
|
v-model="activeWidgets"
|
||||||
|
group="enabledWidgets"
|
||||||
|
class="w-full cursor-grab"
|
||||||
|
chosen-class="cursor-grabbing"
|
||||||
|
drag-class="cursor-grabbing"
|
||||||
|
:animation="100"
|
||||||
|
item-key="id"
|
||||||
|
>
|
||||||
|
<template #item="{ element }">
|
||||||
|
<SubgraphNodeWidget
|
||||||
|
:node-id="`${element[0].id}`"
|
||||||
|
:node-title="element[0].title"
|
||||||
|
:widget-name="element[1].name"
|
||||||
|
:is-shown="true"
|
||||||
|
:toggle-visibility="toggleVisibility"
|
||||||
|
:is-draggable="true"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
<div v-if="filteredCandidates.length" class="widgets-section">
|
||||||
|
<div class="widgets-section-header">
|
||||||
|
<div>{{ t('subgraphStore.hidden') }}</div>
|
||||||
|
<a @click.stop="showAll"> {{ t('subgraphStore.showAll') }}</a>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="element in filteredCandidates"
|
||||||
|
:key="toKey(element)"
|
||||||
|
class="w-full"
|
||||||
|
>
|
||||||
|
<SubgraphNodeWidget
|
||||||
|
:node-id="`${element[0].id}`"
|
||||||
|
:node-title="element[0].title"
|
||||||
|
:widget-name="element[1].name"
|
||||||
|
:toggle-visibility="toggleVisibility"
|
||||||
/>
|
/>
|
||||||
</template>
|
</div>
|
||||||
<template #body>
|
</div>
|
||||||
<div v-if="filteredActive.length" class="widgets-section">
|
<div v-if="recommendedWidgets.length" class="justify-center flex py-4">
|
||||||
<div class="widgets-section-header">
|
<Button size="small" @click.stop="showRecommended">
|
||||||
<div>{{ t('subgraphStore.shown') }}</div>
|
{{ t('subgraphStore.showRecommended') }}
|
||||||
<a @click.stop="hideAll"> {{ t('subgraphStore.hideAll') }}</a>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="searchQuery" class="w-full">
|
|
||||||
<div
|
|
||||||
v-for="element in filteredActive"
|
|
||||||
:key="toKey(element)"
|
|
||||||
class="w-full"
|
|
||||||
>
|
|
||||||
<SubgraphNodeWidget
|
|
||||||
:node-id="`${element[0].id}`"
|
|
||||||
:node-title="element[0].title"
|
|
||||||
:widget-name="element[1].name"
|
|
||||||
:toggle-visibility="toggleVisibility"
|
|
||||||
:is-shown="true"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<draggable
|
|
||||||
v-else
|
|
||||||
v-model="activeWidgets"
|
|
||||||
group="enabledWidgets"
|
|
||||||
class="w-full cursor-grab"
|
|
||||||
chosen-class="cursor-grabbing"
|
|
||||||
drag-class="cursor-grabbing"
|
|
||||||
:animation="100"
|
|
||||||
item-key="id"
|
|
||||||
>
|
|
||||||
<template #item="{ element }">
|
|
||||||
<SubgraphNodeWidget
|
|
||||||
:node-id="`${element[0].id}`"
|
|
||||||
:node-title="element[0].title"
|
|
||||||
:widget-name="element[1].name"
|
|
||||||
:is-shown="true"
|
|
||||||
:toggle-visibility="toggleVisibility"
|
|
||||||
:is-draggable="true"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</draggable>
|
|
||||||
</div>
|
|
||||||
<div v-if="filteredCandidates.length" class="widgets-section">
|
|
||||||
<div class="widgets-section-header">
|
|
||||||
<div>{{ t('subgraphStore.hidden') }}</div>
|
|
||||||
<a @click.stop="showAll"> {{ t('subgraphStore.showAll') }}</a>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-for="element in filteredCandidates"
|
|
||||||
:key="toKey(element)"
|
|
||||||
class="w-full"
|
|
||||||
>
|
|
||||||
<SubgraphNodeWidget
|
|
||||||
:node-id="`${element[0].id}`"
|
|
||||||
:node-title="element[0].title"
|
|
||||||
:widget-name="element[1].name"
|
|
||||||
:toggle-visibility="toggleVisibility"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-if="recommendedWidgets.length" class="justify-center flex py-4">
|
|
||||||
<Button size="small" @click.stop="showRecommended">
|
|
||||||
{{ t('subgraphStore.showRecommended') }}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</SidebarTabTemplate>
|
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.widgets-section-header {
|
.widgets-section-header {
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import { markRaw } from 'vue'
|
|
||||||
|
|
||||||
import SubgraphNode from '@/components/selectionbar/SubgraphNode.vue'
|
|
||||||
import type { SidebarTabExtension } from '@/types/extensionTypes'
|
|
||||||
|
|
||||||
export const useSubgraphNodeTab = (): SidebarTabExtension => {
|
|
||||||
return {
|
|
||||||
id: 'sgn',
|
|
||||||
icon: 'pi pi-chart-bar',
|
|
||||||
iconBadge: () => {
|
|
||||||
return null
|
|
||||||
},
|
|
||||||
title: 'subgraph widgets',
|
|
||||||
tooltip: 'Change displayed subgraph widgets',
|
|
||||||
label: 'subgraph widgets',
|
|
||||||
component: markRaw(SubgraphNode),
|
|
||||||
type: 'vue'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
21
src/core/graph/subgraph/useSubgraphNodeDialog.ts
Normal file
21
src/core/graph/subgraph/useSubgraphNodeDialog.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import SubgraphNode from '@/components/selectionbar/SubgraphNode.vue'
|
||||||
|
import { type DialogComponentProps, useDialogStore } from '@/stores/dialogStore'
|
||||||
|
|
||||||
|
const key = 'global-subgraph-node-config'
|
||||||
|
|
||||||
|
export function showSubgraphNodeDialog() {
|
||||||
|
const dialogStore = useDialogStore()
|
||||||
|
const dialogComponentProps: DialogComponentProps = {
|
||||||
|
headless: true,
|
||||||
|
modal: false,
|
||||||
|
closable: false,
|
||||||
|
position: 'right'
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogStore.showDialog({
|
||||||
|
title: 'Parameters',
|
||||||
|
key,
|
||||||
|
component: SubgraphNode,
|
||||||
|
dialogComponentProps
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import { useNodeAnimatedImage } from '@/composables/node/useNodeAnimatedImage'
|
|||||||
import { useNodeCanvasImagePreview } from '@/composables/node/useNodeCanvasImagePreview'
|
import { useNodeCanvasImagePreview } from '@/composables/node/useNodeCanvasImagePreview'
|
||||||
import { useNodeImage, useNodeVideo } from '@/composables/node/useNodeImage'
|
import { useNodeImage, useNodeVideo } from '@/composables/node/useNodeImage'
|
||||||
import { addWidgetPromotionOptions } from '@/core/graph/subgraph/proxyWidgetUtils'
|
import { addWidgetPromotionOptions } from '@/core/graph/subgraph/proxyWidgetUtils'
|
||||||
|
import { showSubgraphNodeDialog } from '@/core/graph/subgraph/useSubgraphNodeDialog'
|
||||||
import { st, t } from '@/i18n'
|
import { st, t } from '@/i18n'
|
||||||
import {
|
import {
|
||||||
type IContextMenuValue,
|
type IContextMenuValue,
|
||||||
@@ -825,13 +826,21 @@ export const useLitegraphService = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this instanceof SubgraphNode) {
|
if (this instanceof SubgraphNode) {
|
||||||
options.unshift({
|
options.unshift(
|
||||||
content: 'Unpack Subgraph',
|
{
|
||||||
callback: () => {
|
content: 'Edit Subgraph Widgets',
|
||||||
useNodeOutputStore().revokeSubgraphPreviews(this)
|
callback: () => {
|
||||||
this.graph.unpackSubgraph(this)
|
showSubgraphNodeDialog()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
content: 'Unpack Subgraph',
|
||||||
|
callback: () => {
|
||||||
|
useNodeOutputStore().revokeSubgraphPreviews(this)
|
||||||
|
this.graph.unpackSubgraph(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
if (this.graph && !this.graph.isRootGraph) {
|
if (this.graph && !this.graph.isRootGraph) {
|
||||||
const [x, y] = canvas.canvas_mouse
|
const [x, y] = canvas.canvas_mouse
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { computed, ref } from 'vue'
|
|||||||
import { useModelLibrarySidebarTab } from '@/composables/sidebarTabs/useModelLibrarySidebarTab'
|
import { useModelLibrarySidebarTab } from '@/composables/sidebarTabs/useModelLibrarySidebarTab'
|
||||||
import { useNodeLibrarySidebarTab } from '@/composables/sidebarTabs/useNodeLibrarySidebarTab'
|
import { useNodeLibrarySidebarTab } from '@/composables/sidebarTabs/useNodeLibrarySidebarTab'
|
||||||
import { useQueueSidebarTab } from '@/composables/sidebarTabs/useQueueSidebarTab'
|
import { useQueueSidebarTab } from '@/composables/sidebarTabs/useQueueSidebarTab'
|
||||||
import { useSubgraphNodeTab } from '@/composables/sidebarTabs/useSubgraphNodeTab'
|
|
||||||
import { t, te } from '@/i18n'
|
import { t, te } from '@/i18n'
|
||||||
import { useWorkflowsSidebarTab } from '@/platform/workflow/management/composables/useWorkflowsSidebarTab'
|
import { useWorkflowsSidebarTab } from '@/platform/workflow/management/composables/useWorkflowsSidebarTab'
|
||||||
import { useCommandStore } from '@/stores/commandStore'
|
import { useCommandStore } from '@/stores/commandStore'
|
||||||
@@ -93,7 +92,6 @@ export const useSidebarTabStore = defineStore('sidebarTab', () => {
|
|||||||
registerSidebarTab(useNodeLibrarySidebarTab())
|
registerSidebarTab(useNodeLibrarySidebarTab())
|
||||||
registerSidebarTab(useModelLibrarySidebarTab())
|
registerSidebarTab(useModelLibrarySidebarTab())
|
||||||
registerSidebarTab(useWorkflowsSidebarTab())
|
registerSidebarTab(useWorkflowsSidebarTab())
|
||||||
registerSidebarTab(useSubgraphNodeTab())
|
|
||||||
|
|
||||||
const menuStore = useMenuItemStore()
|
const menuStore = useMenuItemStore()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user