fix: App mode - Widget dropdowns clipped in sidebar (#10338)

## Summary

Popover components for graph mode are appendTo self so scale/translate
works, however in the sidebar this causes them to be clipped by the
parent overflow. This adds a provide/inject flag to change these to be
appended to the body.

## Changes

- **What**: 
- add append to injection for overriding where popovers are mounted
- ensure dropdowns respect this flag
- extract enterAppModeWithInputs helper
- tests

Before:  
<img width="225" height="140" alt="image"
src="https://github.com/user-attachments/assets/bd83b0cd-49a9-45dd-8344-4c10221444fc"
/>

After:  
<img width="238" height="225" alt="image"
src="https://github.com/user-attachments/assets/286e28e9-b37d-4ffc-91a9-7c340757d3fc"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10338-fix-App-mode-Widget-dropdowns-clipped-in-sidebar-3296d73d365081e2ba38e3e82006d65e)
by [Unito](https://www.unito.io)
This commit is contained in:
pythongosssss
2026-03-20 21:18:54 +00:00
committed by GitHub
parent 3b85227089
commit 7501a3eefc
7 changed files with 228 additions and 58 deletions

View File

@@ -1,5 +1,3 @@
import type { Page } from '@playwright/test'
import {
comfyPageFixture as test,
comfyExpect as expect
@@ -11,58 +9,10 @@ test.describe('Linear Mode', { tag: '@ui' }, () => {
await comfyPage.setup()
})
async function enterAppMode(comfyPage: {
page: Page
nextFrame: () => Promise<void>
}) {
// LinearControls requires hasOutputs to be true. Serialize the current
// graph, inject linearData with output node IDs, then reload so the
// appModeStore picks up the outputs via its activeWorkflow watcher.
await comfyPage.page.evaluate(async () => {
const graph = window.app!.graph
if (!graph) return
const outputNodeIds = graph.nodes
.filter(
(n: { type?: string }) =>
n.type === 'SaveImage' || n.type === 'PreviewImage'
)
.map((n: { id: number | string }) => String(n.id))
// Serialize, inject linearData, and reload to sync stores
const workflow = graph.serialize() as unknown as Record<string, unknown>
const extra = (workflow.extra ?? {}) as Record<string, unknown>
extra.linearData = { inputs: [], outputs: outputNodeIds }
workflow.extra = extra
await window.app!.loadGraphData(
workflow as unknown as Parameters<
NonNullable<typeof window.app>['loadGraphData']
>[0]
)
})
await comfyPage.nextFrame()
// Toggle to app mode via the command which sets canvasStore.linearMode
await comfyPage.page.evaluate(() => {
window.app!.extensionManager.command.execute('Comfy.ToggleLinear')
})
await comfyPage.nextFrame()
}
async function enterGraphMode(comfyPage: {
page: Page
nextFrame: () => Promise<void>
}) {
await comfyPage.page.evaluate(() => {
window.app!.extensionManager.command.execute('Comfy.ToggleLinear')
})
await comfyPage.nextFrame()
}
test('Displays linear controls when app mode active', async ({
comfyPage
}) => {
await enterAppMode(comfyPage)
await comfyPage.appMode.enterAppModeWithInputs([])
await expect(
comfyPage.page.locator('[data-testid="linear-widgets"]')
@@ -70,7 +20,7 @@ test.describe('Linear Mode', { tag: '@ui' }, () => {
})
test('Run button visible in linear mode', async ({ comfyPage }) => {
await enterAppMode(comfyPage)
await comfyPage.appMode.enterAppModeWithInputs([])
await expect(
comfyPage.page.locator('[data-testid="linear-run-button"]')
@@ -78,7 +28,7 @@ test.describe('Linear Mode', { tag: '@ui' }, () => {
})
test('Workflow info section visible', async ({ comfyPage }) => {
await enterAppMode(comfyPage)
await comfyPage.appMode.enterAppModeWithInputs([])
await expect(
comfyPage.page.locator('[data-testid="linear-workflow-info"]')
@@ -86,13 +36,13 @@ test.describe('Linear Mode', { tag: '@ui' }, () => {
})
test('Returns to graph mode', async ({ comfyPage }) => {
await enterAppMode(comfyPage)
await comfyPage.appMode.enterAppModeWithInputs([])
await expect(
comfyPage.page.locator('[data-testid="linear-widgets"]')
).toBeVisible({ timeout: 5000 })
await enterGraphMode(comfyPage)
await comfyPage.appMode.toggleAppMode()
await expect(comfyPage.canvas).toBeVisible({ timeout: 5000 })
await expect(
@@ -101,7 +51,7 @@ test.describe('Linear Mode', { tag: '@ui' }, () => {
})
test('Canvas not visible in app mode', async ({ comfyPage }) => {
await enterAppMode(comfyPage)
await comfyPage.appMode.enterAppModeWithInputs([])
await expect(
comfyPage.page.locator('[data-testid="linear-widgets"]')