Skip to content

Commit 4d238ea

Browse files
authored
Merge branch 'main' into feat/onboarding-survey-redesign
2 parents 06334d8 + 1efe8d9 commit 4d238ea

22 files changed

Lines changed: 1924 additions & 579 deletions

File tree

apps/website/src/components/common/SiteFooter.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ const companyColumn: { title: string; links: FooterLink[] } = {
8686
{ label: t('footer.about', locale), href: routes.about },
8787
{ label: t('nav.careers', locale), href: routes.careers },
8888
{ label: t('footer.termsOfService', locale), href: routes.termsOfService },
89+
{ label: t('footer.enterpriseMsa', locale), href: routes.enterpriseMsa },
8990
{ label: t('footer.privacyPolicy', locale), href: routes.privacyPolicy }
9091
]
9192
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { describe, expect, it } from 'vitest'
2+
3+
import { getRoutes } from '../../config/routes'
4+
import { hasKey, translationKeys } from '../../i18n/translations'
5+
6+
const PREFIX = 'enterprise-msa'
7+
8+
function deriveMsaSectionIds(): string[] {
9+
const labelRegex = new RegExp(`^${PREFIX}\\.([0-9]+-[a-z-]+)\\.label$`)
10+
const ids: string[] = []
11+
for (const key of translationKeys) {
12+
const match = key.match(labelRegex)
13+
if (match && !ids.includes(match[1])) ids.push(match[1])
14+
}
15+
return ids
16+
}
17+
18+
describe('enterprise MSA i18n', () => {
19+
it('every derived section has a title and at least one block', () => {
20+
const sectionIds = deriveMsaSectionIds()
21+
expect(sectionIds.length).toBeGreaterThan(0)
22+
for (const id of sectionIds) {
23+
expect(hasKey(`${PREFIX}.${id}.title`)).toBe(true)
24+
expect(hasKey(`${PREFIX}.${id}.block.0`)).toBe(true)
25+
}
26+
})
27+
28+
it('exposes the page-chrome keys the .astro file references', () => {
29+
for (const suffix of [
30+
'effective-date',
31+
'page.title',
32+
'page.description',
33+
'page.heading',
34+
'page.tocLabel',
35+
'page.effectiveDateLabel',
36+
'page.parties'
37+
]) {
38+
expect(hasKey(`${PREFIX}.${suffix}`)).toBe(true)
39+
}
40+
})
41+
42+
it('serves the enterprise MSA at the canonical /enterprise-msa path regardless of locale', () => {
43+
expect(getRoutes('en').enterpriseMsa).toBe('/enterprise-msa')
44+
expect(getRoutes('zh-CN').enterpriseMsa).toBe('/enterprise-msa')
45+
})
46+
})

