We are doing a soft rollout for log pricing including log ingest and log
querying. We currently only want to display usage/soft warnings, which
is why the metrics are filtered out in some components.
## What kind of change does this PR introduce?
Refactor. Follow-up to #49871.
## What is the current behavior?
Branded (green) text still uses the `text-brand` classname while the
colour comes from `--primary`.
## What is the new behavior?
**Rename-only:** `text-brand` → `text-primary` across callsites and
docs. Leftover `bg-brand` / `border-brand` alias to `brand-default`. No
intentional colour changes in this PR.
This better matches how we treat our green in other components and
props, like `variant="primary"` for green buttons.
## To test
On light mode: smoke-test that branded text still looks like #49871
(readable green, not the bright fill).
-
[Homepage](https://zone-www-dot-com-git-dnywh-depr-316-text-brand-de2380-supabase.vercel.app/):
“Scale to millions” uses `text-primary`
- [Docs
homepage](https://docs-git-dnywh-depr-316-text-brand-to-primary-supabase.vercel.app/docs):
branded links like “More on self-hosting” are still readable
- [Typography
docs](https://design-system-git-dnywh-depr-316-text-brand-to-primary-supabase.vercel.app/design-system/docs/typography):
documents `text-primary`
- [Colour
usage](https://design-system-git-dnywh-depr-316-text-brand-to-primary-supabase.vercel.app/design-system/docs/color-usage):
`text-primary` is visibly darker than `bg-brand-default` _on light mode_
- [Studio auth
providers](https://studio-staging-git-dnywh-depr-316-text-brand-to-60fa6c-supabase.vercel.app/dashboard/project/_/auth/providers):
enabled provider badge text readable; status dot stays bright green
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Style**
* Updated branded text, link hover states, icons, badges, indicators,
and highlighted content across the Design System, Docs, Studio, Learn,
UI Library, and marketing experiences to use the primary theme color.
* Updated syntax highlighting and table-of-contents styling for
consistent primary-color presentation.
* Refined brand color fallback behavior for bright fills and borders.
* **Documentation**
* Updated color-usage and typography guidance to recommend the primary
text utility.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
platform, v1 and v2 have been already completely migrated and introduced
some changes.
Some types have been renamed, some outputs and inputs updated.
## Solution
- Update the API types
- Fix the TS errors
## Update
Taking this over to unblock #50134, which needs the new scoped token
permission ids from the regenerated types.
- Merged `master`.
- Regenerated `api-v2.d.ts` from the production spec. The previous files
came from a local API that exposed a webhook events endpoint production
doesn't have yet. Production has since added standardized 400 error
responses on the v2 organization endpoints. `api-v1.d.ts` and
`platform.d.ts` already matched production.
- Fixed `verify-production-types`. It formatted the regenerated files in
a temp directory outside the repository, so Prettier fell back to its
defaults and the comparison could never match the committed files. It
now passes the repository config explicitly. `pnpm api:verify-types`
passes on this branch.
- Verified locally: `pnpm typecheck`, `pnpm api:verify-types`, Studio
unit tests.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Preserved descriptions when saving, sharing, moving, or unsharing
notebooks, reports, SQL snippets, and saved queries.
* Improved handling of empty or null values across notebook
descriptions, billing usage, pooler settings, and infrastructure fields.
* Improved read-replica connection handling, including read-only
connection strings.
* Updated storage configuration and capability handling to match current
settings.
* **API and Compatibility**
* Updated organization, project, storage, OAuth, billing, and
infrastructure data handling to match current API responses.
* OAuth app creation and updates now require scopes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
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>
## What kind of change does this PR introduce?
Shared UI pattern and Studio UX improvement.
## What is the current behavior?
Async selectors use bespoke loading and error layouts. Some replace the
entire field while fetching, and opening a selector does not
consistently refresh its options.
## What is the new behavior?
Adds shared loading, error, and empty states for Select, command, and
MultiSelector lists, including a persistent polite live region and
reduced-motion support. Analytics Bucket and DuckLake selectors keep
their controls in place, retain populated options during background
refreshes, and refresh when reopened.
## To test
Open the [Replication
preview](https://studio-staging-git-dnywh-featasync-selection-feedback-supabase.vercel.app/dashboard/project/_/database/replication?destinationType=Analytics%20Bucket).
The destination sheet should already be open on **Analytics Bucket**.
You do not need to create a bucket, configure a destination, or start a
pipeline. Open **Select a bucket**, then review these outcomes:
1. **The trigger stays put.** Opening the picker must not replace the
form field with a full-width loading placeholder.
2. **Loading belongs inside the menu.** While options are fetched, the
open menu shows a compact skeleton list.
3. **No resources has a clear explanation.** If the project has no
Analytics Buckets, the menu says **No buckets available**. It still
offers **Create a new bucket** beneath that message.
4. **Existing options do not disappear on refresh.** If the project does
have buckets, close and reopen the picker. Its current options remain
visible while the refresh happens in the background, rather than
flashing back to skeletons.
5. **The pattern is consistent.** If convenient, select a bucket and
open the namespace or access-key picker. The same in-menu loading,
empty, and error treatment applies there too.
The deterministic request-error and reduced-motion cases are covered by
focused unit tests because the deploy preview cannot reliably force
those states.
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
A/B test for the plan-change side panel
(`/org/_/billing?panel=subscriptionPlan`) — gated behind PostHog flag
`pricingPanelPlanPresentation` (multivariate, 3 arms).
The current panel drops `description`, `preface`, and `footer` from
`shared-data/plans.ts` and uses a much smaller type scale than the www
pricing page, so the two surfaces look unrelated and plan differences
are hard to reason about. This experiment tests whether matching the www
style and surfacing plan gaps improves upgrade conversion.
| Variant | Surface |
| --- | --- |
| `control` | Current panel — no change (baseline cohort, still tracked)
|
| `parity` | www pricing page style: mono uppercase heading,
description, CTA above price, large mono price, preface ("Everything in
the Free Plan, plus:"), 13px features |
| `gaps` | `parity` + gap rows at the bottom showing what the plan is
missing (✗ Daily backups, ✗ Email support, dimmed ✓ 1-day log retention)
|
## Variants
Control
<img width="3520" height="2394" alt="Arc 2026-08-26 16 14 09"
src="https://github.com/user-attachments/assets/95464e83-b377-4754-85ee-c65dce0206c7"
/>
Parity
<img width="3520" height="2394" alt="Arc 2026-08-26 16 14 01"
src="https://github.com/user-attachments/assets/f50e66e2-7cbe-4e65-b1fb-083efd79ff00"
/>
Gaps
<img width="3520" height="2394" alt="Arc 2026-08-26 16 29 48"
src="https://github.com/user-attachments/assets/fbb08a12-1b76-4ce5-9247-20a6e8399be3"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a refreshed subscription plan selector with pricing,
descriptions, features, exclusions, and plan-specific messaging.
* Added upgrade and downgrade actions with loading states and
eligibility-based controls.
* Added plan comparison views highlighting missing and lower-tier
features.
* Added tailored handling for enterprise plans and supported billing
arrangements.
* Improved accessibility by respecting reduced-motion preferences during
plan highlights.
* **Tests**
* Expanded coverage for plan eligibility, feature comparisons, and
presentation variants.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: kemal <hello@kemal.earth>
## What kind of change does this PR introduce?
Change the update billing email component so it uses the update customer
endpoint instead of the update org endpoint. This allows users that have
the BILLING_WRITE permission to use the endpoint to update relevant
organization data, while keeping the restrictions of the update
organization endpoint that allow updating other values (e.g. the org
name).
This change requires an update in the Update Customer endpoint to
support billing email updates. Do not merge until that is deployed.
## What is the current behavior?
- Admins are not allowed to update the billing emails of an
organization.
- The update organization endpoint (`PATCH
/platform/organizations/{slug}/`) is used to update the billing email
details.
## What is the new behavior?
- Both admin and owners are allowed to update the billing email details.
- The update customer endpoint (`PUT
/platform/organizations/{slug}/customer`) is used to update the billing
email details.
### Additional Context
[Platform PR](https://github.com/supabase/platform/pull/37145), needs to
be deployed first.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Billing email settings now use customer profile information.
* Added support for updating primary and additional billing email
addresses.
* Billing customer details now display address and billing name
information.
* **Bug Fixes**
* Prevented unrelated billing profile fields from being overwritten
during updates.
* Billing forms now synchronize correctly when customer profile data
changes.
* Removed unnecessary organization name requirements from billing
profile updates.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Update the API types by running `api:codegen`. Some of the changes are
fixed in code, some of the type changes had to be reverted (JIT Access,
SSO features).
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Billing**
* Updated subscription messaging to reflect AWS Marketplace billing.
* Removed outdated partner-billing downgrade notices.
* **Bug Fixes**
* Improved request handling for API keys, custom domains, SQL snippets,
branches, and storage operations.
* Improved legacy signing-key compatibility.
* Refined temporary database access availability messaging.
* **Updates**
* Removed Fly as an available cloud provider for region selection.
<!-- 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>
## Context
There's a chance users may run into tax ID issues when upgrading a plan
as such:
<img width="412" height="120" alt="image"
src="https://github.com/user-attachments/assets/4c559ae0-d942-4c10-b83a-c5944a2a49ee"
/>
Adding a CTA here to guide users and mitigate confusion on how to
proceed to remediate
<img width="399" height="147" alt="image"
src="https://github.com/user-attachments/assets/3bcaca14-bd77-4168-b9ab-cd6b75f79e24"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved billing-profile validation feedback by standardizing error
messaging for tax ID vs. billing address country mismatches.
* Added an in-toast “Update tax ID” action to guide users directly to
the fix.
* Updated the billing dialog’s close behavior so it returns users to the
relevant address section (including scrolling to it automatically).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Downgrading to Free tier is blocked server-side when an org has an
active branch, but the resulting error toast in `ExitSurveyModal.tsx`
used the default 4s toast duration, making it easy to miss.
- Adds `duration: 10_000, dismissible: true`, matching the pattern
already used for other important billing error toasts
(`org-subscription-update-mutation.ts`, `NewOrgForm.tsx`).
Fixes FE-3882
## Test plan
- [ ] Attempt to downgrade an org with an active branch to Free tier and
confirm the error toast stays visible for 10s and can be dismissed
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved the downgrade error message to stay visible longer and be
easier to dismiss, making failures clearer for users.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
App-level fixes that reproduce on BOTH the Next and TanStack builds —
split out of #47657 (which stays TanStack-only) for reviewability. All
were found by a full-site click-through of the dashboard.
## Invalid HTML nesting (React 19 "will cause a hydration error" console
errors)
- **FormLayout description rendered in a `<p>`**
(`packages/ui-patterns`): consumers pass arbitrary JSX (the RowEditor's
`created_at` timezone note passes a `<div>` with `<p>`s) →
`<p>`-in-`<p>` / `<div>`-in-`<p>`. Container is now a `<div>` with
identical classes (Tailwind preflight makes them render the same).
- **Switch toggles nested inside Tooltip trigger buttons**
(button-in-button) in ColumnEditor ("Allow Nullable" + "Is Unique"),
ExtensionRow, and PublicationsTableItem → repo-standard `TooltipTrigger
asChild` + `<div>` wrapper.
- **Saved log queries rendered a `<div>` directly inside `<tbody>`**
(`/logs/explorer/saved`) → rows are now proper `<tr><td colSpan>`
wrappers; the component itself is untouched (it's valid in its sidebar
usage).
- **Nested anchors in observability metric cards**: a card-level
`<Link>` wrapped MetricCard's "More information" `<Link>` (identical
URLs) → the chevron affordance renders as a `<span>` when no `href` is
passed; clicks bubble to the card link, tooltips preserved.
Design-system standalone usage unaffected.
- **`objectFit="cover"` passed to modern `next/image`** on the featured
integration card (unknown-prop warning) — the className already had
`object-cover`; prop dropped.
## Ghost dead-snippet after deletion
Deleting the active SQL snippet left its id in `useDashboardHistory`
(`history.sql`), so the "SQL Editor" nav item navigated to
`/sql/<deleted-id>` — content fetch 404s, no editor pane renders, and a
phantom tab reappears. Fixed both ends: delete flows now purge dashboard
history (and the tabs store clears a stale `previewTabId`), and
`/sql/[id]` treats a snippet 404 as "clean up + `router.replace` to
`/sql/new` + toast" instead of rendering the dead state. Unit tests for
the store/history cleanup.
## `pg-meta` migrations query 400s on every project load
`ActivityStats` on project home runs the migrations list query, whose
SQL was a bare `select * from supabase_migrations.schema_migrations` —
that table only exists once a migration has run, so every other project
logged a failed `?key=migrations` request on every load (visible in
production consoles too). The SQL is now guarded with `to_regclass` +
`query_to_xml` (same pattern as the advisor lints' `storage.buckets`
guard), returning zero rows instead of erroring; legacy version-only
tables still work. Tested against real dockerized Postgres (absent
table, populated ordering, special chars, legacy schema) + MSW hook
tests.
Found and verified via /test-supabase-local (browser click-through +
console audit on both builds).
## To test
Console must stay free of React DOM-nesting errors ("cannot be a
descendant of" / "cannot contain a nested") on each surface:
1. Table editor → Insert row panel (`created_at` field renders its
timezone note) and Edit column panel ("Allow Nullable"/"Is Unique"
tooltips still hover).
2. `/database/extensions` and `/database/publications` → toggle switches
render, tooltips hover.
3. `/logs/explorer/saved` (with ≥1 saved query) → rows render full-width
inside the table, hover shows Actions.
4. `/observability` → no nested-anchor error on load; card body click
and the chevron both navigate; label help-icons still show tooltips.
5. `/integrations` → no `objectFit` unknown-prop warning; featured card
images still cover.
6. **Ghost snippet**: open a SQL snippet → delete it via the sidebar →
click the "SQL Editor" nav item → lands on `/sql/new` (no phantom tab,
no 404 content fetch). Direct-load `/sql/<random-uuid>` → toast +
redirect to `/sql/new`.
7. **Migrations 400**: load project home with a project that has never
run a migration → the `pg-meta/<ref>/query?key=migrations` request
returns **200** with `[]` (previously a 400 on every load). Database →
Migrations still lists real migrations when they exist.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Summary by CodeRabbit
* **Bug Fixes**
* Deleted SQL snippets are fully removed from dashboard history and
stale editor/tab state; users are redirected with a toast.
* Closing preview tabs no longer leaves stale references.
* Improved toggle/tooltip/dialog interactions to avoid broken UI,
including metric headers showing tooltips even without direct links.
* Migrations display safely when migration tables/relations are missing.
* **UI Improvements**
* Refreshed layout for saved queries, form descriptions, and integration
imagery.
* **Tests**
* Added coverage for snippet history cleanup, tab removal, migrations
SQL behavior, and query edge cases.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---
### Review feedback: `query_to_xml` breaks on Multigres (Ivan)
The defensive migrations query (added here to stop the `?key=migrations`
400 when the table doesn't exist yet) originally guarded with
`query_to_xml`, which is forbidden through Multigres's pooler (MUL-736 /
PSQL-1318). Rewritten without `query_to_xml`/`xmltable` using the
splinter#170 pattern: a PL/pgSQL `do` block guarded by `to_regclass`
(PL/pgSQL defers planning, so a missing table never errors) stashes the
rows into a transaction-local GUC via `set_config`, and a trailing
`select` reads them back with `jsonb_array_elements`. Verified that
postgres-meta sends the whole SQL as one simple-query string → single
implicit transaction → the local GUC survives to the `select` and
doesn't leak into the pooled connection. 6/6 dockerized-Postgres tests
(absent table → `[]`, populated/ordered/special-chars, legacy
version-only table, full pg-meta-shaped multi-statement string, GUC
non-leakage).
Note (out of scope, pre-existing):
`packages/pg-meta/src/sql/studio/advisor/lints.ts` still uses
`query_to_xml` — a separate pre-existing Multigres risk that should get
its own splinter-pattern sync.
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: Saxon Fletcher <saxonafletcher@gmail.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 -->
**Stack 1/6** of the TanStack Start migration (#46424), split into
reviewable, independently-mergeable PRs.
> [!IMPORTANT]
> **Next stays the default and only active framework after this PR.**
This wires up the Vite/TanStack-Start build pipeline behind the
`STUDIO_FRAMEWORK` flag, but there are no TanStack routes yet — so the
TanStack build isn't functional or tested until later PRs in the stack.
Nothing about the Next build, dev, or deploy changes behaviourally here.
## What's in this PR
- **Dispatch:** `dev`/`build`/`start` now go through
`scripts/dispatch.js`, which runs the Next variant unless
`STUDIO_FRAMEWORK=tanstack`. The original commands are preserved as
`dev:next`/`build:next`/`start:next`.
- **Build pipeline:** `vite.config.ts`, `serve.js`, `smoke-server.mjs`,
vite/tanstack deps, `turbo.jsonc`.
- **`tsconfig.json`:** `jsx: react-jsx`, `moduleResolution: Bundler`,
`target: ES2022`. Because `include` is `**/*.ts(x)`, this re-typechecks
the whole app, so the companion adaptations below land with it.
- **Shared adaptations (companions to the tsconfig change):**
`BufferSource` casts, `packages/ui` unused-`React` import removals, etc.
- **Routing/middleware plumbing:** `next.config.ts` +
`redirects.shared.ts` (redirect rules now shared with `vercel.ts`),
`proxy.ts`/`start.ts` middleware + `hosted-api-allowlist.ts`.
## Verification
Run locally off `master`: frozen install ✓, `studio` typecheck ✓, **Next
build ✓** (compiles + generates all routes), lint ratchet ✓ ("some rules
improved"), prettier ✓.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a hosted API endpoint allowlist to return 404 for non-supported
`/api/*` routes.
* Introduced a TanStack route-migration checklist and expanded TanStack
Start routing support.
* **Improvements**
* Enhanced deployment refresh/detection by tightening cookie handling
for “latest deployment” updates.
* Centralized redirect/maintenance-mode rules for consistent platform vs
self-hosted behavior.
* Improved production serving with a dedicated static + proxy server and
a post-build smoke test.
* **Dependencies**
* Updated TanStack-related packages and React Table/query tooling
versions.
* **Documentation / Chores**
* Updated formatting and tooling config; added shared build environment
parsing utilities.
<!-- 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>
Replaced the `DowngradeModal`'s `AlertDialog` with a normal `Dialog`,
since `AlertDialog` won't close if you click outside the modal by
design.
Left is current PR, right is staging:
<img width="1600" height="537" alt="Screenshot 2026-06-18 at 10 07 46"
src="https://github.com/user-attachments/assets/ce1bcc17-d1c9-4fcd-ad3b-f2fcfd8824f6"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Updated the downgrade confirmation modal to use the newer dialog UI
components.
* Preserved the existing warning and checklist content (including
project impact and email/reset notices) and kept the same confirm/cancel
behavior and disabled state handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
## 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>
The usage page link in the UpcomingInvoice billing breakdown used the
incorrect path, resulting in a 404. Corrected to to match the rest of
the app.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Corrected the usage page link shown in the billing breakdown tooltip
for non-compute items so it now points to the proper /org/... URL,
ensuring users are taken to the correct usage page from billing
documentation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Extracts the Cancellation Flow from the subscriptions side panel and
adds a new button that initiates the flow (old journey is still
possible):
(screenshots see below)
Verified manually:
- ✅ confirmed the old downgrade flow works, Team -> Pro; Pro -> Free
- ✅ confirmed the new downgrade flow works
- ✅ button does not show up when on free plan; no flicker
- ✅ button does not show up on enterprise/platform plan
- ✅ verified button is disabled when managed by AWS marketplace
(hardcoded in `useSelectedOrganizationQuery`)
- ✅ verified button is disabled if `canUpdateSubscriton` is false,
hardcoded in `useAsyncCheckPermissions`
- ✅ modal for exceeding-free-projects shows up
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a guided subscription cancellation flow with confirmation steps,
member/usage checks, and an exit survey.
* Exposed a visible "Cancel Subscription" control in billing settings,
enabled/disabled with contextual tooltip messaging.
* **Improvements**
* Downgrade/exit survey confirm action can be disabled when appropriate;
exit survey confirm label updated to "Downgrade Now".
* **Chores**
* Added frontend telemetry for cancellation button interactions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Studio is on `react@^19.2.6`, and `useEffectEvent` shipped stable in
React 19.2 with the same signature as the userland polyfill. This drops
the local hook in `apps/studio` and `apps/www` in favor of the built-in.
**Removed:**
- `apps/studio/hooks/useStaticEffectEvent.ts`
- `apps/www/hooks/useStaticEffectEvent.ts`
- `.claude/skills/use-static-effect-event/` — skill is obsolete
**Changed:**
- 26 call sites: dropped the `useStaticEffectEvent` import, added
`useEffectEvent` to the existing `react` import, renamed call sites
- `.claude/CLAUDE.md`: `apps/studio` row updated React 18 → React 19
- `.claude/skills/vercel-composition-patterns/SKILL.md`: removed stale
"Studio uses React 18, skip these patterns" warning
## To test
- `pnpm typecheck --filter=studio` — passes locally
- `pnpm typecheck --filter=www` — passes locally
- `grep -rn "useStaticEffectEvent"` returns nothing outside
`node_modules`
- Smoke-test areas that use the hook: schema visualizer edges
(intersection check), spreadsheet import, sign-in/CLI login flows, side
panels with unsaved-changes prompts
**Out of scope:** pre-existing Tailwind lint warning on
`DefaultEdge.tsx:141` (`outline` + `outline-1` conflict) — unrelated to
this migration
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Internal event handling migrated to React’s built-in event hooks
across the Studio app; no user-facing changes.
* **Documentation**
* Clarified React 19 compatibility and noted Studio now targets React
19.
* Removed obsolete documentation for a deprecated internal hook.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46415?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 -->
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
## What kind of change does this PR introduce?
Feature / abuse-prevention update. Resolves DEPR-198.
## What is the current behaviour?
Free projects using Supabase's built-in email service can edit raw Auth
email template subjects and HTML in Studio. That is the risky cohort
this project is trying to constrain.
## What is the new behaviour?
### Template editing restrictions
For free projects using Supabase's built-in email service, Studio keeps
Auth email templates viewable and previewable but disables subject/body
editing and saving. Editing is unlocked by setting up Custom SMTP,
configuring a send-email hook, or upgrading to a paid plan.
**Grandfathering:** projects created before `2026-06-01T00:00:00Z` (the
platform enforcement cutoff) are exempt; their editing UI stays
unlocked. This mirrors `FREE_TIER_TEMPLATE_BLOCK_CUTOFF_DATE` in the
platform PR exactly.
| After |
| --- |
| <img width="1024" height="759" alt="Emails Authentication Fizz Test
Supabase-173BB09B-0FB9-4133-8202-9E310DDB347A"
src="https://github.com/user-attachments/assets/c966212d-ed0c-443b-8197-440cc2937ef6"
/> |
| <img width="1024" height="759" alt="Emails Authentication Fizz Test
Supabase-CD5845EB-0E45-4779-8989-44E775B2411A"
src="https://github.com/user-attachments/assets/055a64d6-b5e8-4d37-a261-6e280f04536a"
/> |
### Warning dialogs on transitions that reset templates
Two flows now surface a warning before the user commits to a state
change that resets their custom email templates to defaults:
1. **Disabling custom SMTP** (SMTP settings page): a confirmation dialog
warns that templates will be reset to defaults and the email rate limit
reduced to 2 per hour. On confirm, Studio resets all 13 templates via
the existing per-template reset endpoint (`Promise.allSettled`). The
"won't be able to edit" sentence is shown only for post-cutoff projects;
grandfathered projects skip it. The corresponding server-side
enforcement is in the Platform PR:
https://github.com/supabase/platform/pull/33129
2. **Downgrading to the Free plan** (billing settings): an admonition in
the existing downgrade confirmation modal warns that custom templates
will be reset to defaults and won't be editable without custom SMTP. The
admonition is shown only when the org has at least one post-cutoff
project; orgs whose projects are all grandfathered skip it.
| Custom SMTP | Downgrading |
| --- | --- |
| <img width="862" height="586" alt="66764"
src="https://github.com/user-attachments/assets/6470c8a6-2f79-40a5-ad3b-bfe5b0ba9c54"
/> | <img width="1268" height="1552" alt="CleanShot 2026-05-22 at 17 28
37@2x-FEB1901E-38E6-42DF-8C27-0A036D8A1B94"
src="https://github.com/user-attachments/assets/e8caa9e6-c3ed-4787-b771-af77a43eb854"
/> |
### Informational admonition when enabling SMTP
When a user enables custom SMTP for the first time, a sandwiched
admonition above the save footer informs them that the email rate limit
will be increased to 30 per hour and can be adjusted.
_This is just a minor cosmetic change, unrelated to the email template
disabling. Sorry._
| Before | After |
| --- | --- |
| <img width="1024" height="759" alt="Emails Authentication Chisel
Toolshed Supabase-54317D18-803C-4A58-8211-2359355D083B"
src="https://github.com/user-attachments/assets/29eff649-02dc-40f3-a379-0b4d484a76c7"
/> | <img width="1024" height="759" alt="Emails Authentication Chisel
Toolshed Supabase-9E12399E-E9FB-4F9A-B029-A08008EA4B50"
src="https://github.com/user-attachments/assets/e542ed86-4da6-407e-8293-0f4c0f071e18"
/> |
## How to test
All existing projects pre-date the enforcement cutoff
(`2026-06-01T00:00:00Z`) and are grandfathered, so the restriction UI
won't appear by default. To force the restricted state locally,
back-date the cutoff in one file:
In
`apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.utils.ts`,
temporarily change:
```ts
export const FREE_TIER_TEMPLATE_BLOCK_CUTOFF_DATE = '2026-06-01T00:00:00Z'
```
to:
```ts
export const FREE_TIER_TEMPLATE_BLOCK_CUTOFF_DATE = '2025-01-01T00:00:00Z'
```
Revert before committing. With the cutoff back-dated, use a free-plan
project and:
- **Template restriction + admonition:** navigate to Authentication >
Emails with no custom SMTP configured. Subject/body fields should be
read-only and the "Set up SMTP" admonition should appear, with its
dropdown offering upgrade and send-email hook options.
- **SMTP disable warning:** enable custom SMTP on a project, then
disable it via Authentication > SMTP Settings. The confirmation dialog
should warn that templates will reset to defaults and that editing will
be restricted after disabling.
- **Downgrade warning:** in billing settings, initiate a downgrade to
the Free plan. The downgrade modal should include an admonition warning
about template reset and restricted editing (only if the org has at
least one post-cutoff project).
## Additional context
The default Auth email template copy was also improved across docs,
examples, and UI library snippets (separate prior commits).
The per-template reset button (`ResetTemplateDialog`) was migrated to
the async `AlertDialogAction` pattern introduced in #45960; the dialog
stays open and shows a loading state while the reset is in-flight,
closes on success, and stays open on error.
Closes PRODSEC-183
---------
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Stephen Morgan <stephen@doublethink.co.nz>
## Summary
I migrated every `useSendEventMutation` call site in `apps/studio` to
`useTrack`, deleted the legacy hook, and added a lint guardrail so it
can't return. `useTrack` is the type-safe replacement: it auto-injects
`groups: { project, organization }` from the selected project/org and
types `action` + `properties` against `TelemetryEvent`. Existing call
sites built groups manually and were not type-checked at the action
level. The migration covers 81 files (60 trivial swaps, 9 org-only, 3
pre-auth, 5 bespoke, 4 test mocks).
## Changes
- Migrated trivial call sites across `pages/project/[ref]`,
`components/interfaces/*` (Reports, Storage, Realtime/Inspector,
SQLEditor, Functions, EdgeFunctions, Integrations, ProjectAPIDocs,
Branching/BranchManagement, TableGridEditor, Connect, Docs, Auth,
Support, Home, ProjectHome, App), `components/layouts/*`, and
`components/ui/*`.
- Migrated org-only sites (`Organization/Documents/*`,
`Organization/BillingSettings/Subscription/*`,
`Organization/SecuritySettings.tsx`,
`Account/Preferences/DashboardSettingsToggles.tsx`) by dropping the
manual `groups: { organization: ... }` and letting `useTrack`
auto-inject. Verified `useSelectedProjectQuery` is disabled on org
routes (gates on URL `[ref]`).
- Migrated pre-auth sites (`SignInForm.tsx`, `sign-in-mfa.tsx`,
`profile.tsx`) where neither project nor org is resolved.
- Bespoke handling:
- `execute-sql-mutation.ts` and `table-row-create-mutation.ts`: pass `{
project: projectRef }` via `groupOverrides` since the mutation can
target a non-selected project ref.
- `useStudioCommandMenuTelemetry.ts`: kept a direct `sendTelemetryEvent`
call because studio groups must override pre-built event groups
(opposite of `useTrack`'s override direction).
- `AIAssistantOption.tsx`: passes sentinel-aware `groupOverrides` so
`NO_PROJECT_MARKER`/`NO_ORG_MARKER` continue to suppress group emission.
- `SidePanelEditor.utils.tsx`: utility functions `createTable` and
`updateTable` now take a `track: Track` parameter (threaded from
`SidePanelEditor.tsx`); dropped the `organizationSlug` arg since groups
are no longer assembled manually.
- Branch-event attribution: preserved `parentProjectRef` overrides on
`branch_updated`, `branch_merge_completed`, `branch_merge_failed`,
`branch_merge_submitted`, `branch_delete_button_clicked`,
`branch_review_with_assistant_clicked`, and
`branch_*_merge_request_button_clicked`. Original code grouped these
under the parent (production) project, not the branch ref;
auto-injection would have shifted them onto the branch.
- Switched 4 test mocks from `@/data/telemetry/send-event-mutation` to
`@/lib/telemetry/track`. Removed obsolete tests around manual groups and
`try/catch` on telemetry rejection.
- Deleted `apps/studio/data/telemetry/send-event-mutation.ts`. The
deleted module is its own guardrail: any reintroduction of the import
fails at TypeScript module resolution before lint runs.
## Testing
Tested on preview deploy:
- [x] SQL editor `CREATE TABLE` fires `table_created` with method
`sql_editor` and `groups.project` set to the mutation's `projectRef`.
- [x] Table editor creates a table from the side panel; `table_created`
fires from `SidePanelEditor.utils` via threaded `track`.
- [x] Help button (`/project/[ref]/...`) fires `help_button_clicked`
with auto-injected project + org groups.
- [x] Sign-in form fires `sign_in` with empty groups (pre-auth,
expected).
- [x] Org documents page (`/org/[slug]/documents`) fires
`document_view_button_clicked` with org group only, no stale project
ref.
- [x] Command menu (`Cmd+K`) inside a project still fires
`command_menu_opened` with studio's project/org overriding any
event-supplied groups.
- [x] Support form "Ask the Assistant" without selected org fires
`ai_assistant_in_support_form_clicked` with no project/org groups
(sentinels suppress).
- [x] On a branch, "Update branch" / "Merge branch" / "Close merge
request" events fire with `groups.project` set to the parent project
ref, not the branch ref.
Local checks:
- [x] 22/22 tests pass across the 4 updated test files
(`SidePanelEditor.utils.createTable`, `EdgeFunctionRenderer`,
`LayoutSidebar`, `PlanUpdateSidePanel`).
- [x] `rg useSendEventMutation apps/studio` returns 0 hits.
## Linear
- fixes GROWTH-860
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Standardized telemetry across the Studio to a unified tracking system;
events now send simplified payloads with less contextual/grouping data.
* No user-facing flows changed; UI behavior, permissions, and
interactions remain the same.
* **Tests**
* Updated telemetry mocks and tests to align with the new tracking
approach.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46140?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
Organization settings still uses the deprecated `Modal` for:
- downgrading subscription
- requesting feedback after downgrading
- showing an alert about members limit
- requesting feedback after upgrading
- deleting a published OAuth app
- showing preview of a new OAuth app
- Revoking an OAuth app
## Solution
- use `Dialog` instead
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Replaced legacy modal UI with the app's modern dialog/alert-dialog
components across billing and OAuth settings (upgrade/downgrade, exit
survey, members-limit, delete/revoke, preview), keeping existing content
and flows.
* Confirm/cancel flows updated for more reliable async handling and
clearer loading/disabled states during actions.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46332?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 `Select` components
## Solution
Remove it. No other changes
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Updated internal component architecture to standardize and simplify
the codebase. These changes improve code maintainability and consistency
across the application without affecting existing functionality or user
experience.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45988)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
- Most changes are related to either types or `useRef` usages (it now
requires an initial value).
- also updated `vaul` to its latest version and haven't noticed any
change ([design-system
demo](https://design-system-git-react-19-supabase.vercel.app/design-system/docs/components/drawer))
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Upgraded workspace to React 19.
* **Bug Fixes**
* Improved null-safety and ref handling across editors, UI components,
shortcuts, and markdown/image rendering to reduce runtime errors.
* Safer event/timeout/interval cleanup and more robust command/context
handling.
* **Chores**
* Bumped vaul dependency versions.
* **Documentation**
* Type and TypeScript accuracy improvements for clearer developer
feedback.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45886)
<!-- 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 -->
Related PR: https://github.com/supabase/supabase/pull/45803
Opting for a simpler way to prevent requesting billing owners for
downgrading of plan as such:
<img width="933" height="258" alt="image"
src="https://github.com/user-attachments/assets/604b8c2f-9341-4aec-885c-e2d9d2861b9f"
/>
Currently we're incorrectly showing a "Request to upgrade to Free" CTA
## To test
- [ ] For a pro plan or above organization, and a user that has a
"Developer" role, ensure that you're not able to downgrade the org nor
send a upgrade request
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Clarified CTA behavior for users without billing update permission:
downgrade actions now show a disabled button with an explicit tooltip,
while non-downgrade upgrade attempts prompt a request to billing owners.
Tooltip messaging has been refined across enterprise, free-tier, and
marketplace-managed plans for clearer guidance.
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45823)
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
We have multiple `Collapsible` components.
## Solution
Reduce their number by using only the one from shadcn.
I haven't noticed any visual nor functional changes.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Migrated expandable/collapsible UI to a unified shadcn-based
implementation for more consistent expand/collapse behavior across the
app.
* **Style**
* Updated listbox check icon sizing and removed obsolete collapsible
open/close animations.
* **Chores**
* Removed deprecated collapsible variants and consolidated UI component
surface for simpler maintenance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->