Skip to content

Commit 9fb93a5

Browse files
pythongosssssgithub-actions
andauthored
App mode - more updates & fixes (#9137)
## Summary - fix sizing of sidebars in app mode - update feedback button to match design - update job queue notification - clickable queue spinner item to allow clear queue - refactor mode out of store to specific workflow instance - support different saved vs active mode - other styling/layout tweaks ## Changes - **What**: Changes the store to a composable and moves the mode state to the workflow. - This enables switching between tabs and maintaining the mode they were in ## Screenshots (if applicable) <img width="1866" height="1455" alt="image" src="https://github.com/user-attachments/assets/f9a8cd36-181f-4948-b48c-dd27bd9127cf" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9137-App-mode-more-updates-fixes-3106d73d365081a18ccff6ffe24fdec7) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com>
1 parent ac12a3d commit 9fb93a5

32 files changed

+689
-236
lines changed
-12 Bytes
Loading
4.58 KB
Loading
-321 Bytes
Loading
-242 Bytes
Loading

src/components/LiteGraphCanvasSplitterOverlay.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ import { computed } from 'vue'
124124
import { useI18n } from 'vue-i18n'
125125
126126
import { useSettingStore } from '@/platform/settings/settingStore'
127-
import { useAppModeStore } from '@/stores/appModeStore'
127+
import { useAppMode } from '@/composables/useAppMode'
128128
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'
129129
import { useRightSidePanelStore } from '@/stores/workspace/rightSidePanelStore'
130130
import { useSidebarTabStore } from '@/stores/workspace/sidebarTabStore'
@@ -145,12 +145,12 @@ const unifiedWidth = computed(() =>
145145
146146
const { focusMode } = storeToRefs(workspaceStore)
147147
148-
const appModeStore = useAppModeStore()
148+
const { mode } = useAppMode()
149149
const { activeSidebarTabId, activeSidebarTab } = storeToRefs(sidebarTabStore)
150150
const { bottomPanelVisible } = storeToRefs(useBottomPanelStore())
151151
const { isOpen: rightSidePanelVisible } = storeToRefs(rightSidePanelStore)
152152
const showOffsideSplitter = computed(
153-
() => rightSidePanelVisible.value || appModeStore.mode === 'builder:select'
153+
() => rightSidePanelVisible.value || mode.value === 'builder:select'
154154
)
155155
156156
const sidebarPanelVisible = computed(() => activeSidebarTab.value !== null)

src/components/appMode/AppModeToolbar.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemp
88
import { useCommandStore } from '@/stores/commandStore'
99
import { useWorkspaceStore } from '@/stores/workspaceStore'
1010
import { cn } from '@/utils/tailwindUtil'
11-
import { useAppModeStore } from '@/stores/appModeStore'
11+
import { useAppMode } from '@/composables/useAppMode'
1212
1313
const { t } = useI18n()
1414
const commandStore = useCommandStore()
1515
const workspaceStore = useWorkspaceStore()
16-
const appModeStore = useAppModeStore()
16+
const { enableAppBuilder, setMode } = useAppMode()
1717
const tooltipOptions = { showDelay: 300, hideDelay: 300 }
1818
1919
const isAssetsActive = computed(
@@ -24,7 +24,7 @@ const isWorkflowsActive = computed(
2424
)
2525
2626
function enterBuilderMode() {
27-
appModeStore.setMode('builder:select')
27+
setMode('builder:select')
2828
}
2929
3030
function openAssets() {
@@ -61,7 +61,7 @@ function openTemplates() {
6161
</WorkflowActionsDropdown>
6262

6363
<Button
64-
v-if="appModeStore.enableAppBuilder"
64+
v-if="enableAppBuilder"
6565
v-tooltip.right="{
6666
value: t('linearMode.appModeToolbar.appBuilder'),
6767
...tooltipOptions

src/components/builder/BuilderToolbar.vue

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
)
2121
"
2222
:aria-current="activeStep === step.id ? 'step' : undefined"
23-
@click="appModeStore.setMode(step.id)"
23+
@click="setMode(step.id)"
2424
>
2525
<StepBadge :step :index :model-value="activeStep" />
2626
<StepLabel :step />
@@ -31,9 +31,9 @@
3131

3232
<!-- Save -->
3333
<ConnectOutputPopover
34-
v-if="!appModeStore.hasOutputs"
34+
v-if="!hasOutputs"
3535
:is-select-active="activeStep === 'builder:select'"
36-
@switch="appModeStore.setMode('builder:select')"
36+
@switch="setMode('builder:select')"
3737
>
3838
<button :class="cn(stepClasses, 'opacity-30 bg-transparent')">
3939
<StepBadge :step="saveStep" :index="2" :model-value="activeStep" />
@@ -50,7 +50,7 @@
5050
: 'hover:bg-secondary-background bg-transparent'
5151
)
5252
"
53-
@click="appModeStore.setBuilderSaving(true)"
53+
@click="setSaving(true)"
5454
>
5555
<StepBadge :step="saveStep" :index="2" :model-value="activeStep" />
5656
<StepLabel :step="saveStep" />
@@ -62,31 +62,25 @@
6262
<script setup lang="ts">
6363
import { computed } from 'vue'
6464
import { useI18n } from 'vue-i18n'
65-
import { useEventListener } from '@vueuse/core'
6665
66+
import { useAppMode } from '@/composables/useAppMode'
67+
import type { AppMode } from '@/composables/useAppMode'
6768
import { useAppModeStore } from '@/stores/appModeStore'
68-
import type { AppMode } from '@/stores/appModeStore'
6969
import { cn } from '@/utils/tailwindUtil'
7070
71+
import { useBuilderSave } from './useBuilderSave'
7172
import ConnectOutputPopover from './ConnectOutputPopover.vue'
7273
import StepBadge from './StepBadge.vue'
7374
import StepLabel from './StepLabel.vue'
7475
import type { BuilderToolbarStep } from './types'
76+
import { storeToRefs } from 'pinia'
7577
7678
const { t } = useI18n()
77-
const appModeStore = useAppModeStore()
79+
const { mode, setMode } = useAppMode()
80+
const { hasOutputs } = storeToRefs(useAppModeStore())
81+
const { saving, setSaving } = useBuilderSave()
7882
79-
useEventListener(document, 'keydown', (e: KeyboardEvent) => {
80-
if (e.key !== 'Escape') return
81-
82-
e.preventDefault()
83-
e.stopPropagation()
84-
void appModeStore.exitBuilder()
85-
})
86-
87-
const activeStep = computed(() =>
88-
appModeStore.isBuilderSaving ? 'save' : appModeStore.mode
89-
)
83+
const activeStep = computed(() => (saving.value ? 'save' : mode.value))
9084
9185
const stepClasses =
9286
'inline-flex h-14 min-h-8 cursor-pointer items-center gap-3 rounded-lg py-2 pr-4 pl-2 transition-colors border-none'

src/components/builder/useBuilderSave.ts

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,36 @@
1-
import { watch } from 'vue'
1+
import { ref } from 'vue'
22

3+
import { useErrorHandling } from '@/composables/useErrorHandling'
34
import { useWorkflowService } from '@/platform/workflow/core/services/workflowService'
45
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
56
import { useDialogService } from '@/services/dialogService'
7+
import { useAppMode } from '@/composables/useAppMode'
68
import { useAppModeStore } from '@/stores/appModeStore'
79
import { useDialogStore } from '@/stores/dialogStore'
810

911
import BuilderSaveDialogContent from './BuilderSaveDialogContent.vue'
1012
import BuilderSaveSuccessDialogContent from './BuilderSaveSuccessDialogContent.vue'
13+
import { whenever } from '@vueuse/core'
1114

1215
const SAVE_DIALOG_KEY = 'builder-save'
1316
const SUCCESS_DIALOG_KEY = 'builder-save-success'
1417

1518
export function useBuilderSave() {
16-
const appModeStore = useAppModeStore()
19+
const { setMode } = useAppMode()
20+
const { toastErrorHandler } = useErrorHandling()
1721
const workflowStore = useWorkflowStore()
1822
const workflowService = useWorkflowService()
1923
const dialogService = useDialogService()
24+
const appModeStore = useAppModeStore()
2025
const dialogStore = useDialogStore()
2126

22-
watch(
23-
() => appModeStore.isBuilderSaving,
24-
(saving) => {
25-
if (saving) void onBuilderSave()
26-
}
27-
)
27+
const saving = ref(false)
28+
29+
whenever(saving, onBuilderSave)
30+
31+
function setSaving(value: boolean) {
32+
saving.value = value
33+
}
2834

2935
async function onBuilderSave() {
3036
const workflow = workflowStore.activeWorkflow
@@ -33,13 +39,14 @@ export function useBuilderSave() {
3339
return
3440
}
3541

36-
if (!workflow.isTemporary && workflow.activeState.extra?.linearMode) {
42+
if (!workflow.isTemporary && workflow.initialMode != null) {
43+
// Re-save with the previously chosen mode — no dialog needed.
3744
try {
38-
workflow.changeTracker?.checkState()
39-
appModeStore.saveSelectedToWorkflow()
45+
appModeStore.flushSelections()
4046
await workflowService.saveWorkflow(workflow)
41-
showSuccessDialog(workflow.filename, appModeStore.isAppMode)
42-
} catch {
47+
showSuccessDialog(workflow.filename, workflow.initialMode === 'app')
48+
} catch (e) {
49+
toastErrorHandler(e)
4350
resetSaving()
4451
}
4552
return
@@ -73,17 +80,19 @@ export function useBuilderSave() {
7380
const workflow = workflowStore.activeWorkflow
7481
if (!workflow) return
7582

76-
appModeStore.saveSelectedToWorkflow()
83+
appModeStore.flushSelections()
84+
const mode = openAsApp ? 'app' : 'graph'
7785
const saved = await workflowService.saveWorkflowAs(workflow, {
7886
filename,
79-
openAsApp
87+
initialMode: mode
8088
})
8189

8290
if (!saved) return
8391

8492
closeSaveDialog()
8593
showSuccessDialog(filename, openAsApp)
86-
} catch {
94+
} catch (e) {
95+
toastErrorHandler(e)
8796
closeSaveDialog()
8897
resetSaving()
8998
}
@@ -97,7 +106,7 @@ export function useBuilderSave() {
97106
workflowName,
98107
savedAsApp,
99108
onViewApp: () => {
100-
appModeStore.setMode('app')
109+
setMode('app')
101110
closeSuccessDialog()
102111
},
103112
onClose: closeSuccessDialog
@@ -118,6 +127,8 @@ export function useBuilderSave() {
118127
}
119128

120129
function resetSaving() {
121-
appModeStore.setBuilderSaving(false)
130+
saving.value = false
122131
}
132+
133+
return { saving, setSaving }
123134
}

src/components/graph/GraphCanvas.vue

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
</div>
2222
</div>
2323
</template>
24-
<template v-if="showUI && !appModeStore.isBuilderMode" #side-toolbar>
24+
<template v-if="showUI && !isBuilderMode" #side-toolbar>
2525
<SideToolbar />
2626
</template>
2727
<template v-if="showUI" #side-bar-panel>
@@ -31,27 +31,24 @@
3131
<ExtensionSlot v-if="activeSidebarTab" :extension="activeSidebarTab" />
3232
</div>
3333
</template>
34-
<template v-if="showUI && !appModeStore.isBuilderMode" #topmenu>
34+
<template v-if="showUI && !isBuilderMode" #topmenu>
3535
<TopMenuSection />
3636
</template>
3737
<template v-if="showUI" #bottom-panel>
3838
<BottomPanel />
3939
</template>
4040
<template v-if="showUI" #right-side-panel>
41-
<AppBuilder v-if="appModeStore.mode === 'builder:select'" />
42-
<NodePropertiesPanel v-else-if="!appModeStore.isBuilderMode" />
41+
<AppBuilder v-if="mode === 'builder:select'" />
42+
<NodePropertiesPanel v-else-if="!isBuilderMode" />
4343
</template>
4444
<template #graph-canvas-panel>
4545
<GraphCanvasMenu
46-
v-if="canvasMenuEnabled && !appModeStore.isBuilderMode"
46+
v-if="canvasMenuEnabled && !isBuilderMode"
4747
class="pointer-events-auto"
4848
/>
4949
<MiniMap
5050
v-if="
51-
comfyAppReady &&
52-
minimapEnabled &&
53-
betaMenuEnabled &&
54-
!appModeStore.isBuilderMode
51+
comfyAppReady && minimapEnabled && betaMenuEnabled && !isBuilderMode
5552
"
5653
class="pointer-events-auto"
5754
/>
@@ -127,10 +124,10 @@ import {
127124
import { useI18n } from 'vue-i18n'
128125
129126
import { isMiddlePointerInput } from '@/base/pointerUtils'
130-
import AppBuilder from '@/components/builder/AppBuilder.vue'
131127
import LiteGraphCanvasSplitterOverlay from '@/components/LiteGraphCanvasSplitterOverlay.vue'
132128
import TopMenuSection from '@/components/TopMenuSection.vue'
133129
import BottomPanel from '@/components/bottomPanel/BottomPanel.vue'
130+
import AppBuilder from '@/components/builder/AppBuilder.vue'
134131
import ExtensionSlot from '@/components/common/ExtensionSlot.vue'
135132
import DomWidgets from '@/components/graph/DomWidgets.vue'
136133
import GraphCanvasMenu from '@/components/graph/GraphCanvasMenu.vue'
@@ -184,7 +181,7 @@ import { useExecutionErrorStore } from '@/stores/executionErrorStore'
184181
import { useNodeDefStore } from '@/stores/nodeDefStore'
185182
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
186183
import { useSearchBoxStore } from '@/stores/workspace/searchBoxStore'
187-
import { useAppModeStore } from '@/stores/appModeStore'
184+
import { useAppMode } from '@/composables/useAppMode'
188185
import { useWorkspaceStore } from '@/stores/workspaceStore'
189186
import { isNativeWindow } from '@/utils/envUtil'
190187
import { forEachNode } from '@/utils/graphTraversalUtil'
@@ -205,7 +202,7 @@ const nodeSearchboxPopoverRef = shallowRef<InstanceType<
205202
const settingStore = useSettingStore()
206203
const nodeDefStore = useNodeDefStore()
207204
const workspaceStore = useWorkspaceStore()
208-
const appModeStore = useAppModeStore()
205+
const { mode, isBuilderMode } = useAppMode()
209206
const canvasStore = useCanvasStore()
210207
const workflowStore = useWorkflowStore()
211208
const executionStore = useExecutionStore()

src/components/sidebar/tabs/SidebarTabTemplate.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
ref="containerRef"
44
:class="
55
cn(
6-
'comfy-vue-side-bar-container group/sidebar-tab flex h-full flex-col',
6+
'comfy-vue-side-bar-container group/sidebar-tab flex h-full flex-col w-full',
77
props.class
88
)
99
"

0 commit comments

Comments
 (0)