linear v2: Simple Mode (#7734)

A major, full rewrite of linear mode, now under the name "Simple Mode". 
- Fixes widget styling
- Adds a new simplified history
- Adds support for non-image outputs
- Supports right sidebar
- Allows and panning on the output image preview
- Provides support for drag and drop zones
- Moves workflow notes into a popover.
- Allows scrolling through outputs with Ctrl+scroll or arrow keys

The primary means of accessing Simple Mode is a toggle button on the
bottom right. This button is only shown if a feature flag is enabled, or
the user has already seen linear mode during the current session. Simple
Mode can also be accessed by
- Using the toggle linear mode keybind
- Loading a workflow that that was saved in Simple Mode workflow
- Loading a template url with appropriate parameter

<img width="1790" height="1387" alt="image"
src="https://github.com/user-attachments/assets/d86a4a41-dfbf-41e7-a6d9-146473005606"
/>

Known issues:
- Outputs on cloud are not filtered to those produced by the current
workflow.
  - Output filtering has been globally disabled for consistency
- Outputs will load more items on scroll, but does not unload
- Performance may be reduced on weak devices with very large histories.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7734-linear-v2-2d16d73d3650819b8a10f150ff12ea22)
by [Unito](https://www.unito.io)
This commit is contained in:
AustinMroz
2026-01-13 20:18:31 -08:00
committed by GitHub
parent 773f5f5cd9
commit 25afd39d2b
32 changed files with 1431 additions and 319 deletions

View File

@@ -11,6 +11,7 @@ import {
useWorkflowStore
} from '@/platform/workflow/management/stores/workflowStore'
import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useWorkflowThumbnail } from '@/renderer/core/thumbnail/useWorkflowThumbnail'
import { app } from '@/scripts/app'
import { blankGraph, defaultGraph } from '@/scripts/defaultGraph'
@@ -311,6 +312,11 @@ export const useWorkflowService = () => {
workflowData: ComfyWorkflowJSON
) => {
const workflowStore = useWorkspaceStore().workflow
if (
workflowData.extra?.linearMode !== undefined ||
!workflowData.nodes.length
)
useCanvasStore().linearMode = !!workflowData.extra?.linearMode
if (value === null || typeof value === 'string') {
const path = value as string | null
@@ -332,6 +338,11 @@ export const useWorkflowService = () => {
}
}
if (useCanvasStore().linearMode) {
app.rootGraph.extra ??= {}
app.rootGraph.extra.linearMode = true
}
const tempWorkflow = workflowStore.createNewTemporary(
path ? appendJsonExt(path) : undefined,
workflowData

View File

@@ -13,7 +13,6 @@ import type {
ComfyWorkflowJSON,
NodeId
} from '@/platform/workflow/validation/schemas/workflowSchema'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useWorkflowThumbnail } from '@/renderer/core/thumbnail/useWorkflowThumbnail'
import { api } from '@/scripts/api'
import { app as comfyApp } from '@/scripts/app'
@@ -334,7 +333,6 @@ export const useWorkflowStore = defineStore('workflow', () => {
tabActivationHistory.value.shift()
}
useCanvasStore().linearMode = !!loadedWorkflow.activeState.extra?.linearMode
return loadedWorkflow
}

View File

@@ -121,28 +121,7 @@ export function useTemplateWorkflows() {
if (!template || !template.sourceModule) return false
// Use the stored source module for loading
const actualSourceModule = template.sourceModule
json = await fetchTemplateJson(id, actualSourceModule)
// Use source module for name
const workflowName =
actualSourceModule === 'default'
? t(`templateWorkflows.template.${id}`, id)
: id
if (isCloud) {
useTelemetry()?.trackTemplate({
workflow_name: id,
template_source: actualSourceModule
})
}
dialogStore.closeDialog()
await app.loadGraphData(json, true, true, workflowName, {
openSource: 'template'
})
return true
sourceModule = template.sourceModule
}
// Regular case for normal categories