Commit Graph

8528 Commits

Author SHA1 Message Date
dante01yoon
4e609999d4 test(billing): harden personal→team gate test against cold-run emit race (FE-991)
The new container gate test could fail on a cold-cache first run (onChooseTeam
observed 0 calls) due to a userEvent/happy-dom event-dispatch warm-up race; the
gate source is synchronous and correct. Wrap the positive assertions in
vi.waitFor so the emit lands deterministically.
2026-06-22 00:20:55 +09:00
dante01yoon
d526bcd3dc feat(billing): route personal-workspace team-plan pick to workspace create/switch (FE-991)
A team plan can't be subscribed in place from a personal workspace, so a
personal user choosing a team plan in the unified pricing table is routed to
the Team Workspaces create/switch dialog instead of advancing into team
checkout. Gate on isInPersonalWorkspace; team workspaces keep the normal flow.
2026-06-21 23:39:55 +09:00
dante01yoon
09dd1f4826 feat(billing): role-gate Plan & Credits menu and action buttons (FE-768)
Port of the FE-768 Plan & Credits redesign onto the integration base,
using canManageSubscriptionLifecycle for the original-owner gate.

- ... menu per role: original owner = Edit / Cancel plan / Delete;
  promoted owner = Edit / Leave; member = Leave; personal = Edit, plus
  Cancel plan + Delete once on a paid plan.
- Cancel/Delete are creator-or-personal-owner only; the creator can't
  leave; Delete is locked while a team subscription is active.
- Render the menu via the design-system DropdownMenu (dividers, danger
  Delete) to match Figma; cancelled state shows Manage billing +
  Reactivate plan; personal Free shows Subscribe, both with the menu.
2026-06-21 23:03:17 +09:00
dante01yoon
d29a0b4167 fix(billing): match team-upgrade invite block to Figma (FE-965)
- give the email input a persistent tertiary-background fill so it reads as a
  field at rest, not only on focus (Figma 3084-6116)
- add a showSubmit prop to InviteMembersForm and expose submit/canSubmit/loading
  so the success screen places "Send invites" in the footer next to Close,
  not glued under the input (Figma 3698-10316)
2026-06-21 01:11:45 +09:00
dante01yoon
13ca482b77 fix(billing): show the checkout success page after team/async subscribe (FE-934)
A Stripe-backed subscribe (needs_payment_method / pending_payment) only fired
the billing op poll; on completion billingOperationStore.handleSuccess closed
the pricing dialog and opened settings, so "You're all set" never showed. Team
subscribes were also gated out of the success step by a selectedTierKey-only
guard.

- await the billing op in the async checkout branches and advance to the
  success step instead of tearing the dialog down
- leave the subscription dialog open in handleSuccess (only top-ups close +
  surface settings); keep the success toast
- render the success step for team checkouts, sourcing the name, price and
  credits from the selected slider stop
- drive the team success invite block off the flat MAX_WORKSPACE_MEMBERS cap
2026-06-21 00:32:30 +09:00
dante01yoon
3d228e3306 fix(billing): cancelled team sub on a different stop reads Change plan, not Resubscribe (FE-934) 2026-06-20 23:09:27 +09:00
dante01yoon
456cf7227e fix(billing): keep both credits-row buttons inside the user popover
A cancelled-but-still-active personal subscription renders both "Add credits" and "Resubscribe" in the credits row. With a wide (7-digit) balance the second button overflowed the fixed-width w-80 popover. Make the popover width fluid (w-fit, clamped min-w-80..max-w-96) so it stays 320px in the common single-action case and only grows (to ~370px) to fit both buttons.

