Move widget configuration out of sidebar

This commit is contained in:
Austin Mroz
2025-09-27 12:23:45 -05:00
parent 7c20f37973
commit 44d57ce041
7 changed files with 136 additions and 109 deletions

View File

@@ -22,7 +22,8 @@
<ColorPickerButton v-if="showColorPicker" />
<FrameNodes v-if="showFrameNodes" />
<ConvertToSubgraphButton v-if="showConvertToSubgraph" />
<PublishSubgraphButton v-if="showPublishSubgraph" />
<ConfigureSubgraph v-if="showSubgraphButtons" />
<PublishSubgraphButton v-if="showSubgraphButtons" />
<MaskEditorButton v-if="showMaskEditor" />
<VerticalDivider
v-if="showAnyPrimaryActions && showAnyControlActions"
@@ -50,6 +51,7 @@ import { computed, ref } from 'vue'
import BypassButton from '@/components/graph/selectionToolbox/BypassButton.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 DeleteButton from '@/components/graph/selectionToolbox/DeleteButton.vue'
import ExecuteButton from '@/components/graph/selectionToolbox/ExecuteButton.vue'
@@ -112,7 +114,7 @@ const showInfoButton = computed(() => !!nodeDef.value)
const showColorPicker = computed(() => hasAnySelection.value)
const showConvertToSubgraph = computed(() => hasAnySelection.value)
const showFrameNodes = computed(() => hasMultipleSelection.value)
const showPublishSubgraph = computed(() => isSingleSubgraph.value)
const showSubgraphButtons = computed(() => isSingleSubgraph.value)
const showBypass = computed(
() =>
@@ -130,7 +132,7 @@ const showAnyPrimaryActions = computed(
showColorPicker.value ||
showConvertToSubgraph.value ||
showFrameNodes.value ||
showPublishSubgraph.value
showSubgraphButtons.value
)
const showAnyControlActions = computed(() => showBypass.value)

View 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>

View File

@@ -5,7 +5,6 @@ import draggable from 'vuedraggable'
import SearchBox from '@/components/common/SearchBox.vue'
import SubgraphNodeWidget from '@/components/selectionbar/SubgraphNodeWidget.vue'
import SidebarTabTemplate from '@/components/sidebar/tabs/SidebarTabTemplate.vue'
import {
type ProxyWidgetsProperty,
parseProxyWidgets
@@ -14,6 +13,7 @@ import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
import { SubgraphNode } from '@/lib/litegraph/src/subgraph/SubgraphNode'
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useDialogStore } from '@/stores/dialogStore'
type WidgetItem = [LGraphNode, IBaseWidget]
@@ -32,6 +32,7 @@ function toKey(item: WidgetItem) {
const activeNode = computed(() => {
const node = canvasStore.selectedItems[0]
if (node instanceof SubgraphNode) return node
useDialogStore().closeDialog()
return undefined
})
@@ -184,85 +185,76 @@ const filteredActive = computed<WidgetItem[]>(() => {
})
</script>
<template>
<SidebarTabTemplate
:title="'Parameters'"
class="workflows-sidebar-tab bg-[var(--p-tree-background)]"
>
<template #header>
<SearchBox
v-model:model-value="searchQuery"
class="model-lib-search-box p-2 2xl:p-4"
:placeholder="$t('g.search') + '...'"
<SearchBox
v-model:model-value="searchQuery"
class="model-lib-search-box p-2 2xl:p-4"
:placeholder="$t('g.search') + '...'"
/>
<div v-if="filteredActive.length" class="widgets-section">
<div class="widgets-section-header">
<div>{{ t('subgraphStore.shown') }}</div>
<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>
<template #body>
<div v-if="filteredActive.length" class="widgets-section">
<div class="widgets-section-header">
<div>{{ t('subgraphStore.shown') }}</div>
<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"
/>
</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>
</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>
<style scoped>
.widgets-section-header {

View File

@@ -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'
}
}

View 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
})
}

View File

@@ -5,6 +5,7 @@ import { useNodeAnimatedImage } from '@/composables/node/useNodeAnimatedImage'
import { useNodeCanvasImagePreview } from '@/composables/node/useNodeCanvasImagePreview'
import { useNodeImage, useNodeVideo } from '@/composables/node/useNodeImage'
import { addWidgetPromotionOptions } from '@/core/graph/subgraph/proxyWidgetUtils'
import { showSubgraphNodeDialog } from '@/core/graph/subgraph/useSubgraphNodeDialog'
import { st, t } from '@/i18n'
import {
type IContextMenuValue,
@@ -825,13 +826,21 @@ export const useLitegraphService = () => {
}
}
if (this instanceof SubgraphNode) {
options.unshift({
content: 'Unpack Subgraph',
callback: () => {
useNodeOutputStore().revokeSubgraphPreviews(this)
this.graph.unpackSubgraph(this)
options.unshift(
{
content: 'Edit Subgraph Widgets',
callback: () => {
showSubgraphNodeDialog()
}
},
{
content: 'Unpack Subgraph',
callback: () => {
useNodeOutputStore().revokeSubgraphPreviews(this)
this.graph.unpackSubgraph(this)
}
}
})
)
}
if (this.graph && !this.graph.isRootGraph) {
const [x, y] = canvas.canvas_mouse

View File

@@ -4,7 +4,6 @@ import { computed, ref } from 'vue'
import { useModelLibrarySidebarTab } from '@/composables/sidebarTabs/useModelLibrarySidebarTab'
import { useNodeLibrarySidebarTab } from '@/composables/sidebarTabs/useNodeLibrarySidebarTab'
import { useQueueSidebarTab } from '@/composables/sidebarTabs/useQueueSidebarTab'
import { useSubgraphNodeTab } from '@/composables/sidebarTabs/useSubgraphNodeTab'
import { t, te } from '@/i18n'
import { useWorkflowsSidebarTab } from '@/platform/workflow/management/composables/useWorkflowsSidebarTab'
import { useCommandStore } from '@/stores/commandStore'
@@ -93,7 +92,6 @@ export const useSidebarTabStore = defineStore('sidebarTab', () => {
registerSidebarTab(useNodeLibrarySidebarTab())
registerSidebarTab(useModelLibrarySidebarTab())
registerSidebarTab(useWorkflowsSidebarTab())
registerSidebarTab(useSubgraphNodeTab())
const menuStore = useMenuItemStore()