Skip to content

Port settings billing/storage/compute drift from platform#31436

Merged
ashleeradka merged 4 commits into
mainfrom
claude/polish-billing-ui-FEMjT
May 21, 2026
Merged

Port settings billing/storage/compute drift from platform#31436
ashleeradka merged 4 commits into
mainfrom
claude/polish-billing-ui-FEMjT

Conversation

@ashleeradka
Copy link
Copy Markdown
Contributor

Summary

Brings apps/web/src/domains/settings/ to feature parity with the platform repo's settings/billing/storage/compute end state. Covers four "Web App Repo Move" drift issues that piled up after settings paths were frozen on May 20.

Issues rolled in:

Approach is "match end state" — files are ported to reflect the current platform main, not commit-by-commit. PR #7476 (unify into resize-card) is not yet merged in platform and is therefore not included.

What's in this PR so far

  • chore(web): refresh apps/web/openapi-schemas/platform.yaml from the platform repo so the regenerated client exposes assistantsResize, AssistantResizeRequestRequest, provisioned_storage_gib, selected_storage_gib, and the onboarding/storage endpoint. Prerequisite for the LUM-1760 cluster.

More commits to follow (settings component port, deletions of obsolete cards, tier-picker/plan-feature-list/assistant-storage-card/resize-errors/compute-upgrade-card, design-library Dropdown enhancement, removal of the referralCodes feature flag).

Test plan

  • bun run openapi-ts succeeds with refreshed schema
  • bun run typecheck passes for apps/web
  • Billing page renders: PaymentMethodsCard, BillingPanel, ReferralPanel, BillingUsagePanel in correct order
  • AdjustPlanModal upgrade flow surfaces machine + storage tier pickers
  • Per-assistant Storage and Compute cards mount in general settings
  • Onboarding wizard applies storage + compute to the active assistant

🤖 Draft — work in progress


Generated by Claude Code