Adds a @cloud e2e that asserts the Resubscribe button stays within the popover bounds.
2026-06-20 23:04:09 +09:00
dante01yoon
298529895d fix(billing): gate team CTA on current stop (Current plan/Change plan), drop slider stop disable (FE-934) 2026-06-20 22:58:51 +09:00
dante01yoon
2d12005629 feat(billing): disable the active team stop in the pricing slider; cancelled re-subscribes (FE-934) 2026-06-20 22:33:34 +09:00
dante01yoon
fc18ae7f8a feat(billing): price team Plan & Credits header from subscribed credit stop (FE-768) 2026-06-20 20:29:32 +09:00
dante01yoon
dafcf206fb feat(billing): surface team_credit_stops + drive CreditsTile monthly total from current stop (FE-964) 2026-06-20 20:23:26 +09:00
dante01yoon
eef3d739aa Merge FE-768 test fix (invoice-card assertions) into FE-991 integration 2026-06-20 13:00:05 +09:00
dante01yoon
9a0becfd06 test(billing): drop invoice-card assertions after card removal (FE-768) 2026-06-20 12:59:19 +09:00
dante01yoon
de466b72e5 Merge FE-768 plan-credits tip (remove Next month invoice card) into FE-991 integration 2026-06-20 12:56:44 +09:00
dante01yoon
29df1542d5 feat(billing): remove Next month invoice card from Plan & Credits panel (FE-768) 2026-06-20 12:46:31 +09:00
dante01yoon
67ea86e60c fix(billing): reopen team pricing tab from Members Upgrade to Team (FE-934)
Members upsell 'Upgrade to Team' was re-wired to showSubscriptionDialog()
during the FE-768 members merge, dropping the FE-934 team-tab fix on this
integration branch. Restore showTeamPlans() -> show({ planMode: 'team' }).
2026-06-20 09:58:48 +09:00
dante01yoon
0ebf3618f6 chore(preview): repoint backend pin to pr-4378 ephemeral env [do not merge] 2026-06-20 09:03:31 +09:00
dante01yoon
b6909e37c7 chore(preview): pin backend to pr-4393 ephemeral env [do not merge]
Route all same-origin /api, websocket, and bootstrap /api/features calls to https://pr-4393.testenvs.comfy.org so the labeled preview build exercises that ephemeral backend. Throwaway, scoped to this DO NOT MERGE integration PR.
2026-06-20 08:30:49 +09:00
dante01yoon
0574c2971d feat(billing): inline "Invite your team" block on team-upgrade success (FE-965 / DES-394)
Renders an inline invite block in the team variant of the "You're all set" success card so a buyer can invite teammates right after a team-plan upgrade.

- New shared InviteMembersForm.vue (chips/TagsInput multi-email form)
- Team upgrades only; seats capped via useBillingContext.getMaxSeats
- workspace_invite_sent telemetry + success-card i18n
- Storybook story + mocks

Stacked on FE-934 #12975 (success-card host).

(cherry picked from commit af8a7a1f41)
2026-06-20 00:29:54 +09:00
dante01yoon
fd79281e43 fix(billing): await members fetch before the deep-link gate (FE-1104)
(cherry picked from commit 4cd6f2f8b9)
2026-06-19 23:40:23 +09:00
dante01yoon
ab082bf952 test(billing): add @cloud e2e for the pricing deep link (FE-1104)
(cherry picked from commit c9babcdb85)
2026-06-19 23:40:18 +09:00
dante01yoon
6c3856d8c4 feat(billing): deep link to open the pricing table (FE-1104)
Add a /?pricing=1 (and /?pricing=team / =personal) deep link that opens the
pricing table on app load, gated to the original owner via
canManageSubscriptionLifecycle. Members and promoted owners are a silent
no-op (param stripped, app loads normally). Mirrors the existing preserved-
query URL-loader pattern; survives the login redirect. Eligible opens emit
the subscription modal_opened telemetry with a new deep_link reason.

(cherry picked from commit 0708c01f79)
2026-06-19 23:40:12 +09:00
dante01yoon
2b9dd72d87 fix(workspace): only preload members for team workspaces
The watch now gates ensureMembersLoaded on activeWorkspace.type === 'team'
so personal/undefined workspaces never invoke the store loader. This keeps
consumer composables that mock the store minimally (useSubscriptionDialog)
working, while the store method stays the idempotent safe loader.

(cherry picked from commit dde38af722)
2026-06-19 23:40:07 +09:00
dante01yoon
a0c7127155 refactor(workspace): move members preload into store ensureMembersLoaded
Address review: own the team members-preload coordination in the store
instead of the composable. ensureMembersLoaded no-ops for personal /
already-loaded workspaces, dedupes in-flight calls, and logs failures so a
later call retries. Inline the redundant isCurrentUserOriginalOwner computed.

