mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 19:21:54 +00:00
[Refactor] Split SelectionToolbox buttons to components (#3902)
This commit is contained in:
@@ -6,96 +6,41 @@
|
|||||||
content: 'p-0 flex flex-row'
|
content: 'p-0 flex flex-row'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<ExecuteButton v-show="nodeSelected" />
|
<ExecuteButton />
|
||||||
<ColorPickerButton v-show="nodeSelected || groupSelected" />
|
<ColorPickerButton />
|
||||||
<Button
|
<BypassButton />
|
||||||
v-show="nodeSelected"
|
<PinButton />
|
||||||
v-tooltip.top="{
|
<DeleteButton />
|
||||||
value: t('commands.Comfy_Canvas_ToggleSelectedNodes_Bypass.label'),
|
<RefreshButton />
|
||||||
showDelay: 1000
|
<ExtensionCommandButton
|
||||||
}"
|
|
||||||
severity="secondary"
|
|
||||||
text
|
|
||||||
data-testid="bypass-button"
|
|
||||||
@click="
|
|
||||||
() => commandStore.execute('Comfy.Canvas.ToggleSelectedNodes.Bypass')
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<i-game-icons:detour />
|
|
||||||
</template>
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
v-show="nodeSelected || groupSelected"
|
|
||||||
v-tooltip.top="{
|
|
||||||
value: t('commands.Comfy_Canvas_ToggleSelectedNodes_Pin.label'),
|
|
||||||
showDelay: 1000
|
|
||||||
}"
|
|
||||||
severity="secondary"
|
|
||||||
text
|
|
||||||
icon="pi pi-thumbtack"
|
|
||||||
@click="() => commandStore.execute('Comfy.Canvas.ToggleSelected.Pin')"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
v-tooltip.top="{
|
|
||||||
value: t('commands.Comfy_Canvas_DeleteSelectedItems.label'),
|
|
||||||
showDelay: 1000
|
|
||||||
}"
|
|
||||||
severity="danger"
|
|
||||||
text
|
|
||||||
icon="pi pi-trash"
|
|
||||||
@click="() => commandStore.execute('Comfy.Canvas.DeleteSelectedItems')"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
v-show="isRefreshable"
|
|
||||||
severity="info"
|
|
||||||
text
|
|
||||||
icon="pi pi-refresh"
|
|
||||||
@click="refreshSelected"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
v-for="command in extensionToolboxCommands"
|
v-for="command in extensionToolboxCommands"
|
||||||
:key="command.id"
|
:key="command.id"
|
||||||
v-tooltip.top="{
|
:command="command"
|
||||||
value:
|
|
||||||
st(`commands.${normalizeI18nKey(command.id)}.label`, '') || undefined,
|
|
||||||
showDelay: 1000
|
|
||||||
}"
|
|
||||||
severity="secondary"
|
|
||||||
text
|
|
||||||
:icon="typeof command.icon === 'function' ? command.icon() : command.icon"
|
|
||||||
@click="() => commandStore.execute(command.id)"
|
|
||||||
/>
|
/>
|
||||||
</Panel>
|
</Panel>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Button from 'primevue/button'
|
|
||||||
import Panel from 'primevue/panel'
|
import Panel from 'primevue/panel'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
import ColorPickerButton from '@/components/graph/selectionToolbox/ColorPickerButton.vue'
|
import ColorPickerButton from '@/components/graph/selectionToolbox/ColorPickerButton.vue'
|
||||||
import ExecuteButton from '@/components/graph/selectionToolbox/ExecuteButton.vue'
|
import ExecuteButton from '@/components/graph/selectionToolbox/ExecuteButton.vue'
|
||||||
import { useRefreshableSelection } from '@/composables/useRefreshableSelection'
|
|
||||||
import { st, t } from '@/i18n'
|
|
||||||
import { useExtensionService } from '@/services/extensionService'
|
import { useExtensionService } from '@/services/extensionService'
|
||||||
import { ComfyCommand, useCommandStore } from '@/stores/commandStore'
|
import { type ComfyCommandImpl, useCommandStore } from '@/stores/commandStore'
|
||||||
import { useCanvasStore } from '@/stores/graphStore'
|
import { useCanvasStore } from '@/stores/graphStore'
|
||||||
import { normalizeI18nKey } from '@/utils/formatUtil'
|
|
||||||
import { isLGraphGroup, isLGraphNode } from '@/utils/litegraphUtil'
|
import BypassButton from './selectionToolbox/BypassButton.vue'
|
||||||
|
import DeleteButton from './selectionToolbox/DeleteButton.vue'
|
||||||
|
import ExtensionCommandButton from './selectionToolbox/ExtensionCommandButton.vue'
|
||||||
|
import PinButton from './selectionToolbox/PinButton.vue'
|
||||||
|
import RefreshButton from './selectionToolbox/RefreshButton.vue'
|
||||||
|
|
||||||
const commandStore = useCommandStore()
|
const commandStore = useCommandStore()
|
||||||
const canvasStore = useCanvasStore()
|
const canvasStore = useCanvasStore()
|
||||||
const extensionService = useExtensionService()
|
const extensionService = useExtensionService()
|
||||||
const { isRefreshable, refreshSelected } = useRefreshableSelection()
|
|
||||||
const nodeSelected = computed(() =>
|
|
||||||
canvasStore.selectedItems.some(isLGraphNode)
|
|
||||||
)
|
|
||||||
const groupSelected = computed(() =>
|
|
||||||
canvasStore.selectedItems.some(isLGraphGroup)
|
|
||||||
)
|
|
||||||
|
|
||||||
const extensionToolboxCommands = computed<ComfyCommand[]>(() => {
|
const extensionToolboxCommands = computed<ComfyCommandImpl[]>(() => {
|
||||||
const commandIds = new Set<string>(
|
const commandIds = new Set<string>(
|
||||||
canvasStore.selectedItems
|
canvasStore.selectedItems
|
||||||
.map(
|
.map(
|
||||||
@@ -108,7 +53,7 @@ const extensionToolboxCommands = computed<ComfyCommand[]>(() => {
|
|||||||
)
|
)
|
||||||
return Array.from(commandIds)
|
return Array.from(commandIds)
|
||||||
.map((commandId) => commandStore.getCommand(commandId))
|
.map((commandId) => commandStore.getCommand(commandId))
|
||||||
.filter((command) => command !== undefined)
|
.filter((command): command is ComfyCommandImpl => command !== undefined)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
31
src/components/graph/selectionToolbox/BypassButton.vue
Normal file
31
src/components/graph/selectionToolbox/BypassButton.vue
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<Button
|
||||||
|
v-show="canvasStore.nodeSelected"
|
||||||
|
v-tooltip.top="{
|
||||||
|
value: t('commands.Comfy_Canvas_ToggleSelectedNodes_Bypass.label'),
|
||||||
|
showDelay: 1000
|
||||||
|
}"
|
||||||
|
severity="secondary"
|
||||||
|
text
|
||||||
|
data-testid="bypass-button"
|
||||||
|
@click="
|
||||||
|
() => commandStore.execute('Comfy.Canvas.ToggleSelectedNodes.Bypass')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<i-game-icons:detour />
|
||||||
|
</template>
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Button from 'primevue/button'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
import { useCommandStore } from '@/stores/commandStore'
|
||||||
|
import { useCanvasStore } from '@/stores/graphStore'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const commandStore = useCommandStore()
|
||||||
|
const canvasStore = useCanvasStore()
|
||||||
|
</script>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<Button
|
<Button
|
||||||
|
v-show="canvasStore.nodeSelected || canvasStore.groupSelected"
|
||||||
severity="secondary"
|
severity="secondary"
|
||||||
text
|
text
|
||||||
@click="() => (showColorPicker = !showColorPicker)"
|
@click="() => (showColorPicker = !showColorPicker)"
|
||||||
|
|||||||
22
src/components/graph/selectionToolbox/DeleteButton.vue
Normal file
22
src/components/graph/selectionToolbox/DeleteButton.vue
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<Button
|
||||||
|
v-tooltip.top="{
|
||||||
|
value: t('commands.Comfy_Canvas_DeleteSelectedItems.label'),
|
||||||
|
showDelay: 1000
|
||||||
|
}"
|
||||||
|
severity="danger"
|
||||||
|
text
|
||||||
|
icon="pi pi-trash"
|
||||||
|
@click="() => commandStore.execute('Comfy.Canvas.DeleteSelectedItems')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Button from 'primevue/button'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
import { useCommandStore } from '@/stores/commandStore'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const commandStore = useCommandStore()
|
||||||
|
</script>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<Button
|
<Button
|
||||||
|
v-show="canvasStore.nodeSelected"
|
||||||
v-tooltip.top="{
|
v-tooltip.top="{
|
||||||
value: isDisabled
|
value: isDisabled
|
||||||
? t('selectionToolbox.executeButton.disabledTooltip')
|
? t('selectionToolbox.executeButton.disabledTooltip')
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<Button
|
||||||
|
v-tooltip.top="{
|
||||||
|
value:
|
||||||
|
st(`commands.${normalizeI18nKey(command.id)}.label`, '') || undefined,
|
||||||
|
showDelay: 1000
|
||||||
|
}"
|
||||||
|
severity="secondary"
|
||||||
|
text
|
||||||
|
:icon="typeof command.icon === 'function' ? command.icon() : command.icon"
|
||||||
|
@click="() => commandStore.execute(command.id)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Button from 'primevue/button'
|
||||||
|
|
||||||
|
import { st } from '@/i18n'
|
||||||
|
import { ComfyCommand, useCommandStore } from '@/stores/commandStore'
|
||||||
|
import { normalizeI18nKey } from '@/utils/formatUtil'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
command: ComfyCommand
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const commandStore = useCommandStore()
|
||||||
|
</script>
|
||||||
25
src/components/graph/selectionToolbox/PinButton.vue
Normal file
25
src/components/graph/selectionToolbox/PinButton.vue
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<Button
|
||||||
|
v-show="canvasStore.nodeSelected || canvasStore.groupSelected"
|
||||||
|
v-tooltip.top="{
|
||||||
|
value: t('commands.Comfy_Canvas_ToggleSelectedNodes_Pin.label'),
|
||||||
|
showDelay: 1000
|
||||||
|
}"
|
||||||
|
severity="secondary"
|
||||||
|
text
|
||||||
|
icon="pi pi-thumbtack"
|
||||||
|
@click="() => commandStore.execute('Comfy.Canvas.ToggleSelected.Pin')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Button from 'primevue/button'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
import { useCommandStore } from '@/stores/commandStore'
|
||||||
|
import { useCanvasStore } from '@/stores/graphStore'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const commandStore = useCommandStore()
|
||||||
|
const canvasStore = useCanvasStore()
|
||||||
|
</script>
|
||||||
17
src/components/graph/selectionToolbox/RefreshButton.vue
Normal file
17
src/components/graph/selectionToolbox/RefreshButton.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<Button
|
||||||
|
v-show="isRefreshable"
|
||||||
|
severity="info"
|
||||||
|
text
|
||||||
|
icon="pi pi-refresh"
|
||||||
|
@click="refreshSelected"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Button from 'primevue/button'
|
||||||
|
|
||||||
|
import { useRefreshableSelection } from '@/composables/useRefreshableSelection'
|
||||||
|
|
||||||
|
const { isRefreshable, refreshSelected } = useRefreshableSelection()
|
||||||
|
</script>
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import type { LGraphCanvas, LGraphGroup, LGraphNode } from '@comfyorg/litegraph'
|
import type { LGraphCanvas, LGraphGroup, LGraphNode } from '@comfyorg/litegraph'
|
||||||
import type { Positionable } from '@comfyorg/litegraph/dist/interfaces'
|
import type { Positionable } from '@comfyorg/litegraph/dist/interfaces'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { type Raw, markRaw, ref, shallowRef } from 'vue'
|
import { type Raw, computed, markRaw, ref, shallowRef } from 'vue'
|
||||||
|
|
||||||
|
import { isLGraphGroup, isLGraphNode } from '@/utils/litegraphUtil'
|
||||||
|
|
||||||
export const useTitleEditorStore = defineStore('titleEditor', () => {
|
export const useTitleEditorStore = defineStore('titleEditor', () => {
|
||||||
const titleEditorTarget = shallowRef<LGraphNode | LGraphGroup | null>(null)
|
const titleEditorTarget = shallowRef<LGraphNode | LGraphGroup | null>(null)
|
||||||
@@ -27,6 +29,9 @@ export const useCanvasStore = defineStore('canvas', () => {
|
|||||||
selectedItems.value = items.map((item) => markRaw(item))
|
selectedItems.value = items.map((item) => markRaw(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nodeSelected = computed(() => selectedItems.value.some(isLGraphNode))
|
||||||
|
const groupSelected = computed(() => selectedItems.value.some(isLGraphGroup))
|
||||||
|
|
||||||
const getCanvas = () => {
|
const getCanvas = () => {
|
||||||
if (!canvas.value) throw new Error('getCanvas: canvas is null')
|
if (!canvas.value) throw new Error('getCanvas: canvas is null')
|
||||||
return canvas.value
|
return canvas.value
|
||||||
@@ -35,6 +40,8 @@ export const useCanvasStore = defineStore('canvas', () => {
|
|||||||
return {
|
return {
|
||||||
canvas,
|
canvas,
|
||||||
selectedItems,
|
selectedItems,
|
||||||
|
nodeSelected,
|
||||||
|
groupSelected,
|
||||||
updateSelectedItems,
|
updateSelectedItems,
|
||||||
getCanvas
|
getCanvas
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user