apps/website/src/config/routes.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const baseRoutes = {
1515
demos: '/demos',
1616
learning: '/learning',
1717
termsOfService: '/terms-of-service',
18+
enterpriseMsa: '/enterprise-msa',
1819
privacyPolicy: '/privacy-policy',
1920
affiliates: '/affiliates',
2021
affiliateTerms: '/affiliates/terms',
@@ -35,10 +36,15 @@ type Routes = typeof baseRoutes
3536
// block in src/i18n/translations.ts for the reasoning.
3637
//
3738
// termsOfService: legal-reviewed English-only document, same reasoning.
39+
//
40+
// enterpriseMsa: legal-reviewed English-only document (Comfy Enterprise
41+
// Customer Agreement template), same reasoning. See the comment header
42+
// in src/pages/enterprise-msa.astro.
3843
const LOCALE_INVARIANT_ROUTE_KEYS = new Set<keyof Routes>([
3944
'affiliates',
4045
'affiliateTerms',
41-
'termsOfService'
46+
'termsOfService',
47+
'enterpriseMsa'
4248
])
4349

4450
export function getRoutes(locale: Locale = 'en'): Routes {
@@ -60,7 +66,7 @@ export const externalLinks = {
6066
cloudStatus: 'https://status.comfy.org',
6167
discord: 'https://discord.com/invite/comfyorg',
6268
docs: 'https://docs.comfy.org/',
63-
docsApi: 'https://docs.comfy.org/api-reference/cloud',
69+
docsApi: 'https://docs.comfy.org/development/cloud/overview#quick-start',
6470
docsMcp: 'https://docs.comfy.org/agent-tools/cloud',
6571
docsSubscription: 'https://docs.comfy.org/support/subscription/subscribing',
6672
github: 'https://github.com/Comfy-Org/ComfyUI',

apps/website/src/i18n/translations.ts

Lines changed: 423 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
// Enterprise Customer Agreement (Enterprise MSA) — English only, by design.
3+
// Legal-reviewed copy must not be served under a localized route until legal
4+
// explicitly approves a translation; rendering an unreviewed translation as
5+
// the active MSA exposes us to liability from the translation diverging from
6+
// the approved English source. See the matching comment in
7+
// src/i18n/translations.ts for the i18n block, and the entry in
8+
// LOCALE_INVARIANT_ROUTE_KEYS in src/config/routes.ts.
9+
import BaseLayout from '../layouts/BaseLayout.astro'
10+
import HeroSection from '../components/legal/HeroSection.vue'
11+
import LegalContentSection from '../components/legal/LegalContentSection.vue'
12+
import { t } from '../i18n/translations'
13+
---
14+
15+
<BaseLayout
16+
title={t('enterprise-msa.page.title')}
17+
description={t('enterprise-msa.page.description')}
18+
>
19+
<HeroSection title={t('enterprise-msa.page.heading')} />
20+
<p class="text-primary-warm-gray mt-2 text-center text-sm">
21+
{t('enterprise-msa.page.effectiveDateLabel')}: {
22+
t('enterprise-msa.effective-date')
23+
}
24+
</p>
25+
<p
26+
class="text-primary-comfy-canvas mx-auto mt-8 max-w-3xl px-4 text-center text-sm/relaxed lg:px-0"
27+
>
28+
{t('enterprise-msa.page.parties')}
29+
</p>
30+
<LegalContentSection
31+
prefix="enterprise-msa"
32+
locale="en"
33+
tocLabelKey="enterprise-msa.page.tocLabel"
34+
client:load
35+
/>
36+
</BaseLayout>

browser_tests/fixtures/selectors.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ export const TestIds = {
110110
},
111111
propertiesPanel: {
112112
root: 'properties-panel',
113-
errorsTab: 'panel-tab-errors'
113+
errorsTab: 'panel-tab-errors',
114+
selectionContextStrip: 'selection-context-strip'
114115
},
115116
assets: {
116117
browserModal: 'asset-browser-modal',

browser_tests/tests/propertiesPanel/errorsTabModeAware.spec.ts

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ test.describe('Errors tab - Mode-aware errors', { tag: '@ui' }, () => {
286286
await expect(missingModelGroup).toBeHidden()
287287
})
288288

289-
test('Selecting a node filters errors tab to only that node', async ({
289+
test('Selecting a node keeps all errors visible and shows selection context', async ({
290290
comfyPage
291291
}) => {
292292
await loadWorkflowAndOpenErrorsTab(
@@ -301,14 +301,25 @@ test.describe('Errors tab - Mode-aware errors', { tag: '@ui' }, () => {
301301

302302
const node1 = await comfyPage.nodeOps.getNodeRefById('1')
303303
await node1.click('title')
304+
304305
await expect(
305306
getMissingModelLabel(missingModelGroup, FAKE_MODEL_NAME)
306307
).toBeVisible()
308+
await expectReferenceBadge(missingModelGroup, 2)
309+
const strip = comfyPage.page.getByTestId(
310+
TestIds.propertiesPanel.selectionContextStrip
311+
)
312+
await expect(strip).toBeVisible()
307313
await expect(
308-
missingModelGroup.getByTestId(TestIds.dialogs.missingModelLocate)
309-
).toHaveCount(1)
314+
strip,
315+
'The strip count is scoped to the selection, diverging from the global reference badge'
316+
).toContainText('1 error')
310317

311318
await comfyPage.canvas.click()
319+
await expect(
320+
strip,
321+
'Deselecting swaps the always-visible strip back to the summary'
322+
).toContainText('2 nodes — 1 error')
312323
await expectReferenceBadge(missingModelGroup, 2)
313324
})
314325
})
@@ -381,7 +392,7 @@ test.describe('Errors tab - Mode-aware errors', { tag: '@ui' }, () => {
381392
await expect(missingMediaGroup).toBeHidden()
382393
})
383394

384-
test('Selecting a node filters errors tab to only that node', async ({
395+
test('Selecting a node keeps all media rows visible and shows selection context', async ({
385396
comfyPage
386397
}) => {
387398
await comfyPage.workflow.loadWorkflow('missing/missing_media_multiple')
@@ -403,13 +414,66 @@ test.describe('Errors tab - Mode-aware errors', { tag: '@ui' }, () => {
403414

404415
const node = await comfyPage.nodeOps.getNodeRefById('10')
405416
await node.click('title')
406-
await expect(mediaRows).toHaveCount(1)
417+
418+
// Selection no longer filters the list — rows stay global and the
419+
// selection is surfaced via the context strip instead.
420+
const strip = comfyPage.page.getByTestId(
421+
TestIds.propertiesPanel.selectionContextStrip
422+
)
423+
await expect(strip).toBeVisible()
424+
await expect(strip).toContainText('1 error')
425+
await expect(mediaRows).toHaveCount(2)
407426

408427
await comfyPage.canvas.click({ position: { x: 400, y: 600 } })
428+
// Deselecting swaps the always-visible strip back to the summary
429+
await expect(strip).toContainText('2 nodes — 2 errors')
409430
await expect(mediaRows).toHaveCount(2)
410431
})
411432
})
412433

434+
test.describe('Selection emphasis', () => {
435+
test('Selecting a node collapses unrelated groups and highlights its rows', async ({
436+
comfyPage
437+
}) => {
438+
await loadWorkflowAndOpenErrorsTab(
439+
comfyPage,
440+
'missing/missing_nodes_and_media'
441+
)
442+
443+
const missingNodeCard = comfyPage.page.getByTestId(
444+
TestIds.dialogs.missingNodeCard
445+
)
446+
const mediaRow = comfyPage.page.getByTestId(
447+
TestIds.dialogs.missingMediaRow
448+
)
449+
const strip = comfyPage.page.getByTestId(
450+
TestIds.propertiesPanel.selectionContextStrip
451+
)
452+
await expect(missingNodeCard).toBeVisible()
453+
await expect(mediaRow).toBeVisible()
454+
await expect(strip).toContainText('2 nodes — 2 errors')
455+
456+
const mediaNode = await comfyPage.nodeOps.getNodeRefById('10')
457+
// The node sits near the canvas top where overlays intercept clicks
458+
await mediaNode.centerOnNode()
459+
await mediaNode.click('title')
460+
461+
// The unrelated missing-node group auto-collapses while the matched
462+
// media row stays visible and is marked as part of the selection
463+
await expect(missingNodeCard).toBeHidden()
464+
await expect(mediaRow).toBeVisible()
465+
await expect(mediaRow).toHaveAttribute('aria-current', 'true')
466+
await expect(strip).toContainText('1 error')
467+
468+
await comfyPage.canvas.click({ position: { x: 400, y: 600 } })
469+
// Emphasis ends: the collapsed group re-expands and the strip
470+
// returns to the workflow summary
471+
await expect(missingNodeCard).toBeVisible()
472+
await expect(mediaRow).not.toHaveAttribute('aria-current', 'true')
473+
await expect(strip).toContainText('2 nodes — 2 errors')
474+
})
475+
})
476+
413477
test.describe('Subgraph', () => {
414478
test.beforeEach(async ({ comfyPage }) => {
415479
await cleanupFakeModel(comfyPage)

0 commit comments

Comments
 (0)