(cherry picked from commit 8278c9d874)
2026-06-19 23:40:00 +09:00
dante01yoon
78dcc16a3b fix(billing): repoint FE-965 team-success story to renamed creator fixture
The FE-934 single-plan-confirm cherry-pick renamed the stories' plan
fixtures (creatorPlan -> creatorMonthly/creatorAnnual); the FE-965
TeamSuccessWithInvite story still referenced the removed creatorPlan.
2026-06-19 23:38:18 +09:00
GitHub Action
6ec0f331b3 [automated] Apply ESLint and Oxfmt fixes
(cherry picked from commit f45b9e80ab)
2026-06-19 23:35:54 +09:00
dante01yoon
e3c3473f97 fix(billing): tertiary CTA surface + correct success check color (FE-934)
The confirm CTA used the `secondary` variant (charcoal-600), nearly
indistinguishable from the dialog surface. Add a `tertiary-background`
design-system token (charcoal-400 per the DES spec) and a matching Button
variant, and use it for the confirm CTAs. The success check pointed at the
undefined `success-foreground` token (no color); switch it to the defined
`success-background` (#00cd72).

(cherry picked from commit 5b113faa20)
2026-06-19 23:35:49 +09:00
dante01yoon
a3858b39c4 feat(billing): single-plan plan-change confirm + monthly billed note (FE-934)
Rewrite the plan-change confirm to the single-plan layout from the design
mockup: immediate upgrades show prorated line items with upfront (yearly)
or monthly credit refill; scheduled downgrades show "Starts {date}", $0
due today, and an "After that" block. Add the "Billed monthly" note to the
new-subscription confirm and Storybook stories covering each variation.

(cherry picked from commit d61ab982c5)
2026-06-19 23:35:32 +09:00
dante01yoon
47ec1de9d0 fix(test): use namespace type import for vi.mock importOriginal
(cherry picked from commit af2e9bbc7b)
2026-06-19 23:14:20 +09:00
dante01yoon
912320bb7d feat(workspace): reactivate-vs-upgrade copy for lapsed team plans (FE-768)
The members upsell banner read 'Upgrade to Team' regardless of prior subscription. Branch the copy on a lapsed team plan (subscription_status 'canceled' or 'ended') so cancelled/ended workspaces see 'Reactivate Team' / 'To add more teammates, reactivate your plan.' instead, while never-subscribed workspaces keep the upgrade copy.

- useTeamPlan: hasLapsedTeamPlan (team-only, canceled|ended)
- MemberUpsellBanner: reactivate prop branches banner + CTA copy
- i18n: upsellBannerReactivate, reactivateTeam
- tests + Storybook stories (Upgrade/Reactivate/BothStates)

(cherry picked from commit 4b4c3ccf92)
2026-06-19 23:14:10 +09:00
dante01yoon
17bea9d97c merge: FE-934 yearly confirm + back-nav/Backspace fixes into FE-991 integration
# Conflicts:
#	src/platform/workspace/components/SubscriptionRequiredDialogContentUnified.vue
2026-06-19 19:40:38 +09:00
dante01yoon
6389549199 fix(billing): preserve pricing-table selection on back, add Backspace (FE-934)
Render the pricing table with v-show instead of v-if so the plan mode,
billing cycle, and credit-stop selection survive a round trip to the
confirm step and back. Backspace on the confirm step mirrors the back
arrow (ignored while an editable element is focused).
2026-06-19 19:34:05 +09:00
dante01yoon
2bbbf65321 fix(billing): align yearly checkout confirm to updated Figma (FE-934)
Yearly headline now shows the monthly-equivalent price with a
"{total} Billed yearly" subtitle and "Each year credits refill to" (x12);
monthly is unchanged. Pass the selected billing cycle to the team confirm
so the subtitle renders, drop the redundant header credits/month line, and
reword "Starting today" to "Starts today".
2026-06-19 18:24:43 +09:00
dante01yoon
b86f24bd3c merge: FE-768 members-invite-ui latest (#12759) into FE-991 integration
Resolve DropdownMenu z-index conflict with FE-770 (5a7ff04b01): FE-768's
dynamic contentStyle (lift past the current top modal) supersedes FE-770's
static z-3000 bump, so keep the static base at z-1700 per FE-768's design.
2026-06-19 17:51:24 +09:00
dante01yoon
75da9212d1 chore(billing): remove preview billing mock harness
The in-app harness was a preview-only stand-in while the team-workspaces
backend was unavailable. The real backend now serves workspaces, billing
status, plans and the team-workspaces flag, so the mock is no longer needed.
2026-06-19 16:01:12 +09:00
dante01yoon
757156b09d fix(billing): keep pricing dialog size constant across plan toggle (FE-934)
The unified pricing dialog hugged its content, so switching For Personal / For Teams resized it (personal ~1108px, team grew to 95vw, with differing heights). Pin the pricing step's content root to a fixed width (1280) and a min-height floor so both plan scopes render at the same size; the compact confirm/success steps still shrink to their content.
2026-06-19 15:38:09 +09:00
dante01yoon
b2b1fe8730 fix(ui): stack DropdownMenu popover above modal dialogs (FE-768)
The body-portaled menu kept a static z-1700, so it lost to dialogs that
join @primeuix's auto-incrementing 'modal' counter (z-1701+) and rendered
behind them (e.g. the workspace members more-options menu inside Settings).
Lift the open menu past the current top overlay when one exists; otherwise
keep the static z-index. Covered by a behavioral z-index test.
2026-06-19 14:05:39 +09:00
dante01yoon
f528e6b8b6 merge: FE-966 latest (#12953) into FE-991 integration
- runtime billing-type reinit fix (watch [workspaceId, type] -> reinit on type flip)
- adopt FE-966 flag-only billing dispatch: drop the stale personalWorkspaceBillingReady gate (absent on main + FE-966-latest; leftover from an earlier FE-966 merge)
- keep integrated #12975 subscribe(planSlug, options) signature + FE-964 topup validation
- useBillingContext.test.ts taken from FE-966-latest (flag-only reactive mock + reinit tests)
2026-06-19 12:16:52 +09:00
dante01yoon
88133b0b56 merge: team-subscribe credit-stop wire (#12975) into FE-991 integration
- subscribe() signature change rippled into FE-977 useDowngradeToPersonal (3-arg -> planSlug + {returnUrl,cancelUrl})
- members-panel files kept at FE-991 redesign (FE-768/770); team-subscribe upsell tweak dropped as base-drift
2026-06-19 11:31:01 +09:00
dante01yoon
74799d2e94 test(billing): assert reinit from a settled legacy init
Await initialize() before flipping the flag so the test exercises true
reinitialization from an initialized legacy context rather than first-time
workspace activation. Still red without the type watch (verified locally).
2026-06-19 11:00:53 +09:00
Dante
2b642e77f6 Merge branch 'main' into jaewon/fe-966-b1-single-billing-path-drop-isinpersonalworkspace-route 2026-06-19 10:43:35 +09:00
dante01yoon
0073063bdb fix(billing): drop unused exports and mock subscription dialog in members test 2026-06-19 10:42:23 +09:00
dante01yoon
9fe12cf975 fix(billing): reinitialize billing context when billing type flips at runtime
The init watch only tracked the active workspace id, so when the resolved
billing type flipped after setup (e.g. team-workspaces flag resolving from
authenticated remote config), the active backend swapped without running its
initialize(), leaving subscription/balance stale or empty.

Watch the resolved type alongside the workspace id and reinitialize on either.
2026-06-19 10:11:12 +09:00
dante01yoon
a4e53bdbe1 test(billing): reinitialize billing when resolved type flips at runtime 2026-06-19 10:11:02 +09:00
dante01yoon
a5781c483b Merge remote-tracking branch 'origin/jaewon/fe-934-unified-pricing-table' into jaewon/fe-934-team-subscribe-wire
# Conflicts:
#	src/platform/cloud/subscription/constants/teamPlanCreditStops.ts
#	src/platform/workspace/components/UnifiedPricingTable.vue
#	src/platform/workspace/composables/useSubscriptionCheckout.test.ts
2026-06-19 10:07:13 +09:00
AustinMroz
7f25d28b71 Filter canvasOnly non-preview widgets in editor (#12957)
Non preview, `canvasOnly` widgets like `control_after_generate` could be
displayed in the subgraph editor even though promoting them would have
no visual or functional effect when in vue mode.

In vue mode, these entries are now hidden from the list of candidate
items for promotion to reduce confusion.
2026-06-19 00:59:00 +00:00
Dante
3b07b5e1c4 Merge branch 'main' into jaewon/fe-966-b1-single-billing-path-drop-isinpersonalworkspace-route 2026-06-19 09:55:22 +09:00
Dante
67b884d0f7 fix(billing): route subscription/sign-in/credit preconditions to modal, out of error panel (FE-878) (#12785)
## Summary

Account preconditions (sign-in / subscription / credits) on running a
workflow now open their modal directly and stay out of the error panel +
error count — previously `subscription_required` fell through to a red
"1 ERROR — Subscription required to queue workflows" banner. This covers
**both** paths: the `execution_error` websocket event and the `POST
/prompt` 402 queue paywall (`{ type: "PAYMENT_REQUIRED", message:
"Subscription required to queue workflows" }`), which is the exact
payload reported in #12840.

## Changes

- **What**: `execution_error` is classified by a pure
`accountPreconditionRouting` resolver (precedence sign-in > subscription
> credits) and routed to the existing modal via
`useAccountPreconditionDialog`; `executionStore` returns early for
preconditions so they never populate `lastExecutionError` /
`lastPromptError` / `lastNodeErrors` → fully excluded from the panel and
`totalErrorCount`. Runtime credit error at a node → credits modal (out
of panel; can name the node).
- **Queue paywall**: the `queuePrompt` catch resolves the same
precondition from the `POST /prompt` 402 response and opens the modal,
short-circuiting before `lastPromptError`, so the queue paywall stays
out of the panel too. The runtime matcher learns the `"Subscription
required to queue workflows"` message.
- **Breaking**: none.

## Before / After

Free-tier queue paywall (`POST /prompt` → 402) on a cloud build:

**Before** — raw `Subscription required to queue workflows` surfaced in
the error panel (no actionable upgrade):

<img width="1600" height="873" alt="before-error-panel"
src="https://github.com/user-attachments/assets/1b76b742-16bf-47e3-9245-17e35f8f1e70"
/>

**After** — clean subscription modal opens; nothing in the error panel
or error count:

<img width="1600" height="873" alt="after-subscription-modal"
src="https://github.com/user-attachments/assets/13d238cb-20bf-4795-a530-5abcf9968dc7"
/>

## Review Focus

- **Routing-only — the run button is intentionally untouched.** The
original AC#3 ("no Subscribe-to-Run button") is superseded by the FE-978
run-lock decision (pre-emptive role-aware lock, Figma 3253-18671).
Complements #12786 (FE-978 run-lock); disjoint file sets.
- Tests: `accountPreconditionRouting` / `useAccountPreconditionDialog` /
`executionStore` — each precondition routes to its modal and is excluded
from the panel/count; precedence resolves on co-occurrence. Plus
Playwright `browser_tests/tests/subscriptionPaywallError.spec.ts` — the
queue paywall (402) stays out of the error panel, with a control
asserting ordinary queue errors still surface. typecheck / oxlint /
eslint / stylelint / oxfmt / knip clean.

Fixes FE-878
Fixes #12840
2026-06-19 00:51:52 +00:00
Benjamin Lu
05efee07ce Move Comfy Desktop bridge types into frontend (#12857)
## Summary

Adds `@comfyorg/comfyui-desktop-bridge-types` as a workspace package in
the frontend monorepo and changes the frontend app dependency to
`workspace:*`.

Adds a dedicated `Publish Desktop Bridge Types` workflow for publishing
`packages/comfyui-desktop-bridge-types` by its own package version,
without coupling it to the generated `@comfyorg/comfyui-frontend-types`
release. The generated frontend types package still emits a concrete
`@comfyorg/comfyui-desktop-bridge-types@0.1.2` dependency instead of
leaking workspace/catalog protocol references.

The Desktop2 missing-model path uses `window.__comfyDesktop2.isRemote()`
when available, but falls back to the legacy
`window.__comfyDesktop2Remote` marker so frontend rollout stays
compatible with older Desktop builds.

Paired Desktop PR: https://github.com/Comfy-Org/Comfy-Desktop/pull/1112
2026-06-18 18:02:13 -07:00
Christian Byrne
bc212e8a19 fix: remove unused export from ExportFormatOption interface (#12973)
## Summary

Remove unused `export` keyword from `ExportFormatOption` interface. The
interface is only used internally in `constants.ts` and is not imported
elsewhere.

Fixes knip "unused exported types" error.

Co-authored-by: Connor Byrne <c.byrne@comfy.org>
2026-06-18 17:57:44 -07:00