Upgrades Vitest from 4.1.4 to 5.0.0 across the monorepo, fixes the
handful of things v5 turned into hard errors, and drops the
`vi.clearAllMocks()` boilerplate that v5's `clearMocks` default makes
redundant.
**Changed:**
- `vitest`, `@vitest/ui`, `@vitest/coverage-v8` 4.1.4 → 5.0.0 (catalog)
- `vi.mock` calls that lived inside `beforeAll`/`beforeEach`/test bodies
moved to module scope (v5 throws on nested calls). Affects the Studio
and docs setup files and four Studio tests.
- `detectBrowser` test restores `navigator` via `vi.unstubAllGlobals()`
instead of assigning `global.navigator`, which now reaches jsdom's
getter-only property.
- `RowEditor.utils.test.ts` restores its `JSON.stringify` spy. It used
to leak a throwing mock for the rest of the file, which v5's coverage
provider now trips over. A later test in the same file had been
asserting the leak's side effect (valid JSON reported as invalid) and
now asserts the correct behavior.
- `@testing-library/jest-dom` 6.6 → 7.0.1. Its vitest type augmentation
resolves through a peer now, so it lands on each package's own `vitest`
instead of whichever copy pnpm hoisted. Fixes `toBeInTheDocument` type
errors in dev-tools after the reshuffle.
- `@testing-library/react` 16.0.0 → 16.3.3 for the React 19 peer range.
- `vite: catalog:` added to dev-tools, www, and common. Without it they
resolved a newer vite than the catalog pin, which forked a second vitest
instance in the lockfile. There's now one.
- ai-commands custom matcher types use v5's `Matchers<R, T>` form.
- 110 test files: `vi.clearAllMocks()` removed from
`beforeEach`/`afterEach` hooks, along with hooks that only did that and
the imports they left unused. Calls that also reset/restore mocks are
untouched. Second commit, mechanical.
**Added:**
- `.vitest/` to the root gitignore (v5 writes JSON/JUnit/HTML reporter
output there)
**Removed:**
- `vite-tsconfig-paths` catalog entry and deps. Vitest 5 resolves
tsconfig paths itself.
Release-age note: this sat in draft with a temporary
`minimumReleaseAgeExclude` entry for `vitest` and `@vitest/*` while
5.0.0 was inside the workspace's 3-day `minimumReleaseAge` window. That
window has closed, so the exclusion is gone and nothing bypasses the
release-age gate.
**Perf** (local, medians of 3 runs, same machine):
| Suite | v4.1.4 | v5.0.0 |
|---|---|---|
| studio | 144.1s | 141.7s (-2%) |
| studio `--coverage` | 156.9s | 146.4s (-7%) |
| ui-patterns | 6.27s | 5.07s (-19%) |
| ui `--coverage` | 3.35s | 2.14s (-36%) |
| www | 0.89s | 0.47s (-47%) |
Studio is dominated by jsdom environment setup per file, which v5
doesn't change. `vitest doctor` recommends keeping the current pool
config: the vm pools and `isolate: false` all break tests.
## To test
- `pnpm install --frozen-lockfile` succeeds with no
`minimumReleaseAgeExclude` entry for vitest.
- CI: Studio unit tests, ui, ui-patterns, www, docs, and typecheck/lint
should all be green. The lint ratchet was checked locally: warning
counts on touched Studio files are identical to master.
- `pnpm test:studio` locally passes with coverage (588 files, 6240
tests).
- Open a Studio test that uses `toBeInTheDocument` in your editor and
confirm no type errors on jest-dom matchers, in Studio and in
`packages/dev-tools`.
- Known pre-existing failures unrelated to this PR: one dev-tools test
(`getEventCountBadge` capped pill) fails on master too.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Tests
- Improved test coverage for JSON validation and mobile navigation
behavior.
- Updated test setup, cleanup, environment configuration, and matcher
support across application and shared package suites.
- Removed obsolete coverage for alternate MCP transport selection.
## Chores
- Streamlined TypeScript path resolution and Vitest reporter output
handling.
- Updated testing libraries and Vitest tooling across documentation,
Studio, website, and shared packages.
- Added Vitest reporter output to ignored files.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
This PR removes all `paths` in `tsconfig.json` for all apps and
packages. They were added previosly because some of the components had a
`_Shadcn` suffix because of an ongoing migration. How that the migration
is done, the paths can be removed.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Standardized shared UI component, utility, and icon imports across
design-system examples and application screens.
* Simplified shared component access and project configuration.
* Added shared access to anchor-link helpers and animation styles.
* **Compatibility**
* Updated component exports and imports without changing existing
behavior.
* No changes to user-facing workflows, screens, or functionality.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What kind of change does this PR introduce?
There are some expensive queries that are requested every time the
Billing Settings page loads, some of them happen for components that are
outside of the initial viewport. We can avoid performing those requests
unless the user explicitly scrolls to the relevant section. A similar
pattern has been implemented in the past for the Credit Balance section
in https://github.com/supabase/supabase/pull/45481.
I decided to skip the lazy load pattern in the components that appear at
the top of the Billing Settings (Subscription and Cost Control).
## What is the current behavior?
When loading the billing settings page, all components (except
CreditBalance) will perform requests to load the data they need.
## What is the new behavior?
The components will perform the request to load their data until they
are inside the viewport. You can verify this by opening the developer
tools and monitor the requests as you scroll through the page.
## Testing
These changes can be easily tested by making your browser's height very
short then opening the org billing settings `/org/{slug}/billing`. Open
the developer tools and filter for XHR requests. As you scroll through
the page, the requests will be made.
To verify that all potential requests are covered, I compared the
requests done during a fresh load with another settings page, the only
extra requests made by the billing settings page are the ones relevant
to the components at the very top (or the BillingSettings container
itself, which requests the subscription).
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Performance Improvements**
* Billing, payment methods, billing customer details, upcoming invoices,
and invoice lists now load only when their sections scroll into view,
reducing initial loading.
* Existing access/permission checks are still applied before fetching
billing-related data.
* **Tests**
* Updated billing and invoices tests to mock viewport intersection
behavior (IntersectionObserver) to match the new lazy-loading behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Context
Replaces all usage of `form.watch()` to use `useWatch` instead + follows
the "name what you watch" convention as specified in the react-hook-form
skills.
There's also a small refactor in `SmtpForm.tsx` which removes the
unnecessary use of a `useState` to track if SMTP is enabled or not
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Improvements**
* Updated many Studio forms to watch specific fields more precisely,
improving live UI updates for previews, warnings, conditional sections,
and validation messages.
* Enhanced responsiveness across settings, authentication, billing,
storage, integrations, and support flows while keeping save/update
behavior the same.
* **Refined Experiences**
* Improved the analytics table creation flow with tighter, enum-based
column type validation and structured, type-specific column options.
* **Preserved Behavior**
* Maintained existing permission checks, submission flows, and
account-management workflows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Follow-up to #48344: collapses the two resolution paths for the
Admonition module into one.
`src/admonition.tsx` was a back-compat shim re-exporting
`src/Admonition/`. Two ways to resolve one module is exactly what
produced the macOS self-import bug fixed in #48344, and the local
typecheck errors that #48374 worked around. This removes the shim and
standardizes on the PascalCase subpath, matching every other export in
the package.
**Changed:**
- Codemodded all 246 `ui-patterns/admonition` imports to
`ui-patterns/Admonition` (240 `.tsx`, 5 `.mdx`, 1 `.ts` across studio,
docs, www, design-system, and lite-studio)
- Pointed the 5 internal `'../admonition'` imports back at the
`'../Admonition'` directory
**Removed:**
- `packages/ui-patterns/src/admonition.tsx`, and its `./admonition`
entry in the exports map (regenerated with `pnpm gen:exports`)
## To test
- `grep -r "ui-patterns/admonition" --include='*.ts*'` → no hits
- `pnpm test:case-hazards` → passes
- `pnpm typecheck` → all 15 tasks green
- `pnpm --filter studio run lint:ratchet` → passes
- `pnpm --filter ui-patterns vitest run src/Admonition` → 11 tests pass
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Standardized Admonition component imports across the application and
documentation.
* Improved compatibility with case-sensitive environments by using the
canonical component path.
* Removed the legacy Admonition import entry point.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
## Problem
We now export components under a subpath in ui-patterns to avoid barrel
files as they slow down every tools (from IDE to linters, etc.) and may
also affect bundles our users have to download.
## Solution
- Remove the UI patterns index file
- Fix invalid impors
## Problem
Knip reports many duplicate exports (both named and default). Besides,
we're moving away from default exports and even have an eslint rule to
enforce it on new code.
## Solution
- Cleanup those exports
- Update imports when necessary
No functional changes. If it builds, it's fine
### Summary
This PR trims the Tax ID value on the frontend so that whitespace-only
entries (e.g. " ") are correctly treated as "not set" instead of a valid
value.
Previously the "is the Tax ID set?" checks relied on string
length/truthiness, so whitespace-only input slipped through as a real
value - bypassing validation and getting persisted.
### Testing
- Subscription upgrade & top-up forms: verified the form no longer
submits when only whitespace is entered for the Tax ID. The validation
message now shows.
- Billing address form: no inline message is shown, but the Tax ID is
submitted as null, which clears it. This is unchanged from current
behaviour.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Tax ID values are now trimmed before validation and submission,
reducing errors caused by accidental leading or trailing spaces.
* Billing and payment flows now consistently use the cleaned Tax ID
value when deciding whether to save or send it.
* Customer tax ID details passed to payment setup now reflect the
trimmed value, helping avoid mismatches with external payment
processing.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
We have many unused files, left overs from features refactoring
## Solution
- Remove unused files
- Move some files closer to their usage
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Removed multiple legacy Studio UI components and placeholders to
streamline the interface (including onboarding panels, navigation
elements, docs layout helpers, and various UI building blocks).
* **UI Updates**
* Updated the layout’s API keys section to use the Project-specific
presentation.
* **Maintenance**
* Adjusted internal sourcing for documentation tab menu logic without
changing visible behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
Our `<Button>` component breaks the default `button` contract by
redefining the `type` prop to set its variant (`primary`, `default`,
etc) instead of the button type (`submit`, `button`, etc).
This is confusing and forces to write more code when using it with
shadcn components that expect/inject the standard button props.
## Solution
- rename the `type` prop to `variant`
- rename the `htmlType` prop to `type`
- propagate the changes where necessary
- format code
## How to test
As this is just prop renaming, if it builds it's ok
---------
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
Reword the "I'm purchasing as a business" tooltip to frame it around
needing a tax ID rather than being "tax-registered."
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Updated payment method setup guidance to clarify when to enable tax ID
information and confirm receipts remain available regardless of this
setting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Adds an info tooltip next to the "I'm purchasing as a business" checkbox
explaining that it's for tax-registered businesses and requires a tax
ID.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a help icon with tooltip next to the "I’m purchasing as a
business" checkbox. The tooltip clarifies when to select the business
option and notes that tax ID entry is required only for tax‑registered
businesses, reducing confusion and helping users provide correct billing
information.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
We still use the deprecated `Modal` for:
- Adding a new payment card
- Deleting a payment a card
- Changing the payment method
- Displaying the spend cap details when creating a new org
## Solution
- use `Dialog` instead
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Updated billing dialogs (add/change/delete payment methods and spend
cap) to use a newer dialog/alert dialog system.
* Result: more consistent dialog behavior, clearer confirmation flows,
and improved handling of loading/confirmation states for payment
actions.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46385?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
The `_Shadcn_` suffix isn't needed anymore on `Command` components
## Solution
- Remove the `_Shadcn_` suffix
- Simplify UI package exports
- Apply prettier
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Simplified command component imports and exports across the UI library
by removing internal naming aliases and adopting direct component
references. Updated the public UI package barrel export to use wildcard
re-exports for cleaner API surface.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46153?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
The `_Shadcn_` suffix isn't needed anymore on label component
## Solution
Remove it. No other changes
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Standardized Label usage across the codebase by removing the legacy
alias and using the direct Label export from the UI package
consistently.
* **Documentation**
* Updated component examples and docs to use the standardized Label
component in usage snippets and demos.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45986)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
We have multiple Popover components
## Solution
- [x] migrate Popover usages to Shadcn components
- Migrated JSON and text editor in the `TableEditor` (inline row
edition)
- Migrated the template popover in the logs explorer templates page
- [x] remove `_Shadcn_` suffix from Popover components (renaming +
prettier)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Unified popover implementation across the app and design system;
dropdowns, calendars, menus and tooltips now use a consistent popover
API with no visual or interaction changes.
* **Chores**
* Minor prop typing update for the logs date-picker to align with the
consolidated popover content type.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45980)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This PR migrates the JS config for Tailwind into a CSS config. As such,
all variables have been defined as CSS variables and they're using the
specialized Tailwind syntax for generating utility classes.
Beside the migration, these changes were also added:
- Added `tailwind.config.css` to few packages to make the Tailwind
Intellisense work.
- Migrated away from Radix style color classes to our defined classes,
the values will remain the same.
- Most of the CSS is generated by scripts, they'll be removed in next
PRs.
* Removed redundant `border-light` classes from several components since
it was undefined.
* Removed redundant `text-strong` classes from several components since
it was undefined.
How to test:
- Open all apps, compare the UI (mainly colors) to builds from #45417
and try to find a difference.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Style**
* Harmonized color variable usages and updated UI color references
(affects palettes, charts, gradients, hero illustrations, and
scrollbars).
* Tweaked border, tab, and selection visuals across components.
* **New Features**
* Added a suite of theme animations and refined typography presets used
by site prose and docs.
* **Refactor**
* Overhauled Tailwind/theme configuration and color token generation for
more consistent theming.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This PR migrates the whole monorepo to use Tailwind v4:
- Removed `@tailwindcss/container-queries` plugin since it's included by
default in v4,
- Bump all instances of Tailwind to v4. Made minimal changes to the
shared config to remove non-supported features (`alpha` mentions),
- Migrate all apps to be compatible with v4 configs,
- Fix the `typography.css` import in 3 apps,
- Add missing rules which were included by default in v3,
- Run `pnpm dlx @tailwindcss/upgrade` on all apps, which renames a lot
of classes
- Rename all misnamed classes according to
https://tailwindcss.com/docs/upgrade-guide#renamed-utilities in all
apps.
---------
Co-authored-by: Jordi Enric <jordi.err@gmail.com>
## What kind of change does this PR introduce?
Bug fix.
## What is the current behavior?
PR #44965 introduced an unused `cardExpiryLabel` constant in
`CreditCard.tsx`, which causes `studio#typecheck` to fail with `TS6133`
after the branch is merged into `master`.
## What is the new behavior?
Removes the unused constant so Studio typecheck passes again without
changing payment method behaviour.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Removed unused code to improve code quality and maintainability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What kind of change does this PR introduce?
UI changes for Stripe-managed billing surfaces.
- Resolves DEPR-537
- Related to DEPR-538
## What is the current behaviour?
Stripe-connected organisations still look too self-serve in Studio.
- Payment Methods still reads mostly like ordinary Supabase card
management, even though billing is handled through a Shared Payment
Token via Stripe Projects
- invoice messaging still implies support is the path to changing
payment methods, even for Stripe-managed orgs
- the Subscription Plan flow still needs Stripe-specific guardrails so
users are redirected to the correct upgrade path rather than trying to
self-serve everything in Studio
- the base branch now correctly separates `integration_source` from
`billing_partner`, but this stacked work still needs to carry that split
through the Stripe billing-token surfaces
## What is the new behaviour?
This PR makes the Stripe-managed billing surfaces behave like
Stripe-managed billing surfaces, while leaving AWS and Vercel on the
existing `billing_partner` path.
- Payment Methods now keeps the familiar saved-card row, but augments
Stripe-managed rows with Shared Payment Token context, token status, and
Stripe Projects affordances
- Stripe-managed invoice messaging now points users to Stripe Projects
rather than to support for payment-method changes
- the Subscription Plan flow keeps the existing managed-billing shape,
with Stripe-specific guardrails layered in where plan changes should be
handled outside Studio
- AWS and Vercel continue to use the existing partner-managed alerts and
CTAs driven by `billing_partner` / `billing_via_partner`
| Subscription plan sheet |
| --- |
| <img width="1780" height="448" alt="CleanShot 2026-04-24 at 17 21
43@2x"
src="https://github.com/user-attachments/assets/34c0f3ba-fc42-4d07-97a2-0e4f4cefc55e"
/> |
| _Upgrade instructions_ |
| <img width="1786" height="460" alt="CleanShot 2026-04-24 at 17 20
12@2x"
src="https://github.com/user-attachments/assets/bb67c835-b9b2-4648-b0e1-9c2f8d2317d3"
/> |
| _Downgrade instructions_ |
> [!NOTE]
> The below screenshots are outdated. The _Shared Payment Token_
terminology has been removed in favour of more generic copy such as
_Stripe Projects token_.
| Stripe payment method states |
| --- |
| <img width="1436" height="234" alt="CleanShot 2026-04-23 at 19 03
49@2x"
src="https://github.com/user-attachments/assets/52ed7a00-dfba-4b66-9a07-a6346692d3c8"
/> |
| _Healthy_ |
| <img width="1434" height="224" alt="CleanShot 2026-04-23 at 19 04
50@2x"
src="https://github.com/user-attachments/assets/94efd943-b7bf-4da2-9e1b-1828aae97126"
/> |
| _Card expiring soon_ |
| <img width="1436" height="236" alt="CleanShot 2026-04-23 at 19 06
51@2x"
src="https://github.com/user-attachments/assets/272cb707-c724-4629-890e-853972e53a18"
/> |
| _Card expired_ |
| <img width="1308" height="238" alt="CleanShot 2026-04-23 at 19 07
21@2x"
src="https://github.com/user-attachments/assets/3eadd2a9-def3-4f43-850e-7d82adfb0b57"
/> |
| _Token expired_ |
## Dependencies
This PR is stacked on:
- #44328
It also depends on the private platform work that exposes Stripe project
connection state and SPT details:
- https://github.com/supabase/platform/pull/31874
- https://github.com/supabase/platform/pull/31940
## Platform dependency status
Most of the remaining platform work for this stack is now covered by the
private dependency below:
- https://github.com/supabase/platform/pull/31940
That PR is expected to provide the SPT details and paid-flow fixes this
Studio work depends on. In practice, the main caveat here is less
“Studio still needs a bunch of new platform work” and more “do not merge
this until `platform#31940` has landed and the end-to-end Stripe-managed
flow has been rechecked”.
## Local testing
Use the same local Stripe setup as the base branch, with
`integration_source: 'stripe_projects'` returned consistently for:
- `/platform/organizations`
- `/platform/organizations/:slug/projects`
- `/platform/projects/:ref`
For payment method demos, the temporary local mock currently lives in
private `platform` on:
- `/platform/organizations/:slug/payments`
That mock can be flipped between:
- healthy token + healthy underlying card
- healthy token + card expiring soon
- healthy token + expired card
- expired token
Then verify:
- the org and project connection affordances from #44328 still render
correctly
- Payment Methods shows Stripe-managed token context rather than
implying ordinary self-serve card management
- regression test ordinary non-Stripe payment methods too, to confirm
the standard saved-card row still renders with the existing `Expires:`
copy and no Shared Payment Token affordances
- invoice messaging points Stripe-managed orgs to Stripe Projects rather
than support
- Subscription Plan keeps the managed-billing guardrails for Stripe
- AWS and Vercel orgs still show the existing partner-managed messaging
rather than the Stripe-specific notices
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Stripe-managed organizations show Stripe Projects billing guidance,
replace in-app payment management with Stripe links, and adjust billing
copy.
* Payment methods support Shared Payment Tokens (SPTs): token
expiry/status badges with tooltips, “Handled via Stripe Projects”
indicator, token last4/expiry display, and disabled local update/delete
actions for SPTs.
* **API**
* Payments response now includes optional shared payment token details
for payment methods.
* **Documentation**
* Added links to Stripe Projects billing docs in relevant flows.
* **Tests**
* Updated and added tests covering Stripe-managed and SPT behaviors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Raúl Barroso <code@raulb.dev>
## Problem
With #45211 and #45218 merged, we don't need the `_Shadcn_` suffix
anymore
## Solution
- [x] Remove the `_Shadcn_` suffix
- [x] Update exports and imports
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Standardized UI component exports by removing legacy naming
conventions and providing direct imports for checkbox and radio group
components throughout the design system.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
We used to have a `_Shadcn_` suffix for all the shadcn form components
because we also had `formik` form components.
This is not needed anymore.
## Solution
- Remove the suffix
- Update all usages
## What kind of change does this PR introduce?
UI improvements.
- Resolves DEPR-401
- Resolves DEPR-424
- Resolves DEPR-425
## What is the current behaviour?
Studio currently blurs two different concepts together:
- `billing_partner` / `billing_via_partner`, which represent real
billing ownership for marketplace-managed organisations such as AWS and
Vercel
- Stripe connection state, which is not actually partner billing in the
same sense, but was previously being mocked through the same UI paths
That made the Stripe work harder to reason about and left some local
behaviour dependent on temporary overrides rather than the API shape we
want to ship.
## What is the new behaviour?
This PR separates those concerns while keeping the existing AWS and
Vercel marketplace experience intact.
- AWS and Vercel continue to use `billing_partner` /
`billing_via_partner` for billing ownership, lockouts, and manage CTAs
- Stripe display state now comes from `integration_source`, which lets
Studio show Stripe-specific badges and alerts without treating Stripe as
a billing partner
- organisation-level partner UI is unified across AWS, Vercel, and
Stripe, including the org banner, navbar icon treatment, and
organisation cards
- project-level Stripe UI now appears only when the project itself is
marked as Stripe-connected, including the project switcher, project list
surfaces, and a project-level banner
- Stripe-connected organisations are no longer incorrectly blocked
behind the AWS/Vercel-style billing management alerts for invoices,
billing address, payment methods, or plan changes
- banner dismissal is scoped to the relevant org/project and
partner/integration state
## Review order
Most of the diff size here is regression tests and generated types. The
behavioural changes are concentrated in a smaller set of files.
Recommended review order:
1. `integration_source` vs `billing_partner` data-model split and
org/project query mapping
2. org-level UI: partner icon, org banner, org dropdown/card treatment
3. billing gating updates for Stripe vs AWS/Vercel
4. project-level Stripe UI: dropdown, list surfaces, banner
5. tests and generated types
| Stripe Org(s) |
| --- |
| <img width="1024" height="759" alt="Organizations Supabase"
src="https://github.com/user-attachments/assets/d0ef338c-3b41-4c6d-b3bd-f21a2c182840"
/> |
| Vercel Org(s) |
| --- |
| <img width="1024" height="759" alt="Organizations Supabase"
src="https://github.com/user-attachments/assets/1dc57770-3f24-45ac-840f-34680555cde8"
/> |
| AWS Org(s) |
| --- |
| <img width="1024" height="759" alt="Organizations Supabase"
src="https://github.com/user-attachments/assets/7847dad0-ee30-4a65-ab0b-b3b16af0d34f"
/> |
| Stripe Org, Non-Stripe Project |
| --- |
| <img width="1152" height="885" alt="Mallet Toolshed
Supabase-1673E019-792C-462C-B6F8-C5DDB810B331"
src="https://github.com/user-attachments/assets/556fbea3-b5ae-4f2f-96b9-6f66c6654e4a"
/> |
| Stripe Org, Stripe Project |
| --- |
| <img width="1152" height="885" alt="Hammer Toolshed
Supabase-7E86C17C-561F-4221-BD16-EAFF7D41AAE0"
src="https://github.com/user-attachments/assets/94f8daf6-0320-413e-8d56-59f9acaaea15"
/> |
| Vercel Org |
| --- |
| <img width="1024" height="759" alt="Projects Toolshed
Supabase-A7891653-9366-4B99-89DD-789D70CD52E3"
src="https://github.com/user-attachments/assets/c87ee6e8-4451-4866-a905-23a38b2593e3"
/> |
| AWS Org |
| --- |
| <img width="1024" height="759" alt="Projects Toolshed
Supabase-58A43ECE-569E-4541-9463-346A90B02CFF"
src="https://github.com/user-attachments/assets/9350a180-4d58-42a1-ad1a-95893c2e8b12"
/> |
This also removes the old Stripe mock override path in Studio so the
frontend matches the intended API model more closely.
## ~~Dependencies~~ (merged!)
This work depends on the private platform change that exposes
`integration_source` on the relevant organisation and project payloads:
- https://github.com/supabase/platform/pull/31874
_Update: now merged._
## Local testing
### Stripe
If you have the private `platform` repo checked out locally, make sure
your local API returns `integration_source: 'stripe_projects'`
consistently for the Stripe-linked org/project you are testing.
Important responses:
- `/platform/organizations`
- `/platform/organizations/:slug/projects`
- `/platform/projects/:ref`
Verify:
- org banner and org icon show the Stripe connected state
- unopened and opened project switcher both show Stripe only for
Stripe-linked projects
- project cards / table rows show the Stripe chip only for Stripe-linked
projects
- the project-level Stripe banner appears across project surfaces
- billing address, tax ID, invoices, payment methods, and plan changes
remain editable in Studio for Stripe orgs
### Vercel
Use a Vercel Marketplace org with real `billing_partner` /
`billing_via_partner` values.
Important org-level endpoints for local mocking in `platform`:
- `/platform/organizations`
- `/platform/organizations/:slug`
- `/platform/organizations/:slug/billing/subscription`
Project-level Vercel indicators still come from
`/platform/integrations/:slug`, not `integration_source`.
### AWS
Use an AWS Marketplace org with real `billing_partner` /
`billing_via_partner` values.
Important org-level endpoints for local mocking in `platform`:
- `/platform/organizations`
- `/platform/organizations/:slug`
- `/platform/organizations/:slug/billing/subscription`
AWS does not currently have a Stripe-like project-level indicator in
these org/project payloads.
## Notes
- `billing_partner` is no longer the right abstraction for the
Stripe-connected case in this PR. It remains the source of truth for
marketplace billing ownership, while Stripe currently uses
`integration_source` as a connection/display signal.
- I re-ran `pnpm api:codegen` while tightening this PR and kept only the
generated type changes this branch actually depends on, to avoid
unrelated API drift in the review.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Stripe Projects integration added for billing and project flows
* Partner icons/badges shown across org and project lists, dropdowns,
and rows
* Dismissible, partner-specific marketplace/integration banners with
contextual CTA behavior
* Improved partner-billing detection to drive billing UI and
invoice/plan availability
* **Tests**
* Extensive new test coverage for billing UI, partner-managed fallbacks,
banners, icons, and related flows
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
## Summary
Reorder AddPaymentMethodForm and PaymentMethodSelection to use a dry run
validation → Stripe payment setup → real update flow:
- Validate address and tax ID via `dry_run: true` before touching Stripe
- Proceed with Stripe payment method creation / 3DS only if validation
passes
- Persist the customer profile update with dry run disabled after Stripe
succeeds
- Add `dry_run` support
to `useOrganizationCustomerProfileUpdateMutation`
- Add `getFormValues()` to `PaymentMethodElementRef` to read address and
tax ID form state
- Delete the now-unused `organization-tax-id-update-mutation.ts`
## Test plan
### Adding a Payment Method
From the billing dashboard `/org/_/billing`:
- [ ] Add a payment method with a valid tax ID: should dry-run
validate, then create the payment method via Stripe, then persist the
billing profile
- [ ] Add a payment method with an invalid tax ID: should show a
validation error from the dry run and not proceed to Stripe payment
setup
- [ ] Add a payment method with the "primary billing address" checkbox
unchecked: should skip the customer profile update entirely and only
create the payment method
- [ ] Add a payment method where Stripe 3DS fails: billing profile
should not be persisted (only the dry run ran)
### Credit Top Up
- [ ] Top up credits with a new payment method and valid tax ID: should
dry-run validate, then create the payment method, then process the
top-up
- [ ] Top up credits with a new payment method and invalid tax ID:
should show a validation error from the dry run and not proceed to
Stripe payment method creation
### Plan Upgrade
- [ ] Upgrade plan with a new payment method and valid tax ID: should
dry-run validate before creating the payment method
- [ ] Upgrade plan with a new payment method and invalid tax ID: should
show a validation error and not proceed to Stripe
- [ ] Upgrade plan with an existing payment method: should proceed
without dry-run validation
- Call the new `POST /platform/organizations/preview-creation` endpoint
when creating an organization on a paid plan to show a tax breakdown
before submission
- Preview is triggered reactively when the user completes the billing
address in the Stripe AddressElement (debounced, same pattern as
subscription upgrades)
- Displays plan price, tax line (with percentage), and total due today -
hides the plan price row when there's no tax adjustment
## Test plan
- [ ] Create a new org on the Free plan - no preview should appear
- [ ] Create a new org on Pro/Team - fill in billing address with all
fields including name
- [ ] Verify tax preview appears after address is complete (1s
debounce)
- [ ] Verify tax line shows for taxable jurisdictions (NY Zip Code
10001), hidden for non-taxable
- [ ] Verify plan price row is hidden when total equals plan price (no
tax)
- [ ] Change address country - verify preview updates
- [ ] Add a tax ID - verify preview updates
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Pricing preview during organization signup that shows plan price
differences, tax details (rate/amount or estimation failure), and “Total
due today.”
* Preview updates reactively based on selected plan and spend cap (PRO
without spend cap treated as PAYG) and appears only for paid plans after
preview initialization.
* Debounced billing address and tax ID input collection for accurate
previews; panel opacity reduced while fetching.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- The `availableTaxIds` memo and
preselect `useEffect` in `NewPaymentMethodElement` depended on the
full `stripeAddress` object. Since the
Stripe `AddressElement` fires `onChange` on every keystroke (org name,
street, city, etc.), this created a new object reference each time,
causing the memo to recompute and the effect to re-fire, which
cleared `tax_id_value` to `''`.
- Narrowed both dependencies to `addressCountry`, so the tax ID is only
reset when the billing country actually changes.
- Used a `prevCountryRef` to distinguish initial mount from country
changes: on mount we preserve any existing `currentTaxId`, on country
change we always reset to the new country's default.
## Test plan
- [ ] New org flow: select paid plan, check "purchasing as a business",
fill in tax ID value, type in org name / address fields - tax ID should
persist
- [ ] New org flow: change country - tax ID selector should update to
the new country's default
- [ ] Plan upgrade flow: open upgrade dialog with existing tax ID, type
in address fields - tax ID should persist
- [ ] Plan upgrade flow: change country - tax ID should reset to new
country's default
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Tax ID handling is now country-aware and updates correctly when the
billing country changes.
* Address name and country persist across form remounts, preventing
accidental resets when toggling purchase mode.
* Tax ID selection/reset logic refined to avoid overwriting existing tax
IDs on initial load and to choose appropriate defaults after country
changes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Passes billing address and tax ID from the payment form to the
subscription preview endpoint, so taxes are recalculated live as the
user updates their details
- Debounces address/tax ID changes (1s) in `NewPaymentMethodElement` to
avoid excessive API calls while typing
- Decouples the preview refetch from the payment form's mount state -
uses `keepPreviousData` so the form stays mounted and the breakdown dims
with `opacity-50` instead of unmounting/remounting during refetches.
Shimmer skeleton only shows on initial load.
- Disables the "Confirm upgrade" button while a refetch is in progress
to prevent submitting with stale tax data
- Respects the "Use address as my org's billing address" checkbox: the
preview should mirror what will actually happen - if the checkbox is
unchecked, the address won't be saved to Orb, so it shouldn't be used
for the tax estimate either. Otherwise the user sees one price and gets
charged another. The logic for this lives in `PlanUpdateSidePanel`
``` mermaid
flowchart TD
A[User opens upgrade dialog] --> B[Fetch subscription preview]
B --> C[Show payment form + price breakdown]
C --> D[User edits address or tax ID]
D -->|1s debounce| E{Use as billing address?}
E -->|Yes| F[Re-fetch preview with new address]
E -->|No| G[Re-fetch preview without address override]
F --> H[Update breakdown — form stays mounted]
G --> H
H --> C
```
## Test plan
- [x] Open the plan upgrade dialog, verify the payment form and
breakdown load normally on first open
- [x] Change the billing address country - verify the breakdown dims
briefly and updates with new tax amounts without the payment form
unmounting
- [x] Toggle the tax ID on/off and change its value - verify the
preview refreshes after ~1s debounce
- [x] Confirm the upgrade button is disabled while the preview is
refetching
- [x] Uncheck "Use address as my org's billing address" - verify the
preview refetches without address/tax overrides
- [x] Re-check the checkbox - verify the preview refetches again with
the current form address
- [x] Assert that adding a new billing address in the CreditTopUp form
works and saves the address
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Payment and subscription flows now propagate billing address and tax
ID via new callbacks; subscription preview requests include these values
and preserve prior results while fetching.
* Preview updates are debounced to reduce noise; loading state disables
confirm actions and visually dims charge breakdown.
* **UX**
* Address input emits complete normalized address updates (empty second
line cleared).
* Tax ID input emits updates and explicit clears (null).
* “Use address as my org's billing address” is now controlled and
reports changes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
### Summary
This PR refactors the billing address form to use Stripe AddressElement
on both the org billing page and the missing-address modal, adding
Google Maps autocomplete and country-aware state/province inputs.
### Testing
- Address element renders on org billing page, autocomplete works, and
state/province options update per country.
- Existing billing address data loads correctly into the form.
- Need to verify this with invalid country/state as well.
- Save enables only when the form is dirty after editing address or tax
ID fields.
- Cancel restores both address and tax ID to the original values.
- Submitting with missing required address fields shows a validation
toast.
- Tax ID options are filtered by the selected billing country.
- Tax-ID-only edits submit successfully without interacting with the
address form.
- Without billing write permission, address fields are read-only.
- Update billing address modal behaves the same as the org billing page.
- Address element appearance looks correct in both light and dark mode.
- Payment method form remains unchanged and still uses floating labels.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Billing form now uses Stripe Address Element via Stripe Elements with
an embedded custom font and theme-aware appearance; tax-ID entry remains
separate.
* **Bug Fixes**
* Stronger address validation and submit gating, improved dirty-state
tracking, explicit save confirmation and reset behavior, and clearer
error toasts on update failures.
* **Tests**
* Expanded tests covering hook behavior, address element validation,
submit gating, payloads, reset, and permission scenarios.
* **Style**
* Adjusted billing email form spacing/layout.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
### Summary
This PR adds support for Isle of Man customers to use GB VAT tax IDs.
Isle of Man uses the UK VAT system, so Orb requires country: 'GB' for
validation - but the billing address country is IM.
- Adds an IM VAT entry to `TAX_IDS` with a new `taxCountryIso2` override
field, so the UI shows "IM VAT" while sending country: 'GB' to Orb
- Introduces `getEffectiveTaxCountry()` to resolve the correct country
code for Orb
- Introduces `resolveStoredTaxId()` to map stored Orb data back to the
correct UI entry, using billing address country to disambiguate IM vs GB
- Updates all three billing forms to use these utilities: Billing
Settings page, Add Payment Method modal and Update Billing Address modal
### Testing
#### Automated tests
I've added unit tests in this PR
#### Manual tests
You can use the following country/city/postal code combinations to test:
- Isle of Man, Douglas, IM1 2LE
- United Kingdom, Crumlin, BT29 4AA
**Billing Settings page**
- Select Isle of Man as billing country → tax ID dropdown shows "Isle of
Man - IM VAT"
- Select United Kingdom as billing country → tax ID dropdown shows
"United Kingdom - UK VAT" / "United Kingdom - GB VAT" (not "IM VAT")
- Select IM VAT, enter a valid GB VAT number, save → check network tab,
Orb receives country: 'GB'
- Reload page for an IM customer with existing tax ID → "IM VAT" is
pre-selected (not "UK VAT")
- Reload page for a GB customer with existing tax ID → "UK VAT" is
pre-selected (no regression)
- Change country from IM to GB → available tax IDs update, IM VAT no
longer shown
**Add Payment Method modal**
- Open modal for an IM customer with existing tax ID → "IM VAT" is
pre-selected
- Check "I'm purchasing as a business", select Isle of Man in Stripe
address → tax ID dropdown shows "IM VAT"
- Check "I'm purchasing as a business", select United Kingdom in Stripe
address → tax ID dropdown shows "UK VAT" / "GB VAT"
- Submit with IM VAT → check network tab, tax ID is saved with country:
'GB'
- Open modal for a GB customer → no regression, "UK VAT" shown as before
**Update Billing Address modal**
Appears for paid orgs missing a billing address
- Open modal for an IM customer with existing tax ID → "IM VAT" is
pre-selected
- Open modal for a GB customer with existing tax ID → "UK VAT" is
pre-selected
- Fill in IM address + IM VAT and save → saves correctly, modal closes
---------
Co-authored-by: Ignacio Dobronich <ignacio@dobronich.com>
* Add shimmering-loader CSS to ui-patterns.
* Import the shimmering-loader classes from the ui-patterns component.
* Remove ShimmeringLoader from studio.
* Migrate studio to use ui-patterns/ShimmeringLoader.
* Migrate away from using default import for ShimmeringLoader.
* Fix the css imports in docs and studio.
* Bump the deps, refactor deprecated code.
* Migrate keepPreviousData usage.
* Migrate all uses of InfiniteQuery.
* Fix refetchInterval in queries.
* Migrate all use of isLoading to isPending in mutations.
* Fix accessing location in claim-project.
* Fix a bug in duplicate query keys.
* Migrate all queries to use isPending.
* Revert "Fix accessing location in claim-project."
This reverts commit 2a07df64b5.
* Revert the rss.xml file to master.
* Migrate all uses of invalidateQueries to use object syntax.
* Migrate the remainder of useInfiniteQuery.
* Migrate all setQueriesData.
* Migrate all fetchQuery uses.
* Migrate some leftover functions from RQ.
* Fix issues found by Charis.
* o11y: mirror and sanitize breadcrumbs
Mirror Sentry breadcrumbs as the basis for our own support logging. Also
adds more sanitization to breadcrumbs.
* feat(support form): toggle for attaching dashboard logs
Add a toggle to the support form when the category is "Dashboard bug",
to attach recent dashboard logs. Users can preview the attached logs and
opt out.
* feat(support links): dedicated support link component
Add a new component for support links, which:
- Uses the serializer for support link params to ensure
serialization/deserialization pairs correctly
- Snapshots breadcrumbs so the attached log on the support form will be
cut off at the support link click (otherwise we will get support form
actions cluttering up the log)
* tests(support form): extend timeout on flaky test
* Minor clean up
* fix(support form): allow url to specifically indicate no specified project
* minor nits
* Fix tests
* Fix tests
---------
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
* basic fixes
* improve form contents
* fix border clipping
* remove redundant animation and classes
* polish confirm org
* improvements
* fix header rounding
* prevent password managers from appearing
* Fix the handling of token when redirecting back. Use nuqs for getting URL params. Simplify some logic.
* Minor fix to the useEffect for org name.
---------
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
* Add UpgradePlanButton which handles redirecting either to subscription page or support page
* Update upgrade CTAs to go to support if billing:all flag is disabled
* Nit
* Nit
* Smol fix
* Temp show plan upgrade support category
* revert as instructed
* asChild
---------
Co-authored-by: Alaister Young <a@alaisteryoung.com>
* Update perms checking in audit logs
* Deprecate useCheckPermissions, useIsPermissionsLoaded and useCheckProjectPermissions as they're no longer used
* Rename useAsyncCheckProjectPermissions to useAsyncCheckPermissions
* Fix TS
* Wrap up remaining swapping of useCheckPermissions
* remove OrganizationSettingsLayout on billing, team, integrations and usage org pages
* Fix missing loading state in usage page
* Add comments for next step
Security approval is required for PCI compliance. This means we need security approval wherever we embed Stripe for payment methods.
Security approval was previously very coarse and most billing changes required security approval unnecessarily.
This PR aims to move all files relevant for payment method display/changes into a single folder and adjusts the ownership to only require security approval for that.
* Replace all usage of useProjectContext with useSelectedProjectQuery
* Replace all usage of useSelectedProject with useSelectedProjectQuery
* Replace all usage of useProjectByRef with useProjectByRefQuery
* Replace all usage of useSelectedOrganization with useSelectedOrganizationQuery
* Deprecate useSelectedProject, useSelectedOrganization, and useProjectByRef hooks
* Deprecate ProjecContext