mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 14:30:41 +00:00
## Summary
Fix right-side sidebar panels and left-side panels sharing the same
PrimeVue Splitter state key, causing them to incorrectly apply each
other's saved widths.
## Changes
- **What**: Make `sidebarStateKey` position-aware by including
`sidebarLocation` and offside panel visibility in the localStorage key
## Problem
When sidebar location is set to **right**, all panels (both the
right-side sidebar like Job History and left-side panels like Workflow
overview) share a single PrimeVue Splitter `state-key`
(`unified-sidebar`). PrimeVue persists panel widths to localStorage
using this key, so any resize on one side gets applied to the other.
### AS-IS (before fix)
The `sidebarStateKey` is computed without any awareness of panel
position:
```typescript
// Always returns 'unified-sidebar' (when unified width enabled)
// or the active tab id — regardless of sidebar location or offside panel state
const sidebarStateKey = computed(() => {
return unifiedWidth.value
? 'unified-sidebar'
: (activeSidebarTabId.value ?? 'default-sidebar')
})
```
This produces a **single localStorage key** for all layout
configurations. The result:
1. Set sidebar to **right**, open **Job History** → resize it smaller →
saved to `unified-sidebar`
2. Open **Workflow overview** (appears on the left as an offside panel)
→ loads the same `unified-sidebar` key → gets the Job History width
applied to a completely different panel position
3. Both panels open simultaneously share the same persisted width, even
though they are on opposite sides of the screen
This is exactly the behavior shown in the [issue
screenshots](https://github.com/Comfy-Org/ComfyUI_frontend/issues/9440):
pulling the Workflow overview smaller also changes Job History to that
same size, and vice versa.
### TO-BE (after fix)
The `sidebarStateKey` now includes `sidebarLocation` (`left`/`right`)
and whether the offside panel is visible:
```typescript
const sidebarTabKey = computed(() => {
return unifiedWidth.value
? 'unified-sidebar'
: (activeSidebarTabId.value ?? 'default-sidebar')
})
const sidebarStateKey = computed(() => {
const base = sidebarTabKey.value
const suffix = showOffsideSplitter.value ? '-with-offside' : ''
return `${base}-${sidebarLocation.value}${suffix}`
})
```
This produces **distinct localStorage keys** per layout configuration:
| Layout | Key |
|--------|-----|
| Sidebar left, no offside | `unified-sidebar-left` |
| Sidebar left, right panel open | `unified-sidebar-left-with-offside` |
| Sidebar right, no offside | `unified-sidebar-right` |
| Sidebar right, left panel open | `unified-sidebar-right-with-offside`
|
Each configuration now persists and restores its own panel sizes
independently, so resizing Job History on the right no longer affects
Workflow overview on the left.
## Review Focus
- The offside suffix (`-with-offside`) is necessary because the Splitter
transitions from a 2-panel layout (sidebar + center) to a 3-panel layout
(sidebar + center + offside) — these are fundamentally different panel
configurations and should not share persisted sizes.
Fixes #9440
## Screenshots (if applicable)
See issue for reproduction screenshots:
https://github.com/Comfy-Org/ComfyUI_frontend/issues/9440
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
123 lines
4.3 KiB
TypeScript
123 lines
4.3 KiB
TypeScript
import { expect } from '@playwright/test'
|
|
|
|
import type { ComfyPage } from '../../fixtures/ComfyPage'
|
|
import { comfyPageFixture as test } from '../../fixtures/ComfyPage'
|
|
|
|
test.describe('Sidebar splitter width independence', () => {
|
|
test.beforeEach(async ({ comfyPage }) => {
|
|
await comfyPage.settings.setSetting('Comfy.UseNewMenu', 'Top')
|
|
await comfyPage.settings.setSetting('Comfy.Sidebar.UnifiedWidth', true)
|
|
await comfyPage.settings.setSetting('Comfy.NodeLibrary.NewDesign', false)
|
|
})
|
|
|
|
async function dismissToasts(comfyPage: ComfyPage) {
|
|
const buttons = await comfyPage.page.locator('.p-toast-close-button').all()
|
|
for (const btn of buttons) {
|
|
await btn.click({ timeout: 2000 }).catch(() => {})
|
|
}
|
|
// Brief wait for animations
|
|
await comfyPage.nextFrame()
|
|
}
|
|
|
|
async function dragGutter(comfyPage: ComfyPage, deltaX: number) {
|
|
const gutter = comfyPage.page
|
|
.locator('.p-splitter-gutter:not(.hidden)')
|
|
.first()
|
|
await expect(gutter).toBeVisible()
|
|
const box = await gutter.boundingBox()
|
|
expect(box).not.toBeNull()
|
|
const centerX = box!.x + box!.width / 2
|
|
const centerY = box!.y + box!.height / 2
|
|
await comfyPage.page.mouse.move(centerX, centerY)
|
|
await comfyPage.page.mouse.down()
|
|
await comfyPage.page.mouse.move(centerX + deltaX, centerY, { steps: 10 })
|
|
await comfyPage.page.mouse.up()
|
|
await comfyPage.nextFrame()
|
|
}
|
|
|
|
async function openSidebarAt(
|
|
comfyPage: ComfyPage,
|
|
location: 'left' | 'right'
|
|
) {
|
|
await comfyPage.settings.setSetting('Comfy.Sidebar.Location', location)
|
|
await comfyPage.nextFrame()
|
|
await dismissToasts(comfyPage)
|
|
await comfyPage.menu.nodeLibraryTab.open()
|
|
}
|
|
|
|
test('left and right sidebars use separate localStorage keys', async ({
|
|
comfyPage
|
|
}) => {
|
|
// Open sidebar on the left and resize it
|
|
await openSidebarAt(comfyPage, 'left')
|
|
await dragGutter(comfyPage, 100)
|
|
|
|
// Read the sidebar panel width after resize
|
|
const leftSidebar = comfyPage.page.locator('.side-bar-panel').first()
|
|
const leftWidth = (await leftSidebar.boundingBox())!.width
|
|
|
|
// Close sidebar, switch to right, open again
|
|
await comfyPage.menu.nodeLibraryTab.close()
|
|
await openSidebarAt(comfyPage, 'right')
|
|
|
|
// Right sidebar should use its default width, not the left's resized width
|
|
const rightSidebar = comfyPage.page.locator('.side-bar-panel').first()
|
|
await expect(rightSidebar).toBeVisible()
|
|
const rightWidth = (await rightSidebar.boundingBox())!.width
|
|
|
|
// The right sidebar should NOT match the left's resized width.
|
|
// We dragged the left sidebar 100px wider, so there should be a noticeable
|
|
// difference between the left (resized) and right (default) widths.
|
|
expect(Math.abs(rightWidth - leftWidth)).toBeGreaterThan(50)
|
|
})
|
|
|
|
test('localStorage keys include sidebar location', async ({ comfyPage }) => {
|
|
// Open sidebar on the left and resize
|
|
await openSidebarAt(comfyPage, 'left')
|
|
await dragGutter(comfyPage, 50)
|
|
|
|
// Left-only sidebar should use the legacy key (no location suffix)
|
|
const leftKey = await comfyPage.page.evaluate(() =>
|
|
localStorage.getItem('unified-sidebar')
|
|
)
|
|
expect(leftKey).not.toBeNull()
|
|
|
|
// Switch to right and resize
|
|
await comfyPage.menu.nodeLibraryTab.close()
|
|
await openSidebarAt(comfyPage, 'right')
|
|
await dragGutter(comfyPage, -50)
|
|
|
|
// Right sidebar should use a different key with location suffix
|
|
const rightKey = await comfyPage.page.evaluate(() =>
|
|
localStorage.getItem('unified-sidebar-right')
|
|
)
|
|
expect(rightKey).not.toBeNull()
|
|
|
|
// Both keys should exist independently
|
|
const leftKeyStillExists = await comfyPage.page.evaluate(() =>
|
|
localStorage.getItem('unified-sidebar')
|
|
)
|
|
expect(leftKeyStillExists).not.toBeNull()
|
|
})
|
|
|
|
test('normalized panel sizes sum to approximately 100%', async ({
|
|
comfyPage
|
|
}) => {
|
|
await openSidebarAt(comfyPage, 'left')
|
|
await dragGutter(comfyPage, 80)
|
|
|
|
// Check that saved sizes sum to ~100%
|
|
const sizes = await comfyPage.page.evaluate(() => {
|
|
const raw = localStorage.getItem('unified-sidebar')
|
|
return raw ? JSON.parse(raw) : null
|
|
})
|
|
|
|
expect(sizes).not.toBeNull()
|
|
expect(Array.isArray(sizes)).toBe(true)
|
|
|
|
const sum = (sizes as number[]).reduce((a, b) => a + b, 0)
|
|
expect(sum).toBeGreaterThan(99)
|
|
expect(sum).toBeLessThanOrEqual(101)
|
|
})
|
|
})
|