Pulls the current platform OpenAPI bundle so the regenerated client picks
up assistantsResize, AssistantResizeRequestRequest, provisioned_storage_gib,
selected_storage_gib, and the onboarding/storage endpoint. Prerequisite for
porting the Pro storage/compute UX cluster (LUM-1760) and selected storage
state surfacing (LUM-1682 #7312) from platform to vellum-assistant.

Refs LUM-1683, LUM-1682, LUM-1761, LUM-1760.
@ashleeradka ashleeradka marked this pull request as ready for review May 21, 2026 02:46
@ashleeradka
Copy link
Copy Markdown
Contributor Author

@codex

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

claude added 2 commits May 21, 2026 03:01
Brings apps/web/src/domains/settings/ to feature parity with the
platform repo's current end state for the billing, storage, and
compute settings surfaces. Covers four "Web App Repo Move" drift
issues that accumulated after settings paths were frozen on May 20:

- LUM-1683: Billing UI reorder + referral stats (platform #7376)
- LUM-1682: Pro billing machine resize + storage card + tier
  selection (platform #7310, #7312, #7323, #7338)
- LUM-1761: Noa's billing UI polish (platform #7462, #7473, #7492)
- LUM-1760: Shaarson's Pro storage/compute UX (platform #7389,
  #7390, #7392, #7395, #7399, #7400, #7403, #7404)

The port targets feature parity, not 1:1 file translation:

- Routing translated from platform's useAppNavigate / next/navigation
  to react-router (useNavigate, useSearchParams) per target conventions.
- Feature flag reads translated from useAppFeatureFlags() context to
  the target's useFeatureFlagStore.use.X() Zustand pattern.
- Component imports redirected to @vellum/design-library and
  @/generated/api.
- Shared hooks/utils that already exist in the target
  (use-billing-portal-session, payment-method-brand) wired up rather
  than recreated.
- Daemon-aware Assistant type from @/assistant/api.js used in place
  of platform's @/lib/assistants/api.

New files:
- assistant-storage-card.tsx (per-assistant Storage card)
- compute-upgrade-card.tsx (rewritten with full machine-size range)
- plan-feature-list.tsx (inline + checklist variants for
  AdjustPlanModal and PlanCard)
- resize-errors.ts (extractResizeError envelope for friendly resize
  failure messaging)
- tier-picker.tsx (Dropdown-driven tier selection for Pro upgrade)
- lib/billing/machine-sizes.ts (TIER_TO_SIZES, SIZE_LABEL,
  SIZE_DESCRIPTION, machineSizeRank shared util)

Deletions (functionality moved to general settings, per-assistant):
- storage-card.tsx
- machine-size-card.tsx
- machine-size-modal.tsx

Other changes:
- onboarding-page.tsx: storage step replaces pvc-readiness polling;
  failures count now gates wizard progression.
- billing-page.tsx: drops storage/machine card mounts; ReferralPanel
  renders unconditionally.
- general-page.tsx: mounts AssistantStorageCard alongside
  ComputeUpgradeCard.
- adjust-plan-modal.tsx: tier-picker + plan-feature-list, dynamic
  LOST_FEATURES via prop, copy and layout polish.
- referralCodes and referralCodesAdmin flags removed from the store
  and dev panel (no longer gated upstream).
- preferences-menu.tsx: drops referralCodes gating so Earn Credits
  always renders.
- design-library dropdown.tsx: DropdownOption.disabled support +
  findEnabledIndex helper for keyboard/click guards (needed by
  tier-picker).

Platform PR #7476 (unify per-assistant cards into a single
ResizeCard) is not yet merged in platform and is therefore not
included; the two-card layout is the current end state.
…ve-deps

The directive was ported from platform, but apps/web's eslint config
does not enable react-hooks/exhaustive-deps, so the unknown rule
trips the report-unused-disable check. The useMemo dependency array
still keys on clientSecret intentionally to retrigger appearance
resolution on each new SetupIntent.
vex-assistant-bot[bot]
vex-assistant-bot Bot previously approved these changes May 21, 2026
Copy link
Copy Markdown
Contributor

@vex-assistant-bot vex-assistant-bot Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid port — Devin cleared it and the code holds up. Here's what I checked:

New components:

  • TierPicker: isTierDisabled() reads the disabled field defensively (cast via unknown since it's not in generated types yet) — good future-proofing. Price formatting guards $Infinity correctly via minTierPriceCents. Keyboard navigation skips disabled options.
  • AssistantStorageCard: Only queries onboarding endpoint when on Pro (gated via enabled: isPro). Only shows resize button when current < ceiling. Confirms via ConfirmDialog with restart warning. Backend rejects downsizes with 403 — the button condition (currentGib < availableGib) handles that correctly.
  • PlanFeatureList: Clean dual-mode component (inline vs checklist). Simple, no issues.
  • resize-errors.ts: Maps exceeds_machine_tier / exceeds_storage_tier to friendly copy. Falls back to extractErrorMessage. Correct.
  • machine-sizes.ts: Static config with documented sync risk (comment notes to keep in sync with backend constants). machineSizeRank() via indexOf — safe, unknown sizes return -1 which is fine for comparison.

Modifications:

  • adjust-plan-modal.tsx: resolveTierSelection correctly revalidates against the live tier list before submit — guards stale/disabled tier submission. minTierPriceCents with empty-array guard is correct.
  • compute-upgrade-card.tsx: Switched from assistantsProUpgradeMachineCreateMutationassistantsResizeMutation. Uses TIER_TO_SIZES for size options bounded by max_machine_tier. machineSizeRank comparison for downsize detection is correct.
  • billing-page.tsx: MachineSizeCard + MachineSizeModal + StorageCard removed (replaced by the new per-assistant cards). PaymentMethodsCard moved before BillingPanel. Clean.
  • downgrade-reconfirm-modal.tsx: Removed hardcoded LOST_FEATURES constant, now accepts lostFeatures: string[] prop — more flexible, correct direction.
  • preferences-menu.tsx: referralCodes feature flag check removed, "Earn credits" item is now always shown. Intentional based on the billing-page change removing the same flag.
  • dropdown.tsx: disabled option support with keyboard nav skipping disabled slots looks correct — findEnabledIndex wrapping Arrow/Home/End keys, click guard on selectOption. Clean design-library addition.
  • onboarding-page.tsx: Step 1 switches from polling pvc_ready to explicit POST .../onboarding/storage/ call. More proactive, with user-visible restart warning + skip option. Makes sense given the new per-assistant storage model.

One non-blocking note: machine-sizes.ts SIZE_DESCRIPTION values (2 vCPU, 3 GiB etc.) will drift if backend resource presets change — the comment calls it out but no automated check exists. Low risk for now, worth a follow-up ticket if these values become user-facing in more places.

LGTM.

@vex-assistant-bot
Copy link
Copy Markdown
Contributor

@devin-ai review this PR

@vex-assistant-bot
Copy link
Copy Markdown
Contributor

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25dc331b75

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +64 to +66
const maxMachineTier = onboardingQuery.data?.max_machine_tier ?? null;
const allowedSizes: MachineSizeEnum[] =
(maxMachineTier && TIER_TO_SIZES[maxMachineTier]) || [];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Fall back to medium tier when max_machine_tier is null

Treating max_machine_tier as required here regresses Pro users whose onboarding payload has max_machine_tier: null (the field is nullable): allowedSizes becomes empty, the card shows a configuration warning, and compute resize is fully blocked. In the same commit, onboarding intentionally falls back null/unknown tiers to medium, so this path should do the same to preserve at least the baseline small→medium upgrade flow instead of hard-disabling resizing.

Useful? React with 👍 / 👎.

Comment on lines +103 to +107
const currentGib =
healthz?.disk != null ? Math.round(healthz.disk.totalMb / 1024) : null;

const canResize =
availableGib != null && currentGib != null && currentGib < availableGib;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid gating storage resize on healthz disk metrics

canResize currently requires currentGib from healthz.disk.totalMb, so any healthz miss (transient API failure, unavailable metrics, etc.) forces canResize false and the UI falls through to the neutral “included storage has been applied” state. That hides a valid resize action for users who are still below selected_storage_gib, making storage upgrades impossible whenever healthz data is missing. Use a durable source (for example assistant provisioning fields) or a fallback path instead of hard-blocking on healthz.

Useful? React with 👍 / 👎.

…-ui-FEMjT

# Conflicts:
#	apps/web/openapi-schemas/platform.yaml
@ashleeradka ashleeradka merged commit 10d1305 into main May 21, 2026
20 checks passed
@ashleeradka ashleeradka deleted the claude/polish-billing-ui-FEMjT branch May 21, 2026 12:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants