Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
76639e2
style: Splitter style tailwind conversion part 1
DrJKL Dec 3, 2025
fa6820a
cleanup: Fix focus mode in splitter, more idiomatic store/ref use
DrJKL Dec 3, 2025
41f4813
cleanup: Simplify changes in TopMenuSection
DrJKL Dec 3, 2025
d9caad4
Consistency: Open the info in the properties panel too.
DrJKL Dec 3, 2025
14b37d8
cleanup: unused action
DrJKL Dec 3, 2025
bbf6fab
i18n: Fix Panel title pluralization
DrJKL Dec 3, 2025
82f6add
style: Buttons
DrJKL Dec 3, 2025
2977b3c
fix: Subgraph edit toggle logic
DrJKL Dec 3, 2025
44b14fa
cleanup: Node Info Tab
DrJKL Dec 3, 2025
d093a82
cleanup: Parameters Accordions
DrJKL Dec 3, 2025
0779133
cleanup: Search bar, not fully there
DrJKL Dec 3, 2025
2d152c5
cleanup: Parameters and searchbox padding
DrJKL Dec 3, 2025
e276b76
cleanup: TabSettings part 1
DrJKL Dec 3, 2025
d428e40
fix: Need a simpler way to detect when we can/should re-search
DrJKL Dec 3, 2025
57c90e0
cleanup: TabSettings part 2
DrJKL Dec 3, 2025
f9a2d50
Minimap in focus mode, but not in OG Comfy mode
DrJKL Dec 4, 2025
f6821cd
Node state fix
DrJKL Dec 4, 2025
5a4f1dd
YAGNI: Accordion item properties
DrJKL Dec 4, 2025
390fbde
Suggested change
DrJKL Dec 4, 2025
247d787
[automated] Update test expectations
invalid-email-address Dec 4, 2025
8b3abd9
cleanup: Button classes.
DrJKL Dec 4, 2025
c7d33ed
test: Update the help panel tests
DrJKL Dec 4, 2025
52527e8
Consistently devolved model binding
DrJKL Dec 4, 2025
fe47bda
test: Remove old sidebar button expectation.
DrJKL Dec 4, 2025
84f5b21
feat: make node title editable from Properties Panel
DrJKL Dec 4, 2025
076805a
style: margin for searchbox to let the ring show
DrJKL Dec 4, 2025
8e360d5
fix: Sticky header background
DrJKL Dec 4, 2025
ef362a8
style: Add minimum height for some widgets
DrJKL Dec 4, 2025
d577fa6
Re-add forced refresh. There are some re-render issues still.
DrJKL Dec 4, 2025
37cce6e
test: Minimal properties panel Playwright test
DrJKL Dec 4, 2025
df4c23e
test: Test works! Update expectations
DrJKL Dec 5, 2025
2394cfd
Good rabbit suggestion
DrJKL Dec 5, 2025
b2ab4d9
test: Add properties panel locator to fixture, scope assertions to it.
DrJKL Dec 5, 2025
a2dba09
test: Restructure actionbar locators
DrJKL Dec 5, 2025
475fe28
Fix: Focus mode on the right.
DrJKL Dec 5, 2025
64bbf20
fix: Hide bottom gutter in focus mode
DrJKL Dec 5, 2025
af1e410
[automated] Update test expectations
invalid-email-address Dec 5, 2025
f0f59b2
Title logic cleanup
DrJKL Dec 5, 2025
a5675d3
feat: Handle empty Inputs sections
DrJKL Dec 5, 2025
d8d096d
Yeah, I like that better.
DrJKL Dec 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions browser_tests/fixtures/ComfyPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ class ComfyMenu {
private _topbar: Topbar | null = null

public readonly sideToolbar: Locator
public readonly propertiesPanel: Locator
public readonly themeToggleButton: Locator
public readonly saveButton: Locator

constructor(public readonly page: Page) {
this.sideToolbar = page.locator('.side-tool-bar-container')
this.themeToggleButton = page.locator('.comfy-vue-theme-toggle')
this.propertiesPanel = page.getByTestId('properties-panel')
this.saveButton = page
.locator('button[title="Save the current workflow"]')
.nth(0)
Expand Down
8 changes: 6 additions & 2 deletions browser_tests/helpers/actionbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import type { AutoQueueMode } from '../../src/stores/queueStore'
export class ComfyActionbar {
public readonly root: Locator
public readonly queueButton: ComfyQueueButton
public readonly propertiesButton: Locator

constructor(public readonly page: Page) {
this.root = page.locator('.actionbar')
this.root = page.locator('.actionbar-container')
this.queueButton = new ComfyQueueButton(this)
this.propertiesButton = this.root.getByLabel('Toggle properties panel')
}

async isDocked() {
const className = await this.root.getAttribute('class')
const className = await this.root
.locator('.actionbar')
.getAttribute('class')
return className?.includes('static') ?? false
}
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 30 additions & 15 deletions browser_tests/tests/nodeHelp.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,10 @@ test.describe('Node Help', () => {
await expect(helpButton).toBeVisible()
await helpButton.click()

// Verify that the node library sidebar is opened
await expect(
comfyPage.menu.nodeLibraryTab.selectedTabButton
).toBeVisible()

// Verify that the help page is shown for the correct node
const helpPage = comfyPage.page.locator('.sidebar-content-container')
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
await expect(helpPage).toContainText('KSampler')
await expect(helpPage.locator('.node-help-content')).toBeVisible()
})
Expand Down Expand Up @@ -170,7 +167,9 @@ test.describe('Node Help', () => {
await helpButton.click()

// Verify loading spinner is shown
const helpPage = comfyPage.page.locator('.sidebar-content-container')
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
await expect(helpPage.locator('.p-progressspinner')).toBeVisible()

// Wait for content to load
Expand Down Expand Up @@ -200,7 +199,9 @@ test.describe('Node Help', () => {
await helpButton.click()

// Verify fallback content is shown (description, inputs, outputs)
const helpPage = comfyPage.page.locator('.sidebar-content-container')
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
await expect(helpPage).toContainText('Description')
await expect(helpPage).toContainText('Inputs')
await expect(helpPage).toContainText('Outputs')
Expand Down Expand Up @@ -233,7 +234,9 @@ test.describe('Node Help', () => {
)
await helpButton.click()

const helpPage = comfyPage.page.locator('.sidebar-content-container')
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
await expect(helpPage).toContainText('KSampler Documentation')

// Check that relative image paths are prefixed correctly
Expand Down Expand Up @@ -281,7 +284,9 @@ test.describe('Node Help', () => {
)
await helpButton.click()

const helpPage = comfyPage.page.locator('.sidebar-content-container')
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)

// Check relative video paths are prefixed
const relativeVideo = helpPage.locator('video[src*="demo.mp4"]')
Expand Down Expand Up @@ -354,7 +359,9 @@ This is documentation for a custom node.
if (await helpButton.isVisible()) {
await helpButton.click()

const helpPage = comfyPage.page.locator('.sidebar-content-container')
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
await expect(helpPage).toContainText('Custom Node Documentation')

// Check image path for custom nodes
Expand Down Expand Up @@ -394,7 +401,9 @@ This is documentation for a custom node.
)
await helpButton.click()

const helpPage = comfyPage.page.locator('.sidebar-content-container')
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)

// Dangerous elements should be removed
await expect(helpPage.locator('script')).toHaveCount(0)
Expand Down Expand Up @@ -461,7 +470,9 @@ This is English documentation.
)
await helpButton.click()

const helpPage = comfyPage.page.locator('.sidebar-content-container')
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
await expect(helpPage).toContainText('KSamplerノード')
await expect(helpPage).toContainText('これは日本語のドキュメントです')

Expand All @@ -484,7 +495,9 @@ This is English documentation.
)
await helpButton.click()

const helpPage = comfyPage.page.locator('.sidebar-content-container')
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)

// Should show fallback content (node description)
await expect(helpPage).toBeVisible()
Expand Down Expand Up @@ -528,7 +541,9 @@ This is English documentation.
)
await helpButton.click()

const helpPage = comfyPage.page.locator('.sidebar-content-container')
const helpPage = comfyPage.page.locator(
'[data-testid="properties-panel"]'
)
await expect(helpPage).toContainText('KSampler Help')
await expect(helpPage).toContainText('This is KSampler documentation')

Expand Down
19 changes: 19 additions & 0 deletions browser_tests/tests/propertiesPanel/propertiesPanel.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { expect } from '@playwright/test'

import { comfyPageFixture as test } from '../../fixtures/ComfyPage'

test.describe('Properties panel', () => {
test('opens and updates title based on selection', async ({ comfyPage }) => {
await comfyPage.actionbar.propertiesButton.click()

const { propertiesPanel } = comfyPage.menu

await expect(propertiesPanel.getByText('No node(s) selected')).toBeVisible()

await comfyPage.selectNodes(['KSampler', 'CLIP Text Encode (Prompt)'])

await expect(propertiesPanel.getByText('3 nodes selected')).toBeVisible()

await expect(propertiesPanel.getByText('KSampler')).toHaveCount(1) // Will be 2 in Vue mode
})
})
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
99 changes: 33 additions & 66 deletions src/components/LiteGraphCanvasSplitterOverlay.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<template>
<div class="splitter-overlay-root pointer-events-none flex flex-col">
<div
class="w-full h-full absolute top-0 left-0 z-999 pointer-events-none flex flex-col"
>
<slot name="workflow-tabs" />

<div
Expand All @@ -15,14 +17,13 @@

<Splitter
:key="splitterRefreshKey"
class="splitter-overlay flex-1 overflow-hidden"
:pt:gutter="getSplitterGutterClasses"
class="bg-transparent pointer-events-none border-none flex-1 overflow-hidden"
:state-key="sidebarStateKey"
state-storage="local"
>
<SplitterPanel
v-if="sidebarLocation === 'left'"
class="side-bar-panel pointer-events-auto"
v-if="sidebarLocation === 'left' && !focusMode"
class="side-bar-panel bg-comfy-menu-bg pointer-events-auto"
:min-size="10"
:size="20"
:style="{
Expand All @@ -39,14 +40,16 @@
</SplitterPanel>

<SplitterPanel :size="80" class="flex flex-col">
<slot name="topmenu" :sidebar-panel-visible="sidebarPanelVisible" />
<slot name="topmenu" :sidebar-panel-visible />

<Splitter
class="splitter-overlay splitter-overlay-bottom mr-1 mb-1 ml-1 flex-1"
class="bg-transparent pointer-events-none border-none splitter-overlay-bottom mr-1 mb-1 ml-1 flex-1"
layout="vertical"
:pt:gutter="
'rounded-tl-lg rounded-tr-lg ' +
(bottomPanelVisible ? '' : 'hidden')
cn(
'rounded-tl-lg rounded-tr-lg ',
!(bottomPanelVisible && !focusMode) && 'hidden'
)
"
state-key="bottom-panel-splitter"
state-storage="local"
Expand All @@ -55,16 +58,16 @@
<slot name="graph-canvas-panel" />
</SplitterPanel>
<SplitterPanel
v-show="bottomPanelVisible"
class="bottom-panel pointer-events-auto rounded-lg"
v-show="bottomPanelVisible && !focusMode"
class="bottom-panel border border-(--p-panel-border-color) max-w-full overflow-x-auto bg-comfy-menu-bg pointer-events-auto rounded-lg"
>
<slot name="bottom-panel" />
</SplitterPanel>
</Splitter>
</SplitterPanel>

<SplitterPanel
v-if="sidebarLocation === 'right'"
v-if="sidebarLocation === 'right' && !focusMode"
class="side-bar-panel pointer-events-auto"
:min-size="10"
:size="20"
Expand All @@ -83,8 +86,8 @@

<!-- Right Side Panel - independent of sidebar -->
<SplitterPanel
v-if="rightSidePanelVisible"
class="right-side-panel pointer-events-auto"
v-if="rightSidePanelVisible && !focusMode"
class="bg-comfy-menu-bg pointer-events-auto"
:min-size="15"
:size="20"
>
Expand All @@ -96,6 +99,8 @@
</template>

<script setup lang="ts">
import { cn } from '@comfyorg/tailwind-utils'
import { storeToRefs } from 'pinia'
import Splitter from 'primevue/splitter'
import SplitterPanel from 'primevue/splitterpanel'
import { computed } from 'vue'
Expand All @@ -104,9 +109,12 @@ import { useSettingStore } from '@/platform/settings/settingStore'
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'
import { useRightSidePanelStore } from '@/stores/workspace/rightSidePanelStore'
import { useSidebarTabStore } from '@/stores/workspace/sidebarTabStore'
import { useWorkspaceStore } from '@/stores/workspaceStore'

const workspaceStore = useWorkspaceStore()
const settingStore = useSettingStore()
const rightSidePanelStore = useRightSidePanelStore()
const sidebarTabStore = useSidebarTabStore()
const sidebarLocation = computed<'left' | 'right'>(() =>
settingStore.get('Comfy.Sidebar.Location')
)
Expand All @@ -115,23 +123,19 @@ const unifiedWidth = computed(() =>
settingStore.get('Comfy.Sidebar.UnifiedWidth')
)

const sidebarPanelVisible = computed(
() => useSidebarTabStore().activeSidebarTab !== null
)
const bottomPanelVisible = computed(
() => useBottomPanelStore().bottomPanelVisible
)
const rightSidePanelVisible = computed(() => rightSidePanelStore.isOpen)
const activeSidebarTabId = computed(
() => useSidebarTabStore().activeSidebarTabId
)
const { focusMode } = storeToRefs(workspaceStore)

const { activeSidebarTabId, activeSidebarTab } = storeToRefs(sidebarTabStore)
const { bottomPanelVisible } = storeToRefs(useBottomPanelStore())
const { isOpen: rightSidePanelVisible } = storeToRefs(rightSidePanelStore)

const sidebarPanelVisible = computed(() => activeSidebarTab.value !== null)

const sidebarStateKey = computed(() => {
if (unifiedWidth.value) {
return 'unified-sidebar'
}
// When no tab is active, use a default key to maintain state
return activeSidebarTabId.value ?? 'default-sidebar'
return unifiedWidth.value
? 'unified-sidebar'
: // When no tab is active, use a default key to maintain state
(activeSidebarTabId.value ?? 'default-sidebar')
})

/**
Expand All @@ -142,17 +146,9 @@ const splitterRefreshKey = computed(() => {
? 'main-splitter-with-right-panel'
: 'main-splitter'
})

// Gutter visibility should be controlled by CSS targeting specific gutters
const getSplitterGutterClasses = computed(() => {
// Empty string - let individual gutter styles handle visibility
return ''
})
</script>

<style scoped>
@reference '../assets/css/style.css';

:deep(.p-splitter-gutter) {
pointer-events: auto;
}
Expand All @@ -169,36 +165,7 @@ const getSplitterGutterClasses = computed(() => {
display: none;
}

.side-bar-panel {
background-color: var(--bg-color);
}

.right-side-panel {
background-color: var(--bg-color);
}

.bottom-panel {
background-color: var(--comfy-menu-bg);
border: 1px solid var(--p-panel-border-color);
max-width: 100%;
overflow-x: auto;
}

.splitter-overlay-bottom :deep(.p-splitter-gutter) {
transform: translateY(5px);
}

.splitter-overlay {
@apply bg-transparent pointer-events-none border-none;
}

.splitter-overlay-root {
@apply w-full h-full absolute top-0 left-0;

/* Set it the same as the ComfyUI menu */
/* Note: Lite-graph DOM widgets have the same z-index as the node id, so
999 should be sufficient to make sure splitter overlays on node's DOM
widgets */
z-index: 999;
}
</style>
10 changes: 1 addition & 9 deletions src/components/MenuHamburger.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div
v-show="workspaceState.focusMode"
class="comfy-menu-hamburger no-drag top-0 right-0"
class="fixed z-9999 flex flex-row no-drag top-0 right-0"
>
<Button
v-tooltip="{ value: $t('menu.showMenu'), showDelay: 300 }"
Expand Down Expand Up @@ -44,11 +44,3 @@ watchEffect(() => {
}
})
</script>

<style scoped>
@reference '../assets/css/style.css';

.comfy-menu-hamburger {
@apply fixed z-9999 flex flex-row;
}
</style>
Loading