Port settings billing/storage/compute drift from platform#31436
Conversation
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.
|
Codex Review: Didn't find any major issues. What shall we delve into next? ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
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". |
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.
There was a problem hiding this comment.
Solid port — Devin cleared it and the code holds up. Here's what I checked:
New components:
TierPicker:isTierDisabled()reads thedisabledfield defensively (cast viaunknownsince it's not in generated types yet) — good future-proofing. Price formatting guards$Infinitycorrectly viaminTierPriceCents. Keyboard navigation skips disabled options.AssistantStorageCard: Only queries onboarding endpoint when on Pro (gated viaenabled: isPro). Only shows resize button when current < ceiling. Confirms viaConfirmDialogwith 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: Mapsexceeds_machine_tier/exceeds_storage_tierto friendly copy. Falls back toextractErrorMessage. Correct.machine-sizes.ts: Static config with documented sync risk (comment notes to keep in sync with backend constants).machineSizeRank()viaindexOf— safe, unknown sizes return -1 which is fine for comparison.
Modifications:
adjust-plan-modal.tsx:resolveTierSelectioncorrectly revalidates against the live tier list before submit — guards stale/disabled tier submission.minTierPriceCentswith empty-array guard is correct.compute-upgrade-card.tsx: Switched fromassistantsProUpgradeMachineCreateMutation→assistantsResizeMutation. UsesTIER_TO_SIZESfor size options bounded bymax_machine_tier.machineSizeRankcomparison 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 hardcodedLOST_FEATURESconstant, now acceptslostFeatures: string[]prop — more flexible, correct direction.preferences-menu.tsx:referralCodesfeature flag check removed, "Earn credits" item is now always shown. Intentional based on the billing-page change removing the same flag.dropdown.tsx:disabledoption support with keyboard nav skipping disabled slots looks correct —findEnabledIndexwrapping Arrow/Home/End keys, click guard onselectOption. Clean design-library addition.onboarding-page.tsx: Step 1 switches from pollingpvc_readyto explicitPOST .../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.
|
@devin-ai review this PR |
|
@codex review |
There was a problem hiding this comment.
💡 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".
| const maxMachineTier = onboardingQuery.data?.max_machine_tier ?? null; | ||
| const allowedSizes: MachineSizeEnum[] = | ||
| (maxMachineTier && TIER_TO_SIZES[maxMachineTier]) || []; |
There was a problem hiding this comment.
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 👍 / 👎.
| const currentGib = | ||
| healthz?.disk != null ? Math.round(healthz.disk.totalMb / 1024) : null; | ||
|
|
||
| const canResize = | ||
| availableGib != null && currentGib != null && currentGib < availableGib; |
There was a problem hiding this comment.
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
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): refreshapps/web/openapi-schemas/platform.yamlfrom the platform repo so the regenerated client exposesassistantsResize,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 thereferralCodesfeature flag).Test plan
bun run openapi-tssucceeds with refreshed schemabun run typecheckpasses forapps/web🤖 Draft — work in progress
Generated by Claude Code