mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-10 07:30:08 +00:00
## Summary Additional fixes and updates based on testing ## Changes - **What**: - add warning to welcome screen & when sharing an app that has had all outputs removed - fix target workflow when changing mode via tab right click menu - change build app text to be conditional "edit" vs "build" depending on if an app is already defined - update empty apps sidebar tab button text to make it clearer - remove templates button from app mode (we will reintroduce this once we have app templates) - add "exit to graph" after applying default mode of node graph - update cancel button to remove item from queue if it hasn't started yet - improve scoping of jobs/outputs to the current workflow [not perfect but should be much improved] - close sidebar tabs on entering app mode - change tooltip to be under the workflow menu rather than covering the button ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9511-feat-fix-App-mode-QA-feedback-2-31b6d73d365081d59bbbc13111100d46) by [Unito](https://www.unito.io)
139 lines
4.0 KiB
TypeScript
139 lines
4.0 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { reactive, computed, watch } from 'vue'
|
|
|
|
import { useEmptyWorkflowDialog } from '@/components/builder/useEmptyWorkflowDialog'
|
|
import { useAppMode } from '@/composables/useAppMode'
|
|
import type { NodeId } from '@/lib/litegraph/src/LGraphNode'
|
|
import type { LinearData } from '@/platform/workflow/management/stores/comfyWorkflow'
|
|
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
|
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
|
|
import { useSidebarTabStore } from '@/stores/workspace/sidebarTabStore'
|
|
import { app } from '@/scripts/app'
|
|
import { resolveNode } from '@/utils/litegraphUtil'
|
|
|
|
export const useAppModeStore = defineStore('appMode', () => {
|
|
const { getCanvas } = useCanvasStore()
|
|
const workflowStore = useWorkflowStore()
|
|
const { mode, setMode, isBuilderMode, isSelectMode } = useAppMode()
|
|
const emptyWorkflowDialog = useEmptyWorkflowDialog()
|
|
|
|
const selectedInputs = reactive<[NodeId, string][]>([])
|
|
const selectedOutputs = reactive<NodeId[]>([])
|
|
const hasOutputs = computed(() => !!selectedOutputs.length)
|
|
const hasNodes = computed(() => {
|
|
// Nodes are not reactive, so trigger recomputation when workflow changes
|
|
void workflowStore.activeWorkflow
|
|
void mode.value
|
|
return !!app.rootGraph?.nodes?.length
|
|
})
|
|
|
|
// Prune entries referencing nodes deleted in workflow mode.
|
|
// Only check node existence, not widgets — dynamic widgets can
|
|
// hide/show other widgets so a missing widget does not mean stale data.
|
|
function pruneLinearData(data: Partial<LinearData> | undefined): LinearData {
|
|
const rawInputs = data?.inputs ?? []
|
|
const rawOutputs = data?.outputs ?? []
|
|
|
|
return {
|
|
inputs: app.rootGraph
|
|
? rawInputs.filter(([nodeId]) => resolveNode(nodeId))
|
|
: rawInputs,
|
|
outputs: app.rootGraph
|
|
? rawOutputs.filter((nodeId) => resolveNode(nodeId))
|
|
: rawOutputs
|
|
}
|
|
}
|
|
|
|
function loadSelections(data: Partial<LinearData> | undefined) {
|
|
const { inputs, outputs } = pruneLinearData(data)
|
|
selectedInputs.splice(0, selectedInputs.length, ...inputs)
|
|
selectedOutputs.splice(0, selectedOutputs.length, ...outputs)
|
|
}
|
|
|
|
function resetSelectedToWorkflow() {
|
|
const { activeWorkflow } = workflowStore
|
|
if (!activeWorkflow) return
|
|
|
|
loadSelections(activeWorkflow.changeTracker?.activeState?.extra?.linearData)
|
|
}
|
|
|
|
watch(
|
|
() => workflowStore.activeWorkflow,
|
|
(newWorkflow) => {
|
|
if (newWorkflow) {
|
|
loadSelections(
|
|
newWorkflow.changeTracker?.activeState?.extra?.linearData
|
|
)
|
|
} else {
|
|
loadSelections(undefined)
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
|
|
watch(
|
|
() =>
|
|
isBuilderMode.value
|
|
? { inputs: selectedInputs, outputs: selectedOutputs }
|
|
: null,
|
|
(data) => {
|
|
if (!data) return
|
|
const graph = app.rootGraph
|
|
if (!graph) return
|
|
const extra = (graph.extra ??= {})
|
|
extra.linearData = {
|
|
inputs: [...data.inputs],
|
|
outputs: [...data.outputs]
|
|
}
|
|
},
|
|
{ deep: true }
|
|
)
|
|
|
|
let unwatch: () => void | undefined
|
|
watch(isSelectMode, (inSelect) => {
|
|
const { state } = getCanvas()
|
|
if (!state) return
|
|
state.readOnly = inSelect
|
|
unwatch?.()
|
|
if (inSelect)
|
|
unwatch = watch(
|
|
() => state.readOnly,
|
|
() => (state.readOnly = true)
|
|
)
|
|
})
|
|
|
|
function enterBuilder() {
|
|
if (!hasNodes.value) {
|
|
emptyWorkflowDialog.show({
|
|
onEnterBuilder: () => enterBuilder(),
|
|
onDismiss: () => setMode('graph')
|
|
})
|
|
return
|
|
}
|
|
|
|
useSidebarTabStore().activeSidebarTabId = null
|
|
|
|
setMode(
|
|
mode.value === 'app' && hasOutputs.value
|
|
? 'builder:arrange'
|
|
: 'builder:inputs'
|
|
)
|
|
}
|
|
|
|
function exitBuilder() {
|
|
resetSelectedToWorkflow()
|
|
setMode('graph')
|
|
}
|
|
|
|
return {
|
|
enterBuilder,
|
|
exitBuilder,
|
|
hasNodes,
|
|
hasOutputs,
|
|
pruneLinearData,
|
|
resetSelectedToWorkflow,
|
|
selectedInputs,
|
|
selectedOutputs
|
|
}
|
|
})
|