From 5376b7ed1e7b4cf81fce6765d30639228cd42529 Mon Sep 17 00:00:00 2001
From: pythongosssss <125205205+pythongosssss@users.noreply.github.com>
Date: Thu, 5 Mar 2026 10:27:05 +0000
Subject: [PATCH] feat: App mode empty graph handling (#9393)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Summary
Adds handling for entering app mode with an empty graph prompting the
user to load a template as a starting point
## Changes
- **What**:
- app mode handle empty workflows, disable builder button, show
different message
- fix fitView when switching from app mode to graph
## Review Focus
Moving the fitView since the canvas is hidden in app mode until after
the workflow is loaded and the mode has been switched back to graph, I
don't see how this could cause any issues but worth a closer eye
## Screenshots (if applicable)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9393-feat-App-mode-empty-graph-handling-3196d73d3650812cab0ce878109ed5c9)
by [Unito](https://www.unito.io)
---
src/components/appMode/AppModeToolbar.vue | 10 ++--
.../builder/EmptyWorkflowDialogContent.vue | 6 +--
src/locales/en/main.json | 9 ++--
.../extensions/linearMode/LinearWelcome.vue | 48 ++++++++++++-----
src/scripts/app.ts | 52 ++++++++++++-------
src/stores/appModeStore.test.ts | 9 ++--
src/stores/appModeStore.ts | 9 +++-
7 files changed, 91 insertions(+), 52 deletions(-)
diff --git a/src/components/appMode/AppModeToolbar.vue b/src/components/appMode/AppModeToolbar.vue
index c4bd31747f..f4b6a8ec19 100644
--- a/src/components/appMode/AppModeToolbar.vue
+++ b/src/components/appMode/AppModeToolbar.vue
@@ -4,18 +4,21 @@ import { useI18n } from 'vue-i18n'
import WorkflowActionsDropdown from '@/components/common/WorkflowActionsDropdown.vue'
import Button from '@/components/ui/button/Button.vue'
+import { useAppMode } from '@/composables/useAppMode'
import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemplateSelectorDialog'
+import { useAppModeStore } from '@/stores/appModeStore'
import { useCommandStore } from '@/stores/commandStore'
import { useWorkspaceStore } from '@/stores/workspaceStore'
import { cn } from '@/utils/tailwindUtil'
-import { useAppMode } from '@/composables/useAppMode'
-import { useAppModeStore } from '@/stores/appModeStore'
+import { storeToRefs } from 'pinia'
const { t } = useI18n()
const commandStore = useCommandStore()
const workspaceStore = useWorkspaceStore()
const { enableAppBuilder } = useAppMode()
-const { enterBuilder } = useAppModeStore()
+const appModeStore = useAppModeStore()
+const { enterBuilder } = appModeStore
+const { hasNodes } = storeToRefs(appModeStore)
const tooltipOptions = { showDelay: 300, hideDelay: 300 }
const isAssetsActive = computed(
@@ -71,6 +74,7 @@ function openTemplates() {
}"
variant="secondary"
size="unset"
+ :disabled="!hasNodes"
:aria-label="t('linearMode.appModeToolbar.appBuilder')"
class="size-10 rounded-lg"
@click="enterBuilder"
diff --git a/src/components/builder/EmptyWorkflowDialogContent.vue b/src/components/builder/EmptyWorkflowDialogContent.vue
index 8951d83bc5..e790478b30 100644
--- a/src/components/builder/EmptyWorkflowDialogContent.vue
+++ b/src/components/builder/EmptyWorkflowDialogContent.vue
@@ -6,7 +6,7 @@
- {{ $t('builderToolbar.emptyWorkflowExplanation') }} + {{ $t('linearMode.emptyWorkflowExplanation') }}
{{ $t('builderToolbar.emptyWorkflowPrompt') }} @@ -19,10 +19,10 @@ size="lg" @click="$emit('backToWorkflow')" > - {{ $t('builderToolbar.backToWorkflow') }} + {{ $t('linearMode.backToWorkflow') }} diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 61fe4fe4c6..c7b3ffd326 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -3037,13 +3037,15 @@ "downloadAll": "Download All", "viewJob": "View Job", "enterNodeGraph": "Enter node graph", + "emptyWorkflowExplanation": "Your workflow is empty. You need some nodes first to start building an app.", + "backToWorkflow": "Back to workflow", + "loadTemplate": "Load a template", "welcome": { "title": "App Mode", "message": "A simplified view that hides the node graph so you can focus on creating.", "controls": "Your outputs appear at the bottom, your controls are on the right. Everything else stays out of the way.", "sharing": "Share your workflow as a simple tool anyone can use. Export it from the tab menu and when others open it, they'll see App Mode. No node graph knowledge needed.", "getStarted": "Click {runButton} to get started.", - "backToWorkflow": "Back to workflow", "buildApp": "Build app" }, "appModeToolbar": { @@ -3388,10 +3390,7 @@ "defaultModeAppliedGraphPrompt": "Would you like to view the app still?", "viewApp": "View app", "emptyWorkflowTitle": "This workflow has no nodes", - "emptyWorkflowExplanation": "Your workflow is empty. You need some nodes first to start building an app.", - "emptyWorkflowPrompt": "Do you want to start with a template?", - "backToWorkflow": "Back to workflow", - "loadTemplate": "Load a template" + "emptyWorkflowPrompt": "Do you want to start with a template?" }, "builderMenu": { "exitAppBuilder": "Exit app builder" diff --git a/src/renderer/extensions/linearMode/LinearWelcome.vue b/src/renderer/extensions/linearMode/LinearWelcome.vue index 8670d7812e..2a629000a2 100644 --- a/src/renderer/extensions/linearMode/LinearWelcome.vue +++ b/src/renderer/extensions/linearMode/LinearWelcome.vue @@ -1,6 +1,7 @@ @@ -41,19 +43,37 @@ const { hasOutputs } = storeToRefs(appModeStore)