mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 02:32:18 +00:00
Add workflow info popover
This commit is contained in:
@@ -11,7 +11,7 @@ import Button from '@/components/ui/button/Button.vue'
|
|||||||
import { cn } from '@/utils/tailwindUtil'
|
import { cn } from '@/utils/tailwindUtil'
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
entries: { label: string; action?: () => void; icon?: string }[][]
|
entries?: { label: string; action?: () => void; icon?: string }[][]
|
||||||
icon?: string
|
icon?: string
|
||||||
}>()
|
}>()
|
||||||
</script>
|
</script>
|
||||||
@@ -29,12 +29,13 @@ defineProps<{
|
|||||||
<PopoverContent
|
<PopoverContent
|
||||||
side="bottom"
|
side="bottom"
|
||||||
:side-offset="5"
|
:side-offset="5"
|
||||||
|
:collision-padding="10"
|
||||||
class="rounded-lg p-2 bg-base-background shadow-sm border border-border-subtle will-change-[transform,opacity] data-[state=open]:data-[side=top]:animate-slideDownAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade"
|
class="rounded-lg p-2 bg-base-background shadow-sm border border-border-subtle will-change-[transform,opacity] data-[state=open]:data-[side=top]:animate-slideDownAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade"
|
||||||
>
|
>
|
||||||
<slot>
|
<slot>
|
||||||
<div class="flex flex-col p-1">
|
<div class="flex flex-col p-1">
|
||||||
<popover-group
|
<popover-group
|
||||||
v-for="(entryGroup, index) in entries"
|
v-for="(entryGroup, index) in entries ?? []"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="flex flex-col border-b-2 last:border-none border-border-subtle"
|
class="flex flex-col border-b-2 last:border-none border-border-subtle"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -73,36 +73,37 @@ const graphNodes = shallowRef<LGraphNode[]>(app.rootGraph.nodes)
|
|||||||
useEventListener(
|
useEventListener(
|
||||||
app.rootGraph.events,
|
app.rootGraph.events,
|
||||||
'configured',
|
'configured',
|
||||||
() => (graphNodes.value = app.rootGraph.nodes)
|
() => (graphNodes.value = app.rootGraph.nodes.reverse())
|
||||||
)
|
)
|
||||||
|
|
||||||
const nodeDatas = computed(() => {
|
function nodeToNodeData(node: LGraphNode) {
|
||||||
function nodeToNodeData(node: LGraphNode) {
|
const mapper = safeWidgetMapper(node, new Map())
|
||||||
const mapper = safeWidgetMapper(node, new Map())
|
const widgets = node.widgets?.map(mapper) ?? []
|
||||||
const widgets = node.widgets?.map(mapper) ?? []
|
const dropIndicator =
|
||||||
const dropIndicator =
|
node.type !== 'LoadImage'
|
||||||
node.type !== 'LoadImage'
|
? undefined
|
||||||
? undefined
|
: {
|
||||||
: {
|
iconClass: 'icon-[lucide--image]',
|
||||||
iconClass: 'icon-[lucide--image]',
|
label: t('Click to browse or drag an image'),
|
||||||
label: t('Click to browse or drag an image'),
|
onClick: node.widgets?.[1]?.callback
|
||||||
onClick: node.widgets?.[1]?.callback
|
}
|
||||||
}
|
//of VueNodeData, only widgets is actually used
|
||||||
//of VueNodeData, only widgets is actually used
|
return {
|
||||||
return {
|
executing: false,
|
||||||
executing: false,
|
id: `${node.id}`,
|
||||||
id: `${node.id}`,
|
mode: 0,
|
||||||
mode: 0,
|
selected: false,
|
||||||
selected: false,
|
title: node.title,
|
||||||
title: node.title,
|
type: node.type,
|
||||||
type: node.type,
|
widgets,
|
||||||
widgets,
|
|
||||||
|
|
||||||
dropIndicator,
|
dropIndicator,
|
||||||
onDragDrop: node.onDragDrop,
|
onDragDrop: node.onDragDrop,
|
||||||
onDragOver: node.onDragOver
|
onDragOver: node.onDragOver
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeDatas = computed(() => {
|
||||||
return graphNodes.value
|
return graphNodes.value
|
||||||
.filter(
|
.filter(
|
||||||
(node) =>
|
(node) =>
|
||||||
@@ -111,7 +112,16 @@ const nodeDatas = computed(() => {
|
|||||||
!['MarkdownNote', 'Note'].includes(node.type)
|
!['MarkdownNote', 'Note'].includes(node.type)
|
||||||
)
|
)
|
||||||
.map(nodeToNodeData)
|
.map(nodeToNodeData)
|
||||||
.reverse()
|
})
|
||||||
|
const noteDatas = computed(() => {
|
||||||
|
return graphNodes.value
|
||||||
|
.filter(
|
||||||
|
(node) =>
|
||||||
|
node.mode === 0 &&
|
||||||
|
node.widgets?.length &&
|
||||||
|
['MarkdownNote', 'Note'].includes(node.type)
|
||||||
|
)
|
||||||
|
.map(nodeToNodeData)
|
||||||
})
|
})
|
||||||
|
|
||||||
const batchCountWidget = {
|
const batchCountWidget = {
|
||||||
@@ -602,7 +612,21 @@ useEventListener(document.body, 'keydown', (e: KeyboardEvent) => {
|
|||||||
v-text="workflowStore.activeWorkflow?.filename"
|
v-text="workflowStore.activeWorkflow?.filename"
|
||||||
/>
|
/>
|
||||||
<div class="flex-1" />
|
<div class="flex-1" />
|
||||||
<i class="icon-[lucide--info]" />
|
<Popover v-if="noteDatas.length">
|
||||||
|
<template #button>
|
||||||
|
<Button variant="muted-textonly">
|
||||||
|
<i class="icon-[lucide--info]" />
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<NodeWidgets
|
||||||
|
v-for="nodeData in noteDatas"
|
||||||
|
:key="nodeData.id"
|
||||||
|
:node-data
|
||||||
|
class="border-b-1 border-node-component-border py-3 last:border-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
<Button> {{ t('publish') }} </Button>
|
<Button> {{ t('publish') }} </Button>
|
||||||
</linear-workflow-info>
|
</linear-workflow-info>
|
||||||
<div
|
<div
|
||||||
|
|||||||
Reference in New Issue
Block a user