mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-28 00:07:32 +00:00
Compare commits
8 Commits
bl/com-304
...
feat/cloud
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d747ee40b9 | ||
|
|
07d32a9284 | ||
|
|
d67a875f8c | ||
|
|
e074c55d16 | ||
|
|
43192607f8 | ||
|
|
e809d74192 | ||
|
|
47c9a027a7 | ||
|
|
6fbc5723bd |
@@ -51,7 +51,8 @@ export const TestIds = {
|
||||
topbar: {
|
||||
queueButton: 'queue-button',
|
||||
queueModeMenuTrigger: 'queue-mode-menu-trigger',
|
||||
saveButton: 'save-workflow-button'
|
||||
saveButton: 'save-workflow-button',
|
||||
subscribeButton: 'topbar-subscribe-button'
|
||||
},
|
||||
nodeLibrary: {
|
||||
bookmarksSection: 'node-library-bookmarks-section'
|
||||
|
||||
28
browser_tests/tests/cloud.spec.ts
Normal file
28
browser_tests/tests/cloud.spec.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
|
||||
import { TestIds } from '../fixtures/selectors'
|
||||
|
||||
test.describe('Cloud distribution UI @cloud', () => {
|
||||
test('subscribe button is attached in cloud mode @cloud', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const subscribeButton = comfyPage.page.getByTestId(
|
||||
TestIds.topbar.subscribeButton
|
||||
)
|
||||
await expect(subscribeButton).toBeAttached()
|
||||
})
|
||||
|
||||
test('bottom panel toggle is hidden in cloud mode @cloud', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const sideToolbar = comfyPage.page.getByTestId(TestIds.sidebar.toolbar)
|
||||
await expect(sideToolbar).toBeVisible()
|
||||
|
||||
// In cloud mode, the bottom panel toggle button should not be rendered
|
||||
const bottomPanelToggle = sideToolbar.getByRole('button', {
|
||||
name: /bottom panel|terminal/i
|
||||
})
|
||||
await expect(bottomPanelToggle).toHaveCount(0)
|
||||
})
|
||||
})
|
||||
@@ -8,6 +8,7 @@
|
||||
"repository": "https://github.com/Comfy-Org/ComfyUI_frontend",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build:cloud": "cross-env DISTRIBUTION=cloud NODE_OPTIONS='--max-old-space-size=8192' nx build",
|
||||
"build:desktop": "nx build @comfyorg/desktop-ui",
|
||||
"build-storybook": "storybook build",
|
||||
"build:types": "nx build --config vite.types.config.mts && node scripts/prepare-types.js",
|
||||
|
||||
@@ -36,7 +36,7 @@ export default defineConfig({
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
timeout: 15000,
|
||||
grepInvert: /@mobile|@perf|@audit/ // Run all tests except those tagged with @mobile, @perf, or @audit
|
||||
grepInvert: /@mobile|@perf|@audit|@cloud/ // Run all tests except those tagged with @mobile, @perf, @audit, or @cloud
|
||||
},
|
||||
|
||||
{
|
||||
@@ -85,6 +85,14 @@ export default defineConfig({
|
||||
// use: { ...devices['Desktop Safari'] },
|
||||
// },
|
||||
|
||||
{
|
||||
name: 'cloud',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
timeout: 15000,
|
||||
grep: /@cloud/, // Run only tests tagged with @cloud
|
||||
grepInvert: /@oss/ // Exclude tests tagged with @oss
|
||||
},
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
{
|
||||
name: 'mobile-chrome',
|
||||
|
||||
@@ -67,7 +67,14 @@ Sentry.init({
|
||||
replaysOnErrorSampleRate: 0,
|
||||
// Only set these for non-cloud builds
|
||||
...(isCloud
|
||||
? {}
|
||||
? {
|
||||
integrations: [
|
||||
// Disable event target wrapping to reduce overhead on high-frequency
|
||||
// DOM events (pointermove, mousemove, wheel). Sentry still captures
|
||||
// errors via window.onerror and unhandledrejection.
|
||||
Sentry.browserApiErrorsIntegration({ eventTarget: false })
|
||||
]
|
||||
}
|
||||
: {
|
||||
integrations: [],
|
||||
autoSessionTracking: false,
|
||||
|
||||
@@ -141,6 +141,7 @@ import { computed, defineAsyncComponent, provide, ref, toRef } from 'vue'
|
||||
import IconGroup from '@/components/button/IconGroup.vue'
|
||||
import LoadingOverlay from '@/components/common/LoadingOverlay.vue'
|
||||
import Button from '@/components/ui/button/Button.vue'
|
||||
import { isCloud } from '@/platform/distribution/types'
|
||||
import { useAssetsStore } from '@/stores/assetsStore'
|
||||
import {
|
||||
formatDuration,
|
||||
@@ -279,7 +280,8 @@ const formattedDuration = computed(() => {
|
||||
// Get metadata info based on file kind
|
||||
const metaInfo = computed(() => {
|
||||
if (!asset) return ''
|
||||
if (fileKind.value === 'image' && imageDimensions.value) {
|
||||
// TODO(assets): Re-enable once /assets API returns original image dimensions in metadata (#10590)
|
||||
if (fileKind.value === 'image' && imageDimensions.value && !isCloud) {
|
||||
return `${imageDimensions.value.width}x${imageDimensions.value.height}`
|
||||
}
|
||||
if (asset.size && ['video', 'audio', '3D'].includes(fileKind.value)) {
|
||||
|
||||
@@ -300,6 +300,25 @@ describe('TeamWorkspacesDialogContent', () => {
|
||||
|
||||
expect(mockCreateWorkspace).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('resets loading state after createWorkspace fails', async () => {
|
||||
mockCreateWorkspace.mockRejectedValue(new Error('Limit reached'))
|
||||
const wrapper = mountComponent()
|
||||
|
||||
await typeAndCreate(wrapper, 'New Team')
|
||||
|
||||
expect(findCreateButton(wrapper).props('loading')).toBe(false)
|
||||
})
|
||||
|
||||
it('resets loading state after onConfirm fails', async () => {
|
||||
mockCreateWorkspace.mockResolvedValue({ id: 'new-ws' })
|
||||
const onConfirm = vi.fn().mockRejectedValue(new Error('Setup failed'))
|
||||
const wrapper = mountComponent({ onConfirm })
|
||||
|
||||
await typeAndCreate(wrapper, 'New Team')
|
||||
|
||||
expect(findCreateButton(wrapper).props('loading')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('close button', () => {
|
||||
|
||||
@@ -201,28 +201,30 @@ async function handleSwitch(workspaceId: string) {
|
||||
async function onCreate() {
|
||||
if (!isValidName.value || loading.value) return
|
||||
loading.value = true
|
||||
const name = workspaceName.value.trim()
|
||||
try {
|
||||
await workspaceStore.createWorkspace(name)
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: t('workspacePanel.toast.failedToCreateWorkspace'),
|
||||
detail: error instanceof Error ? error.message : t('g.unknownError')
|
||||
})
|
||||
const name = workspaceName.value.trim()
|
||||
try {
|
||||
await workspaceStore.createWorkspace(name)
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: t('workspacePanel.toast.failedToCreateWorkspace'),
|
||||
detail: error instanceof Error ? error.message : t('g.unknownError')
|
||||
})
|
||||
return
|
||||
}
|
||||
try {
|
||||
await onConfirm?.(name)
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: t('teamWorkspacesDialog.confirmCallbackFailed'),
|
||||
detail: error instanceof Error ? error.message : t('g.unknownError')
|
||||
})
|
||||
}
|
||||
dialogStore.closeDialog({ key: DIALOG_KEY })
|
||||
} finally {
|
||||
loading.value = false
|
||||
return
|
||||
}
|
||||
try {
|
||||
await onConfirm?.(name)
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: t('teamWorkspacesDialog.confirmCallbackFailed'),
|
||||
detail: error instanceof Error ? error.message : t('g.unknownError')
|
||||
})
|
||||
}
|
||||
dialogStore.closeDialog({ key: DIALOG_KEY })
|
||||
loading.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user