Skip to content
Closed
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
c77f0cb
[backport cloud/1.37] fix: version mismatch warning appearing in Play…
comfy-pr-bot Jan 14, 2026
5ec29f6
[backport cloud/1.37] linear v2: Simple Mode (#8047)
AustinMroz Jan 14, 2026
3c99e75
[backport cloud/1.37] [API Nodes] add price badges for Meshy 3D nodes…
comfy-pr-bot Jan 14, 2026
cd6047f
[backport cloud/1.37] Fix: Update for Image Widget test (#8051)
comfy-pr-bot Jan 14, 2026
d85c469
[backport cloud/1.37] feat(price-badges): add ByteDance SeeDance 1.5 …
comfy-pr-bot Jan 15, 2026
9132f87
[backport cloud/1.37] Linear mode bug fixes (#8072)
comfy-pr-bot Jan 15, 2026
a3cd630
[backport cloud/1.37] fix: prevent Record Audio waveform from overflo…
comfy-pr-bot Jan 15, 2026
40b0954
[backport cloud/1.37] Further linear fixes (#8084)
AustinMroz Jan 15, 2026
5a276f2
[backport cloud/1.37] Make sure toggle visibility checks remote confi…
AustinMroz Jan 16, 2026
ac6adb0
[backport cloud/1.37] Fix copypasted primitives inside subgraphs (#8096)
comfy-pr-bot Jan 16, 2026
3eb8c6a
[backport cloud/1.37] Improve linear compatibility with Safari, run b…
AustinMroz Jan 16, 2026
e036d76
[backport cloud/1.37] Fix asset selection in litegraph (#8119)
comfy-pr-bot Jan 17, 2026
a55cae5
[backport cloud/1.37] Update beta message in linear mode (#8109)
comfy-pr-bot Jan 17, 2026
05cbcce
[backport cloud/1.37] feat: make subgraphs blueprints appear higher i…
comfy-pr-bot Jan 18, 2026
995906a
[backport cloud/1.37] control widget fixes (#8163)
AustinMroz Jan 19, 2026
def9b55
Remove hamburger menu from tabs (#8067)
pythongosssss Jan 15, 2026
b7ddd50
[cloud/1.37] Regenerate expectations (#8198)
DrJKL Jan 21, 2026
f074243
[backport cloud/1.37] feat: When a list of strings is received, show …
comfy-pr-bot Jan 21, 2026
abb2b15
[backport cloud/1.37] feat: add per-tab workspace authentication infr…
comfy-pr-bot Jan 22, 2026
751253f
[backport cloud/1.37] feat: add maxColumns prop to VirtualGrid for re…
comfy-pr-bot Jan 22, 2026
14a2208
[backport cloud/1.37] feat(StatusBadge): add dot mode with CVA varian…
comfy-pr-bot Jan 22, 2026
06bc103
[backport cloud/1.37] feat(ui): add shadcn-vue Select components (#8234)
comfy-pr-bot Jan 22, 2026
a6da367
[backport cloud/1.37] feat(ui): add TagsInput component with click-to…
comfy-pr-bot Jan 22, 2026
32ce523
[backport cloud/1.37] feat: add isCloud guard to team workspaces feat…
simula-r Jan 22, 2026
b8a103b
[backport cloud/1.37] feat: add workspace session, auth, and store in…
simula-r Jan 22, 2026
7faf8e0
[backport cloud/1.37] fix: Consistent keydown handling for EditableTe…
DrJKL Jan 22, 2026
0c3d569
[backport cloud/1.37] feat: add badge support to NavItem component (#…
DrJKL Jan 22, 2026
5d94c11
[backport cloud/1.37] feat: add session download tracking to assetDow…
comfy-pr-bot Jan 22, 2026
2d0f3d6
[backport cloud/1.37] refactor: restructure BaseModalLayout from flex…
DrJKL Jan 22, 2026
eb7d0c7
[backport cloud/1.37] feat: implement progressive pagination for Asse…
DrJKL Jan 22, 2026
b98d53e
[backport cloud/1.37] feat(assets): add ModelInfoPanel for asset brow…
DrJKL Jan 22, 2026
88f7886
[backport cloud/1.37] Updates: Model Management (#8255)
comfy-pr-bot Jan 23, 2026
9db2fd8
[backport cloud/1.37] Workspaces 3 create a workspace (#8221) (#8252)
simula-r Jan 23, 2026
9b7f20c
[backport cloud/1.37] Add telemetry for entering linear mode (#8265)
comfy-pr-bot Jan 23, 2026
7a5fb57
[backport cloud/1.37] fix: use authenticated API for remote config po…
comfy-pr-bot Jan 24, 2026
12761f8
[backport cloud/1.37] Linear: progressbar, tooltips, and output fixes…
comfy-pr-bot Jan 24, 2026
4c3c61f
[backport cloud/1.37] [bugfix] Fix inconsistent menu icon sizes in Co…
comfy-pr-bot Jan 24, 2026
113a6a7
[backport cloud/1.37] fix: fallback to asset metadata/name when filen…
comfy-pr-bot Jan 25, 2026
745ea0a
[backport cloud/1.37] [refactor] Manager dialog simplification (#8306)
DrJKL Jan 25, 2026
ec91aa8
[backport cloud/1.37] Updates: More Modal Modification (#8308)
DrJKL Jan 25, 2026
3eb15bb
[backport cloud/1.37] feat: add getAssetFilename util with fallback c…
comfy-pr-bot Jan 25, 2026
3b7e102
[backport cloud/1.37] Add 3d control buttons to linear mode (#8289)
comfy-pr-bot Jan 25, 2026
1963f28
[backport cloud/1.37] Workspaces 4 members invites (#8301)
simula-r Jan 25, 2026
e82c692
[backport cloud/1.37] fix: workspace icon flash and credits showing 0…
comfy-pr-bot Jan 27, 2026
e751cf4
[backport cloud/1.37] perf: remove autoplay from assets cards (#8327)
comfy-pr-bot Jan 27, 2026
a5f50ac
[backport cloud/1.37] feat: add Hugging Face model source support (#8…
comfy-pr-bot Jan 27, 2026
4c2edae
[backport cloud/1.37] Fix dragging Vue nodes into canvas from library…
comfy-pr-bot Jan 28, 2026
8e5a037
[backport cloud/1.37] Feat/workspaces 5 auth gate check (#8357)
simula-r Jan 28, 2026
72add79
[backport cloud/1.37] fix: move WorkspaceAuthGate to LayoutDefault fo…
comfy-pr-bot Jan 29, 2026
2f9ede1
[backport cloud/1.37] Templates: Search speed (#8397)
comfy-pr-bot Jan 29, 2026
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
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.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ test.describe('Properties panel', () => {
const { propertiesPanel } = comfyPage.menu

await expect(propertiesPanel.panelTitle).toContainText(
'No node(s) selected'
'No item(s) selected'
)

await comfyPage.selectNodes(['KSampler', 'CLIP Text Encode (Prompt)'])
Expand Down
11 changes: 4 additions & 7 deletions browser_tests/tests/templates.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,7 @@ test.describe('Templates', () => {
await expect(comfyPage.templates.content).toBeVisible()

await comfyPage.page
.locator(
'nav > div:nth-child(3) > div > span:has-text("Getting Started")'
)
.getByRole('button', { name: 'Getting Started' })
.click()
await comfyPage.templates.loadTemplate('default')
await expect(comfyPage.templates.content).toBeHidden()
Expand Down Expand Up @@ -189,9 +187,7 @@ test.describe('Templates', () => {
const templateGrid = comfyPage.page.locator(
'[data-testid="template-workflows-content"]'
)
const nav = comfyPage.page
.locator('header')
.filter({ hasText: 'Templates' })
const nav = comfyPage.page.locator('header', { hasText: 'Templates' })

await comfyPage.templates.waitForMinimumCardCount(1)
await expect(templateGrid).toBeVisible()
Expand All @@ -201,7 +197,8 @@ test.describe('Templates', () => {
await comfyPage.page.setViewportSize(mobileSize)
await comfyPage.templates.waitForMinimumCardCount(1)
await expect(templateGrid).toBeVisible()
await expect(nav).not.toBeVisible() // Nav should collapse at mobile size
// Nav header is clipped by overflow-hidden parent at mobile size
await expect(nav).not.toBeInViewport()

const tabletSize = { width: 1024, height: 800 }
await comfyPage.page.setViewportSize(tabletSize)
Expand Down
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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion browser_tests/tests/widget.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@ test.describe('Image widget', () => {
const comboEntry = comfyPage.page.getByRole('menuitem', {
name: 'image32x32.webp'
})
await comboEntry.click({ noWaitAfter: true })
await comboEntry.click()

// Stabilization for the image swap
await comfyPage.nextFrame()

// Expect the image preview to change automatically
await expect(comfyPage.canvas).toHaveScreenshot(
Expand Down
4 changes: 4 additions & 0 deletions docs/testing/vitest-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ describe('MyStore', () => {

**Why `stubActions: false`?** By default, testing pinia stubs all actions. Set to `false` when testing actual store behavior.

## i18n in Component Tests

Use real `createI18n` with empty messages instead of mocking `vue-i18n`. See `SearchBox.test.ts` for example.

## Mock Patterns

### Reset all mocks at once
Expand Down
5 changes: 4 additions & 1 deletion packages/design-system/src/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@
--inverted-background-hover: var(--color-charcoal-600);
--warning-background: var(--color-gold-400);
--warning-background-hover: var(--color-gold-500);
--success-background: var(--color-jade-600);
--border-default: var(--color-smoke-600);
--border-subtle: var(--color-smoke-400);
--muted-background: var(--color-smoke-700);
Expand Down Expand Up @@ -281,7 +282,7 @@
--modal-card-border-highlighted: var(--secondary-background-selected);
--modal-card-button-surface: var(--color-smoke-300);
--modal-card-placeholder-background: var(--color-smoke-600);
--modal-card-tag-background: var(--color-smoke-400);
--modal-card-tag-background: var(--color-smoke-200);
--modal-card-tag-foreground: var(--base-foreground);
--modal-panel-background: var(--color-white);
}
Expand Down Expand Up @@ -372,6 +373,7 @@
--inverted-background-hover: var(--color-smoke-200);
--warning-background: var(--color-gold-600);
--warning-background-hover: var(--color-gold-500);
--success-background: var(--color-jade-600);
--border-default: var(--color-charcoal-200);
--border-subtle: var(--color-charcoal-300);
--muted-background: var(--color-charcoal-100);
Expand Down Expand Up @@ -516,6 +518,7 @@
--color-inverted-background-hover: var(--inverted-background-hover);
--color-warning-background: var(--warning-background);
--color-warning-background-hover: var(--warning-background-hover);
--color-success-background: var(--success-background);
--color-border-default: var(--border-default);
--color-border-subtle: var(--border-subtle);
--color-muted-background: var(--muted-background);
Expand Down
10 changes: 5 additions & 5 deletions src/components/common/EditableText.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('EditableText', () => {
isEditing: true
})
await wrapper.findComponent(InputText).setValue('New Text')
await wrapper.findComponent(InputText).trigger('keyup.enter')
await wrapper.findComponent(InputText).trigger('keydown.enter')
// Blur event should have been triggered
expect(wrapper.findComponent(InputText).element).not.toBe(
document.activeElement
Expand Down Expand Up @@ -79,7 +79,7 @@ describe('EditableText', () => {
await wrapper.findComponent(InputText).setValue('Modified Text')

// Press escape
await wrapper.findComponent(InputText).trigger('keyup.escape')
await wrapper.findComponent(InputText).trigger('keydown.escape')

// Should emit cancel event
expect(wrapper.emitted('cancel')).toBeTruthy()
Expand All @@ -103,7 +103,7 @@ describe('EditableText', () => {
await wrapper.findComponent(InputText).setValue('Modified Text')

// Press escape (which triggers blur internally)
await wrapper.findComponent(InputText).trigger('keyup.escape')
await wrapper.findComponent(InputText).trigger('keydown.escape')

// Manually trigger blur to simulate the blur that happens after escape
await wrapper.findComponent(InputText).trigger('blur')
Expand All @@ -120,7 +120,7 @@ describe('EditableText', () => {
isEditing: true
})
await enterWrapper.findComponent(InputText).setValue('Saved Text')
await enterWrapper.findComponent(InputText).trigger('keyup.enter')
await enterWrapper.findComponent(InputText).trigger('keydown.enter')
// Trigger blur that happens after enter
await enterWrapper.findComponent(InputText).trigger('blur')
expect(enterWrapper.emitted('edit')).toBeTruthy()
Expand All @@ -133,7 +133,7 @@ describe('EditableText', () => {
isEditing: true
})
await escapeWrapper.findComponent(InputText).setValue('Cancelled Text')
await escapeWrapper.findComponent(InputText).trigger('keyup.escape')
await escapeWrapper.findComponent(InputText).trigger('keydown.escape')
expect(escapeWrapper.emitted('cancel')).toBeTruthy()
expect(escapeWrapper.emitted('edit')).toBeFalsy()
})
Expand Down
6 changes: 3 additions & 3 deletions src/components/common/EditableText.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<span v-if="!isEditing">
{{ modelValue }}
</span>
<!-- Avoid double triggering finishEditing event when keyup.enter is triggered -->
<!-- Avoid double triggering finishEditing event when keydown.enter is triggered -->
<InputText
v-else
ref="inputRef"
Expand All @@ -18,8 +18,8 @@
...inputAttrs
}
}"
@keyup.enter.capture.stop="blurInputElement"
@keyup.escape.stop="cancelEditing"
@keydown.enter.capture.stop="blurInputElement"
@keydown.escape.capture.stop="cancelEditing"
@click.stop
@contextmenu.stop
@pointerdown.stop.capture
Expand Down
95 changes: 95 additions & 0 deletions src/components/common/StatusBadge.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import type { Meta, StoryObj } from '@storybook/vue3-vite'

import StatusBadge from './StatusBadge.vue'

const meta = {
title: 'Common/StatusBadge',
component: StatusBadge,
tags: ['autodocs'],
argTypes: {
label: { control: 'text' },
severity: {
control: 'select',
options: ['default', 'secondary', 'warn', 'danger', 'contrast']
},
variant: {
control: 'select',
options: ['label', 'dot', 'circle']
}
},
args: {
label: 'Status',
severity: 'default'
}
} satisfies Meta<typeof StatusBadge>

export default meta
type Story = StoryObj<typeof meta>

export const Default: Story = {}

export const Failed: Story = {
args: {
label: 'Failed',
severity: 'danger'
}
}

export const Finished: Story = {
args: {
label: 'Finished',
severity: 'contrast'
}
}

export const Dot: Story = {
args: {
label: undefined,
variant: 'dot',
severity: 'danger'
}
}

export const Circle: Story = {
args: {
label: '3',
variant: 'circle'
}
}

export const AllSeverities: Story = {
render: () => ({
components: { StatusBadge },
template: `
<div class="flex items-center gap-2">
<StatusBadge label="Default" severity="default" />
<StatusBadge label="Secondary" severity="secondary" />
<StatusBadge label="Warn" severity="warn" />
<StatusBadge label="Danger" severity="danger" />
<StatusBadge label="Contrast" severity="contrast" />
</div>
`
})
}

export const AllVariants: Story = {
render: () => ({
components: { StatusBadge },
template: `
<div class="flex items-center gap-4">
<div class="flex flex-col items-center gap-1">
<StatusBadge label="Label" variant="label" />
<span class="text-xs text-muted">label</span>
</div>
<div class="flex flex-col items-center gap-1">
<StatusBadge variant="dot" severity="danger" />
<span class="text-xs text-muted">dot</span>
</div>
<div class="flex flex-col items-center gap-1">
<StatusBadge label="5" variant="circle" />
<span class="text-xs text-muted">circle</span>
</div>
</div>
`
})
}
43 changes: 20 additions & 23 deletions src/components/common/StatusBadge.vue
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
<script setup lang="ts">
type Severity = 'default' | 'secondary' | 'warn' | 'danger' | 'contrast'
import { statusBadgeVariants } from './statusBadge.variants'
import type { StatusBadgeVariants } from './statusBadge.variants'

const { label, severity = 'default' } = defineProps<{
label: string
severity?: Severity
const {
label,
severity = 'default',
variant
} = defineProps<{
label?: string | number
severity?: StatusBadgeVariants['severity']
variant?: StatusBadgeVariants['variant']
}>()

function badgeClasses(sev: Severity): string {
const baseClasses =
'inline-flex h-3.5 items-center justify-center rounded-full px-1 text-xxxs font-semibold uppercase'

switch (sev) {
case 'danger':
return `${baseClasses} bg-destructive-background text-white`
case 'contrast':
return `${baseClasses} bg-base-foreground text-base-background`
case 'warn':
return `${baseClasses} bg-warning-background text-base-background`
case 'secondary':
return `${baseClasses} bg-secondary-background text-base-foreground`
default:
return `${baseClasses} bg-primary-background text-base-foreground`
}
}
</script>

<template>
<span :class="badgeClasses(severity)">{{ label }}</span>
<span
:class="
statusBadgeVariants({
severity,
variant: variant ?? (label == null ? 'dot' : 'label')
})
"
>
{{ label }}
</span>
</template>
Loading